Using Rxjava to continuously update the UI interface during page switching

Source: Internet
Author: User

Welcome to follow my GitHub and follow my csdn.

In the application development, we need to use background task to update the foreground interface , not because of the page switch to start again, or because some tasks blocking the interface refresh, such as display download or playback progress. In order to pursue a better user experience, you need to use a lot of background tasks, often asynchronous tasks (Asynctask) and background services (service), and of course, Rxjava. I've written an example of how to use these common background methods.

Main
(1) Update pages with asynchronous tasks and background services to avoid memory leaks.
(2) Use Rxjava time interval \ delay send \ Custom iteration, handle background task, save Send status.

Example: Rotate the screen update progress bar to save and get page state when destroying the page and creating a new page.

Source of GitHub

1. Basic

Gradle configuration: lambda expression + butterknife + RxJava + leakcanary.
Page layout: Spinner Select usage mode, ProgressBar display update status, you can choose to start leakcanary.

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

        // 设置存储的Fragment        FragmentManager fm = getFragmentManager();        mRetainedFragment = (RetainedFragment) fm.findFragmentByTag(RETAINED_FRAGMENT);        ifnull) {            new RetainedFragment();            fm.beginTransaction().add(mRetainedFragment, RETAINED_FRAGMENT).commit();        }

(2) When the page is rebuilt, resume the status in Onresume and continue to update the progress bar.

    @Override protected void Onresume() {Super. Onresume ();//Whether it contains memory leaks        if(Mstrackleaks.ischecked ())        {Leakcanary.install (getapplication ());        } Mmode = Mretainedfragment.getmode ();        Mcustomasynctask = Mretainedfragment.getcustomasynctask ();        mobservable = Mretainedfragment.getobservable ();        Msubject = Mretainedfragment.getsubject (); Msubscriber = Createsubscriber ();Switch(Mmode) { CaseAsync_task:if(Mcustomasynctask! =NULL) {if(!mcustomasynctask.iscompleted ()) {mcustomasynctask.setactivity ( This); }Else{Mretainedfragment.setcustomasynctask (NULL); }                } Break; CaseTime_interval:if(Mobservable! =NULL) {Mobservable.subscribeon (Schedulers.io ()). Observeon (androidschedulers.ma Inthread ()). Take (max_progress). Map (x, x +1). Subscribe (Msubscriber); } Break; CaseDelay_emit:if(Mobservable! =NULL) {Mobservable.subscribeon (Schedulers.io ()). Delay (1, timeunit.seconds). Observeon (Androidschedulers.mainthread ()). Subs                Cribe (Msubscriber); } Break; CaseCustom_iterator:if(Msubject! =NULL) {msubject.subscribe (msubscriber); }default: Break;    } setbusy (Mretainedfragment.isbusy ()); }

Life cycle: OnCreate, Onrestoreinstancestate, Onresume.
Set setactivity in Onresume: Because the Onrestoreinstancestate method is executed when the page is rotated, the data saved before the rotated screen is restored, that is, the value of Mpbprogressbar, and then the state is restored. If you move to set at OnCreate, it causes the progress value to be 0 because the activity does not begin to recover the previous data.

2. Asynchronous tasks

Start the exception task Asynctask, in Doinbackground, call publishprogress to show progress, trigger the onprogressupdate callback, and update the progress bar.

 Public classCustomasynctask extends Asynctask<void, Integer, void> {PrivateWeakreference<mainactivity> mactivity;//Weak reference activity to prevent memory leaks    PrivateBoolean mcompleted =false;//whether completed    //Set activity control ProgressBar     Public void setactivity(mainactivity activity) {mactivity =NewWeakreference<> (activity); }//Decide whether to complete     PublicBooleaniscompleted() {returnmcompleted; } @OverrideprotectedVoidDoinbackground(Void ...params) { for(inti =1; I < mainactivity.max_progress +1; i++) {systemclock.sleep (Mainactivity.emit_delay_ms);//Pause TimePublishprogress (i);//Asynctask method, call Onprogressupdate, indicates completion status}return NULL; } @Overrideprotected void onprogressupdate(Integer ... progress) {mactivity.Get(). Setprogressvalue (progress[0]);//Update the value of ProgressBarMactivity.Get(). Setprogresspercenttext (progress[0]);//Set text} @Overrideprotected void OnPreExecute() {mactivity.Get(). Setprogresstext ("Start asynchronous task ...");//Ready to startmcompleted =false; } @Overrideprotected void OnPostExecute(Void result) {mcompleted =true;//EndMactivity.Get(). Setbusy (false); Mactivity.Get(). Setprogressvalue (0); }}

Note Using WeakReference weak reference activity, because thread recycling is not very stable, if you hold activity, it can cause a long time to release, resulting in memory leaks.

How to use

    // 处理异步线程的点击    privatevoidhandleAsyncClick() {        // 获得异步线程        new CustomAsyncTask();        mCustomAsyncTask.setActivity(this);        // 存储异步线程        mRetainedFragment.setCustomAsyncTask(mCustomAsyncTask);        // 执行异步线程        mCustomAsyncTask.execute();    }

Store asynchronous tasks, when the screen is rotated, the page rebuilds, and the current progress can be read to continue the update.

2. Background service

The current status is transferred via Localbroadcastmanager's intent and the page is updated.

 Public  class customservice extends intentservice {     Public Static FinalString key_extra_busy ="Busy"; Public Static FinalString key_extra_progress ="Progress";PrivateLocalbroadcastmanager MLBM; Public Customservice() {Super(CustomService.class.getSimpleName ()); }@Override protected void onhandleintent(Intent Intent)        {MLBM = Localbroadcastmanager.getinstance (Getapplicationcontext ()); Intent broadcastintent =NewIntent (Mainactivity.update_progress_filter); Broadcastintent.putextra (Key_extra_busy,true); Mlbm.sendbroadcast (broadcastintent); for(inti =1; I < mainactivity.max_progress +1; ++i) {broadcastintent =NewIntent (Mainactivity.update_progress_filter);            Broadcastintent.putextra (key_extra_progress, i);            Mlbm.sendbroadcast (broadcastintent);        Systemclock.sleep (Mainactivity.emit_delay_ms); } broadcastintent =NewIntent (Mainactivity.update_progress_filter); Broadcastintent.putextra (Key_extra_busy,false); Broadcastintent.putextra (Key_extra_progress,0);    Mlbm.sendbroadcast (broadcastintent); }}

Use the method, first judge the progress, after judging the state.

    Private void Handleintentserviceclick() {Mtvprogresstext.settext ("Start message service ..."); Intent Intent =NewIntent ( This, Customservice.class);    StartService (Intent); }...PrivateBroadcastreceiver Mupdateprogressreceiver =NewBroadcastreceiver () {@Override  Public void OnReceive(context context, Intent Intent) {if(Intent.hasextra (customservice.key_extra_progress)) {intprogress = 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 a progress bar, such as Rxjava, delay sending, and custom iterators, but if you need to handle continuous updates of page rebuilds, you need to store publishsubject and use a custom iterator.

Time interval: When the page is rotated, the data is refreshed and started again.
Delayed send: When the page is rotated, the previous send is completed and restarted.
Custom iterations: When you rotate a page, continuous updates are completed normally.

Time 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 send

    private void handleDelayEmitClick() {        mTvProgressText.setText("开始延迟发射...");        mSubscriber = createSubscriber();        mObservable = createObservable();        mObservable.subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(mSubscriber);        mRetainedFragment.setObservable(mObservable);    }

When the observer sends the data, it is delayed by one second, or systemclock.sleep.

 //create delay Observer  private  observable<long> createobservable  () {return  observable.create (new  observable.onsubscribe<long> () { @Override  public  void  call  (subscriber<? super  long> subscriber) {for  (long  i = 1 ; I < max_progress + 1 ; i++) {systemclock.sleep (Emit_delay_ms); Subscriber.onnext (i); } subscriber.oncompleted (); } }); }

Custom iterators, which store publishsubject in Retainedfragment.

private void Handlecustomiteratorclick () {Mtvprogresstext. SetText("Start customizing iterators ...");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);}

Custom iterators, overriding the next method, return data.

 Public classCustomiterator implements Iterable<long> {PrivateList<long> mnumberlist =NewArraylist<> (); Public Customiterator() { for(Longi =0; i < mainactivity.max_progress; i++) {Mnumberlist.add (i +1); }} @Override PublicIterator<long>iterator() {return NewIterator<long> () {Private intMcurrentindex =0; @Override PublicBooleanHasnext() {returnMcurrentindex < Mnumberlist.size () && mnumberlist.Get(mcurrentindex)! =NULL; } @Override PublicLongNext() {systemclock.sleep (Mainactivity.emit_delay_ms);returnMnumberlist.Get(mcurrentindex++); }//No Use allowed@Override Public void Remove() {Throw NewUnsupportedoperationexception ();    }        }; }}

Effect animation

In comparison, the use of asynchronous tasks is prone to memory leaks, and scalability is relatively small, suitable for simple updates; Using background service is heavier, need another process, suitable for complex data processing, not suitable for updating the page; The use of Rxjava, easy to expand, can control the release time, is a good choice.

Reference

That ' s all! Enjoy it!

Using Rxjava to update the UI interface continuously while the page is switching

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.