需求描述
在應用Application1中存在A、B兩個activity,當在應用啟動了A、B activity,點擊Recent鍵,如何讓A、B兩個activity都顯示在Recent界面(最近任務)?
需求分析
根據Android SDK介紹,Recent中是管理最近的任務(Task);熟悉Activity的可以知道Activity是隸屬於某個Task的,不熟悉Activity的可以閱讀下面的帖子:
http://blog.csdn.net/ff20081528/article/details/17219951#comments
那么了解了Activity的一些知識后,我們就可以推斷出要讓A、B在Recent中顯示出來,必須將A、B處於不同的Task中;那么需要設置A、B的launchMode為singleInstance;
跟”singleTask”一樣.除了系統不能再啟動其它activity到擁有這個activity實例的任務中.activity永遠是任務的唯一;任何由這個activity啟動的其它activity都在另一個任務中打開.也就可以說singleInstance必然會開辟出一個新的Task。
Demo示例
MainActivity.java:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button btn1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn1 = (Button) findViewById(R.id.button); btn1.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.button: Intent intent1 = new Intent(this,ActivityA.class); intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent1); break; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
ActivityA,java
public class ActivityA extends AppCompatActivity { Button btn2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_activity); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); btn2 = (Button) findViewById(R.id.button2); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent2; intent2 = new Intent(ActivityA.this,ActivityB.class); startActivity(intent2); } }); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="lanchmode.sunrise.com.lanchmode"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" 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:label="@string/title_activity_activity" android:launchMode="singleInstance" android:theme="@style/AppTheme.NoActionBar" /> <activity android:name=".ActivityB" android:label="@string/title_activity_b" android:launchMode="singleInstance" android:theme="@style/AppTheme.NoActionBar" /> </application> </manifest>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
運行程序,然后使用adb shell dumpsys activity activities命令查看activity的棧的信息:
Running activities (most recent first): TaskRecord{b1c230d #265 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1} Run #3: ActivityRecord{638abae u0 lanchmode.sunrise.com.lanchmode/.ActivityB t265} TaskRecord{7b648d3 #264 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1} Run #2: ActivityRecord{65e4f8b u0 lanchmode.sunrise.com.lanchmode/.ActivityA t264} TaskRecord{8ff7c10 #263 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1} Run #1: ActivityRecord{5a771a1 u0 lanchmode.sunrise.com.lanchmode/.MainActivity t263}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
可以看出A、B及主activity都處於不同的Task中,那么我們點擊Recent看下,是否已經實現了我們需求了呢:
結果很是失望,只有最后啟動的B在最近任務中。
需求出現問題解決
不同的Activity已經處於不同的Task了,為什么還是在最近任務中沒有分別顯示呢?是因為在同一個應用中(但是Recent的描述就是管理最近任務,任務就是Task啊)?通過查看activity的屬性,發現了taskAffinity這個屬性;
- taskAffinity表示當前activity具有親和力的一個任務(翻譯不是很准確,原句為The task that the activity has an affinity for.),大致可以這樣理解,這個 taskAffinity表示一個任務,這個任務就是當前activity所在的任務。
-
在概念上,具有相同的affinity的activity(即設置了相同taskAffinity屬性的activity)屬於同一個任務。
-
一個任務的affinity決定於這個任務的根activity(root activity)的taskAffinity。
-
這個屬性決定兩件事:當activity被re-parent時,它可以被re-paren哪個任務中;當activity以FLAG_ACTIVITY_NEW_TASK標志啟動時,它會被啟動到哪個任務中。(這個比較 難以理解,請結合中的屬性allowTaskReparenting和Intent中的標志 FLAG_ACTIVITY_NEW_TASK加以理解)
-
默認情況下,一個應用中的所有activity具有相同的taskAffinity,即應用程序的包名。我們可以通過設置不同的taskAffinity屬性給應用中的activity分組,也可以把不同的 應用中的activity的taskAffinity設置成相同的值。
-
為一個activity的taskAffinity設置一個空字符串,表明這個activity不屬於任何task。
那么就是就使用taskAffinity設置A、B的親和力:
<activity
android:name=".ActivityA" android:label="@string/title_activity_activity" android:launchMode="singleInstance" android:taskAffinity="com.sunrise.A" android:theme="@style/AppTheme.NoActionBar" /> <activity android:name=".ActivityB" android:label="@string/title_activity_b" android:taskAffinity="com.sunrise.B" android:launchMode="singleInstance" android:theme="@style/AppTheme.NoActionBar" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
然后再運行程序,首先查看棧情況:
Running activities (most recent first):
TaskRecord{b1c230d #265 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1}
Run #3: ActivityRecord{638abae u0 lanchmode.sunrise.com.lanchmode/.ActivityB t265}
TaskRecord{7b648d3 #264 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1}
Run #2: ActivityRecord{65e4f8b u0 lanchmode.sunrise.com.lanchmode/.ActivityA t264}
TaskRecord{8ff7c10 #263 A=lanchmode.sunrise.com.lanchmode U=0 StackId=1 sz=1}
Run #1: ActivityRecord{5a771a1 u0 lanchmode.sunrise.com.lanchmode/.MainActivity t263}
棧的情況沒有變化,然后再點擊Recent,運行如下圖
結果是OK了!!!
總結
如果需要將同一個APP的不同Activity在Recent中顯示,需滿足如下兩點:
- LaunchMode設置為singleInstance。
- 設置android:taskAffinity參數。