Android 零基礎(chǔ)到精通之廣播機(jī)制
廣播機(jī)制簡(jiǎn)介
Android 中的廣播主要分為兩種類(lèi)型:
- 標(biāo)準(zhǔn)廣播:一種異步執(zhí)行的廣播,廣播發(fā)出后,所有的 BroadcasterReceiver 幾乎會(huì)在同一時(shí)刻受到這條廣播消息,沒(méi)有任何時(shí)間順序
- 有序廣播:一種同步執(zhí)行的廣播,廣播發(fā)出后,同一時(shí)刻只有一個(gè) BroadcasterReceiver 能夠接受這條廣播消息,當(dāng)該 BroadcasterReceiver 中的邏輯執(zhí)行完畢后,廣播才會(huì)繼續(xù)傳遞
接收系統(tǒng)廣播
Android 內(nèi)置了很多系統(tǒng)級(jí)別的廣播,我們可以在應(yīng)用程序中通過(guò)監(jiān)聽(tīng)這些廣播來(lái)得到各種系統(tǒng)的狀態(tài)信息
1. 動(dòng)態(tài)注冊(cè)監(jiān)聽(tīng)時(shí)間變化
新建一個(gè)類(lèi),繼承自 BroadcasterReceiver,并重寫(xiě)父類(lèi)的 onReceive() 方法,這樣當(dāng)有廣播來(lái)時(shí),onReceive() 方法就會(huì)得到執(zhí)行
class MainActivity : AppCompatActivity() { lateinit var timeChangeReceiver: TimeChangeReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val intentFilter = IntentFilter() intentFilter.addAction("android.intent.action.TIME_TICK") timeChangeReceiver = TimeChangeReceiver() registerReceiver(timeChangeReceiver, intentFilter) } inner class TimeChangeReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show() } } }
- 定義了一個(gè)內(nèi)部類(lèi) TimeChangeReceiver,繼承自 BroadcasterReceiver 并重寫(xiě)父類(lèi)的方法,這樣每當(dāng)系統(tǒng)時(shí)間發(fā)生變化時(shí),就會(huì)使用 Toast 提示一段文本信息
- 在 onCreate() 方法創(chuàng)建一個(gè) IntentFilter 實(shí)例,添加值為 android.intent.action.TIME_TICK 的 action,這也是系統(tǒng)時(shí)間發(fā)生變化時(shí),系統(tǒng)會(huì)發(fā)出的廣播的值
- 創(chuàng)建 TimeChangeReceiver 實(shí)例,然后調(diào)用 registerReceiver() 方法進(jìn)行注冊(cè),將 IntentFilter 實(shí)例和 TimeChangeReceiver 實(shí)例傳進(jìn)去,完成監(jiān)聽(tīng)功能
2. 靜態(tài)注冊(cè)實(shí)現(xiàn)開(kāi)機(jī)啟動(dòng)
動(dòng)態(tài)注冊(cè)的 BroadcasterReceiver 相對(duì)靈活,但必須在程序啟動(dòng)后才能接收廣播,要想讓程序在未啟動(dòng)的情況下也能接收廣播,就需要使用靜態(tài)注冊(cè)的方式
創(chuàng)建類(lèi) BootCompleteReceiver,Exported 屬性表示是否允許這個(gè) BroadcasterReceiver 接收本程序以外的廣播,Enabled 屬性表示是否啟用這個(gè) BroadcasterReceiver,勾選這兩個(gè)屬性,點(diǎn)擊 Finish 完成創(chuàng)建
class BootCompleteReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show() } }
靜態(tài)的 BroadcasterReceiver 要在 AndroidManifest.xml 文件中注冊(cè)才可以使用。由于 Android 系統(tǒng)啟動(dòng)完成后會(huì)發(fā)出一條值為 android.intent.action.BOOT_COMPLETED 的廣播,所以我們?cè)?<receiver> 標(biāo)簽中添加一個(gè) <intent-filter> 標(biāo)簽,并在里面聲明相應(yīng)的 action。另外,還必須在 AndroidManifest.xml 中進(jìn)行權(quán)限聲明。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.fragmenttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.FragmentTest"> ... <receiver android:name="com.example.broadcasttest.BootCompleteReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application> </manifest>
發(fā)送自定義廣播
1. 發(fā)送標(biāo)準(zhǔn)廣播
新建一個(gè) MyBroadcasterReceiver,并在 onReceive() 方法中加入如下代碼:
class MyBroadcasterReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "received in MyBroadcasterReceiver", Toast.LENGTH_SHORT).show() } }
然后在 AndroidManifest.xml 中對(duì)這個(gè) BroadcasterReceiver 進(jìn)行修改
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.fragmenttest"> ... <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.FragmentTest"> ... <receiver android:name="com.example.broadcasttest.MyBroadcasterReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" /> </intent-filter> </receiver> </application> </manifest>
接下來(lái)修改 activity_main.xml,定義一個(gè)按鈕,作為發(fā)送廣播的觸發(fā)點(diǎn)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Send Broadcast" /> </LinearLayout>
修改 MainActivity 中的代碼
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener { val intent = Intent("com.example.broadcasttest.MyBroadcasterReceiver") intent.setPackage(packageName) sendBroadcast(intent) } } }
這里對(duì) setPackage() 方法做個(gè)說(shuō)明,靜態(tài)注冊(cè)的 BroadcasterReceiver 是無(wú)法接收隱式廣播的,而默認(rèn)情況下我們發(fā)出的自定義廣播都是隱式廣播,因此這里要調(diào)用 setPackage() 方法,指定這條廣播是發(fā)送給哪個(gè)應(yīng)用程序的,從而讓它變成一條顯式廣播
2. 發(fā)送有序廣播
有序廣播是一種同步執(zhí)行的廣播,并且可以被截?cái)?,我們?cè)傩陆?AnotherBroadcasterReceiver
class AnotherBroadcasterReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "received in AnotherBroadcasterReceiver", Toast.LENGTH_SHORT).show() } }
然后在 AndroidManifest.xml 中進(jìn)行修改
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.fragmenttest"> ... <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.FragmentTest"> ... <receiver android:name="com.example.broadcasttest.AnotherBroadcasterReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" /> </intent-filter> </receiver> ... </application> </manifest>
到目前為止,程序發(fā)出的都是標(biāo)準(zhǔn)廣播,要發(fā)送有序廣播,就要重新回到 BroadcasterTest 項(xiàng)目,然后修改 MainActivity 中的代碼
class MainActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener { val intent = Intent("com.example.broadcasttest.MyBroadcasterReceiver") intent.setPackage(packageName) sendOrderedBroadcast(intent, null) } ... } }
sendOrderedBroadcast() 方法接收兩個(gè)參數(shù):第一個(gè)參數(shù)仍然是 Intent;第二個(gè)參數(shù)是一個(gè)與權(quán)限相關(guān)的字符串,這里傳入 null 即可
接下來(lái)設(shè)定 BroadcasterReceiver 的先后順序,修改 AndroidManifest.xml 中的代碼
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.fragmenttest"> ... <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.FragmentTest"> <receiver android:name="com.example.broadcasttest.MyBroadcasterReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.example.broadcasttest.MyBroadcasterReceiver" /> </intent-filter> </receiver> ... </application> </manifest>
通過(guò) android:priority 屬性給 BroadcasterReceiver 設(shè)置優(yōu)先級(jí),優(yōu)先級(jí)比較高的 BroadcasterReceiver 就可以先收到廣播。既然 MyBroadcasterReceiver 獲得了接收廣播的優(yōu)先級(jí),那么 MyBroadcasterReceiver 就可以選擇是否允許廣播繼續(xù)傳遞了
class MyBroadcasterReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "received in MyBroadcasterReceiver", Toast.LENGTH_SHORT).show() abortBroadcast() } }
在 onReceive() 方法中調(diào)用 abortBroadcaster() 方法,就表示將這條廣播截?cái)?,后面?BroadcasterReceiver 將無(wú)法再接收這條廣播
到此這篇關(guān)于Android 零基礎(chǔ)到精通之廣播機(jī)制的文章就介紹到這了,更多相關(guān)Android 廣播機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程創(chuàng)建桌面快捷方式的常用方法小結(jié)【2種方法】
這篇文章主要介紹了Android編程創(chuàng)建桌面快捷方式的常用方法,結(jié)合實(shí)例形式總結(jié)分析了2種常見(jiàn)的實(shí)現(xiàn)方法與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02Android中的Button自定義點(diǎn)擊效果實(shí)例代碼
Android中的Button自定義點(diǎn)擊效果實(shí)例代碼,需要的朋友可以參考一下2013-05-05mui.init()與mui.plusReady()區(qū)別和關(guān)系
給大家分享一下在使用MUI進(jìn)行APP開(kāi)發(fā)的時(shí)候,mui.init()與mui.plusReady()區(qū)別以及使用上不同之處。2017-11-11Android onbackpressed實(shí)現(xiàn)返回鍵的攔截和彈窗流程分析
很多網(wǎng)友不明白如何在Android平臺(tái)上捕獲Back鍵的事件,Back鍵是手機(jī)上的后退鍵,一般的軟件不捕獲相關(guān)信息可能導(dǎo)致你的程序被切換到后臺(tái),而回到桌面的尷尬情況,在Android上有兩種方法來(lái)獲取該按鈕的事件2023-01-01Flutter學(xué)習(xí)之實(shí)現(xiàn)自定義themes詳解
一般情況下我們?cè)趂lutter中搭建的app基本上都是用的是MaterialApp這種設(shè)計(jì)模式,MaterialApp中為我們接下來(lái)使用的按鈕,菜單等提供了統(tǒng)一的樣式,那么這種樣式能不能進(jìn)行修改或者自定義呢?答案是肯定的,一起來(lái)看看吧2023-03-03