Why do lifecycle management

Using RxJava this library development has been for many years, from the beginning of the use to now also experienced a lot of stages, the middle also encountered a lot of problems, today we have a good chat on the life cycle of RxJava.

  • How to use RxJava?
Observable.create<String> {   
    // do something
    it.onNext("")
    it.onComplete()
}        
    .subscribeOn(Schedulers.io())      
    .observeOn(AndroidSchedulers.mainThread())      
    .subscribe({  
        // onNext
    }, {           
        // onError
    })
Copy the code
  • This is a simple asynchronous processing, but it can’t be done just like this, because during Android development, if you are doing a time-consuming operation and the operation is not finished, then you can exit the current Activity. The processing of this code does not end with the exit of the Activity, which can cause problems such as memory leaks and, in severe cases, even the APP to flash back.

How do you manage the life cycle

So how do you manage the RxJava life cycle? RxJava provides us with the CompositeDisposable class for managing RxJava.

val disposable = Observable.create<String> {   
    // do something
    it.onNext("")
    it.onComplete()
}        
    .subscribeOn(Schedulers.io())      
    .observeOn(AndroidSchedulers.mainThread())      
    .subscribe({  
        // onNext
    }, {           
        // onError
    })
val disposables = CompositeDisposable()
disposables.add(disposable)
disposables.clear()
Copy the code
  • Every time I useRxJavaWill generate itDisposableObject added toCompositeDisposableObject, and at the end of each interfaceCompositeDisposableThe object’sclear()Method to cancel the event.
  • In newer versionsRxJavaDuring use, we will find that if there is no onsubscribeMethod to process,studioI would have issued an amber alert becauseRxJavasubscribeMethod adds@CheckReturnValueAnnotation, asking us to process its return value.

This is my first phase of processing, adding CompositeDisposable every time I use RxJava and processing it in the Activity’s onDestroy method.

The first version of easy administration

It follows from the above processing that the related operations are encapsulated in a base class, providing a method addDisposable to add RxJava requests to lifecycle management. Later, using the ViewModel in Google Jetpack, we put the final cleared action into the onCleared method of the ViewModel.

  • However, these treatments have one problem in common, and that is a lack of elegance.
addDisposable(
    Observable.create<String> {   
        // do something
        it.onNext("")
        it.onComplete()
    }        
        .subscribeOn(Schedulers.io())      
        .observeOn(AndroidSchedulers.mainThread())      
        .subscribe({  
            // onNext
        }, {           
            // onError}))val disposable = Observable.create<String> {   
    // do something
    it.onNext("")
    it.onComplete()
}        
    .subscribeOn(Schedulers.io())      
    .observeOn(AndroidSchedulers.mainThread())      
    .subscribe({  
        // onNext
    }, {           
        // onError
    })
addDisposable(disposable)
Copy the code
  • Every time in useRxJavaIs calledaddDisposableOnce or twice is nothing, but if the project is used too much, it will feel tedious, so I have the idea to optimize it.
  • The first idea is how to make it complete the lifecycle management binding in the process of chain calls.
  • This would require us to add methods to the RxJava class, which is of course not possible in Java development. We cannot modify the RxJava source code, but in Kotlin we can use extension methods to achieve this effect.
  • First, to manage the lifecycle uniformly, we need to extract the lifecycle management-related methods into an interface:
interface RxLifecycleOwner {   
    /** RxJ lifecycle management */   
    var disposables: CompositeDisposable?   
    
    /** * Add Rx to lifecycle management */   
    fun addDisposable(dis: Disposable){ disposables? .add(dis) }/** * processes all events added to lifecycle management */   
     fun disposeAll(a){ disposables? .clear() disposables =null}}Copy the code
  • Methods of interfaces in Kotlin can be implemented by default.
  • Then add the extension method:
/** * Subscribe and associate lifecycle management **@paramOwner Rx Lifecycle management interface *@paramOnNext Event handling *@paramOnComplete event completes *@paramOnSubscribe Event subscription * *@return[Disposable] Event object */
fun <T> Observable<T>.subscribeWithOwner(owner: RxLifecycleOwner,                                        
                                                            onNext: Consumer<T> = Functions.emptyConsumer(),                                      
                                                            onError: Consumer<Throwable> = Functions.ON_ERROR_MISSING,                            
                                                            onComplete: Action = Functions.EMPTY_ACTION,                     
                                                            onSubscribe: Consumer<Disposable> = Functions.emptyConsumer()
): Disposable {    
    val disposable = this.subscribe(onNext, onError, onComplete, onSubscribe)   
    owner.addDisposable(disposable)    
    return disposable
}

/** * Subscribe and associate lifecycle management **@paramOwner Rx Lifecycle management interface *@paramObserver The observer object */
fun <T> Observable<T>.subscribeWithOwner(owner: RxLifecycleOwner,      
                                                            observer: Observer<T>) {    
    this.subscribe(object : Observer<T> {        
        override fun onComplete(a) {          
            observer.onComplete()        
        }        
        override fun onSubscribe(d: Disposable) {    
            observer.onSubscribe(d)          
            owner.addDisposable(d)     
        }       
        override fun onNext(t: T) {     
            observer.onNext(t)    
        }        
        override fun onError(e: Throwable) {     
            observer.onError(e)     
        }   
    })
}
Copy the code
  • When used, only implementation is requiredRxLifecycleOwnerInterface and initializeCompositeDisposableObjects will do.
class BaseViewModel
    : ViewModel(), RxLifeCycleOwner {
    
    /** Rx lifecycle management */
    override var disposables: CompositeDisposable? = CompositeDisposable()
    
    override fun onCleared(a) {    
         // Handle Rx events
         disposeAll()
    }
}

class MainViewModel : BaseViewModel() {

    fun doSomething(a) {
        Observable.create<String> {   
            // do something
            it.onNext("")
            it.onComplete()
        }        
         .subscribeOn(Schedulers.io())      
         .observeOn(AndroidSchedulers.mainThread())      
         .subscribeWithOwner(this, {  
                 // onNext
         }, {           
                // onError}}})Copy the code
  • This completes the first release, requiring no extra code each time RxJava is used, and life cycle management can be chain-called.

The second version of easy administration

After the above operation, we have to simplify the RxJava lifecycle management, but still feel complicated how to do, why every use of RxLifecycleOwner interface to implement oh, every time to manually cancel the event, so troublesome look, is there a better solution? At this time, LiveData gave me inspiration.

  • As we all know,LiveDataIt’s life cycle aware. He has one inside himLifecycleBoundObserverClass, by implementationLifecycleEventObserverThe interface implements the pairThe Activity and fragmentsLife cycle perception,LifecycleEventObserverThere areonStateChangedThe method will be inThe Activity and fragmentsAfter the lifecycle method is called back, the next operation is then performed.
/** * Rx lifecycle observer **@paramLifecycleOwner Android lifecycle management interface */
class RxLifecycleObserver(lifecycleOwner: LifecycleOwner) : LifecycleEventObserver, RxLifecycleOwner {   
    override var disposables: CompositeDisposable? = null   
    
    init {       
        disposables = CompositeDisposable()       
        // Add the current observer object to Android lifecycle management
        lifecycleOwner.lifecycle.addObserver(this)}override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {   
        if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {   
            // The lifecycle goes to onDestroy, consuming all events
            disposeAll()         
            // Remove the observer
            source.lifecycle.removeObserver(this)       
            // Remove the reference from the collection
            rxLifecycles.remove(source)    
        }  
    }
}
Copy the code
  • You might not be able to find it in some placesLifecycleOwner, but there is a need for life cycle management, so it is retainedRxLifecycleOwnerInterface.
/** * HashMap object, save Rx, Android life cycle management object */
internal val rxLifecycles = hashMapOf<LifecycleOwner, RxLifecycleObserver>()

/** * Get the Rx lifecycle management object ** based on the Android lifecycle object@paramOwner Android life cycle object * *@returnRx lifecycle management object */
internal fun getObserver(owner: LifecycleOwner): RxLifecycleObserver {  
    var observer: RxLifecycleObserver?  
    if (rxLifecycles.containsKey(owner)) {       
        // The collection already contains the observer object
        observer = rxLifecycles[owner]     
        if(observer ! =null) {     
            // And is not empty, returns the existing observer object
            return observer       
        }   
    }   
    // If no existing observer exists, create a new observer object
    observer = RxLifecycleObserver(owner)  
    // Add to Map collection for reuse
    rxLifecycles[owner] = observer   
    return observer
}
Copy the code
  • Use Map collections to hold observer objects for reuse.
/** * Subscribe and associate lifecycle management **@paramOwner Android Life cycle interface *@paramOnNext Event handling *@paramOnComplete event completes *@paramOnSubscribe Event subscription * *@return[Disposable] Event object */
fun <T> Observable<T>.subscribeWithOwner(owner: LifecycleOwner,                                      
                                                            onNext: Consumer<T> = Functions.emptyConsumer(),                                     
                                                            onError: Consumer<Throwable> = Functions.ON_ERROR_MISSING,                                
                                                            onComplete: Action = Functions.EMPTY_ACTION,                                
                                                            onSubscribe: Consumer<Disposable> = Functions.emptyConsumer()
): Disposable {  
    val disposable = this.subscribe(onNext, onError, onComplete, onSubscribe)    
    getObserver(owner).addDisposable(disposable)   
    return disposable
}

/** * Subscribe and associate lifecycle management **@paramOwner Android Life cycle interface *@paramObserver The observer object */
fun <T> Observable<T>.subscribeWithOwner(owner: LifecycleOwner,     
                                                            observer: Observer<T>) {   
    this.subscribe(object : Observer<T> {     
        override fun onComplete(a) {    
            observer.onComplete()     
        }      
        override fun onSubscribe(d: Disposable) {      
            observer.onSubscribe(d)       
            getObserver(owner).addDisposable(d)    
        }     
        override fun onNext(t: T) {   
            observer.onNext(t)     
        }      
        override fun onError(e: Throwable) {        
            observer.onError(e)   
        } 
    })
}
Copy the code
  • It’s easier to use.
class MainActivity : AppCompatActivity() {
    
    fun doSomething(a) {
        Observable.create<String> {   
            // do something
            it.onNext("")
            it.onComplete()
        }        
         .subscribeOn(Schedulers.io())      
         .observeOn(AndroidSchedulers.mainThread())      
         .subscribeWithOwner(this, {  
                 // onNext
         }, {           
                // onError}}})Copy the code
  • Used in Activity.
class BaseViewModel : ViewModel(), LifecycleEventObserver {

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {    
        when (event) {      
            Lifecycle.Event.ON_CREATE -> onCreate(source)     
            Lifecycle.Event.ON_START -> onStart(source)      
            Lifecycle.Event.ON_RESUME -> onResume(source)     
            Lifecycle.Event.ON_PAUSE -> onPause(source)     
            Lifecycle.Event.ON_STOP -> onStop(source)      
            Lifecycle.Event.ON_DESTROY -> onDestroy(source)      
            Lifecycle.Event.ON_ANY -> {    
            }   
        }
    }
}

class MainViewModel : BaseViewModel() {

    override fun onCreate(source: LifecycleOwner) {
        Observable.create<String> {   
                // do something
                it.onNext("")
                it.onComplete()
            }        
             .subscribeOn(Schedulers.io())      
             .observeOn(AndroidSchedulers.mainThread())      
             .subscribeWithOwner(source, {  
                     // onNext
             }, {           
                    // onError}}})Copy the code

The last

  • There you have it, a complete RxJava lifecycle processing, less than 300 lines of code.
  • Welcome to Github address here.