diff --git a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/ConnectivityOnLifecycle.kt b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/ConnectivityOnLifecycle.kt index efdf3951..c1b6c717 100644 --- a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/ConnectivityOnLifecycle.kt +++ b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/ConnectivityOnLifecycle.kt @@ -4,6 +4,7 @@ package com.tinder.scarlet.lifecycle.android +import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -12,12 +13,15 @@ import android.net.ConnectivityManager import com.tinder.scarlet.Lifecycle import com.tinder.scarlet.LifecycleState import com.tinder.scarlet.lifecycle.LifecycleRegistry +import java.lang.Exception internal class ConnectivityOnLifecycle( - applicationContext: Context, - private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry() + private val applicationContext: Context, + private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry() ) : Lifecycle by lifecycleRegistry { + private val connectivityChangeBroadcastReceiver = ConnectivityChangeBroadcastReceiver() + init { emitCurrentConnectivity(applicationContext) subscribeToConnectivityChange(applicationContext) @@ -25,16 +29,16 @@ internal class ConnectivityOnLifecycle( private fun emitCurrentConnectivity(applicationContext: Context) { val connectivityManager = - applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager lifecycleRegistry.onNext(toLifecycleState(connectivityManager.isConnected())) } private fun subscribeToConnectivityChange(applicationContext: Context) { - val intentFilter = IntentFilter() - .apply { addAction(ConnectivityManager.CONNECTIVITY_ACTION) } - applicationContext.registerReceiver(ConnectivityChangeBroadcastReceiver(), intentFilter) + val intentFilter = IntentFilter().apply { addAction(ConnectivityManager.CONNECTIVITY_ACTION) } + applicationContext.registerReceiver(connectivityChangeBroadcastReceiver, intentFilter) } + @SuppressLint("MissingPermission") private fun ConnectivityManager.isConnected(): Boolean { val activeNetworkInfo = activeNetworkInfo return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting @@ -46,6 +50,13 @@ internal class ConnectivityOnLifecycle( LifecycleState.Stopped } + fun unregisterReceiver() { + try { + applicationContext.unregisterReceiver(connectivityChangeBroadcastReceiver) + } catch (e: Exception) { + } + } + private inner class ConnectivityChangeBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val extras = intent.extras ?: return @@ -54,3 +65,4 @@ internal class ConnectivityOnLifecycle( } } } + diff --git a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerResumedLifecycle.kt b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerResumedLifecycle.kt index 70ad2364..e665c86a 100644 --- a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerResumedLifecycle.kt +++ b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerResumedLifecycle.kt @@ -12,28 +12,27 @@ import com.tinder.scarlet.LifecycleState import com.tinder.scarlet.lifecycle.LifecycleRegistry internal class LifecycleOwnerResumedLifecycle( - private val lifecycleOwner: LifecycleOwner, - private val lifecycleRegistry: LifecycleRegistry -) : Lifecycle by lifecycleRegistry { + private val lifecycleOwner: LifecycleOwner, + private val lifecycleRegistry: LifecycleRegistry +) : LifecycleObserver, Lifecycle by lifecycleRegistry { init { - lifecycleOwner.lifecycle.addObserver(ALifecycleObserver()) + lifecycleOwner.lifecycle.addObserver(this) } - private inner class ALifecycleObserver : LifecycleObserver { - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_PAUSE) - fun onPause() { - lifecycleRegistry.onNext(LifecycleState.Stopped) - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_PAUSE) + fun onPause() { + lifecycleRegistry.onNext(LifecycleState.Stopped) + } - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_RESUME) - fun onResume() { - lifecycleRegistry.onNext(LifecycleState.Started) - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_RESUME) + fun onResume() { + lifecycleRegistry.onNext(LifecycleState.Started) + } - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_DESTROY) - fun onDestroy() { - lifecycleRegistry.onComplete() - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_DESTROY) + fun onDestroy() { + lifecycleRegistry.onComplete() + lifecycleOwner.lifecycle.removeObserver(this) } } diff --git a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerStartedLifecycle.kt b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerStartedLifecycle.kt index 08c0dfa0..36099136 100644 --- a/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerStartedLifecycle.kt +++ b/scarlet-lifecycle-android/src/main/java/com/tinder/scarlet/lifecycle/android/LifecycleOwnerStartedLifecycle.kt @@ -12,28 +12,27 @@ import com.tinder.scarlet.LifecycleState import com.tinder.scarlet.lifecycle.LifecycleRegistry internal class LifecycleOwnerStartedLifecycle( - private val lifecycleOwner: LifecycleOwner, - private val lifecycleRegistry: LifecycleRegistry -) : Lifecycle by lifecycleRegistry { + private val lifecycleOwner: LifecycleOwner, + private val lifecycleRegistry: LifecycleRegistry +) : LifecycleObserver, Lifecycle by lifecycleRegistry { init { - lifecycleOwner.lifecycle.addObserver(ALifecycleObserver()) + lifecycleOwner.lifecycle.addObserver(this) } - private inner class ALifecycleObserver : LifecycleObserver { - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_STOP) - fun onPause() { - lifecycleRegistry.onNext(LifecycleState.Stopped) - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_STOP) + fun onPause() { + lifecycleRegistry.onNext(LifecycleState.Stopped) + } - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_START) - fun onResume() { - lifecycleRegistry.onNext(LifecycleState.Started) - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_START) + fun onResume() { + lifecycleRegistry.onNext(LifecycleState.Started) + } - @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_DESTROY) - fun onDestroy() { - lifecycleRegistry.onComplete() - } + @OnLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_DESTROY) + fun onDestroy() { + lifecycleRegistry.onComplete() + lifecycleOwner.lifecycle.removeObserver(this) } } \ No newline at end of file diff --git a/scarlet-protocol-stomp/src/test/java/com/tindre/scarlet/stomp/StompIntegrationTest.kt b/scarlet-protocol-stomp/src/test/java/com/tindre/scarlet/stomp/StompIntegrationTest.kt index 9bcaa347..23ed0602 100644 --- a/scarlet-protocol-stomp/src/test/java/com/tindre/scarlet/stomp/StompIntegrationTest.kt +++ b/scarlet-protocol-stomp/src/test/java/com/tindre/scarlet/stomp/StompIntegrationTest.kt @@ -53,12 +53,13 @@ class StompIntegrationTest { connection1.open() connection1.client.sendText("message1") connection1.client.sendText("message2") + connection1.client.sendText("message3") connection1.clientClosure() connection2.open() LOGGER.info("${queueTextObserver.values}") - queueTextObserver.awaitCount(2) + queueTextObserver.awaitCount(3) } @Test @@ -69,6 +70,7 @@ class StompIntegrationTest { connection1.begin("tx1") connection1.send(DESTINATION, "message1", "tx1", null) connection1.send(DESTINATION, "message2", "tx1", null) + connection1.send(DESTINATION, "message3", "tx1", null) connection1.commit("tx1") connection1.disconnect() @@ -76,7 +78,7 @@ class StompIntegrationTest { val queueTextObserver = connection2.client.observeText().test() - queueTextObserver.awaitCount(2) + queueTextObserver.awaitCount(3) LOGGER.info("${queueTextObserver.values}") } diff --git a/scarlet-stream-adapter-rxjava2/src/test/java/com/tinder/scarlet/streamadapter/rxjava2/FlowableTest.kt b/scarlet-stream-adapter-rxjava2/src/test/java/com/tinder/scarlet/streamadapter/rxjava2/FlowableTest.kt index ea5a1fce..e14fdeff 100644 --- a/scarlet-stream-adapter-rxjava2/src/test/java/com/tinder/scarlet/streamadapter/rxjava2/FlowableTest.kt +++ b/scarlet-stream-adapter-rxjava2/src/test/java/com/tinder/scarlet/streamadapter/rxjava2/FlowableTest.kt @@ -38,8 +38,8 @@ internal class FlowableTest { fun send_givenConnectionIsEstablished_shouldBeReceivedByTheServer() { // Given connection.open() - val textMessage1 = "Hello" - val textMessage2 = "Hi" + val textMessage1 = "Hello!" + val textMessage2 = "Hi!" val bytesMessage1 = "Yo".toByteArray() val bytesMessage2 = "Sup".toByteArray() val testTextSubscriber = connection.server.observeText().test() diff --git a/scarlet/src/main/java/com/tinder/scarlet/lifecycle/FlowableLifecycle.kt b/scarlet/src/main/java/com/tinder/scarlet/lifecycle/FlowableLifecycle.kt index d8155b3d..802e9655 100644 --- a/scarlet/src/main/java/com/tinder/scarlet/lifecycle/FlowableLifecycle.kt +++ b/scarlet/src/main/java/com/tinder/scarlet/lifecycle/FlowableLifecycle.kt @@ -8,14 +8,45 @@ import com.tinder.scarlet.Lifecycle import com.tinder.scarlet.LifecycleState import io.reactivex.Flowable import org.reactivestreams.Publisher +import java.lang.reflect.Method internal class FlowableLifecycle( - private val flowable: Flowable + private val flowable: Flowable ) : Lifecycle, Publisher by flowable { + companion object { + const val CONNECTIVITY_ON_LIFECYCLE_CLASS_NAME = "com.tinder.scarlet.lifecycle.android.ConnectivityOnLifecycle" + const val UNREGISTER_CONNECTIVITY_BROADCAST_RECEIVER_METHOD_NAME = "unregisterReceiver" + } + override fun combineWith(others: List): Lifecycle { val lifecycles = others + this - val flowable = Flowable.combineLatest(lifecycles) { it.map { it as LifecycleState }.combine() } + + val flowable = + Flowable.combineLatest(lifecycles) { lifecycle -> + val state = lifecycle.map { it as LifecycleState }.combine() + try { + lifecycles.unregisterConnectivityBroadcastReceiver(state) + } catch (e: Exception) { + } + state + } return FlowableLifecycle(flowable) } + + private fun List.unregisterConnectivityBroadcastReceiver(state: LifecycleState) { + if (state == LifecycleState.Completed) { + val connectivityClazz: Class<*>? = Class.forName(CONNECTIVITY_ON_LIFECYCLE_CLASS_NAME) + connectivityClazz?.let { + val connectivityOnLifecycle: Lifecycle? = this.find { connectivityClazz.isInstance(it) } + connectivityOnLifecycle?.let { + val obj: Any? = connectivityClazz.cast(connectivityOnLifecycle) + val method: Method? = connectivityClazz.getMethod(UNREGISTER_CONNECTIVITY_BROADCAST_RECEIVER_METHOD_NAME) + if (obj != null && method != null) { + method.invoke(obj) + } + } + } + } + } } diff --git a/scarlet/src/main/java/com/tinder/scarlet/lifecycle/LifecycleStateUtils.kt b/scarlet/src/main/java/com/tinder/scarlet/lifecycle/LifecycleStateUtils.kt index e76270e1..f6a355c8 100644 --- a/scarlet/src/main/java/com/tinder/scarlet/lifecycle/LifecycleStateUtils.kt +++ b/scarlet/src/main/java/com/tinder/scarlet/lifecycle/LifecycleStateUtils.kt @@ -8,8 +8,11 @@ import com.tinder.scarlet.LifecycleState internal fun List.combine(): LifecycleState { val shouldStop = any { it == LifecycleState.Stopped } - if (shouldStop) { - return LifecycleState.Stopped + val completed = any { it == LifecycleState.Completed } + + return when { + shouldStop -> LifecycleState.Stopped + completed -> LifecycleState.Completed + else -> LifecycleState.Started } - return LifecycleState.Started }