Android進階面試題之Activity干貨篇

Activity知識點.png

Activity是什么

Activity是Android四大組件之一状答,它提供一個界面讓用戶點擊和各種滑動操作,這就是Activity墓塌。

Activity生命周期

image.png

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)

image.png

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)換心剥。


image.png

啟動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)

Activity啟動模式.png

standard:每次激活A(yù)ctivity時(startActivity)链峭,都創(chuàng)建Activity實例畦娄,并放入任務(wù)棧;

image.png

singleTop:如果某個Activity自己激活自己弊仪,即任務(wù)棧棧頂就是該Activity熙卡,則不需要創(chuàng)建,其余情況都要創(chuàng)建Activity實例励饵;

image.png

singleTask:如果要激活的那個Activity在任務(wù)棧中存在該實例驳癌,則不需要創(chuàng)建,只需要把此Activity放入棧頂役听。并調(diào)用其onNewIntent()颓鲜;

image.png

singleInstance:應(yīng)用1的任務(wù)棧中創(chuàng)建了MainActivity實例,如果應(yīng)用2也要激活MainActivity典予,則不需要創(chuàng)建甜滨,兩應(yīng)用共享該Activity實例。

image.png

進程的優(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()方法哄辣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赠尾,隨后出現(xiàn)的幾起案子力穗,更是在濱河造成了極大的恐慌,老刑警劉巖气嫁,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件当窗,死亡現(xiàn)場離奇詭異,居然都是意外死亡寸宵,警方通過查閱死者的電腦和手機崖面,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門元咙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人巫员,你說我怎么就攤上這事庶香。” “怎么了简识?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵赶掖,是天一觀的道長。 經(jīng)常有香客問我财异,道長倘零,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任戳寸,我火速辦了婚禮呈驶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疫鹊。我一直安慰自己袖瞻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布拆吆。 她就那樣靜靜地躺著聋迎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枣耀。 梳的紋絲不亂的頭發(fā)上霉晕,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音捞奕,去河邊找鬼牺堰。 笑死,一個胖子當(dāng)著我的面吹牛颅围,可吹牛的內(nèi)容都是我干的伟葫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼院促,長吁一口氣:“原來是場噩夢啊……” “哼筏养!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起常拓,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤渐溶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弄抬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掌猛,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年眉睹,在試婚紗的時候發(fā)現(xiàn)自己被綠了荔茬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡竹海,死狀恐怖慕蔚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斋配,我是刑警寧澤孔飒,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站艰争,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拓春,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一洒擦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逾柿,春花似錦缀棍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弱匪,卻和暖如春青瀑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萧诫。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工斥难, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人财搁。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓蘸炸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尖奔。 傳聞我的和親對象是個殘疾皇子搭儒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容