Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
renetik committed Jul 28, 2023
1 parent cc47c90 commit 5522cef
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 168 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package renetik.android.event.common

fun CSHasDestruct.destruct() = onDestruct()
import renetik.android.core.java.util.concurrent.background
import renetik.android.event.registration.task.CSBackground
import renetik.android.event.registration.task.CSBackground.executor

fun CSHasDestruct.destruct() = onDestruct()
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package renetik.android.event.registration

import androidx.annotation.AnyThread
import androidx.annotation.WorkerThread
import renetik.android.core.lang.Func
import renetik.android.event.registration.CSRegistration.Companion.CSRegistration
import renetik.android.event.registration.task.CSBackground.background

//TODO: Can CSHasDestruct.background bew used instead without memory leak reports ?
@AnyThread
inline fun CSHasRegistrations.registerBackground(
@WorkerThread crossinline function: Func,
): CSRegistration = register(background {
function()
cancel(it)
})
@WorkerThread crossinline function: Func
) = registerBackground(after = 0, function)

//TODO: Can CSHasDestruct.background bew used instead without memory leak reports ?
@AnyThread
inline fun CSHasRegistrations.registerBackground(
after: Int, @WorkerThread crossinline function: () -> Unit,
): CSRegistration {
lateinit var registration: CSRegistration
registration = register(background(after) {
function()
cancel(registration)
})
return CSRegistration { if (!registration.isCanceled) cancel(registration) }
}
Original file line number Diff line number Diff line change
@@ -1,60 +1,13 @@
package renetik.android.event.registration

import androidx.annotation.AnyThread
import renetik.android.core.lang.CSHandler.mainHandler
import renetik.android.core.lang.CSHandler.main
import renetik.android.event.registration.CSRegistration.Companion.CSRegistration
import renetik.android.event.registration.task.CSBackground.background

//@AnyThread
//fun CSHasRegistrations.registerLater(
// after: Int = 0, function: () -> Unit,
//): CSRegistration {
// lateinit var registration: CSRegistration
// registration = register(later(if (after < 10) 10 else after) {
// cancel(registration)
// function()
// })
// return CSRegistration { if (!registration.isCanceled) cancel(registration) }
//}

//@Deprecated("Can we use instead later extension on HasDestroy ?")
//@AnyThread
//fun CSHasRegistrations.registerLater(
// function: () -> Unit,
//): CSRegistration {
// lateinit var registration: CSRegistration
// registration = register(later(10) {
// cancel(registration)
// function()
// })
// return CSRegistration { if (!registration.isCanceled) cancel(registration) }
//}

@AnyThread
fun CSHasRegistrations.registerLaterEach(
after: Int, period: Int = after, function: () -> Unit,
): CSRegistration {
val registration = register(mainHandler.laterEach(after, period, function))
val registration = register(main.laterEach(after, period, function))
return CSRegistration { cancel(registration) }
}

//@AnyThread
//fun <T : CSHasRegistrations> T.registerOnMain(
// function: (T).() -> Unit,
//): CSRegistration? = if (currentThread.isMain) {
// function()
// null
//} else registerLater { function(this) }

@AnyThread
fun CSHasRegistrations.registerBackground(
delay: Int, function: () -> Unit,
): CSRegistration {
lateinit var registration: CSRegistration
registration = register(background(if (delay < 10) 10 else delay) {
function()
cancel(registration)
})
return CSRegistration { if (!registration.isCanceled) cancel(registration) }
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ inline fun Handler.laterEach(
if (!registration.isCanceled) {
if (registration.isActive) function()
if (!registration.isCanceled) postAtTime(
runnable,
token,
uptimeMillis() + period.toLong()
runnable, token, uptimeMillis() + period.toLong()
)
}
}
Expand All @@ -30,40 +28,7 @@ inline fun Handler.laterEach(
return registration
}

//fun laterEach(
// after: Int, period: Int = after, function: () -> Unit
//): CSRegistration = mainHandler.laterEach(after, period, function)

// Worked good:
//fun Handler.repeat(
// delay: Int, period: Int = delay, function: Func
//): CSRegistration {
// val token = object {}
// var isCanceled = false
// var weakRunnable: Func? by weak()
// val runnable = {
// if (!isCanceled) {
// function()
// if (!isCanceled){
//// weakRunnable?.let { postAtTime(it, period.toLong()) }
// weakRunnable?.let { postAtTime(it, token, uptimeMillis() + period.toLong()) }
// }
// }
// }
// weakRunnable = runnable
//// weakRunnable?.let { postDelayed(it, delay.toLong()) }
// weakRunnable?.let { postAtTime(it, token, uptimeMillis() + delay.toLong()) }
// return CSRegistration {
// isCanceled = true
//// weakRunnable?.let { removeCallbacks(it) }
// removeCallbacksAndMessages(token)
// }
//}

//TODO: Why we have this another special later ?
inline fun Handler.later(
after: Int, crossinline function: Func
): CSRegistration {
inline fun Handler.later(after: Int, crossinline function: Func): CSRegistration {
val token = object {}
var isCanceled = false
postAtTime({ if (!isCanceled) function() }, token, uptimeMillis() + after.toLong())
Expand All @@ -73,22 +38,12 @@ inline fun Handler.later(
}
}

//fun later(after: Int, function: () -> Unit): CSRegistration =
// mainHandler.later(after, function)

//fun Handler.later(
// after: Int, function: Func
//): CSRegistration {
// var isCanceled = false
// val runnable: Func = { if (!isCanceled) function() }
// val weakRunnable: Func? by weak(runnable)
// postDelayed(weakRunnable!!, after.toLong())
// return CSRegistration {
// isCanceled = true
// removeCallbacks(runnable)
// }
//}




inline fun Handler.later(crossinline function: Func): CSRegistration {
val token = object {}
var isCanceled = false
postAtTime({ if (!isCanceled) function() }, token, uptimeMillis())
return CSRegistration(isActive = true) {
isCanceled = true
removeCallbacksAndMessages(token)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package renetik.android.event.registration.task

import android.os.Handler
import android.os.HandlerThread
import androidx.annotation.WorkerThread
import renetik.android.core.java.util.concurrent.background
import renetik.android.core.java.util.concurrent.backgroundRepeat
import renetik.android.core.java.util.concurrent.backgroundEach
import renetik.android.core.java.util.concurrent.cancelNotInterrupt
import renetik.android.core.java.util.concurrent.shutdownAndWait
import renetik.android.event.common.CSHasDestruct
Expand All @@ -16,10 +14,6 @@ import java.util.concurrent.ScheduledFuture

object CSBackground {

val handler: Handler by lazy {
HandlerThread("CSBackground handler").run { start(); Handler(looper) }
}

var executor: ScheduledExecutorService = newScheduledThreadPool(3)
private set

Expand All @@ -30,29 +24,32 @@ object CSBackground {
fun restart() {
shutdownBackground()
executor = newScheduledThreadPool(3)
// executor = newSingleThreadScheduledExecutor()
}

inline fun background(
after: Int = 0, @WorkerThread crossinline function: (CSRegistration) -> Unit,
): CSRegistration {
lateinit var task: ScheduledFuture<*>
val registration = CSRegistration(isActive = true) { task.cancelNotInterrupt() }
var task: ScheduledFuture<*>? = null
val registration = CSRegistration(isActive = true) { task?.cancelNotInterrupt() }
task = executor.background(after.toLong()) {
if (registration.isActive) function(registration)
}
if (registration.isCanceled && !task.isCancelled) task.cancel(true)
return CSRegistration(isActive = true) { task.cancelNotInterrupt() }
}

inline fun backgroundRepeat(
interval: Int, delay: Int = interval, @WorkerThread crossinline function: () -> Unit,
): ScheduledFuture<*> =
executor.backgroundRepeat(delay.toLong(), interval.toLong(), function)

inline fun backgroundRepeat(
interval: Int, @WorkerThread crossinline function: () -> Unit,
): ScheduledFuture<*> =
executor.backgroundRepeat(interval.toLong(), function)
inline fun backgroundEach(
after: Int, period: Int = after,
crossinline function: (CSRegistration) -> Unit,
): CSRegistration {
var task: ScheduledFuture<*>? = null
val registration = CSRegistration(isActive = true) { task?.cancelNotInterrupt() }
task = executor.backgroundEach(period.toLong(), after.toLong()) {
if (registration.isActive) function(registration)
}
if (registration.isCanceled && !task.isCancelled) task.cancel(true)
return registration
}

inline fun CSHasDestruct.background(crossinline function: () -> Unit) {
background(after = 0, function)
Expand All @@ -61,19 +58,5 @@ object CSBackground {
inline fun CSHasDestruct.background(after: Int = 0, crossinline function: () -> Unit) {
executor.background(after.toLong()) { if (!isDestructed) function() }
}

// I was getting "lateinit property registration has not been initialized" this is fail safe..
inline fun CSHasDestruct.backgroundRepeat(
interval: Int, after: Int = interval,
crossinline function: (CSRegistration) -> Unit,
): CSRegistration {
var task: ScheduledFuture<*>? = null
val registration = CSRegistration { task?.cancel(true) }
task = executor.backgroundRepeat(interval.toLong(), after.toLong()) {
if (!isDestructed) function(registration)
}
if (registration.isCanceled && !task.isCancelled) task.cancel(true)
return registration
}
}

31 changes: 10 additions & 21 deletions library/src/main/java/renetik/android/event/util/CSLater.kt
Original file line number Diff line number Diff line change
@@ -1,46 +1,35 @@
package renetik.android.event.util

import renetik.android.core.java.lang.isThreadMain
import renetik.android.core.lang.CSHandler.mainHandler
import renetik.android.core.lang.CSHandler.postOnMain
import renetik.android.core.kotlin.primitives.min
import renetik.android.core.lang.CSHandler.main
import renetik.android.core.lang.send
import renetik.android.event.common.CSHasDestruct
import renetik.android.event.registration.CSHasRegistrations
import renetik.android.event.registration.CSRegistration
import renetik.android.event.registration.CSRegistration.Companion.CSRegistration
import renetik.android.event.registration.cancel
import renetik.android.event.registration.later
import renetik.android.event.registration.laterEach
import renetik.android.event.registration.register

object CSLater {
inline fun later(
after: Int, crossinline function: () -> Unit
): CSRegistration = mainHandler.later(after) { function() }

inline fun later(
crossinline function: () -> Unit
): CSRegistration = later(5, function)

// TODO: Move to CSHasDestruct+MainHandler
inline fun CSHasDestruct.later(crossinline function: () -> Unit) =
postOnMain { if (!isDestructed) function() }
main.send { if (!isDestructed) function() }

// TODO: Move to CSHasDestruct+MainHandler
inline fun CSHasDestruct.onMain(crossinline function: () -> Unit) =
if (isThreadMain) function()
else postOnMain { if (!isDestructed) function() }
else main.send { if (!isDestructed) function() }

// = CSLater.later(after) { if (!isDestructed) function() }
// TODO: Move to CSHasRegistrations+MainHandler
inline fun CSHasRegistrations.later(
after: Int, crossinline function: () -> Unit
): CSRegistration {
lateinit var registration: CSRegistration
registration = register(mainHandler.later(if (after < 10) 10 else after) {
cancel(registration)
function()
registration = register(main.later(after.min(10)) {
cancel(registration); function()
})
return CSRegistration { if (!registration.isCanceled) cancel(registration) }
}

inline fun laterEach(
after: Int, period: Int = after, crossinline function: () -> Unit
): CSRegistration = mainHandler.laterEach(after, period, function)
}
8 changes: 5 additions & 3 deletions library/src/test/java/renetik/android/event/CSLaterTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.shadows.ShadowLooper.runUiThreadTasksIncludingDelayedTasks
import renetik.android.event.util.CSLater.later
import renetik.android.core.lang.CSHandler.main
import renetik.android.core.lang.send
import renetik.android.event.registration.later

@RunWith(RobolectricTestRunner::class)
class CSLaterTest {
@Test
fun testUnregisteredAfterNilled() {
var count = 0
later { count++ }
main.send { count++ }
runUiThreadTasksIncludingDelayedTasks()
assertEquals(1, count)

val registration = later {
val registration = main.later {
count++
}
registration.cancel()
Expand Down

0 comments on commit 5522cef

Please sign in to comment.