Activity Review
參考資料
Activity概述
一個(gè)應(yīng)用通常由多個(gè)彼此松散聯(lián)系的 Activity 組成。 一般會(huì)指定應(yīng)用中的某個(gè) Activity 為“主”Activity,即首次啟動(dòng)應(yīng)用時(shí)呈現(xiàn)給用戶的那個(gè) Activity。 而且每個(gè) Activity 均可啟動(dòng)另一個(gè) Activity,以便執(zhí)行不同的操作。 每次新 Activity 啟動(dòng)時(shí),前一 Activity 便會(huì)停止,但系統(tǒng)會(huì)在堆棧(“返回棧”)中保留該 Activity。 當(dāng)新 Activity 啟動(dòng)時(shí),系統(tǒng)會(huì)將其推送到返回棧上,并取得用戶焦點(diǎn)。 返回棧遵循基本的“后進(jìn)先出”堆棧機(jī)制,因此,當(dāng)用戶完成當(dāng)前 Activity 并按“返回”按鈕時(shí),系統(tǒng)會(huì)從堆棧中將其彈出(并銷毀),然后恢復(fù)前一 Activity。
啟動(dòng)Activity
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
隱式意圖
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
Intent 對(duì)象的真正價(jià)值所在 — 您可以創(chuàng)建一個(gè) Intent 對(duì)象,對(duì)您想執(zhí)行的操作進(jìn)行描述,系統(tǒng)會(huì)從其他應(yīng)用啟動(dòng)相應(yīng)的 Activity. <參考文檔>
表述:
如果您想允許用戶發(fā)送電子郵件,可以創(chuàng)建上面的實(shí)例 Intent
添加到 Intent 中的 EXTRA_EMAIL extra 是一個(gè)字符串?dāng)?shù)組,其中包含應(yīng)將電子郵件發(fā)送到的電子郵件地址。 當(dāng)電子郵件應(yīng)用響應(yīng)此 Intent 時(shí),它會(huì)讀取 extra 中提供的字符串?dāng)?shù)組,并將它們放入電子郵件撰寫窗體的“收件人”字段。 在這種情況下,電子郵件應(yīng)用的 Activity 啟動(dòng),并且當(dāng)用戶完成操作時(shí),您的 Activity 會(huì)恢復(fù)執(zhí)行。
Manifest.xml
<activity
android: name="com.alex33.SecondActivity"
android: icon="@drawable/cat"
android: label="第二個(gè)Activity">
<intent-filter>
<action android:name="com.alex33.JumpToSecondActiviy"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
SecondActivity.java
Intent i = new Intent();
i.setAction("com.alex33.JumpToSecondActivity");
i.addCategory("android.intent.category.DEFAULT");
startActivity(intent);
通過(guò)隱式意圖可以不報(bào)樓類文件的情況下, 調(diào)用一個(gè)Activity
Activity幾種狀態(tài)
Active(活動(dòng) | Active/Runing):當(dāng)Activity位于棧頂時(shí),它是可見,有焦點(diǎn)的前臺(tái)Activity,可以用來(lái)響應(yīng)用戶的輸入。
Paused(暫停 | Paused):一般情況,你的Activity可見但不具有焦點(diǎn),例如 當(dāng)前面的Activity是全透明或非透明的Activity時(shí),下面的Activity就位于Paused狀態(tài)。
Stopped(停止 | Stoped):當(dāng)一個(gè)Activity徹底不可見時(shí),就處于這個(gè)狀態(tài)。此時(shí)Activity完全不可見,但在內(nèi)存中仍舊保留該Activity的狀態(tài)和成員信息。
Inactive(銷毀 | Killed):當(dāng)一個(gè)Activity被殺死時(shí),就變成Inactive。Inactive Activity會(huì)從Activity棧中移除,如果重新顯示需要重新啟動(dòng)。一般銷毀由系統(tǒng)Dalvik控制。
Activity加載模式
在android里,有4種activity的啟動(dòng)模式,分別為:
standard: 標(biāo)準(zhǔn)模式,一調(diào)用startActivity()方法就會(huì)產(chǎn)生一個(gè)新的實(shí)例。
singleTop: 來(lái)了intent, 每次都創(chuàng)建新的實(shí)例,僅一個(gè)例外:當(dāng)棧頂?shù)腶ctivity 恰恰就是該activity的實(shí)例(即需要?jiǎng)?chuàng)建的實(shí)例)時(shí),不再創(chuàng)建新實(shí)例。這解決了棧頂復(fù)用問(wèn)題。
singleTask: 來(lái)了intent后,檢查棧中是否存在該activity的實(shí)例,如果存在就把intent發(fā)送給它,否則就創(chuàng)建一個(gè)新的該activity的實(shí)例,放入一個(gè)新的task棧的棧底??隙ㄎ挥谝粋€(gè)task的棧底,而且棧中只能有它一個(gè)該activity實(shí)例,但允許其他activity加入該棧。解決了在一個(gè)task中共享一個(gè)activity。
singleInstance: 這個(gè)跟singleTask基本上是一樣,只有一個(gè)區(qū)別:在這個(gè)模式下的Activity實(shí)例所處的task中,只能有這個(gè)activity實(shí)例,不能有其他的實(shí)例。一旦該模式的activity的實(shí)例已經(jīng)存在于某個(gè)棧中,任何應(yīng)用在激活該activity時(shí)都會(huì)重用該棧中的實(shí)例,解決了多個(gè)task共享一個(gè)activity。
這些啟動(dòng)模式可以在功能清單文件AndroidManifest.xml中進(jìn)行設(shè)置,中的launchMode屬性。
Activity 生命周期


Activity跳轉(zhuǎn)時(shí)的方法回調(diào)
生命周期回調(diào)的順序經(jīng)過(guò)明確定義,當(dāng)兩個(gè) Activity 位于同一進(jìn)程,并且由一個(gè) Activity 啟動(dòng)另一個(gè) Activity 時(shí),其定義尤其明確。 以下是當(dāng) Activity A 啟動(dòng) Activity B 時(shí)一系列操作的發(fā)生順序:
- Activity A 的 onPause() 方法執(zhí)行。
- Activity B 的 onCreate()、onStart() 和 onResume() 方法依次執(zhí)行。(Activity B 現(xiàn)在具有用戶焦點(diǎn)。)
- 然后,如果 Activity A 在屏幕上不再可見,則其 onStop() 方法執(zhí)行。
您可以利用這種可預(yù)測(cè)的生命周期回調(diào)順序管理從一個(gè) Activity 到另一個(gè) Activity 的信息轉(zhuǎn)變。 例如,如果您必須在第一個(gè) Activity 停止時(shí)向數(shù)據(jù)庫(kù)寫入數(shù)據(jù),以便下一個(gè) Activity 能夠讀取該數(shù)據(jù),則應(yīng)在 onPause() 而不是 onStop() 執(zhí)行期間向數(shù)據(jù)庫(kù)寫入數(shù)據(jù)。
Manifest.xml的細(xì)節(jié)
清單文件中, intent過(guò)濾器有MAIN和LAUNCHER, 代表mainActivity的主入口
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
使用Bundle在Activity間傳值
Bundle對(duì)象有如下方法:
存
putXxx(String key,Xxx data) : 向Bundle中放入int、String等各種類型的數(shù)據(jù)
putSerializable(String key,Serializable data) : 向Bundle中放入可序列化的對(duì)象
取
getXxx(String key):取出int、String等各種類型的數(shù)據(jù)
getSerializable(String key):取出可序列化的對(duì)象
當(dāng)然我們還可以直接調(diào)用intent對(duì)象的putExtra(String key,Xxx data)方法存入數(shù)據(jù),但其本質(zhì)還是創(chuàng)建或使用了Bundle對(duì)象進(jìn)行傳值。
startActivityForResult的使用
A-Activity需要在B-Activtiy中執(zhí)行一些數(shù)據(jù)操作,跳轉(zhuǎn)至B-Activity后,B-Activity要將執(zhí)行操作數(shù)據(jù)的結(jié)果返回給A-Activtiy,此時(shí)就需要使用 startActivityForResult()來(lái)啟動(dòng)B-Activity了。
使用的三個(gè)函數(shù):
- startActivityForResult (Intent intent, Int requestCode)
- setResut (int resultCode, Intent intent)
- onActivityResult (int requestCode, int resultCode, Intent intent)
Step1.
在A中跳轉(zhuǎn)的時(shí)候不是采用startActivity(intent) 這個(gè)方法,而是startActivityForResult(intent, Int requestCode)的形式,requestCode可以是大于等于0的任何值。
startActivityForResult(intent, 0);
Step2.
在A中重寫onActivityResult方法,用來(lái)接收B回傳的數(shù)據(jù),因?yàn)閭骰貋?lái)的resultCode不同而做差別處理。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) { //resultCode為回傳的標(biāo)記
case 20:
Bundle b=data.getExtras(); //data為B中回傳的Intent
String str=b.getString("str1");//str即為回傳的值
break;
default:
break;
}
}
Step3.
在B中采用setResult方法,并且之后要調(diào)用finish方法。
Intent intent=new Intent();
intent.putExtra("str1", str_bookname);
setResult(20, data);
finish(); //關(guān)閉掉這個(gè)Activity
關(guān)于A-B Activity切換, Home鍵, Back鍵的機(jī)制
Activity 和任務(wù)的默認(rèn)行為總結(jié)如下:
當(dāng) Activity A 啟動(dòng) Activity B 時(shí),Activity A 將會(huì)停止,但系統(tǒng)會(huì)保留其狀態(tài)(例如,滾動(dòng)位置和已輸入表單中的文本)。如果用戶在處于 Activity B 時(shí)按“返回”按鈕,則 Activity A 將恢復(fù)其狀態(tài),繼續(xù)執(zhí)行。
用戶通過(guò)按“主頁(yè)”按鈕離開任務(wù)時(shí),當(dāng)前 Activity 將停止且其任務(wù)會(huì)進(jìn)入后臺(tái)。 系統(tǒng)將保留任務(wù)中每個(gè) Activity 的狀態(tài)。如果用戶稍后通過(guò)選擇開始任務(wù)的啟動(dòng)器圖標(biāo)來(lái)恢復(fù)任務(wù),則任務(wù)將出現(xiàn)在前臺(tái)并恢復(fù)執(zhí)行堆棧頂部的 Activity。
如果用戶按“返回”按鈕,則當(dāng)前 Activity 會(huì)從堆棧彈出并被銷毀。 堆棧中的前一個(gè) Activity 恢復(fù)執(zhí)行。銷毀 Activity 時(shí),系統(tǒng)不會(huì)保留該 Activity 的狀態(tài)。
即使來(lái)自其他任務(wù),Activity 也可以多次實(shí)例化。
Home鍵與Back鍵對(duì)Activity的生命周期影響
如果按下Back鍵,系統(tǒng)返回到桌面,并依次執(zhí)行A:onPause -> A:onStop -> A:onDestroy。
如果按下Home鍵(非長(zhǎng)按),系統(tǒng)返回到桌面,并依次執(zhí)行A:onPause -> A:onStop。
由此可見,Back鍵和Home鍵主要區(qū)別在于是否會(huì)執(zhí)行onDestroy。
Back鍵實(shí)現(xiàn)Home鍵效果
@Override
public void onBackPressed() {
Intent home = new Intent(Intent.ACTION_MAIN);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);
}
或者
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
moveTaskToBack()此方法直接將當(dāng)前Activity所在的Task移到后臺(tái),同時(shí)保留activity順序和狀態(tài)。
關(guān)于finish()
- 將此Activity從Activity棧中移除。
- 調(diào)用了此Activity的onDestroy方法。
關(guān)于Activity的一些技巧
鎖定為豎屏
<activity android:name="com.alex33.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
// 豎屏為portrait,橫屏為landscape
</activity>
去除標(biāo)題
requestWindowFeature(Window.FEATURE_NO_TITLE);
Android清單文件中MimeType的用途
Intent-Filter中的有一個(gè)mimeType。它的作用是告訴Android系統(tǒng)本Activity可以處理的文件的類型。如設(shè)置為 “text/plain”表示可以處理“.txt”文件。
<intent-filter>
<actionandroid:name="android.intent.action.VIEW" />
<categoryandroid:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/jpeg ">
</intent-filter>
這樣就把當(dāng)前程序注冊(cè)為可以打開/查看jpeg類型的圖片
當(dāng)在文件管理器里點(diǎn)擊任何jpeg文件, 系統(tǒng)都會(huì)試圖去執(zhí)行你的程序。
" image/jpeg "這一類型屬于標(biāo)準(zhǔn)的MIME Type。
一個(gè)簡(jiǎn)單的隱式跳轉(zhuǎn)并傳遞值的Demo
UI
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.goldinfo.sendmessage.MainActivity">
<ListView
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</RelativeLayout>
item
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="TextView"
android:id="@+id/textView"
android:textColor="#123897"
/>
代碼實(shí)現(xiàn)
MainActivity
public class MainActivity extends AppCompatActivity {
private ListView lv;
private String[] msgs = {"天氣太熱了!買了個(gè)涼席,一睡變電熱毯了!遇到個(gè)陌生人,相視一笑,變熟了!桌子太燙,麻將剛碼好,嘿,居然糊了!",
"工作是枯燥的,賺錢是辛苦的,理想?yún)s是遠(yuǎn)大的,等咱有了錢,喝豆?jié){吃油條,想沾白糖沾白糖,豆?jié){買兩碗,喝一碗,倒一碗!",
"給你點(diǎn)陽(yáng)光你就燦爛,給你點(diǎn)洪水你就泛濫。破鍋?zhàn)杂衅棋伾w,丑鬼自有丑女愛(ài),只要情深意似海,麻子也能放光彩!",
"鳥兒,鳥兒,喳喳叫。清風(fēng),清風(fēng),去煩惱。祝福,祝福要趁早。短信,短信,恰恰好。朋友,朋友,看到短信笑一笑!",
"武當(dāng)派,少林派,不如吃個(gè)蘋果派;日月教,全真教,不如睡個(gè)大懶覺(jué);降龍掌,銷魂掌,不如養(yǎng)盆仙人掌;總之,你好我好大家好",
"我的問(wèn)候,就是那冰激凌,融在你嘴里,甜在你胃里,爽在你心里。愿你把高溫?fù)敉?,把快?lè)放飛,生活有滋有味,笑容天天都美!",
"送你西瓜,爽口爽心頂呱呱;送你電扇,吹走煩躁發(fā)發(fā)汗;送你清涼油,神清氣爽爭(zhēng)上游;送你清心茶,伴你天天樂(lè)開花!",
"看事業(yè)線,你正走在成功路上;看生命線,你定會(huì)健康長(zhǎng)壽;看感情線,你桃花運(yùn)正旺。我的祝福三線合一,愿你快樂(lè)無(wú)比!",
"送你五萬(wàn)塊,一萬(wàn)健康,一萬(wàn)快樂(lè),一萬(wàn)平安,一萬(wàn)好運(yùn),一萬(wàn)幸福,一共五萬(wàn)塊紅磚。嘿嘿,自己建造個(gè)美好城堡吧!",
"好好活,慢慢過(guò),一年更比一年樂(lè);不要攀,不要比,不要自己氣自己;少吃鹽,多吃醋,少打麻將多散步。愿你:天天閑里忙著樂(lè)!"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.ll);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.item, msgs);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//去除點(diǎn)擊條目的數(shù)據(jù)
String content = msgs[position];
//使用隱式意圖 跳轉(zhuǎn)到短信頁(yè)面
Intent intent = new Intent();
intent.setAction("android.intent.action.SEND");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
//key值需要到android源碼中找
intent.putExtra("sms_body",content);
//開啟Activity
startActivity(intent);
}
});
}
}