1.當(dāng)默認(rèn)創(chuàng)建一個(gè)新項(xiàng)目時(shí),開發(fā)工具會(huì)幫我們創(chuàng)建一個(gè)MainActivity.java朽们,以下是用AndroidStudio來(lái)創(chuàng)建的部分代碼,MainActivity.java的主要代碼(每個(gè)人的開發(fā)工具不盡相同实束,在新建項(xiàng)目時(shí)可能會(huì)同時(shí)生成多幾個(gè)方法卵惦,這時(shí)可以忽略掉它們,因?yàn)檫@不影響研究)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2.創(chuàng)建和加載新的布局文件
創(chuàng)建新的布局文件這一步可以自己創(chuàng)建一下磕仅,我自己創(chuàng)建的一個(gè)新的布局文件名為 activity_second.xml珊豹。
布局文件創(chuàng)建好之后,再創(chuàng)建一個(gè)新的Activity來(lái)加載activity_second.xml榕订,這里我創(chuàng)建的Activity名為Activity_second店茶。代碼如下:
public class Activity_second extends AppCompatActivity{ //1
@Override //2
protected void onCreate(Bundle savedInstanceState) { //3
super.onCreate(savedInstanceState); //4
}
}
此時(shí)新鮮滾熱辣的Activity_second.java還未將剛才創(chuàng)建的activity_second.xml加載進(jìn)去呢!此時(shí)我們應(yīng)該做的就是在上面的標(biāo)號(hào)為4的此行代碼后面進(jìn)行加載布局文件劫恒,使用setContentView( )方法進(jìn)行加載布局文件贩幻。
public class Activity_second extends AppCompatActivity{ //1
@Override //2
protected void onCreate(Bundle savedInstanceState) { //3
super.onCreate(savedInstanceState); //4
setContentView(R.layout.activity_second);//這一步操作就是加載布局文件啦!两嘴!
}
}
3.在AndroidManifest.xml清單文件中對(duì)Activity_second進(jìn)行注冊(cè)操作
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.andre.testactivityapplication">
<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>
<!-- 下面這些代碼就是對(duì)剛才新建的Activity_second進(jìn)行注冊(cè)-->
<activity android:name=".Activity_second">
</activity>
</application>
</manifest>
4.在代碼中銷毀一個(gè)Activity
調(diào)用finish( )方法即可以銷毀當(dāng)前的Activity丛楚。我下面的代碼是事先在activity_main.xml中定義了一個(gè)Button,并設(shè)置該Button的onClick屬性為finishActivity憔辫。所以在MainActivity中就可以將該Button的onClick屬性聲明為一個(gè)方法用于銷毀當(dāng)前的Activity了趣些。代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void finishActivity(View view){
finish();
}
}
Activity的交互
5.使用Intent(意圖)來(lái)連通各個(gè)Activity
首先,Activity之間交互是通過(guò)(意圖)Intent來(lái)進(jìn)行的贰您,所以我們應(yīng)該先要將這個(gè)(意圖)Intent構(gòu)建出來(lái)坏平,然后將這個(gè)(意圖)Intent作為參數(shù)傳入startActivity(intent)方法即可實(shí)現(xiàn)Activity之間的交互拢操。
Intent是Android程序中各組件之間進(jìn)行交互的一種重要方式,它不僅可以指明當(dāng)前組件想要執(zhí)行的動(dòng)作舶替,還可以在不同組件之間傳遞數(shù)據(jù)令境。Intent一般可被用于啟動(dòng)活動(dòng)、啟動(dòng)服務(wù)顾瞪、以及發(fā)送廣播等場(chǎng)景舔庶。
--5.1多個(gè)Activity使用顯式Intent來(lái)進(jìn)行交互
Intent有多個(gè)構(gòu)造函數(shù)的重載,最常用到的是:Intent(Context packageContext, Class<?> cls)陈醒。
Intent intent = new Intent(MainActivity.this,Activity_second.class);
startActivity(intent);
我們首先是構(gòu)建出了一個(gè)意圖Intent惕橙,將MainActivity.this作為上下文,傳入Activity_second.class作為目標(biāo)活動(dòng)孵延。這個(gè)Intent的意圖(目的)就是在MainActivity這個(gè)活動(dòng)的基礎(chǔ)上打開Activity_second這個(gè)活動(dòng)吕漂。最后,通過(guò)調(diào)用startActivity( )方法來(lái)執(zhí)行這個(gè)Intent意圖尘应。這種意圖比較明顯惶凝,所以稱之為顯式Intent。
--5.2單應(yīng)用中的多個(gè)Activity使用隱式Intent進(jìn)行交互
隱式Intent就是先找到AndroidManifest.xml清單文件中的要跳轉(zhuǎn)到的目標(biāo)Activity注冊(cè)處犬钢,然后在該處添加一個(gè)意圖過(guò)濾器<intent-filter></intent-filter>苍鲜,在這個(gè)意圖過(guò)濾器中指定action和category等信息。最后交由系統(tǒng)去分析這個(gè)Intent并幫我們找出合適的Activity去啟動(dòng)玷犹。
主要的清單文件代碼如下:
<activity android:name=".Activity_second">
<intent-filter>
<action android:name="com.example.andre.testactivityapplication.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在調(diào)用方MainActivity中的主要代碼如下:
Intent intent = new Intent("com.example.andre.testactivityapplication.ACTION_START");
startActivity(intent);
可以看出這里調(diào)用了Intent的另一個(gè)構(gòu)造方法混滔,并將一個(gè)在清單里面注冊(cè)的一個(gè)action字段作為參數(shù),然后再調(diào)用startActivity( )方法跳轉(zhuǎn)到Activity_second中去歹颓。
注意:這里看似調(diào)用Intent的構(gòu)造方法時(shí)漏掉了清單文件中提及的另外一個(gè)category字段坯屿,其實(shí)這個(gè)category字段是系統(tǒng)默認(rèn)的字段,在調(diào)用startActivity( )方法時(shí)會(huì)自動(dòng)將這個(gè)category字段添加到Intent中的巍扛。還有:每個(gè)Intent中只能指定一個(gè)action字段领跛,但可以指定多個(gè)category字段,使用Intent的addCategory( )方法來(lái)指定多個(gè)category字段撤奸,但無(wú)論是在清單文件中新增category字段吠昭,還是在Activity中增加category字段,都一定要在彼此間進(jìn)行category字段的全部匹配胧瓜,<category android:name="android.intent.category.DEFAULT"/>除外矢棚。
--5.3更多的隱式Intent的用法
使用隱式Intent不單單可以啟動(dòng)本程序內(nèi)部的Activity,還可以啟動(dòng)其它程序的Activity府喳。比如說(shuō)你的程序想要打開網(wǎng)頁(yè)時(shí)蒲肋,只需要調(diào)用系統(tǒng)的瀏覽器來(lái)打開網(wǎng)頁(yè)就可以了,沒(méi)必要自己去做一個(gè)瀏覽器出來(lái)。下面就來(lái)看看在自己程序中如何打開瀏覽器并且訪問(wèn)百度首頁(yè)的兜粘。
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("http://www.baidu.com");
intent.setData(uri);
startActivity(intent);
6.Activity之間的數(shù)據(jù)傳遞
--6.1向下一個(gè)Activity傳遞數(shù)據(jù)
在當(dāng)前的Activity向下一個(gè)Activity傳遞數(shù)據(jù)强胰,使用的依然是Intent,因?yàn)镮ntent提供了很多的putExtra( )方法的重載妹沙,可以重載此方法將想要傳遞的一些數(shù)據(jù)加載到Intent中,然后在目標(biāo)Activity中使用getIntent( )方法來(lái)獲取上一個(gè)傳數(shù)據(jù)進(jìn)來(lái)的Activity中的Intent熟吏,最后調(diào)用獲取到的Intent中的getxxx( )來(lái)將砸破Intent中的數(shù)據(jù)取出來(lái)距糖,這樣就完成了向下一個(gè)Activity傳遞數(shù)據(jù)啦。
當(dāng)前Activity中的主要代碼:
String datas = "hello world!";
Intent intent = new Intent(this, Activity_second.class);//使用顯式的Intent方式來(lái)啟動(dòng)Activity_second
intent.putExtra("pass_datas",datas);
startActivity(intent);
需要接收數(shù)據(jù)的目標(biāo)Activity的主要代碼:
Intent intent = getIntent();
String getPassDatas = intent.getStringExtra("pass_datas");
--6.2將數(shù)據(jù)返回給上一個(gè)Activity
∏K隆(這小點(diǎn)里面討論的Activity的啟動(dòng)模式皆為標(biāo)準(zhǔn)模式)討論的是兩種情形悍引,情景一:當(dāng)前MainActivity通過(guò)按鍵來(lái)啟動(dòng)Activity_second,Activity_second啟動(dòng)完畢之后再調(diào)用finish( )方法將自己結(jié)束掉帽氓,然后就回到了MainActivity趣斤;情景二:在啟動(dòng)了Activity_second之后,通過(guò)返回鍵來(lái)返回MainActivity黎休。
情景一(自行設(shè)置點(diǎn)擊事件):
MainActivity中的主要代碼如下:
Intent intent = new Intent(this, Activity_second.class);//使用顯式的Intent方式來(lái)啟動(dòng)Activity_second
startActivityForResult(intent,1);//參數(shù)1為該請(qǐng)求碼浓领,這里傳入1就可以了,也可以傳其它值
Activity_second中的主要代碼如下:
Intent intent = new Intent();//這個(gè)Intent是用來(lái)傳數(shù)據(jù)的势腮,并沒(méi)有啟動(dòng)Activity的意圖
intent.putExtra("return_datas","Datas return to MainActivity!");
setResult(RESULT_OK,intent);
finish();
Activity_second中的代碼setResult(RESULT_OK,intent);這個(gè)方法專門用于向上一個(gè)Activity返回?cái)?shù)據(jù)的联贩,這方法里的第一個(gè)參數(shù)表示向上一個(gè)Activity返回處理結(jié)果,一般只使用RESULT_OK或RESULT_CANCELED這兩個(gè)值捎拯,第二個(gè)參數(shù)是將帶有數(shù)據(jù)的Intent傳遞回去泪幌,最后調(diào)用finish( )方法將自己銷毀掉返回到MainActivity中。
由于在MainActivity中是調(diào)用了startActivityForResult( )方法來(lái)啟動(dòng)Activity_second的署照,所以在Activity_second被銷毀之后會(huì)回調(diào)MainActivity中的onActivityResult()方法祸泪,所以還要在onActivityResult()方法中進(jìn)行相應(yīng)的處理,具體如下:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 1:
String datas = data.getStringExtra("return_datas");
break;
default:
}
}
onActivityResult(int requestCode, int resultCode, Intent data)方法中帶有三個(gè)參數(shù)建芙,第一參數(shù)requestCode即在MainActivity中啟動(dòng)Activity_second時(shí)手動(dòng)設(shè)置的請(qǐng)求碼没隘,第二個(gè)參數(shù)resultCode即為Activity_second返回?cái)?shù)據(jù)時(shí)傳入的處理結(jié)果,第三個(gè)參數(shù)data是一個(gè)攜帶數(shù)據(jù)的Intent岁钓。由于在一個(gè)Activity中有可能會(huì)調(diào)用startActivityForResult()方法來(lái)啟動(dòng)很多個(gè)Activity升略,所以要用requestCode請(qǐng)求碼來(lái)區(qū)分當(dāng)前Activity是啟動(dòng)了哪個(gè)Activity,然后通過(guò)resultCode來(lái)判斷處理結(jié)果是否成功屡限,最后從data中將數(shù)據(jù)取出來(lái)品嚣,這樣就完成了情景一的工作了。
情景二:
在Activity_second的時(shí)候直接按返回鍵時(shí)钧大,這時(shí)情景一里面Activity_second的點(diǎn)擊事件就無(wú)效了翰撑,其實(shí)可以通過(guò)重寫onBackPressed( )方法來(lái)解決這個(gè)問(wèn)題的,代碼如下:
@Overridepublic void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent();//這個(gè)Intent是用來(lái)傳數(shù)據(jù)的,并沒(méi)有啟動(dòng)Activity的意圖
intent.putExtra("return_datas","Datas return to MainActivity!");
setResult(RESULT_OK,intent);
}
看到?jīng)]眶诈,onBackPressed()方法里面的邏輯是從情景一中copy過(guò)來(lái)的涨醋,最后在MainActivity中的代碼跟情景一是一樣的,這樣就可以在該情景中實(shí)現(xiàn)數(shù)據(jù)返回上一個(gè)Activity了逝撬。
Activity的生命周期與啟動(dòng)模式
7.Activity的生命周期
以上是Android官方的Activity生命周期回調(diào)圖浴骂,各個(gè)方法功能如下:
onCreate:初始化;
onStart:開始activity宪潮,界面可見時(shí)調(diào)用這個(gè)方法溯警;
onResume:獲得界面焦點(diǎn);
onPause:失去界面焦點(diǎn)狡相;
onStop:界面不可見梯轻;
onRestart:重新開始打開一個(gè)界面,注意尽棕,重新打開的界面要處于未被銷毀狀態(tài)喳挑;
onDestroy:在銷毀實(shí)例對(duì)象之前調(diào)用這個(gè)方法;
Resumed:在這個(gè)狀態(tài)滔悉, activity是在最前端的伊诵, 用戶可以與它進(jìn)行交互。 (通常也被理解為"running" 狀態(tài))
Paused:在這個(gè)狀態(tài)回官, activity被另外一個(gè)activity所遮蓋:另外的activity來(lái)到最前面日戈, 但是半透明的, 不會(huì)覆蓋整個(gè)屏幕孙乖。 被暫停的activity不會(huì)再接受用戶的輸入且不會(huì)執(zhí)行任何代碼浙炼。 (這里的不會(huì)執(zhí)行任何代碼并不代表了任何后臺(tái)線程都不會(huì)工作)
Stopped:在這個(gè)狀態(tài), activity完全被隱藏, 不被用戶可見唯袄。 可以認(rèn)為是在后臺(tái)弯屈。 當(dāng)stopped, activity實(shí)例與它的所有狀態(tài)信息都會(huì)被保留, 但是activity不能執(zhí)行任何代碼恋拷。
其它狀態(tài) (Created與Started)都是短暫的资厉, 系統(tǒng)快速的執(zhí)行那些回調(diào)函數(shù)并通過(guò)執(zhí)行下一階段的回調(diào)函數(shù)移動(dòng)到下一個(gè)狀態(tài)。 也就是說(shuō)蔬顾, 在系統(tǒng)調(diào)用onCreate(), 之后會(huì)迅速調(diào)用onStart(), 之后再迅速執(zhí)行onResume()宴偿。
上面就是基本的Activity生命周期。
8.Activity的啟動(dòng)模式
注:該小點(diǎn)所用到的圖片皆為郭霖的《第一行代碼》里面的截圖進(jìn)行修改诀豁。
Activity是使用返回棧來(lái)管理Activity的窄刘,其中Activity有4種啟動(dòng)模式:standard;singleTop;singleTask;singleInstance。啟動(dòng)模式是在清單文件中進(jìn)行設(shè)置的舷胜,其中standard模式是默認(rèn)的啟動(dòng)模式娩践,可以不用在清單文件中進(jìn)行添加字段。
--8.1standard模式
在MainActivity中的點(diǎn)擊事件里面加入下面代碼:
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
然后點(diǎn)擊2次這個(gè)點(diǎn)擊事件的按鈕,此時(shí)的返回棧如下圖所示翻伺,需要連按3次返回鍵才能退出程序材泄。
--8.2singleTop模式
在此模式下當(dāng)啟動(dòng)Activity時(shí),如果發(fā)現(xiàn)返回棧的棧頂已經(jīng)是該Activity時(shí)吨岭,則直接使用它拉宗,不會(huì)再創(chuàng)建新的Activity;當(dāng)該返回棧中存在該Activity時(shí)辣辫,但它并不在棧頂簿废,此時(shí)是會(huì)重新創(chuàng)建該Activity的。
這種啟動(dòng)模式需要到清單文件中進(jìn)行添加launchMode字段络它,xml代碼如下:
<activity android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
在MainActivity中啟動(dòng)Activity_second,代碼如下:
Intent intent = new Intent(MainActivity.this, Activity_second.class);
startActivity(intent);
接著在Activity_second中啟動(dòng)MainActivity歪赢,代碼如下:
Intent intent = new Intent(Activity_second.this, MainActivity.class);
startActivity(intent);
在這種模式下化戳,當(dāng)你在Activity_second的點(diǎn)擊按鈕中點(diǎn)擊了無(wú)數(shù)次,都只會(huì)有一個(gè)MainActivity在返回棧的棧頂埋凯,此時(shí)按下2次返回鍵就又回到了MainActivity界面中点楼,再按1次就可以退出該程序,如下圖:
--8.3singleTask模式
在此模式下白对,每次啟動(dòng)Activity時(shí)系統(tǒng)首先會(huì)在返回棧中檢查是否存在該Activity的實(shí)例掠廓,如果發(fā)現(xiàn)已經(jīng)存在則直接使用該實(shí)例,并且把在這個(gè)Activity之上的所有Activity全部出棧甩恼,如果沒(méi)有就會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例蟀瞧。
這種啟動(dòng)模式需要到清單文件中進(jìn)行添加launchMode字段,xml代碼如下:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
重新運(yùn)行程序条摸,在MainActivity界面點(diǎn)擊按鈕進(jìn)入到Activity_second悦污,然后在Activity_second界面點(diǎn)擊按鈕,又會(huì)重新進(jìn)入到MainActivity钉蒲。
返回棧流程如下:
--8.4
此模式可以解決共享Activity實(shí)例的問(wèn)題切端,因?yàn)槊總€(gè)應(yīng)用程序都會(huì)有自己的返回棧,同一個(gè)Activity在不同的返回棧中入棧時(shí)必然是創(chuàng)建了新的實(shí)例顷啼。而使用singleInstane模式時(shí)踏枣,會(huì)有一個(gè)單獨(dú)的返回棧來(lái)管理這個(gè)Activity,從而實(shí)現(xiàn)共享Activity實(shí)例钙蒙。
將Activity_second添加launchMode字段茵瀑,xml代碼如下:
<activity android:name=".Activity_second"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.andre.testactivityapplication.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
首先創(chuàng)建了Activity_third并在清單文件中進(jìn)行注冊(cè)
public class Activity_third extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
}
}
然后修改修改Activity_second中的點(diǎn)擊事件
Intent intent = new Intent(Activity_second.this, Activity_third.class);
startActivity(intent);
重新運(yùn)行程序,在MainActivity界面點(diǎn)擊按鈕進(jìn)入到Activity_second躬厌,然后在Activity_second界面點(diǎn)擊按鈕進(jìn)入到Activity_third瘾婿。當(dāng)按下返回鍵進(jìn)行返回時(shí),發(fā)現(xiàn)Activity_third竟然直接返回到MainActivity,再按下返回鍵又會(huì)返回到Activity_second偏陪,再按一次返回鍵都會(huì)退出程序抢呆。
原理是這樣的,由于MainActivity和Activity_third是在同一個(gè)返回棧里的笛谦,當(dāng)在Activity_third界面中按下返回鍵抱虐,Activity_third就會(huì)被出棧,此時(shí)MainActivity就處于棧頂了從而顯示出來(lái)(也就出現(xiàn)了從Activity_third直接返回到MainActivity的情況)饥脑,當(dāng)再次按下返回鍵時(shí)恳邀,MainActivity就會(huì)被出棧,此時(shí)當(dāng)前的返回棧已經(jīng)空了灶轰,于是就顯示了另一個(gè)返回棧的棧頂Activity谣沸,即Activity_second。最后再次按下返回鍵笋颤,所有的返回棧都已經(jīng)空了乳附,也就 退出了程序。返回棧流程如下: