In-depth analysis of four Android components (8)-end four stages of Activity

Source: Internet
Author: User

In-depth analysis of four Android components (8)-end four stages of Activity

What will happen to ActivityManagerService when we try to end the Activity? This section describes three main methods and four stages for ending an Activity.

 

1. Three main methods for ending an Activity

 

When the Activity ends, we usually use the following three main methods.

 

① End the Activity programmatically

 

This method explicitly calls the finish () method of Activity in the code. In general, we often encounter such a requirement: click a button to exit the interface. In this case, you only need to add the finish () method to the button click event. The code for the finish () method is as follows. By default, finish (false) is called inside finish ):

 

private void finish(boolean finishTask) {    if (mParent == null) {        int resultCode;        Intent resultData;        synchronized (this) {            resultCode = mResultCode;            resultData = mResultData;        }        if (false) Log.v(TAG, "Finishing self: token=" + mToken);        try {            if (resultData != null) {                resultData.prepareToLeaveProcess();            }            if (ActivityManagerNative.getDefault()                    .finishActivity(mToken, resultCode, resultData, finishTask)) {                mFinished = true;            }        } catch (RemoteException e) {            // Empty        }    } else {        mParent.finishFromChild(this);    }}

 

The above marked in red is the main method.

 

② Press the Back key on the keyboard (hard or soft keyboard) to end the Activity.

 

In this case, you can end the Activity without adding any code, but note that not all devices have a Back key. In Android code without customization, it provides a soft keyboard for each Activity interface.

 

When you click this button, the system will notify you that the Activity Back button has been pressed by calling Back onBackPressed. The onBackPressed () method code is as follows:

 

public void onBackPressed() {    if (mActionBar != null && mActionBar.collapseActionView()) {        return;    }    if (!mFragments.getFragmentManager().popBackStackImmediate()) {        finishAfterTransition();    }}

 

The finishAfterTransition () code is as follows:

 

public void finishAfterTransition() {    if (!mActivityTransitionState.startExitBackTransition(this)) {        finish();    }}

 

The code above shows that the onBackPressed () method is essentially a finish () method. Of course, this behavior can also be blocked. You only need to cancel calling super. onBackPressed () in the onBackPressed () method of the self-implemented Activity, but we do not recommend this.

 

③ Use the Home key to disappear the currently displayed Activity and return to the Launcher homepage.

 

Unlike the Back key, not all devices provide hard Home keys. In Android code without customization, it provides a soft keyboard for each Activity interface.

 

Normally, the application cannot capture the Home key unless it is forcibly captured, but this is not recommended. The key will be processed by PhoneWindowManager. The Code is as follows:

 

void startDockOrHome(){    Intent dock=createHomeDockIntent();    if(dock!=null){        try{            mContext.startActivity(dock);            return;        }catch(ActivityNotFoundException e){        }    }    mContext.startActivity(mHomeIntent);}

 

In the end, Android will start Launcher with mHomeIntent so that the current Activity will return to the background and the Launcher will be re-displayed. MHomeIntent is defined as follows:

 

MHomeIntent = new Intent (Intent. ACTION_MAIN, null );

MHomeIntent. addCateGory (Intent. CATEGORY_HOME );

MHomeIntent. addFlags (Intent. FLAG_ACTIVITY_NEW_TASK | Intent. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED );

 

2. End the four stages of the Activity

 

Like starting an Activity, there are also four stages to end the Activity. We will explain it in detail below.

 

① Stage 1 -- parameter initialization and parameter passing

 

Similar to starting an Activity, ActivityManagerProxy also needs to forward the command to end the Activity. When the Back key is pressed, the following line of code is executed:

 

ActivityManagerNative. getDefault (). finishActivity (mToken, resultCode, resultData );

 

In this case, ActivityManagerProxy will call its finishActivity () method to write the parameter to Parcel and forward it out. The finishActivity () method code is as follows:

 

Public boolean finishActivity (IBinder token, int resultCode, Intent resultData) throws RemoteException {Parcel data = Parcel. obtain (); Parcel reply = Parcel. obtain ();...... // forward the command mRemote. transact (FINISH_ACTIVITY_TRANSACTION, data, reply, 0 );...... return res ;}

 

When finishActivity () is called, Android calls back the onTransact () method of ActivityManagerService, and then executes the onTransact () method of its base class (that is, the ActivityManagerNative class) to send a request to ActivityManagerService:

 

@Overridepublic boolean onTransact(int code,Parcel data,Parcel reply,int flags)throws RemoteException{    ......    case FINISH_ACTIVITY_TRANSACTION:{        data.enforceInterface(IActivityManager.descriptor);        IBinder token=data.readStrongBinder();        Intent resultData=null;        int resultCode=data.readInt();        if(data.readInt()!=0){            resultData=Intent.CREATOR.createFromParcel(data);        }        boolean res=finishActivity(token,resultCode,resultData);        reply.writeNoException();;        reply.writeInt(res ? 1 : 0);        return true;    }    ......}

 

So far, the parameter processing and command sending precursor work has been completed, and the next work will be completed by ActivityManagerService.

 

② Stage 2 -- Obtain the record information of the Activity to be completed

 

In the second stage, the first thing to do is to use ActivityManagerService to call the requestFinishActivityLocked () method of ActivityStack to execute information on the mobile phone. The specific code is as follows:

 

public final boolean finishActivity(IBinder token,int resultCode,Intent resultData){    ......    final long origId= Binder.clearCallingIdentity();    boolean res=mMainStack.requestFinishActivityLocked(token,resultCode,resultData,"app-request");    Binder.restoreCallingIdentity(origId);    return  res;}

 

In the requestFinishActivityLocked () method, the indexOfTokenLocked () method is used to obtain the offset of the Activity in the History (mHistory) of the Activity, then, obtain the Activity record information (ActivityRecord) from the startup history. The Code is as follows:

 

Final boolean requestFinishActivityLocked (IBinder token, int resultCode, Intent resultData, String reason ){....... // obtain the index int index = indexOfTokenLocked (token );...... // obtain Activity record information from history records ActivityRecord r = mHistory. get (index); // finishActivityLocked (r, index, resultCode, resultData, reason); return true ;}

 

The key code of the indexOfTokenLocked () method is as follows:

 

Final int indexOfTokenLocked (IBinder token) {ActivityRecord r = (ActivityRecord) token; return mHistory. indexOf (r); // obtain the value of the Activity to be terminated in mHistory ......}

 

③ Stage 3: process the Activity information to be completed

 

In the third stage, we have obtained the record information of the Activity to be terminated. here we need to process them, which is done through the finishActivityLocked () method. The finishActivityLocked () method is as follows:

 

 

The figure provides some special instructions.

 

In code I, r. makeFinishing () sets the ending mark of the ActivityTrue,In addition, the number of activities in the Activity stack of the Activity is reduced by one, which is ready for subsequent operations. The code for makeFinishing () method is as follows:

 

Void makeFinishing () {if (! Finishing) {finishing = true; // identify if (task! = Null & inHistory) {task. numActivities --; // The number of activities on the same stack minus one }}}

 

Ⅱ because the current Activity is about to end, it will be overwritten by at least another Activity. In this case, the current Activity window should not continue distributing the key message to the current Activity. To meet this requirement, ActivityManagerService calls the pauseKeyDispatchingLocked () method. The code for this method is as follows:

 

void pauseKeyDispatchingLocked(){    if(!keyPaused){        keysPaused=true;        service.mWindowManager.pauseKeyDispatching(this);    }}

 

Iii. Assume that startActivityForResult is used to start the current Activity. When the Activity ends, it needs to send the processing result to the called Activity. The following code is used:

 

Resulmetadata. addResultLocked (r, r. resultWho, r. requestCode, resultCode, resultData );

 

The following code shows the behavior of the addResultLocked () method:

 

void addResultLocked(ActivityRecord from,String resultWho,int requestCode,int resultCode,Intent resultData){    Instrumentation.ActivityResult r=new Instrumentation.ActivityResult(from,resultWho,requestCode,resultCode,resultData);    if(results==null){        results=new ArrayList();    }    results.add(r);}

 

④ Stage 4 -- Preparations for inter-Activity scheduling

 

In the third stage, we completed processing of some Activity stacks and windows, made some preparations for Activity scheduling, and then started the ActivityThread scheduling process:

 

StartPausingLocked (false, false );

 

The key code of the startPausingLocked () method is as follows:

 

private final void startPausingLocked(boolean userLeaving,boolean uiSleeping){    .....    mResumedActivity=null;    mPausingActivity=prev;    mLastPausedActivity=prev;    prev.state=ActivityState.PAUSING;    prev.task.touchActiveTime();    prev.updateThumbnail(screenshotActivities(prev),null);    .....    prev.app.thread.schedulePauseActivity(prev,prev.finishing,userleaving,pre.configChangeFlags);}

 

By studying the four stages of Activity initiation, we know that ActivityStack has started the scheduling between ActivityThread activities. Here we will explain the scheduling behavior between activities when the Activity is about to be ended. The schedulePauseActivity () method is used to complete this task. The Code is as follows:

 

public final void schedulePauseActivity(IBinder token, boolean finished,boolean userLeaving,int configChanges){    queueOrSendMessage(            finished? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,token,            (userLeaving?1:0),            configChanges);}

 

Here, the queueOrSendMessage () method assembles a message and sends it to the handler used to process the message. In Handler, handlePauseActivity () is called to process the message. The handlePauseActivity () method code is as follows:

 

Private void handlePauseActivity (IBinder token, boolean finished, boolean userLeaving, int configChanges) {ActivityClientRecord r = mActivities. get (token );...... // pause the current Activity into mpauseactivity (token, finished, r. isPreHoneycomb (); // notifies the service of ActivityManagerNative. getDefault (). activityPaused (token );}

 

This method mainly completes the following two tasks.

 

I call the callback mpauseactivity () method to call back the onPause and other callback interfaces of the Activity and set the Activity status. The specific process is shown in:

 

 

II call the activityPaused () method of the proxy and forward a pause command of the Activity to the Activity management service. The Code is as follows:

 

public boolean onTransact(int code,Parcel data,Parcel reply,int flags)throws RemoteException{    case ACTIVITY_PAUSED_TRANSACTION:{        ......        IBinder token=data.readStrongBinder();        activityPaused(token);        ......        return true;    }}

 

The activityPaused () method of the Activity management service mainly Schedules other lifecycles of the Activity and recovers the previous Activity. Some key code is as follows:

 

Private final void completePauseLocked () {ActivityRecord prev = mPausingActivity ;...... prev = finishCurrentActivityLocked (prev, FINISH_AFTER_VISIBLE );..... destroyActivityLocked (prev, true, false );..... resumeTopActivityLocked (prev); // restore an Activity if (prev! = Null) {// allow the window to distribute the key message to this Activity (prev) prev. resumeKeyDispatchingLocked () ;}...... prev. cpuTimeAtResume = 0; // reset}

 

When the current Activity is re-displayed, it needs to be able to capture key messages. Therefore, the resumeKeyDispatchingLocked () method is called to meet this requirement. The resumeKeyDispatchingLocked () method restores the Key Distribution of the Activity. The Code is as follows:

 

void resumeKeyDispatchingLocked(){    if(keysPaused){        keysPaused=false;        service.mWindowManager.resumeKeyDispatching(false);    }}

 

At this point, the previously displayed Activity disappears because the Back key is pressed, and the Activity that overwrites it is re-displayed.

 

Note 1: pressing the Home Key is different from pressing the Back key or the finish () method of the Activity to end the Activity. Yes, pressing the Home Key forcibly displays the Launcher and overwrites other activities, press the Back key or the finish () method of the Activity to end the Activity. This is because the current Activity disappears and the Activity below the Activity is displayed. They are essentially different. Please note that.

 

NOTE 2: as long as the application starts, the process will be retained unless a serious exception occurs in the application or other tools (such as DDMS) are used to kill the process, even if we press the Back key to end the Activity, its application process remains on the device.

??

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.