標籤:activity啟動模式 standard singletop singletask singleinstance
黑髮不知勤學早,白首方悔讀書遲。——《勸學》
今天花了整個下午+晚上的的時間學習了Activity的啟動模式,本來以為這個知識點很簡單,但是在學習的過程中發現,Activity的啟動模式並沒有自己想象的那麼簡單,下面我們一起來看看這Activity的四種啟動模式吧,如有疑問歡迎留言,如有謬誤歡迎大家批評指正,謝謝
Activity的啟動模式共有四種
1.standard
2.singleTop
3.singleTask
4.singleInstance
:
LaunchMode在多個Activity跳轉的過程中扮演著重要的角色,它可以決定是否產生新的Activity執行個體,是否重用已存在的Activity執行個體,是否和其他Activity執行個體公用一個task裡。這裡簡單介紹一下task的概念,task是一個具有棧結構的對象,一個task可以管理多個Activity,啟動一個應用,也就建立一個與之對應的task。
下面我們就依次來說說這幾種啟動模式
1.standard
standard模式是Activity預設的啟動模式,當我們在沒有配置activity的launchMode時它就會按照standard方式去啟動,
下面通過一個執行個體來解釋下這種啟動模式
FirstActivity代碼如下:
package com.example.activitylauchmodepractice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class FirstActivity extends Activity {private Button btn_jumpToSecondActivity;private TextView tv_showViewClass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);tv_showViewClass=(TextView) findViewById(R.id.tv_showViewClass);tv_showViewClass.setText(FirstActivity.this.toString());btn_jumpToSecondActivity=(Button) findViewById(R.id.btn_jumpToSecondActivity);btn_jumpToSecondActivity.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(FirstActivity.this,FirstActivity.class);startActivity(intent);}});}}啟動後的介面
此時它所對應的任務棧如下
在此基礎上我們點擊按鈕再次啟動Activity此時的介面如下
此時的任務棧變化過程如下
我們再次點擊按鈕跳轉到FirstActivity介面如下
此時的任務棧的變化過程如下
好了到這我們就可以分析一下了,在上述過程中我們點擊了三次按鈕它執行個體化了三個FirstActivity
這就是standard模式的特點:不管任務棧中有沒有執行個體存在它都會執行個體化一個Activity
當我們點擊返回按鈕時它會依次把最上面的Activity出棧,上面的過程中一共執行個體化了三個Activity因此我們需要點擊三次返回按鈕應用才能退出。
2.singleTop
還用上面那個例子,此時我們給FirstActivity的屬性指定為:android:launchMode="singleTop"
啟動後的介面
此時的任務棧如下
我們接著點擊按鈕發現無論點擊幾次介面都沒變說明它只執行個體化一次,此時的任務站始終是一個Activity此時點擊一次返回鍵便可退出應用。
這是只有一個Activity的情況,下面我們說說多個Activity的情況
再來一個SecondActivity代碼如下:
package com.example.activitylauchmodepractice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class SecondActivity extends Activity {private Button btn_jumpToFirstActivity_;private TextView tv_showViewClass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);tv_showViewClass=(TextView) findViewById(R.id.tv_showViewClass);tv_showViewClass.setText(SecondActivity.this.toString());btn_jumpToFirstActivity_=(Button) findViewById(R.id.btn_jumpToFirstActivity);btn_jumpToFirstActivity_.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(SecondActivity.this, FirstActivity.class);startActivity(intent);}});}}把FirstActivity的代碼稍作修改
btn_jumpToSecondActivity.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(FirstActivity.this,SecondActivity.class);startActivity(intent);}});在上面的Activity中FirstActivity的啟動模式是singleTop,SecondActivity的啟動模式是預設的standard,做好準備之後我們來做操作
啟動後的介面如下:
此時的任務棧如下
在此基礎上我們點擊一次按鈕介面如下
此時的任務棧的變化如下
在SecondActivity中再次點擊按鈕的介面如下
此時的任務棧的變化如下
從上面的過程中我們看到再次從SecondActivity跳轉到FirstActivity時兩次的FirstActivity的序號不同說明又重建了一個FirstActivity
singleTop模式的特點:當從SecondActivity跳轉到FirstActivity時,系統發現存在有FirstActivity執行個體,但不是位於棧頂,於是重建一個執行個體。這就是singleTop啟動模式的特點,即如果發現有對應的Activity執行個體正位於棧頂,則重複利用,不再產生新的執行個體,如果棧頂沒有對應的Activity則執行個體化一個。
該模式和standard模式基本一致,但有一點不同,當將要被啟動的Activity已經位於Task棧頂時,系統不會重新建立目標Activity的執行個體,而是直接複用Task棧頂的Activity
3.singleTask(內單例模式)
我們還是建立在上面的基礎上,把FirstActivity的啟動模式改為android:launchMode="singleTask"
啟動後我們點擊三次跳轉按鈕介面如所示
在上面的過程中,FirstActivity的序號是不變的,SecondActivity的序號是改變的,說明從SecondActivity跳轉到FirstActivity時,沒有產生新的執行個體,但是從FirstActivity跳轉到SecondActivity時產生了新的執行個體。
在此過程中任務棧的變化過程如下
在上面的跳轉過程中當從SecondActivity跳轉到FirstActivity時發現SecondActivity消失了,這就是singleTask的特點在這個跳轉過程中系統發現有存在的FirstActivity執行個體,於是不再產生新的執行個體,而是將FirstActivity之上的Activity執行個體統統出棧,將FirstActivity變為棧頂對象,顯示到幕前。
singleTask模式的特點:如果發現有對應的Activity執行個體,則使此Activity執行個體之上的其他Activity執行個體統統出棧,使此Activity執行個體成為棧頂對象,顯示到幕前。
Activity在同一個Task內只有一個執行個體. 當系統採用singleTask模式載入Activity時,又分為以下三種情況:
(1)如果將要啟動的Activity不存在,那麼系統將會建立該執行個體,並將其加入Task棧頂
(2)如果將要啟動的Activity已存在,且存在棧頂,那麼此時與singleTop模式的行為相同
(3)如果將要啟動的Activity存在但是沒有位於棧頂,那麼 此時系統會把位於該Activity上面的所有其他Activity全部移出Task,從而使得該目標Activity位於棧頂
4.singleInstance(全域單例模式)
這種模式是四種模式中最難理解的一種模式,因為這種模式會重新建立一個新的任務棧,將Activity放置於這個棧中,並保證其它的Activity不再進入,由於這種模式比較複雜,我們首先來說說它的原理,然後再結合執行個體進一步的理解,假如現在使用者開啟了兩個應用分別為應用1和應用2,應用1和應用2的任務棧假如如左邊,此時在應用1中想開啟Activity3,這時應用1和應用2就會共用Activity3的引用,
注意:之所以能公用Activity的引用是以應用2中的Activity設定了LaunchMode="singleInstance"為前提的。
由於這種模式比較複雜,我們舉兩個不同例子,來說明不同的問題
舉例一、
還是上面的兩個Activity。FirstActivity和SecondActivity在兩個Activityt跳轉的過程中我們列印兩個Activity所在的任務棧的ID
對以上兩個Activity做如下修改,並且把SecondActivity的啟動模式改為singleInstance
tv_showViewClass=(TextView) findViewById(R.id.tv_showViewClass);
tv_showViewClass.setText("當前Activity:"+"\n"+this.toString()+"\n"+"當前TaskId:"+this.getTaskId());啟動後和點擊跳轉按鈕後的介面如下
我們發現兩個Activity的TaskId是不同的,說明這兩個Activity是位於不同的任務棧中的,從而證實了為SecondActivity重建立立了一個任務棧,可能有的朋友會問,在這個時候如果點擊返回按鈕它們是怎麼出棧的呢?假如現在我們點擊返回按鈕它的任務棧的變化如
假如我們在SecondActivity中點擊按鈕跳轉到FirstActivity然後會以怎樣的方式退出應用呢?此時 它的任務棧的變化如下
圖中下半部分顯示的在SecondActivity中再次跳轉到FirstActivity,這個時候系統會在原始棧結構中產生一個FirstActivity執行個體,然後回退兩次,注意,並沒有退出,而是回到了SecondActivity,為什麼呢?是因為從SecondActivity跳轉到FirstActivity的時候,我們的起點變成了SecondActivity執行個體所在的棧結構,這樣一來,我們需要“迴歸”到這個棧結構。
由於singleInstance比較複雜些,我們再來舉一個兩個應用的例子為了和上面的例子混淆,我們重新寫兩個應用
第一個App中有兩個Activity分別為Activity1和ShareActivity
第二個App中有一個Activity2我們在這個App中啟動第一個App的ShareActivity
第一個App的Activity源碼如下
package com.example.activitylauchmodepractice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class Activity1 extends Activity {private Button btn_jumpToSecondActivity;private TextView tv_showViewClass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);tv_showViewClass=(TextView) findViewById(R.id.tv_showViewClass);tv_showViewClass.setText("當前Activity:"+"\n"+this.toString()+"\n"+"當前TaskId:"+this.getTaskId());btn_jumpToSecondActivity=(Button) findViewById(R.id.btn_jumpToSharedActivity);btn_jumpToSecondActivity.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(Activity1.this,ShareActivity.class);startActivity(intent);}});}}ShareActivity源碼
package com.example.activitylauchmodepractice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class ShareActivity extends Activity {private Button btn_jump;private TextView tv_showViewClass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);tv_showViewClass=(TextView) findViewById(R.id.tv_showViewClass);tv_showViewClass.setText("當前Activity:"+"\n"+this.toString()+"\n"+"當前TaskId:"+this.getTaskId());}}
我們要特別注意ShareActivity在資訊清單檔中的配置如下
<activity android:name="com.example.activitylauchmodepractice.ShareActivity" android:launchMode="singleInstance"> <intent-filter> <action android:name="SecondActivity_action"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
我們需要配置ShareActivity的action在另一個應用中啟動時會用到
第二個App中的Activity2的源碼如下
package com.example.singleinstancepractice;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private Button btn_jump;private TextView tv_showTaskId;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_showTaskId=(TextView) findViewById(R.id.tv_showTaskId);tv_showTaskId.setText("當前Activity:"+"\n"+this.toString()+"\n"+"當前TaskId:"+this.getTaskId());btn_jump=(Button) findViewById(R.id.btn_jump);btn_jump.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent =new Intent();intent.setAction("SecondActivity_action");startActivity(intent);}});}}當我們在第一個App中開啟ShareActivity後再按後退鍵回到原來介面時,ShareActivity做為一個獨立的個體存在,如果這時我們在第二個App中開啟ShareActivity無需建立新的ShareActivity執行個體即可看到結果,因為系統會自動尋找,存在則直接利用。原理圖如下:
注意:是建立在第一個App運行到手機上時點擊第二個App上的跳轉按鈕跳轉到ShareActivity的情況的基礎上的變化過程。
Android開發之Activity的啟動模式