Android-Activity所應該了解的大概就這樣躏敢。(中)

本文出自 “阿敏其人” 簡書博客春感,轉(zhuǎn)載或引用請注明出處慎冤。

Android-Activity所應該了解的大概就這樣疼燥。(上)
Android-Activity所應該了解的大概就這樣。(下)

五蚁堤、任務棧/Activity的啟動模式

知道生命周期醉者、線程的優(yōu)先級和Activity的異常銷毀,下面我們來認識一下任務棧违寿。

我們上面進行的那么多描述和代碼湃交,都是在standard這種默認的任務棧進行的。

棧的概念這里就不再贅述藤巢,這里知道先進后出就好搞莺。就像子彈夾。

不同的任務棧掂咒,也稱為不同的啟動模式才沧。

1、任務棧的分類:

任務棧有以下四種

  • ** standard 默認的啟動模式,標準模式**
  • ** singletop 單一頂部模式 (頂部不會重復)**
  • ** singleTask 單一任務棧绍刮,干掉頭上的其他Activity**
  • ** singleInstance 單一實例(單例)温圆,任務棧里面自已自己一個人**

一般來說用默認的就好,當我們程序感覺切換奇怪孩革,或者某個activity占用開銷太大之類的岁歉,才考慮使用其他的啟動默認。

2膝蜈、指定任務棧Activity的啟動模式

待會我們再來詳細解釋這些不同的任務棧詳細區(qū)別锅移,現(xiàn)在,我們先看一下怎么指定一個Activity的任務棧模式饱搏,也就是啟動模式非剃。

默認的Activity都是standard模式的,那如果我們要把一個Activity指定為 singleTask 模式呢推沸?

有兩種啟動方法:一種方法是manifest指定备绽,另外一種方式是代碼指定。

2.1 manifest指定

比如我們要指定為singleTask模式
manifest里面的Activity有個 launchMode屬性來制定啟動模式:

        <activity android:name=".SecondActivity"
            
            android:launchMode="singleTask"
            
            />

2.2 代碼指定 intent.addFlag

比如我們要指定為singleTop模式

Intent intent  = new Intent();
intent.setClass(FirstActivity.this,SecondActivity.class);
// 通過Intent的addFlag指定
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

2.3鬓催、兩種方式的對比

1肺素、從優(yōu)先級來說,代碼指定優(yōu)先于manifest指定
2深浮、兩者各有局限压怠,
manifest無法設定 FLAG_ACTIVITY_CLEAR_TOP 標識
代碼指定無法指定為 singleInstance啟動模式

3、怎么查看當前app的任務棧數(shù)量和任務棧里面的Activity

3.1 adb shell dumpsys activity

在終端鍵入這樣的指令:
adb shell dumpsys activity

查看當前手機的任務棧運行情況

即可得到我們想要的信息飞苇,回車后會列出相當多的信息菌瘫,我們需要找到如下的分類
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)

下面是一份示例log摘取:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
  Stack #0:
    Task id #1
      TaskRecord{529322d8 #1 A=com.android.launcher U=0 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10600000 cmp=com.android.launcher/com.android.launcher2.Launcher }
        Hist #0: ActivityRecord{5297586c u0 com.android.launcher/com.android.launcher2.Launcher t1}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 cmp=com.android.launcher/com.android.launcher2.Launcher }
          ProcessRecord{5293299c 17717:com.android.launcher/u0a8}

    Running activities (most recent first):
      TaskRecord{529322d8 #1 A=com.android.launcher U=0 sz=1}
        Run #0: ActivityRecord{5297586c u0 com.android.launcher/com.android.launcher2.Launcher t1}

  Stack #1:
    Task id #25
      TaskRecord{52a1682c #25 A=com.amqr.taskstack U=0 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.amqr.taskstack/.FirstActivity }
        Hist #2: ActivityRecord{52980338 u0 com.amqr.taskstack/.ThirdActivity t25}
          Intent { cmp=com.amqr.taskstack/.ThirdActivity }
          ProcessRecord{5296870c 32225:com.amqr.taskstack/u0a85}
        Hist #1: ActivityRecord{5297ef0c u0 com.amqr.taskstack/.SecondActivity t25}
          Intent { flg=0x20000000 cmp=com.amqr.taskstack/.SecondActivity }
          ProcessRecord{5296870c 32225:com.amqr.taskstack/u0a85}
        Hist #0: ActivityRecord{529f1cc8 u0 com.amqr.taskstack/.FirstActivity t25}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.amqr.taskstack/.FirstActivity }
          ProcessRecord{5296870c 32225:com.amqr.taskstack/u0a85}

    Running activities (most recent first):
      TaskRecord{52a1682c #25 A=com.amqr.taskstack U=0 sz=3}
        Run #2: ActivityRecord{52980338 u0 com.amqr.taskstack/.ThirdActivity t25}
        Run #1: ActivityRecord{5297ef0c u0 com.amqr.taskstack/.SecondActivity t25}
        Run #0: ActivityRecord{529f1cc8 u0 com.amqr.taskstack/.FirstActivity t25}

    mResumedActivity: ActivityRecord{52980338 u0 com.amqr.taskstack/.ThirdActivity t25}

  mFocusedActivity: ActivityRecord{52980338 u0 com.amqr.taskstack/.ThirdActivity t25}
  mDismissKeyguardOnNextActivity=false
  mFocusedStack=ActivityStack{52a267fc stackId=10, 1 tasks} mStackState=STACK_STATE_HOME_IN_BACK
  mSleepTimeout=false
  mCurTaskId=25
  mUserStackInFront={}

  Recent tasks:
  * Recent #0: TaskRecord{52a1682c #25 A=com.amqr.taskstack U=0 sz=3}
  * Recent #1: TaskRecord{529322d8 #1 A=com.android.launcher U=0 sz=1}
  * Recent #2: TaskRecord{529890a0 #11 A=com.android.systemui U=0 sz=0}


3.2布卡、 ACTIVITY MANAGER ACTIVITIES

在ACTIVITY MANAGER ACTIVITIES 大分類里雨让,
找到Running activities (most recent first),可以看到最近正在操作的那個程序涉及到任務棧個數(shù)忿等,以及每個任務棧的Activity數(shù)量栖忠,根據(jù)位置上下排序,最上面的是棧頂贸街,最下面的是棧底庵寞。棧頂就是最近的操作界面

3.3、Running activities (most recent first)

我們把Running activities (most recent first)單獨拿出來說薛匪。
下面這份信息捐川,顯示著最近運行的一個程序的只有一個任務棧,任務棧里面有三個activit逸尖,棧頂是ThirdActivity古沥,棧底是FirstActivity。
這個任務棧的名稱是com.amqr.taskstack娇跟。

    Running activities (most recent first):
      TaskRecord{52a1682c #25 A=com.amqr.taskstack U=0 sz=3}
        Run #2: ActivityRecord{52980338 u0 com.amqr.taskstack/.ThirdActivity t25}
        Run #1: ActivityRecord{5297ef0c u0 com.amqr.taskstack/.SecondActivity t25}
        Run #0: ActivityRecord{529f1cc8 u0 com.amqr.taskstack/.FirstActivity t25}

再來一份例子:

    Running activities (most recent first):
      TaskRecord{528f99b4 #12 A=com.taskstack.thirdtask U=0 sz=1}
        Run #1: ActivityRecord{529d828c u0 com.amqr.taskstack/.ThirdActivity t12}
      TaskRecord{529e4584 #11 A=com.amqr.taskstack U=0 sz=1}
        Run #0: ActivityRecord{529a8c5c u0 com.amqr.taskstack/.FirstActivity t11}

比如這份終端信息岩齿。就表示當前當前最近的運行的有兩個任務棧的,(為什么一個程序的運行有兩個任務棧苞俘?這就涉及到singleTask或者singleInstance啟動模式了盹沈,后面會細說漫拭。)
其中答倡,一個任務棧的是com.taskstack.thirdtask崖技,(我們自己指定的名稱)么夫,當前這個任務棧里面只有一個activity肛鹏。
另外一個任務棧的名稱是com.amqr.taskstack遏弱,這個是系統(tǒng)默認自帶的任務棧济蝉,名字就是包名疾就。

我們拿出一條來分析把

TaskRecord{528f99b4 #12 A=com.taskstack.thirdtask U=0 sz=1} 
  Run #1: ActivityRecord{529d828c u0 com.amqr.taskstack/.ThirdActivity t12}

像這個澜驮,528f99b4 #12這么一串里面陷揪,這個#12可以說是這個任務棧的唯一標示(有時候會兩個任務棧出現(xiàn) 任務棧A=“aaa.bbb.ccc”的aaa.bbb.ccc一樣的情況,想要根本區(qū)分?是否為同一個任務棧杂穷,用的就是這個 #號+num悍缠,如果兩個人任務棧的 #+num 和 A="aaa.bbb.ccc" 兩者都一致的話,那么這兩個任務棧絕對會同一個任務棧)
至于最后面的 sz=num耐量,這個num代表這個任務棧里面當前存放了多少個Activity飞蚓。

什么時候出現(xiàn)兩個任務棧 aaa..bbb.ccc 相同的但是 #num 不同:singleInstance
什么時候出現(xiàn)兩個任務棧 aaa.bbb.ccc 和 #num 都相同:singleTask + taskAffinity

3.4、 Recent tasks 手機當前的運行的任務棧

(注意:Recent tasks代表的最近手機運行的程序的任務棧廊蜒,不是對應正在運行的程序的個數(shù)(因為有的程序可能有多個任務棧)趴拧,更加不是進程數(shù)溅漾。)

  Recent tasks:
  * Recent #0: TaskRecord{52a1682c #25 A=com.amqr.taskstack U=0 sz=3}
  * Recent #1: TaskRecord{529322d8 #1 A=com.android.launcher U=0 sz=1}
  * Recent #2: TaskRecord{529890a0 #11 A=com.android.systemui U=0 sz=0}

這個是記錄手機當前的運行的任務棧數(shù)量的。
當我們長按home鍵著榴,或者按下虛擬的菜單鍵添履,(因機型而異),反正就是列出正在運行的運行的任務棧的界面脑又,假設我們的正在運行的是1個任務棧暮胧,一般來說,這時Rcent tasks就會顯示記錄著3個任務棧问麸,如果我們手機顯示正在運行兩個2個往衷,那么終端的Rcent tasks就會顯示記錄著4個任務棧,即為N+2個严卖。(有時候會是N+1席舍,只有com.android.launcher )
多出來的那個兩個上面寫的很清楚,那么就是com.android.launcher 和 com.android.systemui妄田,即為系統(tǒng)啟動器和系統(tǒng)UI界面俺亮。

我們在來個圖文詳細點的吧。

當前手機任務列表運行著3個任務棧(不要以為任務棧就是程序疟呐,一個程序可能有多個任務棧)


當前手機任務列表運行著3個任務棧.png

查看一下終端脚曾,會顯示記錄著5個。

  Recent tasks:
  * Recent #0: TaskRecord{52a0c9e4 #16 A=com.android.systemui U=0 sz=1}
  * Recent #1: TaskRecord{528ea064 #1 A=com.android.launcher U=0 sz=1}
  * Recent #2: TaskRecord{529e0c18 #18 A=android.task.mms U=0 sz=1}
  * Recent #3: TaskRecord{529b3f00 #17 A=android.task.contacts U=0 sz=1}
  * Recent #4: TaskRecord{529589e4 #15 A=android.task.browser U=0 sz=1}

.
.
再次說明启具,列表顯示的是任務棧本讥,不是程序


一個程序的兩個任務棧.png

.
.

4、四種啟動模式詳解

4.1鲁冯、 standard 默認的啟動模式,標準模式

結論:每開啟一個Activity拷沸,就會在棧頂添加一個Activity實例。多次間隔或者直接啟動一個甲Activity會添加多個甲的示例薯演,可重復添加撞芍。(間隔 ABA, 直接 ACC或者AAA)
??這里我們需要明白一個事情,Service和ApplicationContext是沒辦法直接開啟一個新的Activity跨扮,因為只有Activity類型的Context的Activity才能開啟序无,但還是有解決辦法的,那就是讓我們要開的那個新的Activity設置為FLAG_ACTIVITY_NEW_TASK標識衡创。

情景實測

比如我們的程序里面有FirstActivity帝嗡,SecondActivity、ThirdActivity和Fourth四個Activity璃氢,為了表示方便哟玷,我們就用A,B,C和D來分別指代吧。其中一也,A為啟動頁巢寡。(當前A,B,C,D都是standard模式)

  • 情況1: 啟動后顯示A喉脖,接著打開B,緊接著打開C讼渊。那么顯而易見动看,這時候只有一個任務棧尊剔,假設為S1
    啟動A:任務棧S1里面只有A
    接著打開B:任務棧里面變成BA爪幻,B在A上面,B為棧頂须误。
    接著打開C挨稿,任務棧里面變成了CBA,棧頂是C京痢,棧底是A奶甘。

大概是這個樣子

standard模式簡單ABC手機界面.gif
standard模式簡單ABC.gif

后面不會這么貼圖了,第一個就圖文說的清楚一些祭椰。

  • 情況2: 打開A臭家,打開B,再次打開A
    此時任務棧: ABA
    那么任務棧里面的是 ABA , 其中第一次打開的A位于棧底方淤,第二次打開的A為了棧頂钉赁。

利用adb shell dumpsys activity查看Running activities (most recent first)可以得到證實:

    Running activities (most recent first):
      TaskRecord{52995938 #35 A=com.amqr.taskstack U=0 sz=3}
        Run #2: ActivityRecord{52a02754 u0 com.amqr.taskstack/.FirstActivity t35}
        Run #1: ActivityRecord{529fdd68 u0 com.amqr.taskstack/.SecondActivity t35}
        Run #0: ActivityRecord{529ed754 u0 com.amqr.taskstack/.FirstActivity t35}

  • 情況3:打開A,打開C携茂,再打開C
    任務棧 CCA你踩,其中第二個C是棧頂,A位于棧底讳苦。
Running activities (most recent first):
      TaskRecord{529e1bac #4 A=com.amqr.taskstack U=0 sz=3}
        Run #2: ActivityRecord{529ae2d8 u0 com.amqr.taskstack/.ThirdActivity t4}
        Run #1: ActivityRecord{5299b11c u0 com.amqr.taskstack/.ThirdActivity t4}
        Run #0: ActivityRecord{529379d0 u0 com.amqr.taskstack/.FirstActivity t4}


.
順便附上兩次打開C的生命周期方法log带膜,附上這個log是為了跟singleTask的做對比。

12-03 07:15:21.176 15445-15445/com.amqr.taskstack D/Cur: FirstActicity onCreate
12-03 07:15:21.176 15445-15445/com.amqr.taskstack D/Cur: FirstActivity onStart
12-03 07:15:21.176 15445-15445/com.amqr.taskstack D/Cur: FirstActivity onResume
第一次按下打開C
12-03 07:15:23.360 15445-15445/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 07:15:23.376 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-03 07:15:23.376 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-03 07:15:23.376 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-03 07:15:23.788 15445-15445/com.amqr.taskstack D/Cur: FirstActivity onStop
第二次按下打開C
12-03 07:15:25.668 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-03 07:15:25.688 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-03 07:15:25.688 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-03 07:15:25.688 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-03 07:15:26.068 15445-15445/com.amqr.taskstack D/Cur: ThirdActivity onStop

附上FirstActivity的代碼鸳谜,其他三個Activity代碼類似膝藕。

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        Log.d("Cur", "FirstActicity onCreate");

        findViewById(R.id.mBtn1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(FirstActivity.this, FirstActivity.class));
            }
        });

        findViewById(R.id.mBtn2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                startActivity(new Intent(FirstActivity.this,SecondActivity.class));

                /*Intent intent  = new Intent();
                intent.setClass(FirstActivity.this,SecondActivity.class);
                // 通過Intent的addFlag指定 ,這里指定為 single task
                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

                startActivity(intent);*/
            }
        });

        findViewById(R.id.mBtn3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(FirstActivity.this,ThirdActivity.class));
            }
        });

        findViewById(R.id.mBtn4).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(FirstActivity.this,FourtActivity.class));
            }
        });

    }
}

manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".FirstActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".SecondActivity" />
        <activity android:name=".ThirdActivity"/>
        <activity android:name=".FourtActivity"/>
    </application>

</manifest>

.
.

4.2咐扭、singletop 單一頂部模式 (頂部不會重復)

結論:如果開啟的Activity已經(jīng)存在一個實例在任務棧的頂部(僅限于頂部),再去開啟這個Activity芭挽,任務棧不會創(chuàng)建新的Activity的實例了,而是復用已經(jīng)存在的這個Activity草描,onNewIntent方法被調(diào)用览绿;之前打開過,但不是位于棧頂穗慕,那么還是會產(chǎn)生新的實例入棧饿敲,不會回調(diào)onNewIntent方法。

當我們把一個Activity設置為singleTop逛绵,當我們點擊打開這個Activity的時候怀各,我們打開B頁面倔韭,會出現(xiàn)幾種情況:

說明:當前A和C都是Standard,B是singleTop

之前沒打開過:
此時任務棧里面只有A瓢对,A所在的任務棧是S1寿酌,這個時候打開singleTop的B,B入棧硕蛹,入的是S1這個棧醇疼,誰打開它進入誰的棧,此時S1的情況是BA法焰,B為棧頂秧荆。

之前打開過,但是位于棧頂:
那么復用這個棧埃仪,不會有新的實例壓入棧中乙濒。同時 onNewIntent 方法會被回調(diào),我們可以利用這個方法獲得頁面?zhèn)鬟^來的消息或者其他操作卵蛉。

之前打開過颁股,但是不是位于棧頂:
那么還是會產(chǎn)生新的實例入棧。

情景實測

實測前傻丝,我們不改動Standard的代碼甘有,只是在manifest里面的將SecondActivity的啟動模式設置為singleTop

<activity android:name=".SecondActivity"    
android:launchMode="singleTop"    />

以下的談論都是在A和C都是Standard模式,B為singleTop模式的情況進行的桑滩。

  • 情景一:打開A梧疲,然后在打開B
    沒什么好說的,很普通的沒什么區(qū)別

請出終端大哥

    Running activities (most recent first):
      TaskRecord{529c0838 #19 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{52a35f58 u0 com.amqr.taskstack/.SecondActivity t19}
        Run #0: ActivityRecord{52a6c77c u0 com.amqr.taskstack/.FirstActivity t19}

生命周期log

12-03 07:57:20.728 6639-6639/? D/Cur: FirstActicity onCreate
12-03 07:57:20.728 6639-6639/? D/Cur: FirstActivity onStart
12-03 07:57:20.728 6639-6639/? D/Cur: FirstActivity onResume

12-03 07:57:21.988 6639-6639/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 07:57:22.004 6639-6639/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 07:57:22.004 6639-6639/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 07:57:22.004 6639-6639/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 07:57:22.428 6639-6639/com.amqr.taskstack D/Cur: FirstActivity onStop

  • 情況2:打開A运准,打開B幌氮,然后再打開B
    這個時候singleTop的作用就發(fā)揮出來了。這是不會產(chǎn)生新的實例胁澳,會復用的頂部的已經(jīng)存在的實例该互。
    第一次打開B,這時任務棧里面的順序是BA韭畸,B為棧頂
    第二次打開B宇智,這時任務棧里面的順序還是BA,B為棧頂胰丁。

請出終端大哥:

    Running activities (most recent first):
      TaskRecord{52b29134 #21 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{5295bdf8 u0 com.amqr.taskstack/.SecondActivity t21}
        Run #0: ActivityRecord{52a395a8 u0 com.amqr.taskstack/.FirstActivity t21}


生命周期log
簡單說可以認為随橘,由于在我們不開新的實例的基礎上打開自己,所以就只經(jīng)歷了一個 焦點的失去和獲取 的過程锦庸。
在SecondActivity中復寫onNewIntent方法

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("Cur", "SecondActivity onDestroy");
    }

    // onNewIntent 方法机蔗,當被復用時調(diào)用
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d("Cur", "SecondActivity onNewIntent");
    }

SecondActivity 的onNewIntent方法被調(diào)用了,代表被復用。
(需要注意的是萝嘁,當我們第二次打開B的時候梆掸,因為沒有新的實例,所以不存在onCreate和onStart方法的執(zhí)行牙言,也不存在onStop)

12-03 08:02:05.564 9277-9277/? D/Cur: FirstActicity onCreate
12-03 08:02:05.564 9277-9277/? D/Cur: FirstActivity onStart
12-03 08:02:05.564 9277-9277/? D/Cur: FirstActivity onResume
// 第一次打開B
12-03 08:02:10.000 9277-9277/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 08:02:10.024 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 08:02:10.024 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 08:02:10.024 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 08:02:10.436 9277-9277/com.amqr.taskstack D/Cur: FirstActivity onStop

// 第二次打開B 生命周期明顯發(fā)生變化酸钦,只剩下 onRause和onResume
12-03 08:02:11.720 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onPause
12-03 08:02:11.724 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onNewIntent
12-03 08:02:11.724 9277-9277/com.amqr.taskstack D/Cur: SecondActivity onResume

  • 情況3 ,打開A咱枉,打開B卑硫,打開C,再打開B

這時雖然B是singleTop庞钢,但是由于打開A拔恰,打開B,打開C 的步驟走完任務棧里面的順序是CBA基括,C是棧頂,因為B不處于棧頂所以不會復用B财岔,此時還是會產(chǎn)生新的B實例進行入棧风皿。

有請終端先生:


    Running activities (most recent first):
      TaskRecord{52a15e50 #23 A=com.amqr.taskstack U=0 sz=4}
        Run #3: ActivityRecord{529d9310 u0 com.amqr.taskstack/.SecondActivity t23}
        Run #2: ActivityRecord{529d1b64 u0 com.amqr.taskstack/.ThirdActivity t23}
        Run #1: ActivityRecord{5297e728 u0 com.amqr.taskstack/.SecondActivity t23}
        Run #0: ActivityRecord{5297b8fc u0 com.amqr.taskstack/.FirstActivity t23}

從上面的終端信息我們知道,B真的還是產(chǎn)生新的實例匠璧,沒有復用桐款,只要B不在頂部,特技就發(fā)揮不出來夷恍。

生命周期也是沒有什么特別的

12-03 08:10:24.080 11761-11761/com.amqr.taskstack D/Cur: FirstActicity onCreate
12-03 08:10:24.080 11761-11761/com.amqr.taskstack D/Cur: FirstActivity onStart
12-03 08:10:24.080 11761-11761/com.amqr.taskstack D/Cur: FirstActivity onResume
// 第一次打開B
12-03 08:10:26.888 11761-11761/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 08:10:26.908 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 08:10:26.908 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 08:10:26.908 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 08:10:27.340 11761-11761/com.amqr.taskstack D/Cur: FirstActivity onStop

// 打開C
12-03 08:10:27.880 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onPause
12-03 08:10:27.888 11761-11761/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-03 08:10:27.888 11761-11761/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-03 08:10:27.888 11761-11761/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-03 08:10:28.300 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onStop

// 第二次打開B魔眨,
12-03 08:10:29.040 11761-11761/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-03 08:10:29.056 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 08:10:29.056 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 08:10:29.056 11761-11761/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 08:10:29.436 11761-11761/com.amqr.taskstack D/Cur: ThirdActivity onStop

.
.

4.3、singleTask 單一任務 (整個任務棧只有一個對應自身的實例)

結論:如果開啟的甲Activity已經(jīng)存在一個實例在任務棧S1酿雪,再去開啟這個Activity遏暴,位于棧頂則直接復用,回調(diào)onNewIntent方法指黎;位于里面朋凉,也是復用,回調(diào)onNewIntent方法醋安,復用的同時的是直接把自己上方的全部Activity都干掉杂彭。

當我們把一個Activity設置為singleTask模式之后,當我們點擊開啟這個Activity吓揪,會出現(xiàn)3種情況:

說明:打開B亲怠,A和C是Standard,B是singleTask

之前沒開啟過:A開啟B的時候柠辞,B進入A的任務棧团秽。為了頂部

之前開啟過情況1:如果現(xiàn)在任務棧情況是BA,B位于棧頂,此時點擊B徙垫,那么不會創(chuàng)建新的實例讥裤,任務棧還是BA,回調(diào)onNewIntent方法姻报。

之前開啟過情況2:假如現(xiàn)在任務棧情況是CBA己英,C為了棧頂,那么這時打開B吴旋,因為B是singleTask损肛,這時不會創(chuàng)建新的實例,但是肯定會把B置為棧頂(B在回到棧頂?shù)臅r候不是跳過去的荣瑟,而是把自己上面的其他Activity全部干掉治拿,這樣就只剩下自己和自己下面的Activity了),那么這時任務棧里面的情況就剩下 BA笆焰,回調(diào)onNewIntent方法.

.
.

情景實測

好啦劫谅,情況說完了,現(xiàn)在應該進行實測了嚷掠。
原先的代碼不用改捏检,只需要把SecondActivity指定為singleTask模式,我們這里采用manifes指定

        <activity android:name=".SecondActivity"
            android:launchMode="singleTask"
            />

以下討論的都是A和C都為Standard不皆,B為singleTask

  • 情況1贯城,打開A,打開B霹娄,在打開B能犯。
    最終任務棧的結果是 BA. 其中B是棧頂,而且B只有一個犬耻,A是棧底踩晶。此時onNewIntent方法會被回調(diào)。

這個演示需要有一個圖片香追,明確清楚地知道我們第二次打開B的時候是打不開合瓢,沒反應的。

singleTask只有一個實例.gif

通過上圖透典,我們知道第二次點擊“開啟第2個Activity”是沒有辦法再次打開一個已經(jīng)采用singleTask而且已經(jīng)位于頂部的Activity新的實例晴楔。因為他就是那里,不會新增一個新的實例峭咒。(可以跟Standard的 情況3 做比較)

終端的數(shù)據(jù)可以證明一切:

 Running activities (most recent first):
      TaskRecord{529f16ec #2 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{52a52380 u0 com.amqr.taskstack/.SecondActivity t2}
        Run #0: ActivityRecord{529bc564 u0 com.amqr.taskstack/.FirstActivity t2}

查看下面的log税弃,對比生命周期。
這里跟單一頂部一樣的效果凑队。

12-03 07:11:22.024 11795-11795/com.amqr.taskstack D/Cur: FirstActicity onCreate
12-03 07:11:22.024 11795-11795/com.amqr.taskstack D/Cur: FirstActivity onStart
12-03 07:11:22.024 11795-11795/com.amqr.taskstack D/Cur: FirstActivity onResume
第一次按下打開B
12-03 07:11:30.980 11795-11795/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 07:11:30.992 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 07:11:30.992 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 07:11:30.992 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 07:11:31.384 11795-11795/com.amqr.taskstack D/Cur: FirstActivity onStop
第二次按下打開B
12-03 07:11:48.280 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onPause
12-03 07:11:48.280 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onNewIntent
12-03 07:11:48.280 11795-11795/com.amqr.taskstack D/Cur: SecondActivity onResume

  • 情況2 打開A则果,打開B幔翰,打開C,打開D西壮,再次打開B遗增。
    任務棧最終的情況 BA
    這個情況有意思,當我們第二次打開B的時候款青,他會把自己上方的全部Activity給干掉做修,最后只剩下自己和他身下的Activity了。
    說到底也正常抡草,棧的結構看數(shù)據(jù)結構就知道了饰及,其實也可以聯(lián)想到現(xiàn)實,子彈夾我們想把倒數(shù)第二的子彈打出來康震,自然要把他前面的兩個子彈給清掉燎含。

分兩步來吧看個究竟吧
當我們打開A,打開B腿短,打開C屏箍,打開D,任務棧里面的情況是這樣滴

召喚終端大哥

    Running activities (most recent first):
      TaskRecord{52a36d80 #11 A=com.amqr.taskstack U=0 sz=4}
        Run #3: ActivityRecord{529be7bc u0 com.amqr.taskstack/.FourtActivity t11}
        Run #2: ActivityRecord{5295bdf8 u0 com.amqr.taskstack/.ThirdActivity t11}
        Run #1: ActivityRecord{5294692c u0 com.amqr.taskstack/.SecondActivity t11}
        Run #0: ActivityRecord{52a5f5f8 u0 com.amqr.taskstack/.FirstActivity t11}

就在這時答姥,任務棧的順序是:DCBA ,其中D是棧頂铣除。
這時我們按下打開B,倒數(shù)第二的B 發(fā)射出一道閃閃金光鹦付,把上方的C和D全殲了,這時任務棧的順序就只剩下BA了择卦,B為棧頂敲长,好殘忍的說。

然后再次召喚終端出場

    Running activities (most recent first):
      TaskRecord{52a15cdc #12 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{5294692c u0 com.amqr.taskstack/.SecondActivity t12}
        Run #0: ActivityRecord{52a66cc8 u0 com.amqr.taskstack/.FirstActivity t12}

這里在查看一下生命周期的log秉继,發(fā)現(xiàn)D和C付出了血的代價祈噪,直接被onDestroy了。

12-03 07:24:16.536 23760-23760/? D/Cur: FirstActicity onCreate
12-03 07:24:16.536 23760-23760/? D/Cur: FirstActivity onStart
12-03 07:24:16.536 23760-23760/? D/Cur: FirstActivity onResume

12-03 07:24:20.072 23760-23760/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 07:24:20.088 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 07:24:20.088 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 07:24:20.088 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 07:24:20.484 23760-23760/com.amqr.taskstack D/Cur: FirstActivity onStop

12-03 07:24:20.940 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onPause
12-03 07:24:20.956 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-03 07:24:20.956 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-03 07:24:20.956 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-03 07:24:21.352 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onStop

12-03 07:24:21.708 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-03 07:24:21.720 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onCreate
12-03 07:24:21.720 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onStart
12-03 07:24:21.720 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onResume
12-03 07:24:22.128 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onStop
12-03 07:24:24.400 23760-23760/com.amqr.taskstack D/Cur: ThirdActivity onDestroy

12-03 07:24:24.404 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onPause
12-03 07:24:24.408 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onNewIntent
12-03 07:24:24.408 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 07:24:24.408 23760-23760/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 07:24:24.784 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onStop
12-03 07:24:24.784 23760-23760/com.amqr.taskstack D/Cur: FourtActivity onDestroy

singleTask的談論至此完畢尚辑。

.
.

4.4 singleInstance 單一實例(單例)辑鲤,任務棧里面自已自己一個人

結論:當啟動一個啟動模式為singleInstance的Activity時(之前沒啟動過),這時系統(tǒng)將開辟出另外一個任務棧杠茬,用于存放這個Activity月褥,而且這個新的任務棧只能存放自身這唯一一個Activity。singleInstance頁面作為前臺任務打開自己打開自己瓢喉,則復用宁赤,任務棧順序無變化;singleInstance頁面作為后臺任務棧栓票,則切換成為前臺任務棧决左,無新實例產(chǎn)生,復用。

復用就會調(diào)用onNewIntent方法佛猛。

情景實測

以下的A和B都是Standard惑芭,然后C和D我們都通manifest把啟動模式設定為 singleInstance

        <activity android:name=".ThirdActivity"

            android:launchMode="singleInstance"
            />
        <activity android:name=".FourtActivity"
            android:launchMode="singleInstance"
            />
  • 情景1:打開A,打開B继找,打開為singleInstance的C
    打開A遂跟,A存在于任務棧S1,此時任務棧里面只有A码荔,
    打開B, B入棧漩勤,進入S1,此時S1的里面有兩個Activity缩搅,順序為BA越败,B為棧頂。

打開C硼瓣,因為C是singleInstance究飞,所以自己的任務棧。很明顯堂鲤,這個時候C不會進入S1的亿傅。而是會開辟出來一個全新的任務棧,我們就稱為任務棧S2吧瘟栖,
注意葵擎,此時S2屬于前臺任務棧,S1屬于后臺任務棧半哟。

如果非要排個需要序號的話酬滤,那么就是 (S2-C)、(S1-B)寓涨、(S1-A)盯串,前面的是老大。

請出終端大哥:

    Running activities (most recent first):
      TaskRecord{52a54d24 #31 A=com.amqr.taskstack U=0 sz=1}
        Run #2: ActivityRecord{5297e728 u0 com.amqr.taskstack/.ThirdActivity t31}
      TaskRecord{52a193f4 #30 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{5297b8fc u0 com.amqr.taskstack/.SecondActivity t30}
        Run #0: ActivityRecord{52a5f120 u0 com.amqr.taskstack/.FirstActivity t30}

別只看A="aaa.bbb.ccc"相同戒良, 注意体捏,#num ,比如#31和#30就不同就代表是兩個不同任務棧糯崎。#號帶的數(shù)字是最能區(qū)分的標志几缭。我們說的 # 是緊挨著任務棧名稱左邊的那個#。

生命周期沒什么影響

12-03 08:32:27.108 24263-24263/com.amqr.taskstack D/Cur: FirstActicity onCreate
12-03 08:32:27.108 24263-24263/com.amqr.taskstack D/Cur: FirstActivity onStart
12-03 08:32:27.108 24263-24263/com.amqr.taskstack D/Cur: FirstActivity onResume
// 打開B
12-03 08:32:28.828 24263-24263/com.amqr.taskstack D/Cur: FirstActivity onPause
12-03 08:32:28.844 24263-24263/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-03 08:32:28.844 24263-24263/com.amqr.taskstack D/Cur: SecondActivity onStart
12-03 08:32:28.844 24263-24263/com.amqr.taskstack D/Cur: SecondActivity onResume
12-03 08:32:29.236 24263-24263/com.amqr.taskstack D/Cur: FirstActivity onStop
// 打開為 singleInstance 的C
12-03 08:32:29.888 24263-24263/com.amqr.taskstack D/Cur: SecondActivity onPause
12-03 08:32:29.892 24263-24263/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-03 08:32:29.892 24263-24263/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-03 08:32:29.892 24263-24263/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-03 08:32:30.656 24263-24263/com.amqr.taskstack D/Cur: SecondActivity onStop

  • 情景2拇颅、打開A奏司,打開B,打開為singleInstance的C樟插,然后按下返回鍵韵洋,第二次按返回鍵邑雅,第三次再按下返回鍵蚯舱。

也就是在情景1的條件下再按下返回鍵结执。

我們再續(xù)前緣接著說挚币。
第一次按下返回鍵,S2銷毀副编,S1成為前臺任務棧负甸,S1任務棧里面的順序是BA,其中B是棧頂痹届。
界面停留在B界面呻待。

第二次按下返回鍵,界面退到A界面队腐,S1任務里面B出棧蚕捉,任務棧里面只剩A。

第三次按下返回鍵柴淘,整個程序退出迫淹,任務棧S1銷毀。

  • 情景3为严,打開A敛熬,打開B,打開singleInstance的C第股,C打開C(復用应民,無新實例),接著打開singleInstance的D夕吻,接著D打開C瑞妇。(復用,無新實例梭冠,改變?nèi)蝿諚m樞颍?br> C和D都復寫onNewIntent方法以便觀察。

那么這時會產(chǎn)生3個任務棧改备,A和B所在的為S1控漠,C所在的任務棧為S2,D所所在的任務棧為S3.

步驟一:
打開A悬钳,打開B盐捷,B打開的C
終端

    Running activities (most recent first):
      TaskRecord{529819f4 #44 A=com.amqr.taskstack U=0 sz=1}
        Run #2: ActivityRecord{529cfc00 u0 com.amqr.taskstack/.ThirdActivity t44}
      TaskRecord{52a05480 #43 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{529c2564 u0 com.amqr.taskstack/.SecondActivity t43}
        Run #0: ActivityRecord{529a6e24 u0 com.amqr.taskstack/.FirstActivity t43}


生命周期

12-05 23:10:11.178 15891-15891/? D/Cur: FirstActicity onCreate
12-05 23:10:11.178 15891-15891/? D/Cur: FirstActivity onStart
12-05 23:10:11.178 15891-15891/? D/Cur: FirstActivity onResume
// 打開B
12-05 23:10:16.166 15891-15891/com.amqr.taskstack D/Cur: FirstActivity onPause
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onStart
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onResume
12-05 23:10:16.558 15891-15891/com.amqr.taskstack D/Cur: FirstActivity onStop
// 第一次打開C
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onPause
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-05 23:10:18.622 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onStop

.
.
步驟2:再次打開C,復用默勾,終端信息一致碉渡。就不附上了。
生命周期有所不同母剥。

12-05 23:10:11.178 15891-15891/? D/Cur: FirstActicity onCreate
12-05 23:10:11.178 15891-15891/? D/Cur: FirstActivity onStart
12-05 23:10:11.178 15891-15891/? D/Cur: FirstActivity onResume
// 打開B
12-05 23:10:16.166 15891-15891/com.amqr.taskstack D/Cur: FirstActivity onPause
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onCreate
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onStart
12-05 23:10:16.174 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onResume
12-05 23:10:16.558 15891-15891/com.amqr.taskstack D/Cur: FirstActivity onStop
// 第一次打開C
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onPause
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onCreate
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-05 23:10:17.826 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-05 23:10:18.622 15891-15891/com.amqr.taskstack D/Cur: SecondActivity onStop
// 第二次打開C
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onNewIntent
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onResume

步驟3:C打開D

    Running activities (most recent first):
      TaskRecord{529f9160 #45 A=com.amqr.taskstack U=0 sz=1}
        Run #3: ActivityRecord{529f8ff8 u0 com.amqr.taskstack/.FourtActivity t45}
      TaskRecord{529819f4 #44 A=com.amqr.taskstack U=0 sz=1}
        Run #2: ActivityRecord{529cfc00 u0 com.amqr.taskstack/.ThirdActivity t44}
      TaskRecord{52a05480 #43 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{529c2564 u0 com.amqr.taskstack/.SecondActivity t43}
        Run #0: ActivityRecord{529a6e24 u0 com.amqr.taskstack/.FirstActivity t43}

生命周期

接著上次的LOG

// 第二次打開C
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onNewIntent
12-05 23:10:20.650 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onResume
// C打開D
12-05 23:32:29.242 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onCreate
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onStart
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onResume
12-05 23:32:30.038 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onStop

發(fā)現(xiàn)多了一個任務棧滞诺。

步驟4 D打開C

終端

    Running activities (most recent first):
      TaskRecord{529819f4 #44 A=com.amqr.taskstack U=0 sz=1}
        Run #3: ActivityRecord{529cfc00 u0 com.amqr.taskstack/.ThirdActivity t44}
      TaskRecord{529f9160 #45 A=com.amqr.taskstack U=0 sz=1}
        Run #2: ActivityRecord{529f8ff8 u0 com.amqr.taskstack/.FourtActivity t45}
      TaskRecord{52a05480 #43 A=com.amqr.taskstack U=0 sz=2}
        Run #1: ActivityRecord{529c2564 u0 com.amqr.taskstack/.SecondActivity t43}
        Run #0: ActivityRecord{529a6e24 u0 com.amqr.taskstack/.FirstActivity t43}

生命周期

接上次的C打開D的Log
// C打開D
12-05 23:32:29.242 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onPause
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onCreate
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onStart
12-05 23:32:29.246 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onResume
12-05 23:32:30.038 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onStop


// D打開C
12-05 23:56:10.402 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onPause
12-05 23:56:10.402 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onNewIntent
12-05 23:56:10.402 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onStart
12-05 23:56:10.402 15891-15891/com.amqr.taskstack D/Cur: ThirdActivity onResume
12-05 23:56:11.154 15891-15891/com.amqr.taskstack D/Cur: FourtActivity onStop

沒有新的任務棧產(chǎn)生形导,前臺任務棧發(fā)了變化。任務棧里面也不會有新的Activity產(chǎn)生习霹。

singleInstance分析至此結束朵耕。

5、另說singleTask的小伙伴:taskAffinity + allowTaskReparenting

說在前面

taskAffinity是singleTask的好伙伴淋叶,這是肯定的阎曹。

按照官網(wǎng)大概是這么說taskAffinity 和 allowTaskReparenting的:
taskAffinity: 可以指定一個Activity放入哪一個任務棧中,利用taskAffinity制定一個任務棧的名稱煞檩,把Activity放進這個任務棧中处嫌。實現(xiàn)這個過程需要singleTask和allowTaskReparenting兩者的協(xié)助。

allowTaskReparenting:參數(shù)是boolean斟湃,如果我們利用taskAffinity讓Activity放入一個指定的任務棧熏迹,需要allowTaskReparenting的同意,為true就可以跟著別人跑桐早,為false就乖乖在原地呆著那都不許去癣缅。

按照的官網(wǎng)的說法,實測后發(fā)現(xiàn)哄酝,taskAffinity確實可以讓Activity跑到指定的任務棧(不用跟app自帶的任務椨汛妫混了),但是allowTaskReparenting沒什么作用陶衅,設置或者不設置沒什么改變屡立。設置為true,設置為false搀军,或者不設置膨俐,一點都沒區(qū)別。

即是說官方說罩句,taskAffinity要和allowTaskReparenting配合著使用焚刺,實測是上不用,taskAffinity單兵作戰(zhàn)也是可以的门烂。(個人看法乳愉,疏忽之處請熟悉的朋友指點一下)

下面開始正式分析。

5.1屯远、taskAffinity

taskAffinity屬性用于給Activity單獨指定任務棧名稱蔓姚。這個名稱不能和包名相同,否則就沒有意義慨丐。注意taskAffinity屬性值為String坡脐,而且中間必須包含有分隔符 . (英文狀態(tài)下的點),比如com.baidu.test

另外房揭,如果想要指定一個非包名的任務棧备闲,該Activity一定要把啟動模式設置為singleTask模式晌端,否則不會生效。如果taskAffinity指定的名稱是其他程序的包名浅役,那么可以不結合singleTask斩松。念起來好像有點拗口,看下面的實測就知道怎么回事了觉既。

注意:任務棧分為前臺任務棧和后臺任務棧惧盹,后臺任務棧里面的Activity全部處于onStop狀態(tài)。

在minifest里面瞪讼,application可以設定taskAffinity钧椰,activity也可以設定taskAffinity。
taskAffinity設定的任務棧我們也稱其為一個宿主任務棧符欠。

  • application設定

    • applicatipn如果不設定嫡霞,那么就系統(tǒng)默認設定為包名。如果設定了希柿,activity跟著application走诊沪,application指定的是什么activity的任務棧的名稱就是什么。(application自帶的不設定曾撤,一般我們也不手動設定端姚,要設定也是單獨在activity里面設定)
  • activity設定

    • 設定taskAffinity之后,當啟動這個Activity之后挤悉,如果之前沒有任務棧的存在渐裸,那么就啟動系統(tǒng)會開辟出來一個新的任務棧(或者叫宿主任務棧),用于存放這個activity装悲,如果已經(jīng)存在了這個任務棧昏鹃,那么這個activity就對應進入已經(jīng)的宿主任務棧。(設定taskAffinity诀诊,不管之前存不存在洞渤,反正就不跟默認的混了,自己只認指定的任務棧属瓣,當然您宪,如果你非要把taskAffinity指定自己的包名那也沒辦法,只是那沒撒意思嘛)

我們利用taskAffinity+taskAffinity指定非手機里面任何程序的包名的任務棧時奠涌,這個任務是可以容納多個activity的。比如現(xiàn)在有A,B,C三個界面磷杏,B和C都啟動模式都是taskAffinity溜畅,而且taskAffinity指定的都是同一個包名。
那么當我們A開啟B极祸,B再開啟C的時候慈格,結果就是A在app默認自帶的任務棧S1里怠晴,而B和C在同一個任務棧S2里面。這是S2里面的順序是CB浴捆,C是棧頂蒜田。然后這個時候從C打開B,那么事情來了选泻,本來的C下面的B會再次匯聚天地能量冲粤,發(fā)出一道閃閃金光,把自己上方的所有Activity全部殲滅页眯,這個時候C就掛了梯捕。可見窝撵,不管和誰合作傀顾,singleTask依舊霸道,不可阻擋碌奉,誰擋誰卒短曾。

有代碼有真相,先來看一下如何利用taskAffinity給activty指定任務棧:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.amqr.newtaskone" >

    <activity android:name=".OtherActivity"
// android:taskAffinity 的使用一般都是有singeTask一起出現(xiàn)的
        android:taskAffinity="com.task.try"

        />

如上赐劣,我們的包名是 com.amqr.newtaskone嫉拐,然后我們給我們的activity指定了宿主任務棧的的名稱為 com.task.try 。這樣他就和系統(tǒng)默認的任務棧名稱不同了隆豹。

5.2椭岩、allowTaskReparenting

allowTaskReparenting:參數(shù)是boolean。
如果我們利用taskAffinity讓Activity放入一個指定的任務棧璃赡,需要allowTaskReparenting的同意判哥,為true就可以跟著別人跑,為false就乖乖在原地呆著除了自己家那都不許去碉考。

怎么用

        <activity android:name=".OtherActivity"

            android:taskAffinity="com.task.try"
            android:allowTaskReparenting="true"

            />

5.3 實測

情況1和情況2塌计,app2的activity指定的任務棧名稱是app1的包名,所以不需要singleTask(這里指定包名是為了演示效果)

  • 情況1:新建兩個app侯谁。
    app1什么都不改锌仅,自帶一個MainActivity(布局文件標識一下是app1的Mainactivity)。
    在app2的manifest給app2的MainAcivity添加android:taskAffinity屬性墙贱,指定包名為 app1的包名热芹。

也就是說,當app2的MainActivity的啟動的時候會把app的默認任務棧當做自己的宿主惨撇。

我們把兩個程序安裝一下伊脓,清掉其他正在運行的程序
運行app1,然后按下home鍵(讓app1變成后臺程序)魁衙,接著打開app2报腔,我們會發(fā)現(xiàn)株搔,這時候進入的不是app2的界面,而是app1的纯蛾。

先來看一下兩個app的Mainactivty本來的面目:

app1的MainActivityUI截圖

app1的MainActivityUI截圖.png

app2的MainActivityUI截圖

app2的MainActivityUI截圖.png

接下來看一下各自的manifest

app1的manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        >
        <activity android:name=".MainActivity1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

app2的manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity2"
            android:taskAffinity="com.amqr.taskaffinity1"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

查看效果:

宿主.gif

終端大哥也顯示為只有一個任務棧纤房,那就是app1自帶的那個com.amqr.taskaffinity1

    Running activities (most recent first):
      TaskRecord{5296a83c #4 A=com.amqr.taskaffinity1 U=0 sz=1}
        Run #0: ActivityRecord{52983d74 u0 com.amqr.taskaffinity1/.MainActivity1 t4}

生命周期

12-03 22:50:46.324 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onCreate
12-03 22:50:46.324 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onStart
12-03 22:50:46.324 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onResume
// 按下home鍵
12-03 22:50:48.356 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onPause
12-03 22:50:48.872 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onStop
// 啟動app2,結果打開是app1
12-03 22:50:52.868 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onRestart
12-03 22:50:52.868 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onStart
12-03 22:50:52.868 1835-1835/com.amqr.taskaffinity1 D/Cur: MainActivity1, onResume

我們發(fā)現(xiàn)翻诉,我們點擊啟動的app2炮姨,結果啟動的卻是app1,而且米丘,在運行列表里面看不到app2的存在剑令,只有一個app1。

里面發(fā)生的是這樣的一個過程拄查,
當我們啟動app1時:app1的任務棧com.amqr.taskaffinity1 正常作為一個任務棧進入系統(tǒng)吁津,
按下home鍵時:任務棧 com.amqr.taskaffinity1 成為了一個后臺任務棧
點擊app2時: 本來應該打開的是app2的界面,但是要打開的MainActivity2發(fā)現(xiàn)自身含有android:taskAffinity堕扶,而指定的宿主任務棧就是app1打開后就存在的任務棧 com.amqr.taskaffinity1 碍脏,那么這時候 com.amqr.taskaffinity1 就成為了 MainActivity2 的宿主任務棧。
按道理稍算,這個時候本來應該是 MainActivity2 入棧而且作為棧頂?shù)陌〉湮玻鞘聦崊s沒有這么發(fā)生。也就是說糊探,這個時候钾埂,MainActivity2沒有入棧,對的科平,沒有入棧褥紫。他是跑過來搞笑的,通知了一下別人可以變成前臺任務棧了瞪慧,然后自己沒有入棧髓考,具體詳情,不得而知弃酌。
實際上發(fā)生的事情是:com.amqr.taskaffinity1 由后臺任務棧轉(zhuǎn)為前臺任務棧氨菇,而那個MainActity沒有入棧,從終端的信息就可以看得出來妓湘。

有人說查蓉,你沒按谷歌的來,沒有把allowTaskReparenting設置為true榜贴,好奶是,那我們進行其概況2,接著來一遍。

  • 情況2 還是上面的代碼聂沙,我們只是app2的manifest里面給MainActivity加上一句

android:allowTaskReparenting="true"

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity2"
            android:taskAffinity="com.amqr.taskaffinity1"
            android:allowTaskReparenting="true"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我們重新安裝兩個程序,接著來一遍初嘹。
(清除所有運行的程序及汉,打開app1,按下home屯烦,打開app2)

宿主情況2.gif

結果發(fā)現(xiàn)一樣坷随,還是貼一下對應的終端信息吧

    Running activities (most recent first):
      TaskRecord{52992bc4 #10 A=com.amqr.taskaffinity1 U=0 sz=1}
        Run #0: ActivityRecord{52a97bdc u0 com.amqr.taskaffinity1/.MainActivity1 t10}

一個樣,其實就算設置為false也是沒有變化驻龟,有興趣的可以自己試一下温眉。

注意:宿主不是絕對化的,當兩個app都認定一個宿主后翁狐,?就先來后到了类溢,誰先開啟那個任務棧誰是老大。比如說露懒,我們在可以清掉所有運行的程序闯冷,先開啟app2,然后再開啟app1懈词,我們會發(fā)現(xiàn)打開的是app2蛇耀,就不是app1了。

app2宿主.gif
  • 情況三:
    情況三不是指定程序的包名作為指定的任務棧名稱坎弯,所以需要啟動的模式singleTask一起工作纺涤。(如果不跟singleTask合作,又不指定為程序的包名抠忘,那么設置android:taskAffinity不生效)

情況三我們這樣弄撩炊,app1和app2各自都有兩個頁面,各自的啟動頁都是普通常見的褐桌,然后各自的都有另外一個其他頁面衰抑,這分屬于兩個app的其他頁面我們都給他們指定同一個任務棧名(這個任務站名不跟任意一個app包名相同)

也就是說,app1里面有MainActivity1和App1Other兩個Activity荧嵌,
app2里面有MainActivity2和App2Other兩個Activity

MainActivity1和MainActivity2都是普通的Standard
而App1Other和App2Other都在清單文件指定了自定義的任務棧名稱和singelTask啟動模式呛踊。詳見下方代碼

我們這樣操作:
第一階段:先打開app1,再打開App1Other頁面啦撮,接著按下home鍵
第二階段:(接按下home件之后)打開app2谭网,打開app2的App2Other頁面

先貼上相關圖片和代碼先:

Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png

app1的manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        >
        <activity android:name=".MainActivity1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".App1Other"

            android:taskAffinity="com.amqr.independent"
            android:launchMode="singleTask"


            />
    </application>

</manifest>

.
.
app2的manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity2"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".App2Other"
            android:taskAffinity="com.amqr.independent"
            android:launchMode="singleTask"
            />
    </application>

</manifest>

  • 第一階段,
    我們先打開app1赃春,然后打開的app1Other界面愉择。按下home鍵

效果如下圖:打開第一個activity,然后再點擊打開app1Other,按下home鍵盤锥涕,查看運行列表衷戈,會看見變成了兩個任務棧(任務棧是兩個,程序還是一個层坠,進程更加只是一個)


taskAffinity1.gif

任務棧信息



    Running activities (most recent first):
      TaskRecord{52a8eab0 #48 A=com.amqr.independent U=0 sz=1}
        Run #1: ActivityRecord{52ae1518 u0 com.amqr.taskaffinity1/.App1Other t48}
      TaskRecord{52a9cd20 #47 A=com.amqr.taskaffinity1 U=0 sz=1}
        Run #0: ActivityRecord{52a9f230 u0 com.amqr.taskaffinity1/.MainActivity1 t47}

  Recent tasks:
  * Recent #0: TaskRecord{52973240 #52 A=com.amqr.independent U=0 sz=1}
  * Recent #1: TaskRecord{52979df8 #51 A=com.amqr.taskaffinity1 U=0 sz=1}
  * Recent #2: TaskRecord{5295e6f8 #1 A=com.android.launcher U=0 sz=1}
  * Recent #3: TaskRecord{52a90f20 #46 A=com.android.systemui U=0 sz=0}

生命周期

12-04 01:53:51.808 18259-18259/? D/Cur: MainActivity1, onCreate
12-04 01:53:51.808 18259-18259/? D/Cur: MainActivity1, onStart
12-04 01:53:51.808 18259-18259/? D/Cur: MainActivity1, onResume

12-04 01:53:55.704 18259-18259/com.amqr.taskaffinity1 D/Cur: MainActivity1, onPause
12-04 01:53:55.708 18259-18259/com.amqr.taskaffinity1 D/Cur: App1Other, onCreate
12-04 01:53:55.708 18259-18259/com.amqr.taskaffinity1 D/Cur: App1Other, onStart
12-04 01:53:55.708 18259-18259/com.amqr.taskaffinity1 D/Cur: App1Other, onResume
12-04 01:53:56.468 18259-18259/com.amqr.taskaffinity1 D/Cur: MainActivity1, onStop


從上面的圖文我們知道殖妇,
當我們點擊app1時,默認的用的是系統(tǒng)的根據(jù)包名定的默認任務棧破花,這個沒什么可說的谦趣。

但是當我們點擊打開 app1Other 頁面時,就多出來一個任務棧座每,棧名是我們指定的com.amqr.independent前鹅。

而且觀察運行程序的列表,發(fā)現(xiàn)多了個圖標峭梳,但是要知道舰绘,這個絕對不是多了一個進程,只是我們每多產(chǎn)生多一個任務棧延赌,任務列表就會多出來一個圖標者蠕。

一個程序的兩個任務棧.png

進程不變

Paste_Image.png
  • 第二階段

緊接上面的環(huán)節(jié)
接下來我們來打開app2,然后打開app2的 app2Other 界面
(完整的操作:打開app1,打開app1Other界面待榔,按下home,打開app2雕憔,打開app2的Other界面)

終端信息

    Running activities (most recent first):
      TaskRecord{52a2e064 #62 A=com.amqr.independent U=0 sz=2}
        Run #3: ActivityRecord{529d1550 u0 com.amqr.taskaffinity2/.App2Other t62}
      TaskRecord{52a337a0 #63 A=com.amqr.taskaffinity2 U=0 sz=1}
        Run #2: ActivityRecord{5299485c u0 com.amqr.taskaffinity2/.MainActivity2 t63}
      TaskRecord{52a2e064 #62 A=com.amqr.independent U=0 sz=2}
        Run #1: ActivityRecord{529827a0 u0 com.amqr.taskaffinity1/.App1Other t62}
      TaskRecord{528a1e60 #61 A=com.amqr.taskaffinity1 U=0 sz=1}
        Run #0: ActivityRecord{5296bc68 u0 com.amqr.taskaffinity1/.MainActivity1 t61}

程序截圖


Paste_Image.png

我們發(fā)現(xiàn)了,
圖片的任務列表是3個嘲玫,終端的日志任務棧看起來像出現(xiàn)了4個,其實是3個任務棧俩莽,因為有兩個是重復的,為什么重復了呢出刷?

我們先來看一下這里面的兩句:
TaskRecord{52a2e064 #62 A=com.amqr.independent U=0 sz=2}
TaskRecord{52a2e064 #62 A=com.amqr.independent U=0 sz=2}
我們通過名字com.amqr.independent可以知道這肯定是同一個任務棧
其實這個sz后面表示的就是activity的個數(shù)(已測)
至于為什么分開顯示漆魔,這個應該是終端顯示的一種表示方法矢炼,終端的具體規(guī)則不太清楚。這里不是我們深究的方向胰锌。到了這里明白運行的是3個任務棧就好了枷邪。

我們這里了明白singleTask + taskAffinity是如何使用的就好了。

  • 情況4

app1里面弄3個activity,MainActivity凉袱,App1Other专甩,App3Activity,分別用A,B嫩挤,C指代,A是Standard的啟動頁,B和C都是single + taskAffinity且指定的任務棧名稱相同(不跟任何程序包名相同)棍苹。

操作過程蹂午,
第一階段:運行app1奥洼,啟動頁A啟動B,

第二階段:
再通過B啟動C
最后我們發(fā)現(xiàn),在singleTask + taskAffinity模式下還是誰當滅滅誰骡尽,在它前面的全部遭殃。

貼上代碼和相關圖片:

manifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        >
        <activity android:name=".MainActivity1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".App1Other"

            android:taskAffinity="com.amqr.independent"
            android:launchMode="singleTask"


            />


        <activity android:name=".App3Activity"
            
            android:taskAffinity="com.amqr.independent"
            android:launchMode="singleTask"

            />
    </application>

</manifest>

第一階段:

A開啟B锦担,B開啟C,這時候我們的指定任務棧里面的順序就是CB


兩個taskAffinity.gif

第一階段終端信息

    Running activities (most recent first):
      TaskRecord{52983174 #116 A=com.amqr.independent U=0 sz=2}
        Run #2: ActivityRecord{5290923c u0 com.amqr.taskaffinity1/.App3Activity t116}
        Run #1: ActivityRecord{52a80e58 u0 com.amqr.taskaffinity1/.App1Other t116}
      TaskRecord{5299bf74 #115 A=com.amqr.taskaffinity1 U=0 sz=1}
        Run #0: ActivityRecord{52a32b30 u0 com.amqr.taskaffinity1/.MainActivity1 t115}

第一階段結束。

.
.
第二階段:

緊接著上面的操作,在上面的操作里面我們的指定的任務棧里面已經(jīng)有了兩個都是singleTask的任務在里面了蘸拔,B在C的下面张遭,C是棧頂,這個時候我們從C開啟B歉甚,結果C卒,掛了仁烹。

兩個taskAffinity砰诵,消滅上方.gif

第二階段終端信息:


    Running activities (most recent first):
      TaskRecord{5295e6f8 #1 A=com.android.launcher U=0 sz=1}
        Run #1: ActivityRecord{5295cb64 u0 com.android.launcher/com.android.launcher2.Launcher t1}
      TaskRecord{52abf0cc #117 A=com.android.systemui U=0 sz=1}
        Run #0: ActivityRecord{5290923c u0 com.android.systemui/.recent.RecentsActivity t117}

本篇就先說道這里吧征唬,下次說標志位—— FLAG.

對5.2情況3有興趣的可以參考這里Android-Activity5.3情景3之完整Log參考
完。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茁彭,一起剝皮案震驚了整個濱河市总寒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌理肺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耍缴,居然都是意外死亡实胸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酪呻,“玉大人填具,你說我怎么就攤上這事筋量《L荆” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵橙喘,是天一觀的道長。 經(jīng)常有香客問我霉赡,道長棠涮,這世上最難降的妖魔是什么谦屑? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任妖滔,我火速辦了婚禮纲爸,結果婚禮上,老公的妹妹穿的比我還像新娘妆够。我一直安慰自己识啦,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布神妹。 她就那樣靜靜地躺著颓哮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸵荠。 梳的紋絲不亂的頭發(fā)上冕茅,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音腰鬼,去河邊找鬼嵌赠。 笑死,一個胖子當著我的面吹牛熄赡,可吹牛的內(nèi)容都是我干的姜挺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼彼硫,長吁一口氣:“原來是場噩夢啊……” “哼炊豪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拧篮,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤词渤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后串绩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缺虐,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年礁凡,在試婚紗的時候發(fā)現(xiàn)自己被綠了高氮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡顷牌,死狀恐怖剪芍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布纹份,位于F島的核電站吕漂,受9級特大地震影響状共,放射性物質(zhì)發(fā)生泄漏套耕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一口芍、第九天 我趴在偏房一處隱蔽的房頂上張望箍铲。 院中可真熱鬧,春花似錦鬓椭、人聲如沸颠猴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翘瓮。三九已至,卻和暖如春裤翩,著一層夾襖步出監(jiān)牢的瞬間资盅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工踊赠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呵扛,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓筐带,卻偏偏與公主長得像今穿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伦籍,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容