Activity startup mode and task stack (Task), TaskAffinity application scenarios [turn]

Please indicate the source of the reprint (thank you):
Activity startup mode and task stack (Task) comprehensive and in-depth record (below)_activities waiting to finish task stack_zejian_'s blog-CSDN blog

Through the analysis of the previous document, we have a clearer understanding of the startup mode of the Activity. In this article, we will continue to analyze the parameters and task stacks of the startup mode of the Activity. Next, we will continue with the previous question. Explore how to create multiple task stacks in the same application through the taskAffinity attribute.

The taskAffinity attribute of the task stack

The characteristics of TaskAffinity are as follows:

  • The TaskAffinity parameter identifies the name of the task stack required by the activity. By default, the name of the task stack required by all activities in an application is the package name of the application.
  • The TaskAffinity attribute is generally used in combination with the singleTask mode or the allowTaskReparenting attribute, and has no practical meaning in other cases.
  • The value of the TaskAffinity attribute cannot be the same as the current application package name, otherwise its value will be the same as invalid.

Combination of TaskAffinity and singleTask startup mode

When the TaskAffinity and singleTask startup modes are used in combination, the task stack name of the current Activity will be the same as the value specified by the TaskAffinity attribute. Let’s verify through the code below. We start ActivityA with MainActivity, where the MainActivity startup mode is the default mode, and ActivityA starts The mode is singleTask, and the TaskAffinity attribute value is android:taskAffinity="com.zejian.singleTask.affinity"MainActivity and ActivityA. The code is as follows:


package comzejian.myapplication;
 
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
public class MainActivity extends AppCompatActivity {
 
    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn= (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivity.this,ActivityA.class);
                startActivity(i);
            }
        });
    }
}

ActivityA.class code is as follows:


package comzejian.myapplication;
 
import android.app.Activity;
import android.os.Bundle;
 
/**
 * Created by zejian
 * Time 16/7/26.
 * Description:
 */
public class ActivityA extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
    }
}

The manifest file code is as follows:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="comzejian.myapplication">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <activity android:name=".ActivityA"
                    android:launchMode="singleTask"
                    android:taskAffinity="com.zejian.singleTask.affinity"
            />
 
    </application>
</manifest>

Now we start MainActivity, and then start ActivityA, and then we use adb shell dumpsys activity activitiesthe command to check the status of the stack at this time:

We can clearly see two task stacks, one of which is id=249, and the stack name is com.zejian.singleTask.affinity. This stack contains ActivityA, and the other is id=248, and the stack name is default The task stack of the package name contains MainActivity. At this point, we also understand that we can indeed specify the stack name required by our Activity through the combination of singleTask and the android:taskAffinity attribute, so that the corresponding Activity exists in different stacks. The illustration is as follows:

When TaskAffinity is used in combination with allowTaskReparenting

First, let's talk about the allowTaskReparenting attribute. Its main function is the migration of the activity, that is, the migration from one task to another. This migration is related to the taskAffinity of the activity. When the value of allowTaskReparenting is "true", it means that the Activity can move from the started Task to the Task with affinity (when the Task enters the foreground). When the value of allowTaskReparenting is "false", it means that it must stay at startup. Stay in the Task. If this feature is not set, the value of the allowTaskReparenting attribute on the element (of course, it can also be applied to each activity element) will be applied to the Activity. The default value is "false". This may be difficult to understand. Let’s take an example. For example, there are two applications A and B. A starts an Activity C of B, then presses the Home key to return to the desktop, and then clicks the application of B. If at this time , The value of allowTaskReparenting is "true", then the main Activity of B will not be started at this time, but the Activity C that has been started by application A will be displayed directly. We can also think that Activity C has been transferred from A's task stack to B's task stack. This is like we adopted a cat that was lost with its owner on the side of the road. Suddenly one day, the owner came to the door and the cat was taken back. Let's illustrate this situation better:

Let's verify it at the code level. We create two applications, ActivityTask (referred to as A application) and ActivityTask2 (referred to as B application), where A contains ActivityA and B contains ActivityC. We start ActivityC in B application through ActivityA, and then return to Go to the desktop and start application B. At this time, we observe the changes in the respective stacks of application A and application B (because A and B are different applications, the value of the taskAfinity attribute must be different, so we don’t need to specify it here).
ActivityA and its manifest file code are as follows:

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
/**
 * Created by zejian
 * Time 16/7/23.
 * Description:
 */
public class ActivityA extends Activity {
 
    private Button btnC;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
 
        btnC= (Button) findViewById(R.id.mainC);
        btnC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                ComponentName cn = new ComponentName("com.cmcm.activitytask2", "com.cmcm.activitytask2.ActivityC");
                intent.setComponent(cn);
                startActivity(intent);
            }
        });
    }
}


<activity android:name=".ActivityA">
     <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
</activity>

ActivityA and its manifest file code are as follows:


package com.cmcm.activitytask;
 
package com.cmcm.activitytask;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
/**
 * Created by zejian
 * Time 16/7/23.
 * Description:
 */
public class ActivityC extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_c);
    }
}


<activity android:name=".ActivityC" android:exported="true"    
      android:allowTaskReparenting="true">
</activity>

After we start ActivityC of B application through AcitivityA, the stack in memory is as follows:

We can see that ActivityA and ActivityC are in the same stack, and then we go back to the desktop to start application B. At this time, the task stack in memory is as follows:

We found that Activity C moved directly from the task stack of application A to the task stack of application B, which is in line with the phenomenon we mentioned earlier. And when we modify allowTaskReparenting to false, run again, and then repeat the above operations to check the changes in the task stack in the memory:
When application A starts Activity C of application B

When returning to the desktop and starting the B application

By comparison, it is found that if the value of allowTaskReparenting is false, ActivityC will not directly migrate from the task stack of application A to the task stack of application B, but application B directly recreates the instance of ActivityC. So far, our understanding of allowTaskReparenting and taskAffinity attributes has been quite in-depth, but it should be noted that allowTaskReparenting is limited to singleTop and standard modes, because the affinity attribute of an activity is defined by its taskAffinity attribute (representing the stack name), The affinity of a task is defined by its root activity. Therefore, the root activity of a task always has the same affinity as the task in which it resides. Since the activity started with singleTask and singleInstance can only be the root activity of a task, allowTaskReparenting is limited to activities started with standard and singleTop. You can test it yourself. We won’t test it here. Let’s talk about their possibilities Application scenarios.

Possible application scenarios when TaskAffinity is combined with allowTaskReparenting and singleTask

  • TaskAffinity and singleTask application scenarios

If there is such a demand now, our client app is running in the background. At this time, due to some needs, we let WeChat call a certain page of our client app. After the user completes the relevant operation, we do not do any processing, press After the next rollback or the current Activity.finish(), the page will stay on its own client (at this time our app rollback stack is not empty), which is obviously illogical, and the user experience is quite problematic. Our requirement is that the rollback must return to the WeChat client , and we must ensure that our app is not killed. At this time, our solution is to set the properties of the currently invoked Activity to:

LaunchMode=""SingleTask" taskAffinity="com.tencent.mm"

Among them, com.tencent.mm is the name of the WeChat package found with the help of the tool. It is to put your own Activity into the default Task stack of WeChat, so that it will follow the "As long as there is an Activity in the Task, it must be rolled back from the remaining Activities of this Task." "principle, it will not return to its own client; and it will not affect the original Activity and Task logic of its own client.

  • TaskAffinity and allowTaskReparenting application scenarios

An e-mail application message contains a web page link. Clicking this link will start an activity to display this page. Although this activity is defined by the browser application, the activity is loaded by the e-mail application, so at this time the activity It also belongs to the e-mail task. If the e-mail application switches to the background, the browser will display the activity instead of the browser main interface when the browser is opened next time because the value of allowTaskReparenting is true , and the activity will also migrate from the e-mail task stack Go to the task stack of the browser, and the next time you open e-buy, the activity will not be displayed again.
  Now that TaskAffinity is fully introduced, let's finally understand a few attribute parameters related to the task stack;

clear task stack

In addition to providing me with TaskAffinity to specify the name of the task stack, the Android system also provides me with a method to clear the task stack. In general, we only need to specify the corresponding attribute value in the <activity> tag.

  • android:clearTaskOnLaunch

This attribute is used to mark whether to clear all activities except the root Activity from the task, "true" means to clear, "false" means not to clear, and the default is "false". Here is something we must pay attention to. This attribute only works on the root Activity in the task stack, and other activities in the task stack will be ignored. If android:clearTaskOnLaunchthe property is "true", every time we re-enter the application, we will only see the root Activity, and other activities in the task stack will be cleared out of the stack.
  For example, in an application of Activities A, B, and C, where clearTaskOnLaunch is set to true, and C is the default value, we start A, B, and C in sequence, click HOME, and then click the icon on the desktop. A is started, while B and C will be removed from the current task stack. That is to say, when the attribute clearTaskOnLaunch of the Activity is true, it will be started first, and the rest of the Activities (B, C) will be removed from the task stack and destroyed, unless the previous A has been finished and destroyed, and the subsequent registered activity with clearTaskOnLaunch is true (B) will take effect.
  In particular, if our application refers to the activities of other applications, and these activities set android:allowTaskReparentingthe attribute to "true", they will be re-hosted to tasks with a common affinity.

  • android:finishOnTaskLaunch

The finishOnTaskLaunch attribute is somewhat similar to clearTaskOnLaunch. The difference is that finishOnTaskLaunch acts on itself (remove itself from the task stack without affecting other activities), while clearTaskOnLaunch acts on others (remove other activities from the task stack) , if we android:finishOnTaskLaunchset the property value of the Activity to true, after leaving the task stack on which the Activity depends, when we return, the Activity will be finished, and other Activities will not be affected.

  • android:alwaysRetainTaskState

alwaysRetainTaskState actually gives the task stack where the current Activity is located a "death-free gold medal". If the current Activity is android:alwaysRetainTaskStateset to true, then the task stack where the Activity is located will not be affected by any cleanup commands, and the current task stack will always be maintained status.

Well, this is the end of this article. I believe that through the records of the two articles, we have a relatively clear understanding of the startup mode and task stack of the Activity.

Guess you like

Origin blog.csdn.net/iblue007/article/details/129929203