Use RxJava to continuously update the control status during page Switching

Source: Internet
Author: User

Use RxJava to continuously update the control status during page Switching

In application development, we need to useBackground taskUpdateFront-End InterfaceDoes not start again due to page switching, or the interface is refreshed due to some tasks blocking, such as displaying the download or playback progress. in order to pursue a better user experience, a large number of background tasks are required. Common examples are AsyncTask and backend services, and RxJava. I wrote an example to illustrate how to use these common background methods.

Main
(1) Use asynchronous tasks and background services to update pages to avoid Memory leakage.
(2) Use RxJava's time interval \ delayed sending \ custom iteration to process Background tasks and save the sending status.

Example: rotate the screen update progress bar to save and retrieve the page status when the page is destroyed and new pages are created.

1. Basics

Gradle configuration: Lambda expression + Butterknife + RxJava + LeakCanary.
Page Layout: select the usage mode for the Spinner, And the ProgressBar displays the update status. You can choose to start LeakCanary.

Main logic:
(1) Use Fragment to store page information, including asynchronous tasks, RxJava observers and topics.

// Set the storage Fragment FragmentManager fm = getFragmentManager (); mRetainedFragment = (RetainedFragment) fm. findFragmentByTag (RETAINED_FRAGMENT); if (mRetainedFragment = null) {mRetainedFragment = new RetainedFragment (); fm. beginTransaction (). add (mRetainedFragment, RETAINED_FRAGMENT ). commit ();}

(2) When the page is rebuilt, It is restored in onResume and continues to update the progress bar.

@ Override protected void onResume () {super. onResume (); // whether to include memory leakage if (mSTrackLeaks. isChecked () {LeakCanary. install (getApplication ();} mMode = mRetainedFragment. getMode (); mCustomAsyncTask = mRetainedFragment. getCustomAsyncTask (); mObservable = mRetainedFragment. getObservable (); mSubject = mRetainedFragment. getSubject (); mSubscriber = createSubscriber (); switch (mMode) {case ASYNC_TASK: if (m CustomAsyncTask! = Null) {if (! MCustomAsyncTask. isCompleted () {mCustomAsyncTask. setActivity (this);} else {mRetainedFragment. setCustomAsyncTask (null) ;}} break; case TIME_INTERVAL: if (mObservable! = Null) {mObservable. subscribeOn (Schedulers. io ()). observeOn (AndroidSchedulers. mainThread ()). take (MAX_PROGRESS ). map (x-> x + 1 ). subscribe (mSubscriber);} break; case DELAY_EMIT: if (mObservable! = Null) {mObservable. subscribeOn (Schedulers. io ()). delay (1, TimeUnit. SECONDS ). observeOn (AndroidSchedulers. mainThread ()). subscribe (mSubscriber);} break; case CUSTOM_ITERATOR: if (mSubject! = Null) {mSubject. subscribe (mSubscriber);} default: break;} setBusy (mRetainedFragment. isBusy ());}

Life cycle: onCreate-> onRestoreInstanceState-> onResume.
SetActivity is set in onResume: When the page is rotated, the onRestoreInstanceState method is executed to restore the data saved before the screen is rotated, that is, the value of mPbProgressBar, and then restore the status. if it is set during onCreate, the Progress value is 0, because the Activity does not start to restore the previous data.

2. asynchronous tasks

Start the exception task AsyncTask. In doInBackground, call publishProgress to display the progress and trigger the onProgressUpdate callback to update the progress bar.

Public class CustomAsyncTask extends AsyncTask
  
   
{Private WeakReference
   
    
MActivity; // weak reference Activity to prevent memory leakage private boolean mCompleted = false; // whether the Activity is completed // set the activity control ProgressBar public void setActivity (MainActivity Activity) {mActivity = new WeakReference <> (activity) ;}// determine whether public boolean isCompleted () {return mCompleted ;}@ Override protected Void doInBackground (Void... params) {for (int I = 1; I <MainActivity. MAX_PROGRESS + 1; I ++) {SystemClock. sleep (MainActivity. EMIT_DELAY_MS); // pause time publishProgress (I); // AsyncTask method, call onProgressUpdate, indicating completion status} return null;} @ Override protected void onProgressUpdate (Integer... progress) {mActivity. get (). setProgressValue (progress [0]); // update the value of ProgressBar mActivity. get (). setProgressPercentText (progress [0]); // set the text} @ Override protected void onPreExecute () {mActivity. get (). setProgressText ("START asynchronous task... "); // prepare to start mCompleted = false;} @ Override protected void onPostExecute (Void result) {mCompleted = true; // end mActivity. get (). setBusy (false); mActivity. get (). setProgressValue (0 );}}
   
  

Note that WeakReference is used to weakly reference the Activity. Because the thread collection is not stable, if the Activity is held, the Activity cannot be released for a long time, resulting in Memory leakage.

Usage

// Handle asynchronous thread click private void handleAsyncClick () {// obtain asynchronous thread mCustomAsyncTask = new CustomAsyncTask (); mCustomAsyncTask. setActivity (this); // stores the asynchronous thread mRetainedFragment. setCustomAsyncTask (mCustomAsyncTask); // executes the asynchronous thread mCustomAsyncTask.exe cute ();}

Stores asynchronous tasks. When the screen is rotated, the page is rebuilt and the current progress can be read and updated.

2. Background services

Transmits the current status through the Intent of LocalBroadcastManager to update the page.

public class CustomService extends IntentService {    public static final String KEY_EXTRA_BUSY = "busy";    public static final String KEY_EXTRA_PROGRESS = "progress";    private LocalBroadcastManager mLbm;    public CustomService() {        super(CustomService.class.getSimpleName());    }    @Override protected void onHandleIntent(Intent intent) {        mLbm = LocalBroadcastManager.getInstance(getApplicationContext());        Intent broadcastIntent = new Intent(MainActivity.UPDATE_PROGRESS_FILTER);        broadcastIntent.putExtra(KEY_EXTRA_BUSY, true);        mLbm.sendBroadcast(broadcastIntent);        for (int i = 1; i < MainActivity.MAX_PROGRESS + 1; ++i) {            broadcastIntent = new Intent(MainActivity.UPDATE_PROGRESS_FILTER);            broadcastIntent.putExtra(KEY_EXTRA_PROGRESS, i);            mLbm.sendBroadcast(broadcastIntent);            SystemClock.sleep(MainActivity.EMIT_DELAY_MS);        }        broadcastIntent = new Intent(MainActivity.UPDATE_PROGRESS_FILTER);        broadcastIntent.putExtra(KEY_EXTRA_BUSY, false);        broadcastIntent.putExtra(KEY_EXTRA_PROGRESS, 0);        mLbm.sendBroadcast(broadcastIntent);    }}

Usage method: first judge the progress, and then judge the status.

Private void handleIntentServiceClick () {mTvProgressText. setText ("START message service... "); Intent intent = new Intent (this, CustomService. class); startService (intent );}... private BroadcastReceiver mUpdateProgressReceiver = new BroadcastReceiver () {@ Override public void onReceive (Context context, Intent intent) {if (intent. hasExtra (CustomService. KEY_EXTRA_PROGRESS) {int progress = intent. getIntExtra (CustomService. KEY_EXTRA_PROGRESS, 0); mPbProgressBar. setProgress (progress); setProgressPercentText (progress);} if (intent. hasExtra (CustomService. KEY_EXTRA_BUSY) {setBusy (intent. getBooleanExtra (CustomService. KEY_EXTRA_BUSY, false ));}}};
3. RxJava

There are many ways to update the RxJava progress bar. You can use the time interval, delayed sending, and custom iterator. However, if you need to process the continuous update of page reconstruction, you need to store PublishSubject, you can use the custom iterator.

Time Interval: When the page is rotated, the data is refreshed and restarted.
Delayed sending: When you rotate the page, the previous sending will be completed and then restarted.
Custom iteration: Continuous updates can be completed normally when pages are rotated.

Interval

Private void handleTimeIntervalClick () {mTvProgressText. setText ("Start Time Interval... "); mSubscriber = createSubscriber (); mObservable = Observable. interval (1, TimeUnit. SECONDS); mObservable. subscribeOn (Schedulers. io ()). observeOn (AndroidSchedulers. mainThread ()). take (MAX_PROGRESS ). map (x-> x + 1 ). subscribe (mSubscriber); mRetainedFragment. setObservable (mObservable );}

Observable. interval observer, take termination condition, map data processing.

Delayed sending

Private void handleDelayEmitClick () {mTvProgressText. setText ("START delayed launch... "); mSubscriber = createSubscriber (); mObservable = createObservable (); mObservable. subscribeOn (Schedulers. io ()). observeOn (AndroidSchedulers. mainThread ()). subscribe (mSubscriber); mRetainedFragment. setObservable (mObservable );}

When the observer sends data, it will delay one second, namely SystemClock. sleep.

// Create a delay observer private Observable
  
   
CreateObservable () {return Observable. create (new Observable. OnSubscribe
   
    
() {@ Override public void call (Subscriber
    Subscriber) {for (long I = 1; I <MAX_PROGRESS + 1; I ++) {SystemClock. sleep (EMIT_DELAY_MS); subscriber. onNext (I);} subscriber. onCompleted ();}});}
   
  

Customizes the iterator and stores PublishSubject in RetainedFragment.

Private void handleCustomIteratorClick () {mTvProgressText. setText ("start to customize iterator... "); mObservable = Observable. from (new CustomIterator (); mSubscriber = createSubscriber (); mSubject = PublishSubject. create (); mObservable. subscribeOn (Schedulers. io ()). observeOn (AndroidSchedulers. mainThread ()). subscribe (mSubject); mSubject. subscribe (mSubscriber); mRetainedFragment. setObservable (mObservable); mRetainedFragment. setSubject (mSubject );}

Customizes the iterator, overwrites the next method, and returns data.

Public class CustomIterator implements Iterable
  
   
{Private List
   
    
MNumberList = new ArrayList <> (); public CustomIterator () {for (long I = 0; I <MainActivity. MAX_PROGRESS; I ++) {mNumberList. add (I + 1) ;}@override public Iterator
    
     
Iterator () {return new Iterator
     
      
() {Private int mCurrentIndex = 0; @ Override public boolean hasNext () {return mCurrentIndex <mNumberList. size () & mNumberList. get (mCurrentIndex )! = Null;} @ Override public Long next () {SystemClock. sleep (MainActivity. EMIT_DELAY_MS); return mNumberList. get (mCurrentIndex ++);} // @ Override public void remove () {throw new UnsupportedOperationException () ;}}} is not allowed ();}};}}
     
    
   
  

Effect Animation

In comparison, the use of asynchronous tasks may easily cause memory leakage, and the scalability is relatively small, suitable for simple updates; the use of background services is heavy and requires additional processes, suitable for complex data processing, it is not suitable for page update. RxJava is easy to expand and can control the release time, which is a good choice.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.