diff --git a/app/build.gradle b/app/build.gradle index e9b0320..a4c5b6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -136,7 +136,6 @@ dependencies { implementation libs.converter.scalars implementation libs.logger - implementation libs.eventbus } // OpenAPI Generator Configuration diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index fb53bc4..74f1594 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,12 +20,12 @@ -if interface * { @retrofit2.http.* ; } -keep,allowobfuscation interface <1> -## EventBus +## EventBus (Flow-based) -keepattributes *Annotation* -keepclassmembers class * { - @org.greenrobot.eventbus.Subscribe ; + @info.nukoneko.cuc.android.kidspos.di.Subscribe ; } --keep enum org.greenrobot.eventbus.ThreadMode { *; } +-keep enum info.nukoneko.cuc.android.kidspos.di.ThreadMode { *; } #------ Gson ------- -keep class info.nukoneko.cuc.android.kidspos.entity.** { *; } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/App.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/App.kt index ecfe211..826f83f 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/App.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/App.kt @@ -10,8 +10,8 @@ import info.nukoneko.cuc.android.kidspos.di.module.viewModelModule import info.nukoneko.cuc.android.kidspos.event.EventBus import info.nukoneko.cuc.android.kidspos.event.SystemEvent import okhttp3.Interceptor -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode +import info.nukoneko.cuc.android.kidspos.di.Subscribe +import info.nukoneko.cuc.android.kidspos.di.ThreadMode import org.koin.android.ext.android.inject import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/di/EventBusImpl.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/di/EventBusImpl.kt index 06dc23e..5efe254 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/di/EventBusImpl.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/di/EventBusImpl.kt @@ -2,18 +2,91 @@ package info.nukoneko.cuc.android.kidspos.di import info.nukoneko.cuc.android.kidspos.event.Event import info.nukoneko.cuc.android.kidspos.event.EventBus +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch +import java.lang.reflect.Method +import java.util.concurrent.ConcurrentHashMap class EventBusImpl : EventBus { - private val bus = org.greenrobot.eventbus.EventBus.getDefault() + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + private val _events = MutableSharedFlow(replay = 0, extraBufferCapacity = 64) + private val events: SharedFlow = _events.asSharedFlow() + + private val subscribers = ConcurrentHashMap() + + override fun post(event: Event) { + scope.launch { + _events.emit(event) + } + } + override fun register(obj: Any?) { - bus.register(obj) + obj?.let { subscriber -> + val methods = findSubscribeMethods(subscriber::class.java) + if (methods.isNotEmpty()) { + val job = scope.launch { + events.collect { event -> + if (subscribers.containsKey(subscriber)) { + methods.forEach { method -> + val parameterType = method.parameterTypes.firstOrNull() + if (parameterType?.isAssignableFrom(event::class.java) == true) { + try { + method.isAccessible = true + method.invoke(subscriber, event) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + } + } + subscribers[subscriber] = SubscriberInfo(methods, job) + } + } } override fun unregister(obj: Any?) { - bus.unregister(obj) + obj?.let { subscriber -> + subscribers.remove(subscriber)?.job?.cancel() + } } - override fun post(event: Event) { - bus.post(event) + private fun findSubscribeMethods(clazz: Class<*>): List { + val methods = mutableListOf() + var currentClass: Class<*>? = clazz + + while (currentClass != null) { + currentClass.declaredMethods.forEach { method -> + if (method.isAnnotationPresent(Subscribe::class.java)) { + if (method.parameterTypes.size == 1 && + Event::class.java.isAssignableFrom(method.parameterTypes[0])) { + methods.add(method) + } + } + } + currentClass = currentClass.superclass + } + + return methods } -} \ No newline at end of file + + private data class SubscriberInfo( + val methods: List, + val job: Job + ) +} + +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class Subscribe(val threadMode: ThreadMode = ThreadMode.MAIN) + +enum class ThreadMode { + MAIN +} diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainViewModel.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainViewModel.kt index 5b67aaf..06bdb8f 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainViewModel.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainViewModel.kt @@ -15,8 +15,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode +import info.nukoneko.cuc.android.kidspos.di.Subscribe +import info.nukoneko.cuc.android.kidspos.di.ThreadMode import java.io.IOException import kotlin.coroutines.CoroutineContext diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListViewModel.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListViewModel.kt index 1491fc1..fcdeed5 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListViewModel.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListViewModel.kt @@ -12,8 +12,8 @@ import info.nukoneko.cuc.android.kidspos.event.BarcodeEvent import info.nukoneko.cuc.android.kidspos.event.EventBus import info.nukoneko.cuc.android.kidspos.event.SystemEvent import info.nukoneko.cuc.android.kidspos.util.Mode -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode +import info.nukoneko.cuc.android.kidspos.di.Subscribe +import info.nukoneko.cuc.android.kidspos.di.ThreadMode class ItemListViewModel( private val config: GlobalConfig, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 293e3a2..b40e709 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,6 @@ retrofit-client = { module = "com.squareup.retrofit2:retrofit", version.ref = "r retrofit-converter-serialization = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit-kotlin-serialization-converter" } logger = { module = "com.orhanobut:logger", version = "2.2.0" } -eventbus = { module = "org.greenrobot:eventbus", version = "3.2.0" } [plugins] android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }