Android Subnet threads can't update the UI?

Source: Internet
Author: User
Tags message queue

The Android single-threaded model is described in this way:

Android UI actions are not thread-safe, and these actions must be performed on the UI thread

If you access the UI thread on another thread, Android provides the following:

Long ) Handler

Why is it? Can't I manipulate the UI in a child thread?

When a program starts for the first time, Android initiates a corresponding main thread, which is the UI thread, which is activitythread. The UI thread is primarily responsible for handling UI-related events such as keystrokes, user touch screens, and screen drawings. The system does not create a separate thread for each component, and the UI components in the same process are instantiated in the UI thread, and the system's calls to each component are distributed from the UI thread. Therefore, the method of responding to a system callback is always run in the UI thread, such as a onkeydown () callback that responds to the user's action.

So why choose a main thread to do all this work? In other words, why is Android using a single-threaded model, and what is the benefit of it?

Let's start by looking at how the single-threaded event queue model is defined:

Use a dedicated thread to extract events from the queue and forward them to the application-defined event handler

This looks like the Android message queue, Looper, and handler. For similar knowledge, please refer to: In-depth understanding of message, MessageQueue, handler and Looper

In fact, the modern GUI framework uses a model like this: the model creates a dedicated thread, and the event dispatch thread handles GUI events. Single threading is not just Android, Qt, Xwindows, etc. are all single threaded. Of course, some people also try to use multi-threaded GUI, finally due to competition conditions and deadlock caused by stability problems, and then back to single-threaded event queue model old road. The single threaded GUI framework achieves field security through limitations: All objects in the GUI, including visual components and data models, are accessible only by the event thread.

This explains why Android uses a single-threaded model.

What about Android UI operations that aren't thread-safe?

There are two sets of methods for Android to implement view updates, namely invalidate and postinvalidate. The former is used in the UI thread, which is used in a non-UI thread. In other words, Android UI operations that are not thread safe can be described as invalidate called in a child thread that causes thread insecurity. Make a hypothesis, now I use invalidate to refresh the interface in the sub-thread, while the UI thread is also using Invalidate refresh interface, this will not cause the interface refresh can not be synchronized? Now that the refresh is out of sync, invalidate cannot be used in a child thread. This is why invalidate cannot be used in a child thread.

Postinvalidate can be used in sub-threads, how is it done?

See how the source code is implemented:

 Public voidpostinvalidate () {postinvalidatedelayed (0);} Public voidPostinvalidatedelayed (Longdelaymilliseconds) {    //We try only with the attachinfo because there's no point in invalidating//If we is not a attached to our window    if(Mattachinfo! =NULL) {Message msg=Message.obtain (); Msg.what=attachinfo.invalidate_msg; Msg.obj= This;    MAttachInfo.mHandler.sendMessageDelayed (msg, delaymilliseconds); }}

In the final analysis or through the handler sendmessagedelayed Ah, still not escape the message queue, and ultimately to the UI threading processing. Therefore, the view update can only be handled by the UI thread.

If I had to update the UI in a child thread, what would happen?

Android.view.viewroot$calledfromwrongthreadexception:only the original thread that created a view hierarchy can touch it Views.

Throws a Calledfromwrongthreadexception exception.

Believe that many people encounter this exception, it will be resolved by one of the four ways in the preceding:

Long ) Handler

After all, why does this anomaly occur when the underlying is not yet triggered? Where did the anomaly come from?

void Checkthread () {    if (mthread! = Thread.CurrentThread ())        {throwNew  calledfromwrongthreadexception (                "only the original thread, created a view hierarchy can touch its V Iews. " );    }}

This code is derived from Framework/base/core/java/android/view/viewrootimpl.java

Looking at the Viewrootimpl constructor, Mthread is initialized here:

 Public Viewrootimpl (context context, display display) {    = context;     = windowmanagerglobal.getwindowsession ();     = display;     = context.getbasepackagename ();     = display.getdisplayadjustments ();     = Thread.CurrentThread ();    ......}

To look at the stack of calledfromwrongthreadexception exceptions, you will find the Invalidatechild and Invalidatechildinparent methods in the end:

@Override  Public void Invalidatechild (View Child, Rect dirty) {    invalidatechildinparent (null, dirty);} @Override public viewparent invalidatechildinparent (int.[] location, Rect dirty) {    Checkthread ();    ......}

This anomaly was eventually formed by Checkthread. In the final analysis, a non-UI thread can refresh the UI if it has its own viewroot. If you want to create a Viewroot instance directly, you will find that the class cannot be found. How do we do that? Through WindowManager.

classNonuithreadextendsthread{@Override Public voidrun () {looper.prepare (); TextView TX=NewTextView (mainactivity. This); Tx.settext ("Non-uithread Update TextView"); WindowManager WindowManager= Mainactivity. This. Getwindowmanager (); Windowmanager.layoutparams params=NewWindowmanager.layoutparams (200, 200, 200, 200, WindowManager.LayoutParams.FIRST_SUB_WINDOW, Windowmanager.layoutparams.type_toast,pixelformat.opaqu         E);          Windowmanager.addview (TX, params);     Looper.loop (); } }

is to create the AddView method in Viewroot,windowmanagerimpl.java through Windowmanager.addview:

@Override  Public void AddView (@NonNull view view, @NonNull viewgroup.layoutparams params) {    applydefaulttoken (params);    Mglobal.addview (view, params, mdisplay, Mparentwindow);}
Private Final Windowmanagerglobal Mglobal = Windowmanagerglobal.getinstance ();

Mglobal is a Windowmanagerglobal instance, code in Frameworks/base/core/java/android/view/windowmanagerglobal.java, specifically implemented as follows:

 Public voidAddView (view view, Viewgroup.layoutparams params, display display, Window parentwindow) {if(View = =NULL) {            Throw NewIllegalArgumentException ("View must not is null"); }        if(Display = =NULL) {            Throw NewIllegalArgumentException ("Display must not is null"); }        if(! (paramsinstanceofwindowmanager.layoutparams)) {Throw NewIllegalArgumentException ("Params must be Windowmanager.layoutparams"); }        FinalWindowmanager.layoutparams Wparams =(windowmanager.layoutparams) params; if(ParentWindow! =NULL) {Parentwindow.adjustlayoutparamsforsubwindow (wparams); } Else {            //If There ' s no parent, then hardware acceleration for this view is//set from the application ' s hardware acceleration setting.            FinalContext context =View.getcontext (); if(Context! =NULL&&(Context.getapplicationinfo (). Flags& applicationinfo.flag_hardware_accelerated)! = 0) {Wparams.flags|=WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;        }} Viewrootimpl root; View Panelparentview=NULL; synchronized(mLock) {//Start watching for system property changes.            if(Msystempropertyupdater = =NULL) {Msystempropertyupdater=NewRunnable () {@Override Public voidrun () {synchronized(mLock) { for(inti = Mroots.size ()-1; I >= 0; --i) {mroots.get (i). Loadsystemproperties ();                }                        }                    }                };            Systemproperties.addchangecallback (Msystempropertyupdater); }            intindex = findviewlocked (view,false); if(Index >= 0) {                if(Mdyingviews.contains (view)) {//Don ' t wait for Msg_die to make it's the through root ' s queue.mroots.get (Index). Dodie (); } Else {                    Throw NewIllegalStateException ("View" +View+ "have already been added to the window manager."); }                //The previous removeview () had not completed executing. Now it has.            }            //If This is a panel window and then find the window it is being//Attached to for the future reference.            if(Wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&Wparams.type<=WindowManager.LayoutParams.LAST_SUB_WINDOW) {                Final intCount =mviews.size ();  for(inti = 0; I < count; i++) {                    if(Mroots.get (i). Mwindow.asbinder () = =wparams.token) {Panelparentview=Mviews.get (i); }}} root=NewViewrootimpl (View.getcontext (), display);            View.setlayoutparams (Wparams);            Mviews.add (view);            Mroots.add (root);        Mparams.add (Wparams); }        //because it fires off messages to start doing things        Try{root.setview (view, Wparams, Panelparentview); } Catch(RuntimeException e) {//badtokenexception or invaliddisplayexception, clean up.            synchronized(mLock) {Final intindex = findviewlocked (view,false); if(Index >= 0) {removeviewlocked (index,true); }            }            Throwe; }    }

Therefore, a non-UI thread can update the UI as long as it has its own viewroot.

To extend: When did the Android activity itself create viewroot?

Since it is a single-threaded model, it is necessary to find this UI thread implementation class Activitythread, see where it addview. Yes, it is in the Onresume, the corresponding Activitythread is handleresumeactivity this method:

Final voidhandleresumeactivity (IBinder token,BooleanClearhide,BooleanIsforward,BooleanReallyresume) {        //If We are getting ready to GC after going to the background, well//we are back active so skip it.Unschedulegcidler (); Msomeactivitieschanged=true; //TODO Push Resumeargs into the activity for considerationActivityclientrecord r =performresumeactivity (token, clearhide); ......        if(R.window = =NULL&&!a.mfinished &&willbevisible) {R.window=R.activity.getwindow (); View Decor=R.window.getdecorview ();            Decor.setvisibility (view.invisible); Viewmanager WM=A.getwindowmanager (); Windowmanager.layoutparams L=r.window.getattributes (); A.mdecor=Decor; L.type=WindowManager.LayoutParams.TYPE_BASE_APPLICATION; L.softinputmode|=Forwardbit; if(a.mvisiblefromclient) {a.mwindowadded=true;            Wm.addview (decor, L); }        //If The window has a already been added, but during resume//We started another activity, then don ' t yet make the//window visible.}Else if(!willbevisible) {            if(LOCALLOGV) slog.v (TAG,"Launch" + R + "Mstartedactivity set"); R.hidefornow=true; }    ......}

Therefore, if the UI is updated directly through a child thread in OnCreate, the calledfromwrongthreadexception exception is not thrown. But in general, we do not do such a thing in OnCreate.

This is the single-threaded model that Android has designed for us, the core of which is that Android UI operations are not thread-safe, and these operations must be performed on the UI thread. But this sentence behind, but hidden in our usual invisible code implementation, only to understand these, we can know its why.

Reference: Can Android sub-threads refresh the UI without Viewroot?

Can't update UI for Android threads?

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.