Activity是什么
Activity是Android四大組件之一状答,它提供一個界面讓用戶點擊和各種滑動操作,這就是Activity墓塌。
Activity生命周期
onCreate():你必須實現(xiàn)此回調(diào)桩皿,它會在系統(tǒng)創(chuàng)建你的 Activity 時觸發(fā)。你的實現(xiàn)應(yīng)該初始化Activity的基本組件吼渡。
onStart():此回調(diào)包含 Activity 進入前臺與用戶進行互動之前的最后準(zhǔn)備工作。到了這一步用戶可見不可交互乓序。
onResume():此時寺酪,該Activity位于Activity堆棧的頂部,并會捕獲所有用戶輸入替劈。應(yīng)用的大部分核心功能都是在onResume()方法中實現(xiàn)的寄雀。到了這一步用戶可見可交互。
onPause():當(dāng)用戶點按"返回"或"最近使用的應(yīng)用"按鈕時陨献,Activity失去焦點并進入"已暫停"狀態(tài)時盒犹,系統(tǒng)就會調(diào)用onPause()。到這一步用戶可見不可交互眨业。系統(tǒng)會停止動畫等消耗CPU的操作急膀。
onStop():到了這一步用戶不可見。停止動畫和刷新UI等龄捡。
onRestart():當(dāng)處于"onStop()"狀態(tài)的Activity即將重啟時卓嫂,系統(tǒng)就會調(diào)用此回調(diào)。onRestart()會從Activity停止時的狀態(tài)恢復(fù)Activity至運行狀態(tài)聘殖。
onDestroy():這是Activity最后一個方法晨雳。可以用isFinishing()來判斷它奸腺,如果有dialog在運轉(zhuǎn)餐禁,要在這個界面將dialog給cancel掉,不然拋異常突照。
Activity主要的四種狀態(tài)
Running(運行):在屏幕前臺(位于當(dāng)前任務(wù)堆棧的頂部)
Paused(暫停):失去焦點但仍然對用戶可見(覆蓋Activity可能是透明或未完全遮擋)
Stopped(停止):完全被另一個Activity覆蓋
Destroyed(銷毀):退出帮非,完全銷毀
Activity棧(先進后出)
多個Activity運行時,Android 是通過一種 Activity 棧的方式來管理 Activity 的,一個 Activity 的實例的狀態(tài)決定它在棧中的位置讹蘑。
處于前臺的 Activity 總是在棧的頂端末盔,當(dāng)前臺的 Activity 因為異常或其它原因被銷毀時衔肢,處于棧第二層的 Activity 將被激活庄岖,上浮到棧頂。
當(dāng)新的 Activity 啟動入棧時角骤,原 Activity 會被壓入到棧的第二層隅忿。
一個 Activity 在棧中的位置變化反映了它在不同狀態(tài)間的轉(zhuǎn)換心剥。
啟動Activity
1.簡單啟動
在AndroidManifest.xml中聲明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.scc.demo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Demo">
<activity
android:name=".actvitiy.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.scc.demo.actvitiy.RedActivity"/>
<activity android:name="com.scc.demo.actvitiy.BlueActivity"/>
</application>
</manifest>
在MainActivity.java中啟動
Intent intent = new Intent(MainActivity.this,RedActivity.class);
startActivity(intent);
2.數(shù)據(jù)傳遞
2.1簡單數(shù)據(jù)傳遞
MainActivity.class
Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("scc","aiyouyou");
startActivity(intent);
BlueActivity.class
Log.e(getClass().getName(),getIntent().getStringExtra("scc"));
打印結(jié)果:aiyouyou
2.2復(fù)雜數(shù)據(jù)傳遞
2.2.1使用數(shù)據(jù)包Bundle
MainActivity.class
Intent intent = new Intent(MainActivity.this,BlueActivity.class);
Bundle bundle = new Bundle();
bundle.putString("scc","heiha");
bundle.putString("size","18");
intent.putExtras(bundle);
startActivity(intent);
BlueActivity.class
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
Log.e(getClass().getName(),bundle.getString("scc")+":"+bundle.getString("size"));
運行結(jié)果:
heiha:18
2.2.2使用Serializable(序列化)
2.2.2.1創(chuàng)建一個實體類User implements Serializable
MainActivity.class
Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("user",new User("帥次","男",20));
startActivity(intent);
BlueActivity.class
User user = (User)getIntent().getSerializableExtra("user");
Log.e(getClass().getName(),user.getName()+":"+user.getGender()+user.getAge());
運行結(jié)果:
帥次:男20
3.啟動帶返回值
啟動的MainActivity.java
Intent intent = new Intent(MainActivity.this,BlueActivity.class);
intent.putExtra("scc","俺來咧");
startActivityForResult(intent,998);
Log.e(getClass().getName(),"startActivityForResult");
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e(getClass().getName(),"requestCode:"+requestCode+":resultCode:"+resultCode);
//啟動ActivityCode值998,回傳ActivitiyCode值500
if(requestCode==998&&resultCode==500){
Log.e(getClass().getName(),"Intent data:"+data.getStringExtra("scc_result"));
}
}
被啟動的BlueActvitiy.java
Log.e(getClass().getName(),getIntent().getStringExtra("scc"));
btn_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(getClass().getName(),"onClick.setResult");
Intent intent = new Intent();
intent.putExtra("scc_result", "恕瑞瑪你們的皇帝回來啦");
setResult(500, intent);
finish();
}
});
運行結(jié)果:
點擊MainActivity啟動按鈕
MainActivity$1: startActivityForResult
BlueActivity: 俺來咧
點擊BlueActvitiy返回按鈕
lueActivity$1: onClick.setResult
requestCode:998:resultCode:500
Intent data:恕瑞瑪你們的皇帝回來啦
這就算完事了背桐。
注意:requestCode不能等于resultCode优烧,否則回傳會失效。
Activity的啟動模式(launchMode)
standard:每次激活A(yù)ctivity時(startActivity)链峭,都創(chuàng)建Activity實例畦娄,并放入任務(wù)棧;
singleTop:如果某個Activity自己激活自己弊仪,即任務(wù)棧棧頂就是該Activity熙卡,則不需要創(chuàng)建,其余情況都要創(chuàng)建Activity實例励饵;
singleTask:如果要激活的那個Activity在任務(wù)棧中存在該實例驳癌,則不需要創(chuàng)建,只需要把此Activity放入棧頂役听。并調(diào)用其onNewIntent()颓鲜;
singleInstance:應(yīng)用1的任務(wù)棧中創(chuàng)建了MainActivity實例,如果應(yīng)用2也要激活MainActivity典予,則不需要創(chuàng)建甜滨,兩應(yīng)用共享該Activity實例。
進程的優(yōu)先級
1. 前臺進程(Foreground process)瘤袖。它表明用戶正在與該進程進行交互操作優(yōu)先級是最高的衣摩。Android系統(tǒng)依據(jù)下面的條件來將一個進程標(biāo)記為前臺進程:
該進程持有一個用戶正在與其交互的Activity(也就是這個activity的生命周期方法走到了onResume()方法)。
該進程持有一個正在執(zhí)行生命周期方法(onCreate()孽椰、onStart()昭娩、onDestroy())的Service。
該進程持有一個正在執(zhí)行onReceive()方法的BroadcastReceiver黍匾。
2、可見進程(Visible process)呛梆。它表明雖然該進程沒有持有任何前臺組件锐涯,但是它還是能夠影響到用戶看得到的界面。android系統(tǒng)依據(jù)下面的條件將一個進程標(biāo)記為可見進程:
該進程持有一個非前臺Activity填物,但這個Activity依然能被用戶看到(也就是這個Activity調(diào)用了onPause()方法)纹腌。例如,當(dāng)一個activity啟動了一個對話框滞磺,這個activity就被對話框擋在后面升薯。
該進程持有一個正在執(zhí)行方法Service.startForeground()的Service。
3击困、服務(wù)進程(Service process)涎劈。除了符合前臺進程和可見進程條件的Service广凸,其它的Service都會被歸類為服務(wù)進程。
4蛛枚、后臺進程(Background process)谅海。持有不可見Activity(調(diào)用了onStop()方法)的進程即為后臺進程。通常情況下都會有很多后臺進程蹦浦,當(dāng)內(nèi)存不足的時候扭吁,在所有的后臺進程里面,會按照LRU(最近使用)規(guī)則盲镶,優(yōu)先回收最長時間沒有使用過的進程侥袜。
5、空進程(Empty process)溉贿。不持有任何活動組件的進程系馆。保持這種進程只有一個目的,就是為了緩存顽照,以便下一次啟動該進程中的組件時能夠更快響應(yīng)由蘑。當(dāng)資源緊張的時候,系統(tǒng)會平衡進程緩存和底層的內(nèi)核緩存情況進行回收代兵。
- 這些進程通常包含用戶當(dāng)前不可見的一個或多個Activity實例(onStop()方法已被調(diào)用并返回)尼酿。
scheme跳轉(zhuǎn)協(xié)議
1、android中的scheme是一種頁面內(nèi)跳轉(zhuǎn)協(xié)議植影,通過定義自己的scheme協(xié)議裳擎,可以跳轉(zhuǎn)到app中的各個頁面
2、服務(wù)器可以定制化告訴app跳轉(zhuǎn)哪個頁面
3思币、App可以通過跳轉(zhuǎn)到另一個App頁面
4鹿响、可以通過H5頁面跳轉(zhuǎn)頁面
樣例:
1.在AndroidManifest.xml中對activity標(biāo)簽增加intent-filter設(shè)置Schema
<activity android:name="com.scc.demo.actvitiy.RedActivity"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="scc"
android:path="/redActivity"
android:port="2021"
android:scheme="sccdemo" />
</intent-filter>
</activity>
2.調(diào)用
2.1、在html中調(diào)用
<a href="sccdemo://scc:2021/redActivity?color=0000&ad=10086">打開源生應(yīng)用指定的RedActivity</a>
2.2谷饿、應(yīng)用內(nèi)調(diào)用
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sccdemo://scc:2021/redActivity?color=0000&ad=10086"));
startActivity(intent);
2.3惶我、獲取Url和其他參數(shù)
Intent intent = getIntent();
Uri data = intent.getData();
String action = intent.getAction();
String scheme = intent.getScheme();
Set<String> categories = intent.getCategories();
Log.e("SCHEME", "data:"+data);
Log.e("SCHEME", "action:"+action);
Log.e("SCHEME", "categories:"+categories);
Log.e("SCHEME", "DataString:"+intent.getDataString());
Log.e("SCHEME", "-------------------");
Log.e("SCHEME", "scheme:"+scheme);
Log.e("SCHEME", "id:"+data.getQueryParameterNames());
Log.e("SCHEME", "host:"+data.getHost());
Log.e("SCHEME", "path:"+data.getPath());
Log.e("SCHEME", "port:"+data.getPort());
Android本身API并未聲明會拋出異常,則其在運行時有無可能拋出Runtime異常博投,你遇到過嗎绸贡?有的話會導(dǎo)致什么問題?如何解決毅哗?
會听怕。比如NullPointerException。我遇到過虑绵,比如textview.setText()時尿瞭,textview沒有初始化。會導(dǎo)致程序無法正常運行出現(xiàn)forceclose(當(dāng)前應(yīng)用程序發(fā)生了沖突NullPointExection(空指針)翅睛,IndexOutOfBoundsException(角標(biāo)越界)等等一系列未捕獲異常)声搁。打開控制臺查看logcat信息找出異常信息并修改程序黑竞。
如果后臺的Activity由于某原因被系統(tǒng)回收了,如何在被系統(tǒng)回收之前保存當(dāng)前狀態(tài)酥艳?
重寫onSaveInstanceState()方法摊溶,在此方法中保存需要保存的數(shù)據(jù),該方法將會在activity被回收之前調(diào)用充石。通過重寫onRestoreInstanceState()方法可以從中提取保存好的數(shù)據(jù)(建議你將保存的狀態(tài)保持在50k數(shù)據(jù)以下)莫换。
將Activity設(shè)置成窗口的樣式
在AndroidMainfest.xml中的<activity>中配置:android:theme="@android:style/Theme.Dialog" ,另外 android:theme="@android:style/Theme.Translucent"是設(shè)置透明骤铃。
退出Activity拉岁?退出已調(diào)用多個Activity的Application?
對于單個 activity退出:
單一Activity的應(yīng)用來說惰爬,退出很簡單喊暖,直接 finish()即可。也可以用 killProcess()和 System.exit()這樣的方法撕瞧。
對于多個 activity同時退出:
1陵叽、拋異常強制退出:該方法通過拋異常,使程序Force Close丛版。但是巩掺,需要解決的問題是,如何使程序結(jié)束掉页畦,而不彈出Force Close的窗口胖替。
2、記錄打開的 Activity:每打開一個Activity就記錄下來豫缨。在需要退出時關(guān)閉每一個Activity即可独令。
3、發(fā)送特定廣播:在需要結(jié)束應(yīng)用時好芭,發(fā)送一個特定的廣播燃箭,每個 Activity 收到廣播后,關(guān)閉即可栓撞。
4遍膜、遞歸退出在打開新的 Activity 時使用startActivityForResult,然后自己加標(biāo)志瓤湘,在onActivityResult中處理,遞歸關(guān)閉恩尾。
為了編程方便弛说,最好定義一個Activity基類,處理這些共通問題翰意。
Activity之間使用Intent傳遞大量數(shù)據(jù)帶來問題
Intent在傳遞數(shù)據(jù)時是有大小限制的木人,這里官方并未詳細(xì)說明信柿,不過通過實驗的方法可以測出數(shù)據(jù)應(yīng)該被限制在1MB(1024KB)以內(nèi),發(fā)現(xiàn)當(dāng)數(shù)據(jù)大小超過1MB的時候醒第,程序就會出現(xiàn)閃退渔嚷、停止運行等異常(不同的手機反應(yīng)不同),因此可以判斷Intent的傳輸容量在1MB以內(nèi)稠曼,但是根據(jù)不同版本形病、不同廠商,這個值會有區(qū)別霞幅。
解決方案如下:
1漠吻、減少通過 Intent 傳遞的數(shù)據(jù),將非必須字段使用 transient 關(guān)鍵字修飾司恳。
2途乃、將對象轉(zhuǎn)化為 JSON 字符串,減少數(shù)據(jù)體積扔傅。因為 JVM 加載類通常會伴隨額外的空間來保存類相關(guān)信息耍共,將類中數(shù)據(jù)轉(zhuǎn)化為 JSON 字符串可以減少數(shù)據(jù)大小。
橫豎屏切換時候activity的生命周期猎塞?
1试读、不設(shè)置Activity的android:configChanges,橫邢享、豎屏切換時都會重新調(diào)用各個生命周期鹏往。
2、設(shè)置Activity的android:configChanges="orientation"骇塘,橫伊履、豎屏切換時都會重新調(diào)用各個生命周期。
3款违、設(shè)置Activity的android:configChanges="orientation|screenSize"唐瀑,橫、豎屏切換時不會重新調(diào)用各個生命周期插爹。僅執(zhí)行onConfigurationChanged()方法哄辣。