關於Android8.0 靜態注冊廣播 行為變更的說明。


Andorid 8.0 對廣播的使用做了變更。

當廣播接收器使用靜態注冊方式使用時,除了一些例外,這個接收器接收不到隱式廣播。 注意這個“隱式”是重點。

看了網上幾篇文章,對這個變更理解有誤。錯誤的理解是:8.0后,廣播接收器使用靜態注冊,是無法使用的。
實時並非如此。

先看一個例子:

首先,定義一個簡單的廣播接收器:

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,context.toString(),Toast.LENGTH_SHORT).show();
    }
}

它對接收到廣播的行為就是打印一句話。

第二,我們將他注冊到Manifest文件中。

        <receiver android:name=".broadcast.MyReceiver">
            <intent-filter>
                <action android:name="com.demo.recriver"/>
            </intent-filter>
        </receiver>

最后,在Activity中發送一個廣播,intent通過設置Action為com.demo.recriver的形式發送隱式廣播。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = Intent intent = new Intent("com.demo.recriver");//隱式intent,發送隱式廣播
        sendBroadcast(intent);
    }
}

運行這個demo,發現在8.0以下的手機上,會有Toast顯示,8.0以上的手機不會彈出,說明沒有接收到廣播。

原因在於這個廣播 是“隱式” 發送的,8.0中,靜態注冊的廣播接收者無法接受 隱式 廣播。

為了解決這個問題,有兩個方法:

1 在Activity或其他組件中動態注冊廣播

2 發送顯示廣播

對於1 ,如果想廣播讓接收者工作,必須要在某個Activity或者其他組件中調用registerReceiver()進行注冊,在onDestroy()時還要反注冊,代碼稍顯復雜,而且靜態注冊的廣播接收者仍處於不可用的狀態。不合理。

而后一種方法 ,因為sendBroaccast是自己主動發送的,明顯知道要哪個broadcastReceiver來進行處理,直接發送顯示廣播即可。


具體的代碼如下,將MainActivity做修改:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(MainActivity.this,MyReceiver.class));//顯示指定組件名稱
        sendBroadcast(intent);
    }
}

實際上,這種寫法與更常見的以下寫法相同:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(MainActivity.this,MyReceiver.class);//顯示指定組件名
        sendBroadcast(intent);
    }
}

運行,發現可以彈出Toast,靜態注冊的BroadcastReceiver接收到了廣播。證明靜態注冊是可以接收到廣播的。

順便插一句:

Intent指定action, 這個Intent則為隱式Intent,使用它發送的廣播則為隱式廣播。隱式廣播接收者是通過IntentFilter去查找的。
Intent指定了組件名稱,這個Intent為顯式Intent,用他發送的廣播為顯式廣播。廣播接收者直接就是指定的組件名稱對應的廣播接收者。

猜測顯式Intent不使用IntentFilter去查找組件(Activtiy,Service,BroadcastReceiver),這點讀者有興趣可以驗證是否正確。

再來看一下Intent的setComponent()方法:

Intent設置了組件名稱(比如 new Intent(MainActivity.this,MyReceiver.class);)則通過IntentFilter匹配所需要的action,data,type,category信息會被忽略。

如果剛才的例子做如下改動:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent();
        intent.setAction("com.abcdefg.hijklmn");//指定action--不存在的action
        intent.setComponent(new ComponentName(MainActivity.this,MyReceiver.class));//同時顯式指定組件名
        sendBroadcast(intent);
    }
}

同時指定了隱式的action 以及顯式的組件名稱,action是一個不存在的action。這時仍可以接收到廣播。
雖然通過action不可能匹配到一個廣播接收者,但顯示設置了組件,action就被忽略了。

扯遠了。回到最初的那個話題。8.0以后,靜態注冊的廣播接受者是可以接收到廣播的,只要廣播是通過顯示方式發送的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM