AndroidAZ系列:四大組件之Broadcast(All,Face)

Git倉庫地址

配套四維導圖地址

AndroidAZ系列有以下目的:

  1. Android程序猿的面試(初級,中級,高級,資深),拿到滿意的offer。
  2. Android程序猿學習進階。

標記說明:因為筆者是列出所有的Android知識點,因此面試不需要看那么多內(nèi)容,如果是面試的知識點。筆者會加上標記Face,而如果不是面試的知識點,筆者會加上No標記,它是要學的東西;然后筆者將Android面試者或者面試者分為4個等級,初級A1,中級A2,高級A3,資深A(yù)4,如果這個知識點是所有等級的范圍,那么筆者將會以all標記上。因此進階路線就是A1->A2->A3->A4。也是面試者挑選的復(fù)習范圍,假如你是中級程序員,那么你面試要看的內(nèi)容就是包含A2&Face的標記。

  • All : 所有的Android工程師都看。

  • A1: 初級Android工程師。

  • A2: 中級Android工程師。

  • A3: 高級Android工程師。

  • A4: 資深A(yù)ndroid工程師。

  • Face: 是面試的知識點。

  • No: 面試基本遇不到。

1.廣播是什么

在Android中,Broadcast是一種廣泛運用的在應(yīng)用程序之間傳輸信息的機制。

2.廣播的種類

2.1 無序廣播(普通廣播)

普通廣播是完全異步的,通過ContextSendBroadcast()函數(shù)來發(fā)送,消息傳遞的效率比較高,但所有的receivers(接收器)的執(zhí)行順序不確定,缺點是:接收者不能將處理結(jié)果傳遞給下一個接收者,并且無法終止廣播Intent的傳播,直到?jīng)]有與之匹配的的廣播接收器為止。

使用方法:

首先繼承BroadcastReceiver,然后需要重寫onReceiver()方法,這樣我們就實現(xiàn)了一個接收器。

public class MyBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "hello", Toast.LENGTH_SHORT).show();
    }
}

2.2 有序廣播

有序廣播是一種同步執(zhí)行的廣播,在廣播發(fā)出后,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞. 有先后順序,前面的廣播能夠截斷正在傳遞的廣播.

有序廣播通過Context.sendOrderdBroadcast()來發(fā)送,所有的廣播按照優(yōu)先級順序依次進行,廣播接收器的 優(yōu)先級通過receiver的intent-filter中的priority屬性來設(shè)置,數(shù)組越大優(yōu)先級越高(最大為最大數(shù)),當廣播接收器結(jié)收到廣播后可以使用setResult()函數(shù)來將結(jié)果傳遞給下一個接收器接收,然后通過getResult來獲取上 一個接收器的返回的結(jié)果,并可以用abortBroadcast()函數(shù)來讓系統(tǒng)丟棄該廣播,該廣播不在傳遞到別的廣播接收器接收。

首先我們注冊兩個廣播接收器

public class MyBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        int i=1;
        Toast.makeText(context, i+"", Toast.LENGTH_SHORT).show();
        Bundle bundle=new Bundle();
        bundle.putInt("I",i);
        setResult(1,i+"",bundle);
    }
}
public class MyBroadcastReceiver2 extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle resultExtras = getResultExtras(true);
        int i = resultExtras.getInt("I");
        Toast.makeText(context, i+1+"", Toast.LENGTH_SHORT).show();
    }
}

并在androidManifest中注冊并設(shè)置兩個廣播接收器的優(yōu)先級

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter android:priority="10">
        <action android:name="hello"></action>
    </intent-filter>
</receiver>
<receiver android:name=".MyBroadcastReceiver2">
    <intent-filter android:priority="1">
        <action android:name="hello"></action>
    </intent-filter>
</receiver>

然后發(fā)送一條有序廣播,第二個參數(shù)是權(quán)限相關(guān)的字符串,可以傳入null。

sendOrderedBroadcast(new Intent("hello"),null);

這時Toast分別彈出的是1和2,說明我們獲取到了上一個廣播接收器的結(jié)果,當然我們也能通過給優(yōu)先級較高的接收器設(shè)置截斷廣播

abortBroadcast();

這樣,之后的廣播接收器都不會再接收到廣播了。

2.3 本地廣播

前面的兩種廣播都是全局廣播,這樣的廣播可以被任意應(yīng)用程序接收,并且我們也能接收到來自其他應(yīng)用程序的廣播,這樣很容易引起安全問題,android為了解決這個問題引入了本地廣播。,使用這個機制發(fā)送的廣播只能在本應(yīng)用程序內(nèi)部進行傳遞,并且廣播接收器也只能接收本應(yīng)用程序的廣播,這樣所有的安全問題就不存在了。

首先先獲取本地廣播實例,并發(fā)送一條異步廣播

localBroadcastManager=LocalBroadcastManager.getInstance(this);
localBroadcastManager.sendBroadcast(new Intent("hello1"));

然后通過本地廣播接收者接收本地廣播

private BroadcastReceiver register=new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "hello1", Toast.LENGTH_SHORT).show();
    }
};

localBroadcastManager.registerReceiver(register,new IntentFilter("hello1"));

最后在onDestory中注銷本地廣播接收者,避免oom。

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(register);
}

2.4 黏性廣播(Android5.0 Api21失效)

sticky廣播通過Context。sendStickyBroadcast()函數(shù)來發(fā)送,用此函數(shù)發(fā)送的廣播會一直滯留,當有與之匹配的 廣播接收器接被注冊后,該廣播接收器就會接收到廣播,當然sticky廣播需要下面權(quán)限。

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

sticky只保留最后一條廣播,并且一直保留下去,這樣即使有廣播接收器處理了該廣播,當有再與之匹配的廣播接收器接收時,此廣播任會被接收,如果你只想處理一次廣播,可以通過removeStickyBroadcast()函數(shù)實現(xiàn)。

3.廣播接收器

3.1 靜態(tài)注冊

四大組件都需要在Androidmanifest中進行注冊

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter>
        <action android:name="hello"></action>
    </intent-filter>
</receiver>

3.2 動態(tài)注冊

registerReceiver(new MyBroadcastReceiver(),new IntentFilter("hello"));

如果是動態(tài)注冊的,別忘了在onDestory()中注銷廣播

@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(new MyBroadcastReceiver());
}

現(xiàn)在我們能給發(fā)送一條廣播了

sendBroadcast(new Intent("hello"));

當我們發(fā)送一條廣播是會彈出一條Toast,說明廣播接收器接收到了。

3.3 靜態(tài)注冊和動態(tài)注冊的區(qū)別

  • 動態(tài)注冊受Activity的生命周期影響,當Activity銷毀的時候,廣播就失效了.而靜態(tài)注冊的廣播即使Activity銷毀了,仍然可以收到廣播,即使殺死進程,仍然可以收到廣播

  • 動態(tài)注冊的廣播永遠要快于靜態(tài)注冊的廣播,不管靜態(tài)注冊的優(yōu)先級設(shè)置的多高,不管動態(tài)注冊的優(yōu)先級多低.

3.4 系統(tǒng)發(fā)送的廣播有哪些

常見系統(tǒng)廣播

打電話

 <intent-filter >
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
 </intent-filter>

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

接電話

<intent-filter >
                <action android:name="android.intent.action.PHONE_STATE"/>
 </intent-filter>

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

開機

<intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>

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

安裝包相關(guān)

<intent-filter >
                <action android:name="android.intent.action.PACKAGE_ADDED"/>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                //注意這個是必須的
                <data android:scheme="package"/>
</intent-filter>

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

接收短信

<intent-filter >
                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>

<uses-permission android:name="android.permission.RECEIVE_SMS"/>
public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Object[] object = (Object[]) intent.getExtras().get("pdus");
        for (Object obj : object) {
            SmsMessage ss = SmsMessage.createFromPdu((byte[]) obj);
            String messageBody = ss.getMessageBody();
            String originatingAddress = ss.getDisplayOriginatingAddress();

            System.out.println(messageBody+":"+originatingAddress);
        }
    }
}

屏幕的鎖屏和解鎖(只能動態(tài)注冊)

receiver = new BootReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
registerReceiver(receiver, filter);

unregisterReceiver(receiver);

下面5個系統(tǒng)廣播只能動態(tài)注冊而不支持靜態(tài)注冊

android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
android.intent.action.BATTERY_CHANGED
android.intent.action.CONFIGURATION_CHANGED
android.intent.action.TIME_TICK

4.源碼角度分析廣播機制

參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容