1. 程式人生 > >Android 面試題總結之Android 基礎(三)

Android 面試題總結之Android 基礎(三)

Android 面試題總結之Android 基礎Broadcast Receiver(三)

在上一章節Android 面試題總結之Android 基礎ContentProvider(二) 我們講的ContentProvider和Intent基礎知識。本節主要講解Broadcast Receiver相關基礎知識。

在閱讀過程中有任何問題,請及時聯絡。
本章系《Android 之美 從0到1 – 高手之路》Android基礎Broadcast Receiver 總結了Android 開發者面試比較常見的Broadcast Receiver相關面試問題以及關於Broadcast Receiver優化效能問題。希望對廣大Android 開發者,有所幫助。

Broadcast Receiver 常見面試題

  1. BroadcastReceiver 簡介

    BroadCastReceiver 是 Android 四大元件之一,主要用於接收系統或者 app 發 送的廣播事件。
    廣播分兩種:有序廣播和無序廣播。
    內部通訊實現機制:通過 Android 系統的 Binder 機制實現通訊。 無序廣播:完全非同步,邏輯上可以被任何廣播接收者接收到。優點是效率較高。 缺點是一個接收者不能將處理結果傳遞給下一個接收者,並無法終止廣播 intent 的傳播。 有序廣播:按照被接收者的優先順序順序,在被接收者中依次傳播。比如有三個廣 播接收者 A,B,C,優先順序是 A > B > C。那這個訊息先傳給 A,再傳給 B,最 後傳給 C。每個接收者有權終止廣播,比如 B 終止廣播,C 就無法接收到。此外 A 接收到廣播後可以對結果物件進行操作,當廣播傳給 B 時,B 可以從結果物件
    中取得 A 存入的資料。

    在通過 Context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras)時我們可以 指定 resultReceiver 廣播接收者,這個接收者我們可以認為是最終接收者,通 常情況下如果比他優先順序更高的接收者如果沒有終止廣播,那麼他的 onReceive 會被執行兩次,第一次是正常的按照優先順序順序執行,第二次是作為最終接收者 接收。如果比他優先順序高的接收者終止了廣播,那麼他依然能接收到廣播。 在我們的專案中經常使用廣播接收者接收系統通知,比如開機啟動、sd 掛載、 低電量、外播電話、鎖屏等。 如果我們做的是播放器,那麼監聽到使用者鎖屏後我們應該將我們的播放之暫停 等。

    Android 4.0之後,如果系統自動關閉廣播接收者所在程序,在廣播中的action跟廣播接收者的action匹配時,系統會啟動該廣播所在的程序,但是如果是使用者手動關閉該程序,則不會自啟動,只有等使用者手動開啟,廣播接收者所在程序如果從來沒有啟動過,那麼廣播接收者不會生效

  2. 在 manifest 和程式碼中如何註冊和使用 BroadcastReceiver
    在清單檔案中註冊廣播接收者稱為靜態註冊,在程式碼中註冊稱為動態註冊。 靜態註冊的廣播接收者只要 app 在系統中執行則一直可以接收到廣播訊息,動 態註冊的廣播接收者當註冊的 Activity 或者 Service 銷燬了那麼就接收不到廣播 了。

    靜態註冊:在清單檔案中進行如下配置

    <receiver android:name=".BroadcastReceiver1" > <intent-filter>
    <action android:name="android.intent.action.CALL" >
                </action>
            </intent-filter>
    </receiver> 

    動態註冊:在程式碼中進行如下注冊

    receiver = new BroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(CALL_ACTION); context.registerReceiver(receiver, intentFilter);

    兩種註冊型別的區別是:

    • 第一種是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統呼叫自動執行(跟系統版本關係,也可能不自動執行)

    • 第二種不是常駐型廣播,也就是說廣播跟隨程式的元件(比如Activity)生命週期。

不同註冊方式廣播接收器回撥onReceive(context, intent)中context型別不一致?

  • manifest靜態註冊的ContextReceiver,回撥onReceive(context, intent)中的context是ReceiverRestrictedContext;

  • 程式碼動態註冊的ContextReceiver,回撥onReceive(context, intent)中的context是Activity Context;

  • 使用LocalBroadcastManager動態註冊的ContextReceiver,回撥onReceive(context, intent)中的context是Application Context。

    1. BroadCastReceiver 的生命週期
      a. 廣播接收者的生命週期非常短暫的,在接收到廣播的時候建立, onReceive()方法結束之後銷燬;
      b. 廣播接收者中不要做一些耗時的工作,否則會彈出 Application No Response 錯誤對話方塊;
      c. 最好也不要在廣播接收者中建立子執行緒做耗時的工作,因為廣播接收者被 銷燬後進程就成為了空程序,很容易被系統殺掉;
      d. 耗時的較長的工作最好放在服務中完成;

    2. Android 引入廣播機制的用意

    a. 從 MVC 的角度考慮(應用程式內) 其實回答這個問題的時候還可以這樣問,
    android 為什麼要有那 4 大元件,現在的移動開發模型基本上也是照搬的 web 那一套 MVC 架構,只不過是改了點嫁妝而已。android 的四大元件本 質上就是為了實現移動或者說嵌入式裝置上的 MVC 架構,它們之間有時候 是一種相互依存的關係,有時候又是一種補充關係,引入廣播機制可以方便 幾大元件的資訊和資料互動。
    b. 程式間互通訊息(例如在自己的應用程式內監聽系統來電)
    c. 效率上(參考 UDP 的廣播協議在區域網的方便性)
    d. 設計模式上(反轉控制的一種應用,類似監聽者模式)

    1. 如何讓自己的廣播只讓指定的 app 接收?
      通過自定義廣播許可權來保護自己發出的廣播。
      在清單檔案裡receiver必須有這個許可權才能收到廣播。
      首先,需要定義許可權:
      然後,宣告許可權:
      這時接收者就能收到傳送的廣播。

    2. 廣播的優先順序對無序廣播生效嗎?
      生效的

    3. 動態註冊的廣播優先順序誰高?
      誰先註冊誰優先順序高。

    4. 如何判斷當前 BroadcastReceiver 接收到的是有序廣播還是無序廣播?
      在 BroadcastReceiver 類中 onReceive()方法中,可以呼叫 boolean b = isOrderedBroadcast();判斷接收到的廣播是否為有序廣播。

    5. 粘性廣播有什麼作用?怎麼使用?
      粘性廣播主要為了解決,在傳送完廣播之後,動態註冊的接收者,也能夠收到廣播。舉個例子首先發送一廣播,我的接收者是通過程式中的某個按鈕動態註冊的。如果不是粘性廣播,我註冊完接收者肯定無法收到廣播了。這是通過傳送粘性廣播就能夠在我動態註冊接收者後也能收到廣播。

    //傳送粘性廣播 
    Public void sendStickyBroadCast(){ 
              Intent intent=new Intent(); 
               intent.setAction(“com.example.receiver.action”); 
               intent.putExtra(“name”,”tom”); 
               this.sendStickyBroadCast(intent); 
         } 

    傳送粘性廣播還需要傳送粘性廣播的許可權:

    <uses-permission android:name="android.permission.BROADCAST_STICKY" />

    在 android 5.0/api 21中deprecated,不再推薦使用,包括粘性有序廣播

    1. 什麼是最終廣播接收者?
      即使前邊攔截了廣播,還是會收到廣播
      最終廣播是我們自己應用傳送有序廣播時通過 ContextWrapper.sendOrderedBroadcast()方法指定的當前應用 下的廣播,該廣播可能會被執行兩次,第一次是作為普通廣播按照優先順序接收廣播,第二次是作為 final receiver 必須 接收一次。

在android-support-v4.jar中引入了LocalBroadcastManager

LocalBroadcastManager除了能解決BroadcastReceiver程序間安全性問題外,相對Context操作的BroadcastReceiver而言還具有更高的執行效率。
本地廣播通過LocalBroadcastManager.getInstance(context).sendBroadcast(intent)傳送廣播,
LocalBroadcastManager.getInstance(context).registerReceiver註冊服務,通過LocalBroadcastManager.getInstance(context).unregisterReceiver取消註冊服務,其他同普通廣播。
BroadcastReceiver的通訊是走 Binder 機制的,LocalBroadcastManager 的核心實現實際還是 Handler,只是利用到了 IntentFilter 的 match 功能,因為是 Handler 實現的應用內的通訊,自然安全性更好,效率更高。

通常使用BroadcastReceiver進行工作執行緒的任務結果通知也好,還是程序間安全性問題,容易引起效能問題,那麼使用LocalBroadcastManager.getInstance有效提高了安全性和效能。

注意:LocalBroadcastManager方式傳送的應用內廣播,只能通過LocalBroadcastManager動態註冊的ContextReceiver才有可能接收到(靜態註冊或其他方式動態註冊的ContextReceiver是接收不到的)。

關於BroadcastReceiver相關面試問題,本章節就先總結到這來。希望對大家有所幫助。

應用場景

  • App內各個元件通訊(單個或多個執行緒之間),區域性重新整理等;

  • 不同App之間的元件之間訊息通訊;

  • 接收系統廣播等。

系統廣播

在廣播訊息中,有一類特殊的廣播訊息,它們特殊在只能由Android系統發出,這類廣播訊息稱為系統廣播。
ACTION_TIME_TICK 系統時間已經改變。該事件每分鐘被廣播一次,只能通過動態註冊BroadcastReceiver來響應。
ACTION_TIME_CHANGED 系統時間被設定
ACTION_TIMEZONE_CHANGED 系統時區被改變
ACTION_BOOT_COMPLETED 系統啟動完成
ACTION_PACKAGE_ADDED 新的應用程式被安裝
ACTION_PACKAGE_CHANGED 應用程式被改變
ACTION_PACKAGE_REMOVED 應用程式被解除安裝
ACTION_PACKAGE_RESTARTED 應用程式被重新啟動
ACTION_PACKAGE_DATA_CLEARED 應用程式資料被清空
ACTION_UID_REMOVED 使用者ID被刪除
ACTION_BATTERY_CHANGED 點量資訊改變
ACTION_POWER_CONNECTED 外接電源被連通
ACTION_POWER_DISCONNECTED 外接電源被斷開
ACTION_SHUTDOWN 系統關閉

安全性

BroadcastReceiver可以方便應用程式和系統、應用程式之間、應用程式內的通訊,所以對單個應用程式而言BroadcastReceiver是存在元件安全性問題的。
這就讓元件暴露在外,建議在開發客戶端時不要暴露內部元件,如果有特殊需求也需進行許可權控制,使用這些元件時需要申請相應許可權。這樣能有一定的防範。

  • 許可權控制(permission)(傳送某個廣播時系統會將傳送的Intent與系統中所有註冊的BroadcastReceiver的IntentFilter進行匹配,若匹配成功則執行相應的onReceive函式。可以通過類似sendBroadcast(Intent, String)的介面在傳送廣播時指定接收者必須具備的permission。或通過Intent.setPackage設定廣播僅對某個程式有效)
  • 宣告android:exported=”false”
    android:exported 是Android中的四大元件 Activity,Service,Provider,Receiver 四大元件中都會有的一個屬性。
    主要作用:是否支援其它應用呼叫當前元件,預設值:如果包含有intent-filter 預設值為true; 沒有intent-filter預設值為false,如果元件無須跨程序互動,則不應設定exported屬性為true,
    當Activity中該屬性用來標示:當前Activity是否可以被另一個Application的元件啟動:true允許被啟動;false不允許被啟動
    當MyService的exported屬性為true時,將可以被其他應用呼叫,等其他元件類似。

  • 使用上面說的,LocalBroadcastManager只會將廣播限定在當前應用程式中

  • 使用protectionLevel:
    protectionLevel 有一下四類級別:
    normal:低風險許可權,只要申請了就可以使用(在AndroidManifest.xml中新增標籤),安裝時不需要使用者確認
    dangerous:高風險許可權,安裝時需要使用者的確認才可使用
    signature:只有當申請許可權的應用程式的數字簽名與宣告此許可權的應用程式的數字簽名相同時(如果是申請系統許可權,則需要與系統簽名相同),才能將許可權授給它
    signatureOrSystem:簽名相同,或者申請許可權的應用為系統應用(在system image中)才能擁有
    如果需要對自己的應用程式(或部分應用)進行訪問控制,則可以通過在AndroidManifest.xml中新增標籤,將其屬性中的protectionLevel設定為上述四類級別中的某一種來實現。

總結

  • Android5.0 開始粘滯廣播和有序粘滯廣播過期,不再建議使用
  • Android N 後臺優化——三個廣播被禁止監聽或傳送
    • CONNECTIVITY_CHANGE 廣播
      在後臺時不再能接收到 CONNECTIVITY_CHANGE 廣播,前臺不影響。
    • ACTION_NEW_PICTUREACTION_NEW_VIDEO 廣播
      不能傳送或是接收新增圖片(ACTION_NEW_PICTURE)和新增視訊(ACTION_NEW_VIDEO) 的廣播。)

這裡寫圖片描述