This is the 21st day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

preface

Brodastcast is a very common component in Android development,

RxJava

When using RxJava, we can combine Brodastcast’s simple encapsulation with RxJava’s convenient integration into the RxJava ecosystem, for example

class BroadcastReceiverObservable @JvmOverloads constructor( val action: String, val application: Application ) : Observable<Intent>() { override fun subscribeActual(observer: Observer<in Intent>) { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == action) { observer.onNext(intent) } } } val filter = IntentFilter() filter.addAction(action) LocalBroadcastManager.getInstance(application).registerReceiver(receiver, filter) observer.onSubscribe(BroadcastReceiverDisposable(application, receiver)) } } class BroadcastReceiverDisposable( private val context: Context, private val broadcastReceiver: BroadcastReceiver ) : Disposable { private val disposed = AtomicBoolean(false) override fun isDisposed(): Boolean = disposed.get() override fun dispose() { if (! disposed.getAndSet(true)) { LocalBroadcastManager.getInstance(context).unregisterReceiver(broadcastReceiver) } } }Copy the code

It is also easy to use, but because the RxJava lifecycle needs to be maintained ourselves, we generally need to call Dispose# Dispose at specific times to avoid resource and memory leaks.

Val dispose = BroadcastReceiverObservable (ACTION, MyApp. The get ()). The subscribe (...). // Manual maintenance lifecycle dispose. Dispose ()Copy the code

Coroutine

Coroutine naturally has a life cycle. After using Koltin Coroutine, how to combine Brodastcast with Coroutine? Of course there are many ways to do this:

The simplest encapsulation is to listen for a broadcast using a suspend function:

suspend fun waitSomeCondition(action: String): Intent = suspendCancellableCoroutine<Intent> { cont -> val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context? , intent: Intent) { cont.resume(intent) LocalBroadcastManager.getInstance(context).unregisterReceiver(this) } } LocalBroadcastManager.getInstance(context).registerReceiver(receiver, IntentFilter(action)) // Coroutine cancel or normal end need to cancel registration broadcast coroutineContext[Job]? .invokeOnCompletion { LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver) } } fun foo(){ lifeScope.launch{ val passed = waitSomeCondition(ACTION).getBooleanExtra(ARG,false) } }Copy the code

Or listen for multiple broadcasts:

Use callbackFlow to convert the broadcast to flow

val action Flow = callbackFlow<Intent> { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context? , intent: Intent) { offer(intent) } } LocalBroadcastManager.getInstance(context).registerReceiver(receiver, IntentFilter (action)) / / cancellation registration invokeOnClose {LocalBroadcastManager. GetInstance (context). UnregisterReceiver (receiver)}}  fun foo(){ lifeScope.launch{ actionFlow.collect { intent -> //.... }}}Copy the code

It is also possible to use callbackFlow to encapsulate a single broadcast, simply calling close after receiving a broadcast

val action Flow = callbackFlow<Intent> { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context? , intent: Intent) { offer(intent) close() } } LocalBroadcastManager.getInstance(context).registerReceiver(receiver, IntentFilter (action)) / / cancellation registration invokeOnClose {LocalBroadcastManager. GetInstance (context). UnregisterReceiver (receiver)}}  fun foo(){ lifeScope.launch{ val intent = actions.first() } }Copy the code

conclusion

It is important to note that the broadcast is registered in a suspended function. Unlike RxJava synchronous registration, only the suspended function is executed, so our broadcast can normally receive events. We need to pay special attention to this in order to avoid missing broadcast events. Of course, there are some advantages, we do not need to manually unregister the broadcast, the end of the coroutine life, the broadcast will be automatically unregistered.

Happy ending.