Activity start mode, the task stack and taskAffinity property

What is the task stack

A application at startup, to have lots of activity, when we press the back button, it will fall back on one activity, then the system is how to manage these activity it? The answer in the form of a stack (task), and follow the principles advanced out, by default, a stack app is only one task (task), if necessary, we can specify multiple tasks stack (task). We can conclude the following:

1. The task stack is a container app management activity, and follow after the advanced principle
2. A default app only one task stack specified by the system
3. A app can have multiple tasks stack, we need to specify their own

The following task stack all called task
So how do we give a specific activity specified task, specifying a particular task what use is it?
Want to understand this, we need to understand the activity of the startup mode. activity startup mode a total of four, namely, standard, singleTop, singleTask, singleInstance;

standard:
This is the default start-up mode, every time you start an activity, will be added one by one to the current task to go. Why is it currently, we know that an app may have multiple task, if there are two task, namely taskA and taskB, taskB there activityA, this time activityA start activityB, if activityB is standard mode, then put activityB into taskB instead taskA. Speaking somewhat convoluted, move their hands painting a picture becomes clear. There is also a small problem, when we start an activity usually is code like this:

    Intent i = new Intent(context,ActivityB.class);
    context.startActivity(i);

In startActivity time, if the context is a applicationContext, and ActivityB startup mode is standard, then the system will error:

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Because activityB in attempting to enter the current task, I found context (applicationContext) does not belong to any task, can not enter. The solution is to create a new task, the error message has made it very clear, specific code is as follows:

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

singleTop:
As the name suggests, if the activity has been at the top of the task, then when the activity started again, he will not be re-created, but call it onNewIntent (Intent i) method, the data you want to convey, you can intent parameters get in, onCreate, onStart not called. If this activity is not in the top task, then the activity of storage methods and standard, as will be re-created, accumulated to the task.

singleTask:
the stack multiplexing mode. If there is activity in the task, and this activity is singleTask mode, repeatedly launch of this activity will not re-create the instance, but the callback onNewIntent (Intent i) method. Specifically, when activityA as singleTask mode is activated, the system will detect, there is no corresponding task, if not, create a task, and then put into activityA. If the corresponding task exists, it will check whether activityA top of the stack, if the top of the stack, the direct method calls onNewIntent, if not, then on top of all the activity activityA pop, and then call onNewIntent method.

singleInstance:
This mode of activity, exclusive a task, that is to say the task can only have this one activity. Startup, created for this activity will be a task, and to push this activity, if this activity is still in the stack when this activity started again, it does not call onCreate method of this activity, but calls and onNewIntent onStart method.
This pattern of usage scenario is: assuming that there is an active program that allows other programs to call, if you want to make this program and other programs to share examples of this activity, the use of the other three startup mode does not work, because each application return has its own stack, the stack when the stack at different return the same activity must be to create a new instance. The use singleInstance mode can solve this problem, in this mode, there will be a separate return stack to manage this event, no matter which application to access this event, all share the same return stack, but also solve the shared activity instances problem.

About four promoters mode, basically explain, but when the specific use case of multiple tasks stack, press the back button, easy to mess up, we are here to talk about alone. First, such a rule to follow is: a stack of time, let the current stack (foreground stack) empty, go back empty stack.

for example:
Write pictures described here

Into the app, start activityA, then activityA-> activityB-> activityC-> activityD,
if activityA, activityB and activityD are standard mode, activityC is singleInstance mode, this time at this time there are two task within the app (for the time being called the taskA and taskB ). Further comprising a task are as follows:
TaskA: activityA, activityB, activityD.
taskB: activityC.
At this point in the foreground task is taskA, the background is taskB.
Press the back key four times, followed by destruction is activityD-> activityB-> activityA-> activityC.
Yes like this, after the reception stack empty, go back empty stack.

taskAffinity property Detailed
task stack is so basic, but when we want to manually configure the activity to a task, and how to operate it, which was to mention an important property of:

android:taskAffinity

The official document is explained this way :

The task that the activity has an affinity for. Activities with the same affinity conceptually belong to the same task (to the same “application” from the user’s perspective). The affinity of a task is determined by the affinity of its root activity.
The affinity determines two things — the task that the activity is re-parented to (see the allowTaskReparenting attribute) and the task that will house the activity when it is launched with the FLAG_ACTIVITY_NEW_TASK flag.

By default, all activities in an application have the same affinity. You can set this attribute to group them differently, and even place activities defined in different applications within the same task. To specify that the activity does not have an affinity for any task, set it to an empty string.

If this attribute is not set, the activity inherits the affinity set for the application (see the <application> element’s taskAffinity attribute). The name of the default affinity for an application is the package name set by the <manifest> element.

Here is my translation, if inappropriate, please point out:
taskAffinity related tasks stack of activity. We have the same affinity of activity belong to the same task on the concept. Affinity of a task depends on taskaffinity root activity in this task. taskaffinity property can determine two things:
① when the activity is re-parent, he would be placed in the stack which tasks.
② When this activity is added FLAG_ACTIVITY_NEW_TASK mark the start, which will be placed in the task.
By default, application activity all have the same affinity, you can set different values to taskaffinity attribute to group them. You can even put multiple application of activity into the same task in. If you want to clear this activity does not belong to any task, this property is set to null character can be.
If this property is not set, then the value of this property will inherit values from application of this property (see the application of taskaffinity property). The default package name is the application.

After reading the top official interpretation of the document, I think you've got an understanding of taskAffinity property, summed up the time being there are two aspects: 1.taskAffinity attribute to the activity can be specified task, but you must use FLAG_ACTIVITY_NEW_TASK mark. 2. The default value is taskAffinity the name of the application package.

Below we wrote a demo show you:
This is what I have to AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="example.ylh.com" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <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=".activityDemo.ActivityA"></activity>

        <activity android:name=".activityDemo.ActivityB"
            android:taskAffinity="example.ylh.com_new_task01"></activity>

        <activity android:name=".activityDemo.ActivityC"
            android:taskAffinity="example.ylh.com_new_task02"
            android:launchMode="singleTask"></activity>
    </application>
</manifest>

From the above code, a total of four Activity, boot sequence
MainAcitivity-> ActivityA-> ActivityB-> ActivityC
wherein ActivityC added singleTask start mode, since the intent will add mode is activated when singleTask
FLAG_ACTIVITY_NEW_TASK flag.

ActivityA code:

package example.ylh.com.activityDemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import example.ylh.com.R;

/**
 * Created by Administrator on 2017/8/4.
 */

public class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_test);

        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText("A");
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(ActivityA.this,ActivityB.class);
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(i);
            }
        });
    }
}

ActivieyB Code:

package example.ylh.com.activityDemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import example.ylh.com.R;

/**
 * Created by Administrator on 2017/8/4.
 */

public class ActivityB extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_test);

        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText("B");
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(ActivityB.this,ActivityC.class);
                startActivity(i);
            }
        });
    }

}

After the turn starts, from adb to see their details are as follows:
Write pictures described here

We can clearly see, which contains a stack of three tasks:
first: Stack name: example.ylh.com, stack id: 8904, and contains MainActivity ActivityA.
Second: Stack name: example.ylh.com_task01, stack id: 8905, included ActivityB.
Third: Stack name: example.ylh.com_task02, stack id: 8906, included ActivityC.
Results in line with our expectations. This, we can conclude that the use of taskAffinity and FLAG_ACTIVITY_NEW_TASK (or singleTask), our activity can be done to specify the task stack.

allowTaskReparenting attribute
this property to explain trouble spots, but very interesting.
Api official explained:

Whether or not the activity can move from the task that started it to the task it has an affinity for when that task is next brought to the front — “true” if it can move, and “false” if it must remain with the task where it started.

Probably it means that, if set to "true", then the activity can start it from the task of moving to this activity and the associated task. I'm listening to this explanation, you still do not understand estimate,
give you an example: There are two applications A and B, B application has a activityC, and activityC of allowTaskReparenting property is true. Now there is such a scene, launched activityC B of A, then click on the home button to return to the desktop, start the application B, this is not the time to start mainActivity B application, but again shows activityC, activityC A transfer from the stack to the task the task stack B (because activityC and the associated task is appB the task, so the activityC added to the top of the stack).
Below is a specific code:

A application of activityA:

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import example.ylh.com.R;

/**
 * Created by Administrator on 2017/8/4.
 */

public class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_test);

        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText("A");
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent();
                i.setClassName("ylh.bsdf.com","ylh.bsdf.com.ActivityC");
                startActivity(i);
            }
        });
    }
}

Application of activityC B:

package ylh.bsdf.com;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

/**
 * Created by Administrator on 2017/8/12.
 */

public class ActivityC extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.setText("app B activityC");
    }
}

Application AndoridManifest file B:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ylh.bsdf.com">

    <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=".ActivityC"
            android:allowTaskReparenting="true">
        </activity>
    </application>

</manifest>

According to the top of the logic start (activityA (appA) -> activityC (appB) -> home-> appB), the stack of print adb situation as follows:
Write pictures described here
exactly in line with our expectations.
Benpian to end here, from start to finish if you should understand very thorough, and where not understand the words to write a small demo test (this is important).
Reference:
"android developers to explore the art of"
Android official document
http://blog.csdn.net/zhangjg_blog/article/details/10923643

Published 17 original articles · won praise 12 · views 10000 +

Guess you like

Origin blog.csdn.net/qq_24295537/article/details/76559851