Android Neutron line threads can't update the UI?

Source: Internet
Author: User

Android UI access is not locked, so accessing the UI on multiple threads is not secure. So android specifies that the UI can only be accessed in the UI thread.

But is there an extreme situation? Makes it possible for us to access the UI in a child thread to make the program run? Next we'll use an example to confirm it.

To create a new project, the Activity_main.xml layout looks like this:

<?xml version= "1.0" encoding= "Utf-8"?><relativelayout xmlns:android="Http://schemas.android.com/apk/res/android"    android:layout_width="Match_parent"android:layout_height="Match_parent" >            <TextViewandroid:id= "@+id/main_tv"android:layout_width="Wrap_ Content "android:layout_height=" Wrap_content "android:textsize=" 18sp " android:layout_centerinparent="true" />                                        </relativelayout>

Very simple, just add a center TextView

The mainactivity code looks like this:

 Public  class mainactivity extends appcompatactivity {    PrivateTextView Main_tv;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (R.layout.activity_main); MAIN_TV = (TextView) Findviewbyid (R.ID.MAIN_TV);NewThread (NewRunnable () {@Override             Public void Run() {Main_tv.settext ("Access in child threads");    }}). Start (); }}

It is also a very simple line that creates a child thread in the OnCreate method and makes UI access operations.

Click Run. You will find that even if you access the UI in a child thread, the program can run. The results are as follows:

Well, why did you get an error in updating the UI in a child thread before? Is it really possible to access the UI in a child thread?

First of all, this is an extreme situation, modify mainactivity as follows:

 Public  class mainactivity extends appcompatactivity {    PrivateTextView Main_tv;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (R.layout.activity_main); MAIN_TV = (TextView) Findviewbyid (R.ID.MAIN_TV);NewThread (NewRunnable () {@Override             Public void Run() {Try{Thread.Sleep ( $); }Catch(Interruptedexception e)                {E.printstacktrace (); } main_tv.settext ("Access in child threads");    }}). Start (); }}

Let the child thread sleep for 200 milliseconds and then wake up with UI access.

As a result you will find that the program has collapsed. This is the normal phenomenon. Throws a familiar exception like this:

Android.view.viewrootimpl$calledfromwrongthreadexception:only the original thread that created a view hierarchy can Touc H its Views.
At Android.view.ViewRootImpl.checkThread (viewrootimpl.java:6581)
At Android.view.ViewRootImpl.requestLayout (viewrootimpl.java:924)

......

As a developer, we should take a serious look at these exception messages, which can be used to find out why in the first case you can access the UI. Let's analyze the exception information:

First, you can tell from the following exception information

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6581)

This exception is thrown from the Checkthread method of the Android.view.ViewRootImpl.

That now follow Viewrootimpl's Checkthread method look, the source code is as follows:

void checkThread() {    if (mThread != Thread.currentThread()) {        thrownew CalledFromWrongThreadException(                "Only the original thread that created a view hierarchy can touch its views.");    }}

There are only a few lines of code, and Mthread is the main thread, which is initialized when the application is started.

From this we can draw the conclusion that:
When accessing the UI, Viewrootimpl checks which thread is currently accessing the UI, and if it is not the primary thread, throws the following exception:

thethatits views

That doesn't seem to explain anything? Continue to see exception information

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:924)

Now look at the Requestlayout method,

@OverridepublicvoidrequestLayout() {    if (!mHandlingLayoutInLayoutRequest) {        checkThread();        true;        scheduleTraversals();    }}

Here is also called the Checkthread () method to check the current thread, eh? There seems to be no information other than checking threads. Then point into the Scheduletraversals () method to see

void scheduleTraversals() {    if (!mTraversalScheduled) {        true;        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();        mChoreographer.postCallback(                null);        if (!mUnbufferedInputDispatch) {            scheduleConsumeBatchedInput();        }        notifyRendererOfFramePending();        pokeDrawLockIfNeeded();    }}

Notice that the second parameter of the Postcallback method is passed in much like a background task. Then go in.

finalclass TraversalRunnable implements Runnable {    @Override    publicvoid run() {        doTraversal();    }}

If you find it, follow the Dotraversal () method again.

void doTraversal() {    if (mTraversalScheduled) {        false;        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);        if (mProfile) {            Debug.startMethodTracing("ViewAncestor");        }        performTraversals();        if (mProfile) {            Debug.stopMethodTracing();            false;        }    }}

You can see that a performtraversals () method is called inside, and the view drawing process starts with this performtraversals method. The code of the Performtraversals method is a bit long not posted out, if continue to follow up is to learn the drawing of the view. And we now know that every visit to Ui,android will redraw the view. This is very well understood.

Analysis here, in fact, the exception information is not helpful to us, it only tells us the child thread where the access UI throws an exception.
And we think: When the UI is accessed, Viewrootimpl calls the Checkthread method to check which thread is currently accessing the UI, and if not the UI thread throws an exception, which is fine. But why did you start to create a child thread in Mainactivity's OnCreate method to access the UI, or did the program run normally??
The only explanation is that at the time the OnCreate method was executed, Viewrootimpl was not created to check the current thread.

Then you can go into it this way. Find out where Viewrootimpl is and when it was created. Okay, keep moving.

In Activitythread, we find the Handleresumeactivity method, as follows:

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! =NULL) {FinalActivity a = r.activity;//Code omissionR.activity.mvisiblefromserver =true; mnumvisibleactivities++;if(r.activity.mvisiblefromclient) {r.activity.makevisible (); }        }//Code omission}

You can see the internal call of the Performresumeactivity method, this method to see the name is definitely callback Onresume method of the entrance, then we will follow up to see.

publicfinalperformResumeActivity(IBinder token,        boolean clearHide) {    ActivityClientRecord r = mActivities.get(token);    if"Performing resume of " + r            " finished=" + r.activity.mFinished);    ifnull && !r.activity.mFinished) {    //代码省略            r.activity.performResume();    //代码省略    return r;}

You can see R.activity.performresume () This line of code, follow the Performresume method, as follows:

finalvoid performResume() {    performRestart();    mFragments.execPendingActions();    null;    false;    // mResumed is set by the instrumentation    mInstrumentation.callActivityOnResume(this);    //代码省略}

Instrumentation called the Callactivityonresume method, the Callactivityonresume source code is as follows:

public   void  callactivityonresume  (activity activity) {activity.mresumed = true ;    Activity.onresume (); if  (mactivitymonitors! = null )  {synchronized  (msync) {final  int  N = Mactivitymonitors.size (); for  (int  i=0 ; i<n; i++)                {final  activitymonitor am = mactivitymonitors.get (i);            Am.match (activity, activity, activity.getintent ()); }        }    }}

Found, Activity.onresume (). This also confirms that the Performresumeactivity method is indeed the doorway to the callback Onresume method.

So now we look back handleresumeactivity method, after executing the Performresumeactivity method callback Onresume method,
Will come to this piece of code:

r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {    r.activity.makeVisible();}

Activity calls the Makevisible method, which should be what to show, follow up to explore.

void makeVisible() {    if (!mWindowAdded) {        ViewManager wm = getWindowManager();        wm.addView(mDecor, getWindow().getAttributes());        mWindowAdded = true;    }    mDecor.setVisibility(View.VISIBLE);}

To add Decorview to WindowManager, it's time to focus on WindowManager's addview approach. And WindowManager is an interface, we should find WindowManager implementation class, and WindowManager implementation class is Windowmanagerimpl.

Find the AddView method for Windowmanagerimpl, as follows:

@OverridepublicvoidaddViewparams) {    applyDefaultToken(params);    params, mDisplay, mParentWindow);}

It calls the Windowmanagerglobal's AddView method, and now it's locked.
Windowmanagerglobal Method of AddView:

 Public void AddView(View view, Viewgroup.layoutparams params, display display, Window ParentWindow) {//Code omissionViewrootimpl Root; View Panelparentview =NULL;//Code omissionRoot =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 }}

Finally, Viewrootimpl was created in the AddView method of Windowmanagerglobal.

Review the previous analysis and summarize:
Viewrootimpl was created after the Onresume method callback, and we first created the child thread in the OnCreate method and accessed the UI, at that moment, Viewrootimpl was not created to detect whether the current thread is the UI thread, So the program does not crash as can run up, and then modify the program, so that the thread sleeps for 200 milliseconds, the program will collapse. Obviously after 200 milliseconds Viewrootimpl has been created, you can perform the Checkthread method to check the current thread.

The analysis of this blog, like the title, Android Neutron line threads can not update the UI? Child threads created in the OnCreate method access UI is an extreme situation, this does not carefully analyze the source code is not known. I have recently seen a face test, only to find this.

I also learned from the abnormal information to follow up the source to find the answer, you?

Android Neutron line threads can't update the UI?

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.