1,談談你對Activity的理解?
對於這種“你對什麼什麼怎麼理解”的面試題,最好的回到方式就是用你自己的理解說出來,通俗中夾雜些專業術語,偶爾再蹦出幾個英文。當然如果你很牛X,你可以往深了說,只要別漫無目的的說就行。圍繞一條主線。這其中如果你對某一方面比較精通,你就應該往你精通的方向引。面試官可能就會順著你的思路走了。不過現在有很多面試問Android方面的知識不多,問java方面的比較多。
通俗的講,Activity就是一個應用程式的門面,也可以理解成就是WEB程式中一個頁面,當然與web程式中的頁面不同的是,web中的一個頁面可能只是一個純粹的展示頁面不與使用者進行任何互動,而幾乎所有的Activity都會與使用者互動。當然兩者在架構上也有本質區別,Activity與使用者的互動通過觸發UI的不同事件完成的。而Web程式是通過請求,響應來完成互動的。還有在android中顛覆了很多常規想法,比如在一個Activity中可以開啟另一個不在同一應用的Activity。這在其他程式是不可想象的。當然這種設計的出發點也是為了節省系統資源。從View層的角度來看,Activity承載了與使用者互動的不同控制項。從控制層看,也就是內部邏輯,Activity需要保持各個介面的狀態,背後會做很多持久化的操作。包括妥善管理生命週期的各個階段。(把生命週期引出來了,沒準就會問你這方面的)。
下面是文檔式的回答:(最好的回答方式兩者結合)
首先Activity是android四大組件之一。它是單獨的,作為使用者與程式互動的一個載體。幾乎所有的Activity都與使用者互動。Activity建立了一個視窗,你可以通過setContentView這個方法將需要的UI放置在視窗。任何一個應用程式都可以調用單獨的一個Activity。
其次,Activity的繼承關係Activity→ContextThemeWrapper→ContextWrapper→Context
最後大部分的Activity的子類都需要實現以下兩個介面:
onCreate(Bundle savedInstanceState)介面是初始化activity的地方. 在這兒通常可以調用setContentView(int)設定在資源檔中定義的UI, 使用findViewById(int) 可以獲得UI中定義的視窗.
onPause()介面是使用者準備離開activity的地方,在這兒,任何的修改都應該被提交(通常用於ContentProvider儲存資料).
所有Activity必須在資訊清單檔裡註冊一下才能使用。
2,Activity的生命週期?
在系統中的Activity被一個Activity棧所管理。當一個新的Activity啟動時,將被放置到棧頂,成為運行中的Activity,前一個Activity保留在棧中,不再放到前台,直到新的Activity退出為止。
Activity有四種本質區別的狀態:
1)在螢幕的前台(Activity棧頂),叫做活動狀態或者運行狀態(active or running)
2)如果一個Activity失去焦點,但是依然可見(一個新的非全屏的Activity 或者一個透明的Activity 被放置在棧頂),叫做暫停狀態(Paused)。一個暫停狀態的Activity依然保持活力(保持所有的狀態,成員資訊,和視窗管理器保持串連),但是在系統記憶體極端低下的時候將被殺掉。
3)如果一個Activity被另外的Activity完全覆蓋掉,叫做停止狀態(Stopped)。它依然保持所有狀態和成員資訊,但是它不再可見,所以它的視窗被隱藏,當系統記憶體需要被用在其他地方的時候,Stopped的Activity將被殺掉。
4)如果一個Activity是Paused或者Stopped狀態,系統可以將該Activity從記憶體中刪除,Android系統採用兩種方式進行刪除,要麼要求該Activity結束,要麼直接殺掉它的進程。當該Activity再次顯示給使用者時,它必須重新開始和重設前面的狀態。
Activity提供了7個生命週期方法:
onCreate(),onStart(),onResume(),onPause(),onStop(),onDestory(),onRestart()。在這七個生命週期方法中有三個關鍵的迴圈。其實官方給的那張圖畫得很明白,但估計很少人能有耐心去揣摩。那就換種方式展現。看圖吧:
1)以下該圖呈現了一個Activity完整的生命週期,從onCreate(Bundle)開始到onDestroy()結束。Activity在onCreate()設定所有的“全域”狀態,在onDestory()釋放所有的資源。
首先我們運行程式,這是開啟MainActivity依次調用onCreate->onStart->onResume,這時MainActivity在棧頂,與我們互動的Activity都在棧頂。然後我按下返回鍵,則會依次調用onPause->onStop->onDestory。這屬於一個完整的生命週期。
2)可見的生命週期,從onStart()開始到onStop()結束。說白了就是一個Activity被另一個activity完全覆蓋掉,然後又重新回到前台這個一個過程稱之為可見生命週期。
首先我們開啟OtherActivity這個視窗。此時MainActivity將被覆蓋掉。則會依次調用onPause->onStop。在記憶體不足的時候,系統也會殺死MainActivity進程。
然後,按下返回鍵,MainActivity又回到前台此時會調用onRestart->onStart->onResume。
3)前台的生命週期,從onResume()開始到onPause()結束。在這段時間裡,該Activity處於所有Activity的最前面,和使用者進行互動。Activity可以經常性地在resumed和paused狀態之間切換。說白了就是一個Activity覆蓋到另一個Activity上面,但是並沒有完全覆蓋掉。
首先,我們將OtherActivity開啟,這是OtherActivity以對話方塊模式開啟,懸浮在MainActivity上面。直接調用的onPause()。
然後我們按下返回鍵,則調用的onResume。對於這種沒用完全覆蓋的狀態只會在onPause與onResume兩個方法之間切換。
註:還有一種特殊情況,當螢幕發生改變的時候生命週期是怎樣的呢?比如由豎屏調整為橫屏。生命週期的方法依次用:onPause->onStop->onDestroy->onCreate->onStart->onResume。這麼一個過程。它會銷毀掉原先的activity,重新建立。
3,Acitvity啟動模式?
對於這種題,最後就是自己寫個例子,觀察一下,才能真正明白。
Activty啟動提供了四種啟動模式。launchMode:
standard:每次啟動新的使用中視窗(new操作)
singleTop:如果在棧頂是目標活動,則直接開啟.否則開啟新的使用中視窗(new).
singleTask和singleInstance基本上相同.差別在於若根活動設定為singleTask時,則由此所開啟的活動也在同一任務中,即taskId相同。.而若根活動設定為singleInstance時,由此開啟的活動在新的任務中.即棧中只有一個活動,taskid不同。.其餘情況相同.
4,在onCreate方法中Bundle savedInstanceState 這個參數有什麼作用?
在onCreate方法中有saveInstanceState這個參數,其實這個參數對應兩個方法。
void onSaveInstanceState(Bundle outState);void onRestoreInstanceState(Bundle savedInstanceState)。當某個activity變得“容易”被系統銷毀時,說白了就是系統在記憶體不足或者其他異常情況下把你的Activity銷毀時,將調用這個方法。需要注意的是它是系統調用的,並且你的Activity是被動得被銷毀。你可以在銷毀的時候儲存一下資料。然後在onCreate方法中拿出來。那什麼情況下能觸發這兩個方法呢?
1)、當使用者按下HOME鍵時。
這是顯而易見的,系統不知道你按下HOME後要運行多少其他的程式,自然也不知道activity A是否會被銷毀,故系統會調用onSaveInstanceState,讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則
2)、長按HOME鍵,選擇運行其他的程式時。
3)、按下電源按鍵(關閉螢幕顯示)時。
4)、從activity A中啟動一個新的activity時。
5)、螢幕方向切換時,例如從豎屏切換到橫屏時。
在螢幕切換之前,系統會銷毀activity A,在螢幕切換之後系統又會自動地建立activity A,所以onSaveInstanceState一定會被執行
總而言之,onSaveInstanceState的調用遵循一個重要原則,即當系統“未經你許可”時銷毀了你的activity,則onSaveInstanceState會被系統調用,這是系統的責任,因為它必須要提供一個機會讓你儲存你的資料(當然你不儲存那就隨便你了)。
至於onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對的被調用的,onRestoreInstanceState被調用的前提是,activity A“確實”被系統銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被調用,例如,當正在顯示activity A的時候,使用者按下HOME鍵回到主介面,然後使用者緊接著又返回到activity A,這種情況下activity A一般不會因為記憶體的原因被系統銷毀,故activity A的onRestoreInstanceState方法不會被執行
另外,onRestoreInstanceState的bundle參數也會傳遞到onCreate方法中,你也可以選擇在onCreate方法中做資料還原。
5,談談你對BroadCastRceiver的理解?
廣播接收者,android四大組件之一,也是唯一一個能動態註冊的組件。
1)廣播接收者是一個專註於接收廣播通知資訊,並做出對應處理的組件。很多廣播是源自於系統──比如,通知時區改變、電池電量低、拍攝了一張照片或者使用者改變了語言選項。應用程式也可以進行廣播──比如說,通知其它應用程式一些資料下載完成並處於可用狀態。
2)應用程式可以擁有任意數量的廣播接收者以對所有它感興趣的通知資訊予以響應。所有的接收器均繼承自BroadcastReceiver基類。
3)廣播接收者沒有使用者介面。然而,它們可以啟動一個activity來響應它們收到的資訊,或者用NotificationManager來通知使用者。通知可以用很多種方式來吸引使用者的注意力──閃動背燈、震動、播放聲音等等。一般來說是在狀態列上放一個持久的表徵圖,使用者可以開啟它並擷取訊息。
6,廣播分幾種?他們有什麼區別?
廣播被分為兩種不同的類型:“普通廣播(Normal broadcasts)”和“有序廣播(Ordered broadcasts)”。普通廣播是完全非同步,可以在同一時刻(邏輯上)被所有接收者接收到,訊息傳遞的效率比較高,但缺點是:接收者不能將處理結果傳遞給下一個接收者,並且無法終止廣播Intent的傳播。
然而有序廣播是按照接收者聲明的優先順序別,被接收者依次接收廣播。如:A的層級高於B,B的層級高於C,那麼,廣播先傳給A,再傳給B,最後傳給C 。優先順序別聲明在intent-filter 元素的android:priority 屬性中,數越大優先順序別越高,取值範圍:-1000到1000,優先順序別也可以調用IntentFilter對象的setPriority()進行設定。有序廣播的接收者可以終止廣播Intent的傳播,廣播Intent的傳播一旦終止,後面的接收者就無法接收到廣播。
另外,有序廣播的接收者可以將資料傳遞給下一個接收者,如:A得到廣播後,可以往它的結果對象中存入資料,當廣播傳給B時,B可以從A的結果對象中得到A存入的資料。
Context.sendBroadcast()
發送的是普通廣播,所有訂閱者都有機會獲得並進行處理。
Context.sendOrderedBroadcast()
發送的是有序廣播,系統會根據接收者聲明的優先順序別按順序逐個執行接收者,
前面的接收者有權終止廣播(BroadcastReceiver.abortBroadcast()),如果廣播被前面的接收者終止,後面的接收者就再也無法擷取到廣播。對於有序廣播,前面的接收者可以將資料通過setResultExtras(Bundle)方法存放進結果對象,然後傳給下一個接收者,下一個接收者通過代碼:Bundle bundle = getResultExtras(true))可以擷取上一個接收者存入在結果對象中的資料。
7,廣播的生命週期?
廣播的生命週期是非常短的,當發送之後intent會到AndroidManifest.xml檔案中找是不是有匹配的action,如果有就會調用Receiver ,然後獲得Receiver 對象,再執行onReceive方法,這時候Receiver對象就沒有用了,當我們再次點擊按鈕的時候就會重新獲得對象,這就是BroadcastReceiver的生命週期.
在BroadcastReceiver裡不能做一些比較耗時的操作,否側會彈出ANR(Application No
Response)的對話方塊.
如果需要完成一項比較耗時的工作,應該通過發送Intent給Service,由Service來完成.這裡不能使用子線程來解決,因為BroadcastReceiver的生命週期很短,子線程可能還沒有結束,BroadcastReceiver就先結束了.BroadcastReceiver一旦結束,此時BroadcastReceiver的所在進程很容易在系統需要記憶體時被優先殺死,因為它屬於空進程(沒有任何活動組件的進程).如果它的宿主進程被殺死,那麼正在工作的子線程也會被殺死.所以採用子線程來解決是不可靠的.
8,兩種註冊BroadcastReceiver的方法?
使用在manifest中註冊的方法註冊BroadcastReceiver,即使你的應用程式沒有啟動,或者已經被關閉,這個BroadcastReceiver依然會繼續運行,這樣的運行機制可能會給軟體的使用者造成困擾。所以作為程式的開發人員,我們希望能夠有一種靈活的機制完成BroadcastReceiver的綁定和解除綁定操作。Android當然也考慮到了這些問題,所以在Context這個類當中提供了如下兩個函數可以在代碼中註冊:
i. registerReceiver(receiver,filter);
這個函數的作用就是將一個BroadcastReceiver註冊到應用程式當中,這個函數接收兩個參數,第一個參數是需要註冊的BroadcastReceiver對象,第二個是一個IntentFilter。第一個參數是非常容易理解的,第二個參數的作用是定義了哪些Intent才能觸發這個註冊的BroadcastReceiver對象。
ii. unregisterReceiver(receiver);
這個方法就非常的簡單了,用於解除BroadcastReceiver的綁定狀態。一旦解除完成,響應的BroadcastReceiver就不會再接收系統所廣播的Intent了。
兩種註冊BroadcastReceiver的方法
1.在應用程式的代碼中進行註冊
註冊BroadcastReceiver
registerReceiver(receiver,filter);
取消註冊BroadcastReceiver
unregisterReceiver(receiver);
2.在AndroidManifest.xml當中進行註冊
<receiver android:name="SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
兩種註冊BroadcastReceiver方法的比較:
現在我們瞭解了兩種註冊BroadcastReceiver的方法之後,需要考慮一下這兩種方法適用的場合:
i. 第一種註冊的方法可以保證在應用程式安裝之後,BroadcastReceiver始終處於活動狀態,通常用於監聽系統狀態的改變,比如說手機的電量,wifi網卡的狀態(當然,監視這些東西也是取決於軟體的需求)。對於這樣的BroadcastReceiver,通常是在產生某個特定的系統事件之後,進行相應的操作,比如說wifi網卡開啟時,給使用者一個提示;
ii. 第二種註冊方法相對第一種要靈活的多,這樣註冊的BroadcastReceiver通常用於更新UI的狀態。一般來說,都是在一個Activity啟動的時候使用這樣的方法註冊BroadcastReceiver,一旦接收到廣播的事件,就可以在onReceive方法當中更新當前的這個Activity當中的控制項。但是需要注意的是如果這個Activity不可見了,就應該調用unregisterReceiver方法來解除註冊
9,粘性廣播有什麼作用?怎麼使用?
粘性廣播主要為瞭解決,在發送完廣播之後,動態註冊的接收者,也能夠收到廣播。舉個例子首先發送一廣播,我的接收者是通過程式中的某個按鈕動態註冊的。如果不是粘性廣播,我註冊完接收者肯定無法收到廣播了。這是通過發送粘性廣播就能夠在我動態註冊接收者後也能收到廣播。
用法:
//發送粘性廣播
Public void sendStickyBroadCast(){
Intent intent=new Intent();
intent.setAction(“com.iteye.myreceiver.action”);
intent.putExtra(“name”,”tom”);
this.sendStickyBroadCast(intent);
}
發送粘性廣播還需要發送粘性廣播的許可權:<uses-permission android:name="android.permission.BROADCAST_STICKY" />
//動態註冊廣播接收者
MyReceiver mr = new MyReceiver ();
IntentFilter filter = new IntentFilter();
filter.addAction("com.iteye.myreceiver.action ");
filter.addCategory(Intent.CATEGORY_DEFAULT);
Intent ii = this.registerReceiver(mr, filter);
String n = ii.getStringExtra("name");
Toast.makeText(this, "動態註冊接收者完成,收到粘性廣播,name=" + n, 1).show();
10,如何控制接收者或者發送方得許可權?
1)如果廣播發送方要求接收方必須有某個許可權才能收到廣播怎麼做呢?
/**
* 發送廣播,指定接收者許可權
* sendBroadcast(i, "com.iteye.permission.receiver");//指定接收者許可權
*/
public void sendBroadcast() {
//隱式意圖,發送廣播
Intent i = new Intent();
i.setAction("com.iteye.receiver.action");
i.putExtra("name", "tom");
this.sendBroadcast(i, " com.iteye.permission.receiver ");
Log.i("Other",".send ok!");
}
在資訊清單檔裡receiver必須有這個許可權才能收到廣播。
首先,需要定義許可權:<permission android:name=" com.iteye.permission.receiver " />
然後,聲明許可權:<uses-permission android:name=" com.iteye.permission.receiver " />
這時接收者就能收到發送的廣播。
2)反過來,如果接收者要求發送方必須擁有某個許可權,我才接收你的廣播怎麼辦呢?
<!-- 註冊廣播接收者
android:permission:控制發送方需要具備指定許可權,才接收其廣播.
-->
<receiver android:name=".MyReceiver" android:permission="com.permission.sender">
<intent-filter android:priority="100">
<action android:name="com.iteye.receiver.action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
即使過濾器匹配,如果發送方沒有相應許可權,接收者也不會接收其廣播
摘自:揮汗求完美,用心得精品!