Android面試四大元件基礎知識點
四大元件是什麼
目錄
一.activity
生命週期圖
1.一個Activity通常就是一個獨立的視窗,Activity各種情況下的生命週期
①正常情況的生命週期
onCreate –>onStart–>onResume–>onPause–>onStop–>onDestory
②橫豎屏切換的時候
如果突然旋轉螢幕,由於系統配置發生了改變,在預設情況下,Activity就會被銷燬並重新建立
在Activity中新增android:configChanges="orientation|keyboardHidden|screenSize"
③Activity上彈出Dialog,彈出時然後按Home鍵時的生命週期
Activity上彈出Dialog:onCreate–>onStart–>onResume
當啟動和退出Dialog時,Activity的狀態始終未變,,因為Dialog實際上時一個View,它是屬於某一個Activity的,因此如果Dialog顯示在當前Activity之前時不會影響到Activity的生命週期的
dialog彈出時按Home鍵:onPause–>onStop
整個流程如下:
④前臺切換到後臺,然後再回到前臺,Activity生命週期回撥方法。
⑤兩個Activity 之間跳轉
MainActivity 和 DragActivity
MainActivity 經歷的週期:onCreate–>onStart–>onResume–>onPause–>onStop–>onRestart–>onStart–>onResume
DragActivity 經歷的週期:onCreate–>onstart–>onResume–>onPause–>onStop–>onDestory
2.Activity之間的通訊方式
startActivity
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
startActivityForResult
Intent intent = new Intent(getContext(), PresentManageActivity.class);
intent.putExtra(PresentManageActivity.KEY_START_NUM, mStartNum);
startActivityForResult(intent, RequestCode.REQUEST_CODE_GIFT);
LocalBroadcastReceiver
3.android應用中的每個Activity都應該在AndroidManifest.xml配件檔案中宣告,否則系統將不識別也不執行該Activity
4.活動被回收,Activity狀態保存於恢復
Activity提供了onSaveInstanceState()回撥方法,這個方法可以保證在活動回收之前被呼叫,
onSaveInstanceState()方法會攜帶一個Bundle型別的引數,Bundle提供了一些方法用於儲存資料
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("data", "儲存資料");
}
儲存的資料在onCreate()方法中可獲取
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState!=null){
String data = savedInstanceState.getString("data");
}
}
5.Activity的四種啟動模式對比
①Standard:系統預設的啟動模式,每次啟動一個activity都會建立一個新的例項,不管這個例項是否存在
②SingleTop:棧頂複用模式,如果activity已經在任務棧的棧頂了,當再次啟動同一個activity的時候,這個activity不會被重新建立,而且它的onNewIntent()方法會被呼叫
適合接受通知啟動的內容頁面,例如:某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都開啟一個新聞內容頁面是很煩人的。
③SingleTask:棧內複用模式,只要activity存在棧內,那麼多次啟動activity都不會重新建立例項,再次啟動時該例項被移到棧頂,系統會呼叫它的onNewIntent()方法
適合做程式的入口點,例如瀏覽器的主介面,不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘的情況都走onNewIntent,並且會清空主介面上面的其他頁面
④SingleInstance:此模式的activity只能單獨位於一個任務棧中,
*適合需要與程式分離的頁面
例如:鬧鈴提醒,將鬧鈴提醒與鬧鈴設定分離*
6.AlertDialog,popupWindow,Activity區別
二.service
1.Service 的生命週期
2.Service的開啟,停止方式
啟動服務
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);
停止服務
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);
3.Activity 怎麼和Service 繫結並進行資料互動
用Binder 物件連線活動和服務
在service中
private DownloadBinder downloadBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public int getProgress() {
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.v(TAG, "onBind: ");
return downloadBinder;
}
在Activity中建立ServiceConnection的匿名內部類,重寫onServiceConnected()和onServiceDisconnected()方法
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//在Activity中呼叫Binder中的方法
MyService.DownloadBinder binder = (MyService.DownloadBinder) service;
int progress = binder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
繫結服務
Intent startIntent = new Intent(this,MyService.class);
bindService(startIntent,connection,BIND_AUTO_CREATE);
//BIND_AUTO_CREATE 在活動和服務繫結後自動建立服務
解綁服務
unbindService(connection);
4.Service的生命週期與啟動方法由什麼區別?
startService():開啟Service,呼叫者退出後Service仍然存在。
bindService():開啟Service,呼叫者退出後Service也隨即退出。
5.怎麼在Activity 中啟動自己對應的Service
三.broadcast
1.請描述一下廣播BroadcastReceiver的理解
①是四大元件之一,主要用於接受APP傳送的廣播
②內部通訊實現機制:自定義廣播接收者BroadcastReceiver,並複寫onRecvice方法;通過android系統的Binder機制向AMS(Activity Manager Service)進行註冊;廣播發送者通過Binder機制向AMS傳送廣播;AMS查詢符合條件的(IntentFilter/Permission等)的BroadcastReceiver,將廣播發送到BroadcastReceiver(一般情況下是Activity)相應的訊息迴圈佇列中;訊息迴圈執行拿到此廣播,回撥BroadcastReceiver 中的onReceiver()方法
③廣播主要分為兩種型別
- 標準廣播:是一種完全非同步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎同時都會在同一時刻受到這條廣播訊息,這種廣播的效率比較高,但同時也意味著它是無法被截斷的
- 有序廣播:是一個同步執行的廣播,廣播發出後,同一時刻只有一個廣播接收器能夠受到這條廣播訊息,當這個廣播接收器中的邏輯執行完畢後,廣播才會繼續傳遞。所有此時的廣播接收器是有先後順序的,優先順序高的先受到廣播,並且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣後面的廣播接收器就無法接收到廣播訊息了
2.廣播的分類,本地廣播和全域性廣播有什麼差別
- 全域性廣播:是跨應用廣播,利用Binder機制實現。即發出的廣播可以被其他任何應用程式接收到,並且也可以接收來自其他任何應用程式的廣播。這樣會很容易引起安全性問題
- 本地廣播:是應用內廣播,利用Handler實現,利用了IntentFilter的match功能,提供訊息的釋出與接收功能,實現應用內通訊,效率比較高。本地廣播機制的發出的廣播只能在應用程式的內部進行傳遞,並且廣播接收器只能接收來自本應用程式發出的廣播。LocalBroadcastManager是本地廣播管理類
public boolean sendBroadcast(Intent intent) {
synchronized (mReceivers) {
final String action = intent.getAction();
final String type = intent.resolveTypeIfNeeded(
mAppContext.getContentResolver());
final Uri data = intent.getData();
final String scheme = intent.getScheme();
final Set<String> categories = intent.getCategories();
final boolean debug = DEBUG ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
if (debug) Log.v(
TAG, "Resolving type " + type + " scheme " + scheme
+ " of intent " + intent);
ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v(TAG, "Action list: " + entries);
ArrayList<ReceiverRecord> receivers = null;
for (int i=0; i<entries.size(); i++) {
ReceiverRecord receiver = entries.get(i);
if (debug) Log.v(TAG, "Matching against filter " + receiver.filter);
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else {
if (debug) {
String reason;
switch (match) {
case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
default: reason = "unknown reason"; break;
}
Log.v(TAG, " Filter did not match: " + reason);
}
}
}
if (receivers != null) {
for (int i=0; i<receivers.size(); i++) {
receivers.get(i).broadcasting = false;
}
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
}
return true;
}
}
}
return false;
}
3.廣播使用的方式和場景
- 建立一個廣播接收器,新建一個類讓它繼承BroadCast,並重寫onReceive()方法就行
- 使用場景:
1.App全域性監聽,這種主要用於在AndroidManifest中靜態註冊的廣播接收器,一般我們在收到該訊息後,需要做一些相應的動作,而這些動作與當前App的元件,比如Activity或者Service的是否執行無關,比如我們在整合第三方Push SDK時,一般都會新增一個靜態註冊的BroadcastReceiver來監聽Push訊息,當有Push訊息過來時,會在後臺做一些網路請求或者傳送通知等等。
2.元件區域性監聽,這種主要是在Activity或者Service中使用registerReceiver()動態註冊的廣播接收器,因為當我們收到一些特定的訊息,比如網路連線發生變化時,我們可能需要在當前Activity頁面給使用者一些UI上的提示,或者將Service中的網路請求任務暫停。所以這種動態註冊的廣播接收器適合特定元件的特定訊息處理
4.在manifest 和程式碼中如何註冊和使用BroadcastReceiver
- 動態註冊:在程式碼中註冊,動態廣播最好在Activity 的 onResume()註冊、onPause()登出,在onResume()註冊、onPause()登出是因為onPause()在App死亡前一定會被執行,從而保證廣播在App死亡前一定會被登出,從而防止記憶體洩露
- 非 常駐系統,跟隨元件的生命週期變化而變化,元件結束,廣播結束。
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.ACTION_SHUTDOWN");
registerReceiver(new CommonBroadcastReceiver(),intentFilter);
- 靜態註冊:在AndroidManifest.xml中註冊
- 常駐系統,不受元件的生命週期影響,即便應用退出,廣播還是可以被接受,耗電,佔用記憶體
<receiver android:name=".broadcast.CommonBroadcastReceiver">
<intent-filter>
<!-- 關機廣播 -->
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
</intent-filter>
</receiver>
5.廣播發送和接收的原理
- 繼承BroadcastReceiver,重寫onReceive()方法。
- 通過Binder機制向ActivityManagerService註冊廣播。
- 通過Binder機制向ActivityMangerService傳送廣播。
public abstract void sendBroadcast(Intent intent);
- ActivityManagerService查詢符合相應條件的廣播(IntentFilter/Permission)的
- BroadcastReceiver,將廣播發送到BroadcastReceiver所在的訊息佇列中。
- BroadcastReceiver所在訊息佇列拿到此廣播後,回撥它的onReceive()方法。
6.Binder機制
Android Binder是用來做程序通訊的,Android的各個應用以及系統服務都執行在獨立的程序中,它們的通訊都依賴於Binder。
7.Android裡的Intent傳遞的資料有大小限制嗎,如何解決?
Intent傳遞資料大小的限制大概在1M左右,超過這個限制就會靜默崩潰。處理方式如下:
程序內:EventBus,檔案快取、磁碟快取。
程序間:通過ContentProvider進行款程序資料共享和傳遞。
8.BroadcastReceiver的生命週期
BroadcastReceiver的onReceive()方法執行完成後,BroadcastReceiver的例項就會被銷燬。如果onReceive()方法在10s內沒有執行完畢,Android會認為改程式無響應。所以在BroadcastReceiver裡不能做一些比較耗時的操作,否則會彈出“Application NoResponse”對話方塊。特別說明的是,這裡不能使用子執行緒來解決 ,因為BroadcastReceiver的生命週期很短,子執行緒可能還沒有結束BroadcastReceiver就先結束了。BroadcastReceiver一旦結束,此時它所在的程序很容易在系統需要記憶體時被優先殺死,因為它屬於空程序。
四.contentProvider
1.談談你對ContentProvider的理解
ContentProvider管理android以結構化方式存放的資料。他以相對安全的方式封裝資料並且提供簡易的處理機制。Content provider提供不同程序間資料互動的標準化介面。保證被訪問資料的安全性。內容提供器可以選擇只對哪一部分資料進行共享,從而保證我們程式中的隱私資料不會有洩漏的風險。
2.說說ContentProvider、ContentResolver、ContentObserver 之間的關係
ContentResolver中提供了一系列的方法用於對資料進行CRUD,內容URI給內容提供器ContentProvider中的資料建立了唯一識別符號,ContentObserver監聽Uri資料的變化
①ContentProvider:管理資料,提供資料的增刪改查操作,資料來源可以是資料庫、檔案、XML
網路等。ContentProvider為這些資料提供了統一的介面,可以用來做程序間資料共享
②ContentResolver:ContentResolver可以不同的URI操作不同的ContentProvider中的資料庫,外部程序可以通過ContentResolver 與ContentProvider進行互動
③ContentObserver :觀察ContentProvider中的資料變化,並將變化通知給外界。