1.活動(Activity)
Activity
是一種可以包含用戶界面的組件轩勘,主要用于和用戶進行交互。
手動創(chuàng)建活動,我們在創(chuàng)建的時候丘逸,選擇Add No Activity
,這個時候app/src/main/java/com.example.activitytest
目錄是空的。我們右鍵新建一個活動掀宋,但是不要勾選Generate Layout File和Launcher Activity.
Generate Layout File:
表示會自動為FirstActivity
創(chuàng)建一個對應(yīng)的布局文件
Launcher Activity:
表示會自動將FirstActivity
設(shè)置為當前項目的主活動深纲。
項目中的任何活動都應(yīng)該重寫Activity
的onCreate()
方法仲锄。
Android Studio
為我們提供了可視化布局編輯器,在窗口的最下方有兩個切換卡湃鹊,左邊是Design
,是當前的可視化布局編輯器儒喊,右邊是Text
,通過XML
文件的方式來編輯布局的。
setContentView()
方法給當前的活動加載一個布局币呵,在方法中我們一般會傳入一個布局文件的id
.項目中添加的任何資源都會在R
文件中生成一個相應(yīng)的資源id
怀愧。
上圖是手動配置的主活動,其中
android:label
指定活動中標題欄的內(nèi)容余赢,標題欄是顯示在活動最頂部的芯义,需要注意的是,給主活動指定的label
不僅會成為標題欄中的內(nèi)容没佑,還會成為啟動器(Launcher)
中應(yīng)用程序顯示的名稱毕贼。如果你的應(yīng)用程序中沒有聲明任何一個活動作為主活動,這個程序仍然是可以正常安裝的蛤奢,只是你無法在啟動器中看到或者打開這個程序鬼癣,這種程序一般都是作為第三方服務(wù)供其它應(yīng)用在內(nèi)部進行調(diào)用的,如支付寶快捷支付服務(wù)等啤贩。
2. Toast
在活動中待秃,可以通過
findViewById()
方法獲取到在布局文件中定義的元素,findViewById()
方法痹屹,返回的是一個View
對象章郁,我們需要向下轉(zhuǎn)型將他轉(zhuǎn)成Button
對象,調(diào)用setOnClickListener()
方法為按鈕注冊一個監(jiān)聽器志衍,點擊按鈕時就會執(zhí)行監(jiān)聽器中的onClick()
方法暖庄。通過靜態(tài)方法
makeText()
創(chuàng)建出一個Toast
對象,然后調(diào)用show()
方法將Toast
顯示出來就可以了楼肪。makeText()
方法需要傳入三個參數(shù)培廓,第一個參數(shù)是Context
對象,也就是Toast
要求的上下文春叫,第二個參數(shù)是Toast
顯示的文本內(nèi)容肩钠,第三個參數(shù)是Toast
顯示的時長。有兩個內(nèi)置常量可以選擇Toast.LENGTH_SHORT和Toast.LENGTH_LONG
3.在活動中使用Menu
其中<item>
標簽就是用來創(chuàng)建具體的某一個菜單項暂殖,然后通過android:id
給這個菜單項指定一個唯一的標識符价匠,通過android:title
給這個菜單項指定一個名稱。
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
通過getMenuInflater()
方法能夠得到MenuInflater
對象呛每,在調(diào)用它的inflater()
方法踩窖,就可以給當前的活動創(chuàng)建菜單了,inflater()
方法接受兩個參數(shù)晨横,第一個參數(shù)用于指定我們通過哪一個資源文件來創(chuàng)建菜單毙石,第二個參數(shù)用于指定我們的菜單項將添加到哪一個Menu
對象中去廉沮。這里直接使用onCreateOptionMenu()
方法中傳入的Menu
參數(shù),然后給這個方法換回true
徐矩,表示允許創(chuàng)建的菜單顯示出來滞时。如果返回false,創(chuàng)建的菜單將無法顯示。
菜單響應(yīng)事件
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.add_item:
Toast toast1 = Toast.makeText(FirstActivity.this,"You clicked Add",
Toast.LENGTH_LONG);
toast1.show();
break;
case R.id.remove_item:
Toast toast2 = Toast.makeText(FirstActivity.this,"You clicked Remove",
Toast.LENGTH_LONG);
toast2.show();
break;
default:
}
return true;
}
調(diào)用item.getItemId()
來判斷我們點擊的是哪一個菜單項滤灯。
4.Intent的使用
Intent
是Android
程序中各組件之間進行交互的一種重要方式坪稽,它不僅可以指明當前組件想要執(zhí)行的動作,還可以在不同組件之間傳遞數(shù)據(jù)鳞骤。Intent
一般可被用于啟動活動窒百,啟動服務(wù)以及發(fā)送廣播等場景。
Intent
大致可以分為兩種:顯式Intent
和隱式Intent
.
顯式Intent
Intent intent = new Intent(FirstActivity.this;SecondActivity.class);
startActicity(intent);
Intent有多個構(gòu)造函數(shù)的重載豫尽,其中一個是Intent(Context packageContext,Class<?> cls).這個構(gòu)造函數(shù)接受兩個參數(shù)篙梢,第一個參數(shù)Context要求提供一個啟動活動的上下文,第二個參數(shù)Class則是指定想要啟動的目標活動美旧,通過這個構(gòu)造函數(shù)就可以構(gòu)造出Intent的意圖.Activity類中提供了一個startActivity()方法渤滞,這個方法是專門用于啟動活動的,他接受一個Intent參數(shù)榴嗅,這里我們將構(gòu)建好的Intent傳入startActivity()方法就可以啟動目標活動了妄呕。
使用這種方式來啟動活動,Intent的意圖非常明顯嗽测,因此我們稱之為顯式Intent
隱式Intent
相比于顯式Intent绪励,隱式Intent則含蓄了很多,他并不明確指出我們想要啟動哪一個活動唠粥,而是制定了一系列更為抽象的action和category等信息疏魏,然后交于系統(tǒng)去分析這個Intent,并幫我們找出合適的活動去啟動晤愧。
<activity
android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在<action>標簽中我們聲明了當前活動可以相應(yīng)com.example.activitytest.ACTION_START這個action,而<category>標簽則包含了一些附加信息大莫,更精確的指明了當前活動能夠響應(yīng)的Intent中還可能帶有category.只有<action>和<category>中的內(nèi)容同時能夠匹配上Intent中指定的action和category時,這個活動才能夠響應(yīng)該Intent.
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
我們使用了Intent的另一個構(gòu)造函數(shù)养涮,直接將action的字符串傳了進去葵硕,表明我們想要啟動能夠響應(yīng)com.example.activitytest_ACTION_START這個action的活動眉抬,android.intent.category.DEFAULT是一種默認的category贯吓,在調(diào)用startActivity()方法的時候,會自動將這個category添加到Intent中蜀变。
每個Intent中只能指定一個action悄谐,但卻能指定多個category.
Intent intent = new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
我們調(diào)用Intent中的addCategory()方法來添加一個category,我們指定了一個自定義的category,值為:com.example.activitytest.MY_CATEGORY.如果我們在運行的話會出現(xiàn)這樣的錯誤:
Process: com.example.activitytest, PID: 12083
android.content.ActivityNotFoundException: No Activity found to handle
Intent { act=com.example.activitytest.ACTION_START cat=[com.example.activitytest.MY_CATEGORY] }
因為并沒有活動去響應(yīng)我們新增加的category.
<activity
android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.activitytest.MY_CATEGORY"/>
</intent-filter>
</activity>
我們增加一個category就可以了库北。
更多隱式Intent的用法
使用隱式Intent爬舰,我們不僅可以啟動我們自己程序向內(nèi)的活動们陆,還可以啟動其他程序的活動,這使得Android多個應(yīng)用程序之間的功能共享成為了可能情屹。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
我們指定了Intent的action是Intent.ACTION_VIEW坪仇,這是一個Android系統(tǒng)內(nèi)置的活動,其常量值為android.intent.action.View.然后通過Uri.parse()方法垃你,將一個網(wǎng)址字符串解析成一個Uri對象椅文,在調(diào)用Intent的setData()方法將這個Uri對象傳遞進去。setData()方法接受一個Uri對象惜颇,主要用于指定當前Intent正在操作的數(shù)據(jù)皆刺,而這些數(shù)據(jù)通常都是以字符串的形式傳入到Uri,parse()方法中解析產(chǎn)生的。
我們還可以在<intent-filter>標簽中再配置一個<data>標簽凌摄,用于更精確的指定當前活動能夠響應(yīng)什么類型的數(shù)據(jù)羡蛾。<data>標簽中主要可以配置一下內(nèi)容。
- android:scheme :用于指定數(shù)據(jù)的協(xié)議部分锨亏,如上面的http部分痴怨。
- android:host :用于指定數(shù)據(jù)的主機名部分,如上面的www.baidu.com
- android:port :用于指定數(shù)據(jù)的端口部分屯伞,一般緊隨在主機名之后
- android:mineType:用于指定可以處理的數(shù)據(jù)類型腿箩,允許使用通配符的方式指定。
只有<data>標簽中指定的內(nèi)容和Intent中攜帶的Data完全一致時劣摇,當前活動才能夠響應(yīng)該Intent.不過一般在<data>中都不會指定過多的內(nèi)容珠移。如上面的瀏覽器例子中,只需要指定android:scheme為http末融,就可以響應(yīng)所有的http協(xié)議的Intent了钧惧。
<activity
android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
我們添加一個活動,修改<intent-filter>的值勾习,讓他也可以響應(yīng)瀏覽器的Intent.
除了http協(xié)議外浓瞪,我們還可以指定很多其他協(xié)議,比如geo表示顯示地理位置巧婶,tel表示撥打電話乾颁。
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
這是調(diào)用系統(tǒng)撥號界面
指定了Intent的action是Intent.ACTION_DIAL,這又是系統(tǒng)的內(nèi)置動作艺栈。然后data部分指定了協(xié)議是tel,號碼是10086.
向下一個活動傳遞數(shù)據(jù)
Intent
中提供了一系列putExtra()
方法的重載英岭。
String data = "hello SecondActivity";
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("extra_data",data);
startActivity(intent);
注意這里putExtra()
方法接收兩個參數(shù),第一個參數(shù)是鍵湿右,用于后面從Intent
中取值诅妹,第二個參數(shù)才是真正要傳遞的數(shù)據(jù)。
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d(TAG, data);
通過getIntent()
方法獲取到用于啟動SecondActivity
的Intent
,然后調(diào)用getStringExtra()
方法吭狡,傳入相應(yīng)的鍵值尖殃,就可以得到傳遞的數(shù)據(jù)了。如果傳遞的是整形數(shù)據(jù)使用getIntExtra()
方法划煮,如果傳遞的是布爾型數(shù)據(jù)送丰,則使用getBooleanExtra()
方法,以此類推弛秋。
返回數(shù)據(jù)給上一個活動
Activity
中還有一個startActivityForResult()
方法也是用于啟動活動的蚪战,但這個方法期望在活動銷毀的時候能夠返回一個結(jié)果給上一個活動。
startActivityForResult()
方法接收兩個參數(shù)铐懊,第一個參數(shù)還是Intent
邀桑,第二個參數(shù)是請求碼
,用于在之后的回調(diào)中判斷數(shù)據(jù)的來源科乎。
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);
使用startActivityForResult()
來啟動活動壁畸。請求碼只要是一個唯一值就可以了。 ```
Intent intent = new Intent();
intent.putExtra("data_return","hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
我們構(gòu)建了一個Intent
茅茂,只不過這個Intent
僅僅是用于傳遞數(shù)據(jù)而已捏萍,他沒有指定任何的意圖,接著我們把要傳遞的數(shù)據(jù)放入Intent
中空闲,然后調(diào)用setResult()
方法令杈,這個方法非常重要,是專門用于向上一個活動返回數(shù)據(jù)的碴倾。setResult()
方法接收兩個參數(shù)逗噩,第一個參數(shù)用于向上一個活動返回處理的結(jié)果,一般只使用RESULT_OK
或RESULT_CANCELED
兩個值跌榔,第二個參數(shù)則把帶有數(shù)據(jù)的Intent
傳遞回去异雁。
在SecondActivity
銷毀后會回調(diào)上一個活動的onActivityResult()
方法:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d(TAG, "onActivityResult: "+returnedData);
}
break;
default:
}
}
onActivityResult()
方法帶有三個參數(shù),第一個參數(shù)requestCode
,即我們啟動活動時的請求碼僧须,第二個參數(shù)resultCode
纲刀,即我們在返回數(shù)據(jù)時傳入的處理結(jié)果,第三個參數(shù)data
担平,即攜帶者返回數(shù)據(jù)的Intent
,由于在一個活動中有可能調(diào)用startActivityForResult()
方法去啟動很多不同的活動示绊,每一個活動返回的數(shù)據(jù)都會回調(diào)到onActivityResult()
這個方法,因此我們首先要做的就是通過檢查requestCode
的值來判斷數(shù)據(jù)來源暂论,然后再通過resultCode
的值來判斷處理結(jié)果是否成功.
如果用戶在SecondActivity
中并不是通過點擊按鈕面褐,而是通過按下Back
鍵回到FirstActivity
,我們可以通過在SecondActivity
中重寫onBackPressed()
方法空另。
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","hello FirstActivity2");
setResult(RESULT_OK,intent);
finish();
}
5.活動的生命周期
Android是使用任務(wù)(Task)來管理活動的盆耽,一個任務(wù)就是一組存放在棧里的活動的集合蹋砚,這個棧也被稱作返回棧(Back Stack).棧是一種后進先出的數(shù)據(jù)結(jié)構(gòu)扼菠,在默認情況下摄杂,每當我我們啟動了一個新的活動,他會在返回棧中入棧循榆,并處于棧頂?shù)奈恢梦龌郑慨斘覀儼聪翨ack鍵或調(diào)用finish()方法去銷毀一個活動的時候,處于棧頂?shù)幕顒訒鰲Q硪@時前一個入棧的活動就會重新處于棧頂?shù)奈恢糜彻摇O到y(tǒng)總是會顯示處于棧頂?shù)幕顒咏o用戶。
返回棧的工作示意圖:
5.1活動的狀態(tài)
每個活動在其生命周期中最多可能會有4種狀態(tài)盗尸。
1.運行狀態(tài)
當一個活動位于返回棧的棧頂時柑船,這時活動就處于運行狀態(tài)。
2.暫停狀態(tài)
當一個活動不再處于棧頂位置泼各,但仍然可見時鞍时,這是活動就進入暫停狀態(tài)。
3.停止狀態(tài)
當一個活動不在處于棧頂位置扣蜻,并且完全不可見的時候逆巍,就進入停止狀態(tài)。
4.銷毀狀態(tài)
當一個活動從返回棧中移除后就變成了銷毀狀態(tài)莽使。
5.2活動的生存期
Activity類中定義了7個回調(diào)方法锐极,覆蓋了活動生命周期的每一個環(huán)節(jié)。
onCreate(): 在活動第一次被創(chuàng)建的時候調(diào)用芳肌,你應(yīng)該在這個方法中完成活動的初始化操作灵再,比如說加載布局,綁定事件等亿笤。
onStart(): 在活動由不可見變?yōu)榭梢姷臅r候調(diào)用码党。
onResume(): 在活動準備好和用戶進行交互的時候調(diào)用适秩,此時的活動一定位于返回棧的棧頂,并且處于運行狀態(tài)。
onPause(): 在系統(tǒng)準備去啟動或恢復另一個活動的時候調(diào)用赡若,我們通常會在這個方法中將一些小號CPU的資源釋放掉,以及保存一些關(guān)鍵數(shù)據(jù)仰剿,但這個方法的執(zhí)行速度一定要快备徐,不然會影響到新的棧頂活動的使用。
onStop(): 在活動完全不可見的時候調(diào)用爆班,他和onPause()方法的主要區(qū)別是如果啟動的新活動是一個對話框的活動衷掷,那么onPause()方法會得到執(zhí)行,而onStop()方法并不會得到執(zhí)行柿菩。
onDestory(): 在活動貝銷毀之前調(diào)用戚嗅,之后活動的狀態(tài)將變?yōu)殇N毀狀態(tài)。
onRestart(): 在活動有停止狀態(tài)變?yōu)檫\行狀態(tài)之前調(diào)用,也就是活動被重新啟動了懦胞。
完整生存期
活動在onCreate()方法和onDestory()方法之間所經(jīng)歷的替久,就是完整生存期,一般情況下躏尉,一個活動會在onCreate()方法中完成各種初始化操作蚯根,而在onDestory()方法中完成釋放內(nèi)存的操作。
可見生存期
活動在onStart()方法和onStop()方法之間所經(jīng)歷的就是可見生存期胀糜。在onStart()方法中對資源進行加載颅拦,而在onStop()方法中對資源進行釋放,從而保證處于停止狀態(tài)的活動不會占用過多的內(nèi)存教藻。
前臺生存期
活動在onResume()方法和onPause()方法之間所經(jīng)歷的就是前臺生存期距帅。
活動的生命周期圖
<activity
android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
我們給他使用了一個android:theme屬性,這是用于給當前活動指定主題的括堤,Android系統(tǒng)內(nèi)置有很多的主題可以選擇锥债,當然我們也可以定制自己的主題。而這里@android:style/Theme.Dialog,則毫無疑問是讓DialogActivity使用對話框式的主題痊臭。
當MainActivity第一次被創(chuàng)建時會依次執(zhí)行onCreate()哮肚,onStart()和onResume()方法。
NormalActivity把MainActivity完全遮擋住广匙,onPause()和onStop()方法會得到執(zhí)行允趟。
按下Back鍵,之前的MainActivity已經(jīng)進入停止狀態(tài)鸦致,所以onRestart()方法會得到執(zhí)行之后又會依次執(zhí)行onStart()和onResume()方法潮剪。
點擊進入DialogActivity,只有onPause()方法得到了執(zhí)行,onStop()方法并沒有執(zhí)行分唾,這是因為DialogActivity并沒有完全遮擋住MainActivity,此時MainActivity只是進入了暫停狀態(tài)抗碰,并沒有進入停止狀態(tài)。相應(yīng)的绽乔,按下Back鍵返回MainActivity也應(yīng)該只有onResume()方法會得到執(zhí)行弧蝇。
活動被回收了怎么辦?
Activity中還提供了一個onSaveInstanceState()回調(diào)方法折砸,這個方法可以保證在活動被回收之前一定會被調(diào)用看疗。因此我們可以通過這個方法來解決活動被回收時臨時數(shù)據(jù)得不到保存的問題。
onSaveInstanceState()方法會攜帶一個Bundle類型的參數(shù)睦授,Bundle提供了一系列的方法用于保存數(shù)據(jù)两芳,比如可以使用putString()方法保存字符串,使用putInt()方法保存整形數(shù)據(jù)去枷。每個保存方法需要傳入兩個參數(shù)怖辆,第一個參數(shù)是鍵是复,用于后面從Bundle中取值,第二個參數(shù)是真正要保存的內(nèi)容竖螃。
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key",tempData);
}
onCreate()方法其實也有一個Bundle類型的參數(shù)斑鼻。這個參數(shù)在一般情況下都是null坚弱,但是如果在活動被系統(tǒng)回收之前有通過onSaveInstanceState()方法來保存數(shù)據(jù)的話荒叶,這個參數(shù)就會帶有之前所保存的全部數(shù)據(jù)些楣。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
{
String tempData = savedInstanceState.getString("data_key");
}
}
取出值后再做相應(yīng)的操作就可以了愁茁。
Intent還可以結(jié)合Bundle一起用于傳遞數(shù)據(jù),首先可以把需要傳遞的數(shù)據(jù)都保存在Bundle對象中促煮,然后再將Bundle對象存放在Intent里菠齿,到了目標活動之后先從Intent中取出Bundle,在從Bundle中一一取出绳匀。
6.活動的啟動模式
在實際項目中我們應(yīng)該根據(jù)特定的需求為每個活動指定恰當?shù)膯幽J浇笫俊幽J揭还灿?種陋桂,分別是standard,singleTop,singleTask和singleInstance,可以在AndroidManifest.xml中通過給<activity>標簽指定android:launchMode屬性來選擇啟動模式宣渗。
6.1 standard
standard是活動默認的啟動模式痕囱,在不進行顯式指定的情況下鞍恢,所有活動都會自動使用這種啟動模式。Android是使用返回棧來管理活動的在standard(即默認情況下)窒典,每當啟動一個新的活動涩搓,他就會在返回棧中入棧昧甘,并處于棧頂?shù)奈恢眉膊悖瑢τ谑褂胹tandard面膜是的活動痛黎,系統(tǒng)不會在乎這個活動是否已經(jīng)在返回棧中存在湖饱,每次啟動都會創(chuàng)建該活動的一個新的實例。
在代碼中實踐:
Log.d(TAG, this.toString());
Intent intent = new Intent(FirstActivity.this,FirstActivity.class);
startActivity(intent);
連續(xù)點擊兩次仅仆,可以看到打印出當前活動的實例垢袱。
01-06 21:47:26.409 18937-18937/com.example.activitytest D/FirstActivity: com.example.activitytest.FirstActivity@f7397be
01-06 21:47:32.614 18937-18937/com.example.activitytest D/FirstActivity: com.example.activitytest.FirstActivity@6b88a94
6.2 singleTop
使用singleTop模式咳榜,當活動的啟動模式指定為singleTop畔柔,在啟動活動時靶擦,如果發(fā)現(xiàn)返回棧的棧頂已經(jīng)是該活動玄捕,則認為可以直接使用它寂纪,不會再創(chuàng)建新的活動實例。
android:name=".FirstActivity"
android:launchMode="singleTop"
android:label="This is FirstActivity">
01-06 22:12:07.813 15130-15130/? D/FirstActivity: com.example.activitytest.FirstActivity@f7c25bd
無論點擊多少次,都只會創(chuàng)建一次實例庄涡。
6.3 singleTask
使用singleTop模式可以很好地解決重復創(chuàng)建棧頂活動的問題穴店,當活動的啟動模式指定為singleTask模式,每次啟動該活動時系統(tǒng)首先會在返回棧中檢查是否存在該活動的實例球凰,如果發(fā)現(xiàn)已經(jīng)存在則直接使用該實例呕诉,并把在這個活動之上的所有活動統(tǒng)統(tǒng)出棧,如果沒有發(fā)現(xiàn)就會創(chuàng)建一個新的活動實例椿每。
6.4 singleInstance
指定為singleInstance模式的活動會啟用一個新的返回棧來管理這個活動(其實如果singleTask模式指定了不同的taskAffinity,也會啟動一個新的返回棧)贪绘。每個應(yīng)用程序都會有自己的返回棧税灌,同一個活動在不同的返回棧中入棧時必然是創(chuàng)建了新的實例菱涤,在singleInstance模式下粘秆,會有一個單獨的返回棧來管理這個活動不管是哪個應(yīng)用程序來訪問這個活動,都共用的同一個返回棧昔搂,也就解決了共享活動實例的問題摘符。
7.活動的最佳實踐
7.1 知曉當前是在哪一個活動?
新建一個類:BaseActivity
public class BaseActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());
}
}
讓所有的Activity不在繼承AppCompatActivity,而是繼承BaseActivity,getClass().getSimpleName()可以得到當前實例的類名逛裤。
7.2隨時隨地退出程序
我們需要用一個專門的集合類對所有的活動進行管理就可以了。
public class ActivityCollector
{
//添加活動
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity)
{
activities.add(activity);
}
//移除活動
public static void removeActivity(Activity activity)
{
activities.remove(activity);
}
//全部銷毀活動
public static void finishAll()
{
for (Activity activity : activities)
{
if (!activity.isFinishing())
{
activity.finish();
}
}
}
}
通過一個List來暫存活動洽糟,然后提供了一個addActivity()方法用于向List中添加一個活動炉菲,提供了一個removeActivity()方法用于從List中移除活動,最后提供了一個finishAll()方法用于將List中存儲的活動全部銷毀掉.
public class BaseActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy()
{
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
在BaseActivity的onCreate()方法中調(diào)用了ActivityCollector的addActivity()方法坤溃,表明將當前正在創(chuàng)建的活動添加到活動管理器里拍霜,然后在BaseActivity中重寫onDestroy()方法,并調(diào)用了ActivityCollector的removeActivity()方法薪介,表明將一個馬上要銷毀的活動從活動管理器里移除祠饺。
從此以后,不管你想在什么地方退出程序汁政,只需要調(diào)用ActivityCollector.finishAll()方法就可以了并巍。
public class ThirdActivity extends BaseActivity
{
Button button;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
button = (Button) findViewById(R.id.button_3);
initEvent();
}
public void initEvent()
{
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
ActivityCollector.finishAll();
android.os.Process.killProcess(android.os.Process.myPid());
}
});
}
}
你還可以在銷毀所有活動的代碼后面再加上殺掉當前進程的代碼,以保證程序完全退出,殺掉進程的代碼:
android.os.Process.killProcess(android.os.Process.myPid());
killProcess()方法用于殺掉一個進程骇两,它接受一個進程ID的參數(shù)速种,我們可以通過myPid()方法來獲得當前程序的進程ID,需要注意的是,killProcess()方法只能用于殺掉當前程序的進程黔姜,纳寂,我們不能使用這個方法去殺掉其他程序猾浦。
7.3 啟動活動的最佳寫法
在SecondActivity中寫入下面的方法:
public static void actionStart(Context context,String data1,String data2)
{
Intent intent = new Intent(context,SecondActivity.class);
intent.putExtra("param1",data1);
intent.putExtra("param2",data2);
context.startActivity(intent);
}
在FirstActivity里面調(diào)用這個方法:
SecondActivity.actionStart(FirstActivity.this,"data1","data2");
這樣寫的好處是一目了然:SecondActivity所需要的數(shù)據(jù)在方法參數(shù)中全部體現(xiàn)出來了,這樣即使不用閱讀SecondActivity中的代碼靡砌,不去詢問負責編寫SecondActivity的同事画舌,你也可以非常清晰地知道啟動SecodeActivity需要傳遞哪些數(shù)據(jù),另外這樣寫還簡化了啟動活動的代碼。0