廣播📢broadcast
廣播,作為android開發的四大元件之一——活動,廣播,服務,内容提供器;它的用途就是廣播,一個app單向地跟其他的app“
巴拉巴拉”。在進行知識彙總前,可以先看看Google的官方文檔,沒錯,我又讀了一遍它的英文文本——中文文檔,其實多多少少有點機翻的味道。還是推薦讀讀原文,雖然讀的會慢一點但是比中文可能更好了解整體的知識點。
了解同步通信和異步通信的概念
廣播廣播,其實就是通信的一種方式。相信通信工程的小夥伴 聽到這些DNA都要動起來了。
不過這些概念對于我來說,還是有一些模糊的,畢竟術業有專攻嘛~
同步通信與異步通信差別:同步通信要求接收端時鐘頻率和發送端時鐘頻率一緻,發送端發送連續的比特流;異步通信時不要求接收端時鐘和發送端時鐘同步,發送端發送完一個位元組後,可經過任意長的時間間隔再發送下一個位元組。同步通信效率高,異步通信效率較低。
同步通信較複雜,雙方時鐘的允許誤差較小;異步通信簡單,雙方時鐘可允許一定誤差。
同步通信可用于點對多點,異步通信隻适用于點對點。
-
标準廣播
這一種就是根據異步通信為基礎的廣播模式。
-
有序廣播
根據同步通信為基礎的廣播模式,接收方随時可以中斷廣播。
系統廣播
android作為一個強大的作業系統,自然有很多很多的事情需要跟它底下的app“打招呼”什麼的——告訴他們,我要開機了,我的網絡發送變化等等事情。android就會給廣播出去。
這些一些系列的動作,action都會有自己unique獨一無二的String進行封裝的。詳細的名稱比對,可以在android的SDK中查閱
BROADCAST_ACTIONS.TXT
。
一發一收,那麼我們的app就需要根據實際需要進行接收并且做出相應的反應.
接收器對象需要繼承
BroadcastReceiver
且重寫
onReceive
方法
-
- 動态注冊
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
String log = sb.toString();
Log.d(TAG, log);
Toast.makeText(context, log, Toast.LENGTH_LONG).show();
}
}
超級簡單的監聽網絡變化的廣播實作:當網絡發生變化的時候,彈出一個toast進行提示。
package com.example.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangerReceiver networkChangerReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//根據官方文檔,廣播接收的開關必須是對立的,在Create中啟動就得在Destroy中關閉
intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
networkChangerReceiver = new NetworkChangerReceiver();
registerReceiver(networkChangerReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangerReceiver);
}
private class NetworkChangerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"NetworkChange",Toast.LENGTH_LONG).show();
}
}
}
-
-
靜态注冊
通過靜态方法進行注冊。這個直接在IDE中進行建立即可!建立後它會自動在manifest中進行注冊;在注冊的時候有兩個關鍵的屬性配置
表是否接收本程式外的廣播;android:exported
表是否啟用該廣播。android:enabled
-
通過靜态注冊的方法進行開機廣播,建立broadcast之後記得在其
onReceive()
方法中實作一些不太耗時的功能即可。
主要是在xml配置好相關的action:
<receiver
android:name=".BootCompleteRecevier"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
自定義的廣播
廣播僅僅依靠系統自帶的其實是不夠用的,那麼就需要我們自定義一些隔廣播——例如“三年二班,周傑倫,你媽媽喊你回家吃飯~”。玩笑話,别憨憨的在程式設計的時候寫上這個廣播【囧】,廣播action的String唯一清晰具有強烈的辨別資訊!要不很容易在廣播的時候“撞車”!
自定義主要是對于廣播名的自定義!
注意⚠️:
根據官方文檔可知廣播的要求是越來越嚴格!在自定義過程中采用原始方法是行不通的!以下代碼你會發現,怎麼沒彈出廣播toast呢?自從android8之後廣播的靜态注冊是越來越嚴格!!!!是以我們想要自定義的廣播就比較難了,不過還是有的救的,參考:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcasttest.DIY_BROADCAST");
sendBroadcast(intent);
}
});
正确的寫法:在intent中添加元件,元件的屬性是包名和對應的Receiver的路徑;
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcasttest.DIY_BROADCAST");
intent.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.DIYReceiver"));//重點
sendBroadcast(intent);
}
});
有序廣播
有序廣播講究一個優先級,誰的優先級高,誰就可以最先接到廣播并對該廣播進行相應的處理。有序廣播的優先級設定一般在靜态檔案中實作:
<intent-filter android:priority="10">
<action android:name="com.example.broadcasttest.DIY_BROADCAST"/>
</intent-filter>
優先級的數值越大優先級越高!
不過還是因為android8之後對于廣播的限制🚫越來越明顯,導緻實際按照第二版的《第一行代碼》進行代碼的編寫,很多是實作不了的,不過,一般情況來說,應用和應用之間基于商業利益等等因素考量通常不會直接進行跨應用的廣播。
這裡我認為需要好好了解一下即可;有序廣播的中止方法
abortBroadcast()
,廣播就不會傳遞下去了。該方法隻在有序中有效!
This method does not work with non-ordered broadcasts such as those sent with Context.sendBroadcast
本地廣播
之前的廣播的作用域是全局的,意味着整個系統中每一個app都聽得到——你想關門說悄悄話都沒轍。本地廣播顧名思義隻是在本app中進行廣播,結合目前的國際時事即“阿政府軍的政令不出喀布爾“(現在是阿塔當政,希望世界和平!還有祖國真好!)。
強調一下廣播的和
register
的生命周期是對稱性的,即在create中進行
unregister
那麼就得在destory中進行
register
,這樣就會相對提高應用的安全性和應用的健壯性。
unregister
本地廣播無法通過靜态方法進行注冊接收。
實戰岀真知
通過一個強制下線的功能來對廣播的學習進行回報。該功能有點類似qq的退出,直接回退到登陸界面。
這裡的實戰思路:(事件觸發)發送廣播,接收廣播,彈出對話框,關閉所有活動。
實戰開發過程的主要遇到的問題:對話框彈不出來!
// 回顧Ui程式設計的部分
AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);//特别注意這個context,上下文,之前直接用receive中的context為參,但是死活彈不出來;dialog是需要根據實際的activity存在的
builder.setTitle("Warning:").setCancelable(false).setMessage("你的賬号在異地登陸,被迫強制下線!");
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 下線所有activity
UtilActivityController.removeAll();
Toast.makeText(context,"你已成功下線!",Toast.LENGTH_SHORT).show();
}
});
這裡按照書上敲的話,就會陷入一個困境。上面這個代碼才是正确的,詳細可以看我的廣播demo。
困境就是
context
看來得空的時候要好好回顧一下context的知識點,我對這個上下文看來并不是很了解!學海無涯,回頭是岸,不過上了賊船回不來頭了【狗頭】!