標准廣播
標准廣播 (normal broadcasts)是一個完全異步的廣播,在廣播發出后,所有的廣播接收器幾乎在同一時刻接收到消息。因為他們沒有任何先后之分。這種廣播效率高,但同時也是無法阻斷的。
有序廣播
有序廣播(ordered broadcasts)則是一種同步執行的廣播 ,在廣播發出后同一時刻會有一個廣播接收器能夠接收到這條廣播。當這個接收器的邏輯執行完畢才會繼續傳遞。此刻的廣播是有先后順序,優先級高的接收器可以先接收到消息。並且可以截斷正在傳遞的廣播。相對會安全些。
接收系統廣播
Android中內置了很多系統級的廣播,我們可以通過監聽這些廣播來獲取手機的狀態信息。來看看怎么使用吧
動態注冊監聽時間的變化
開始代碼部分,注意一下在使用 inner的時候會有一行 TODO("Not yet implemented") 記得把它刪了,否則會報錯。
這里我們在MainActivty中定義了一個TimeChangeReceiver的內部類。這個類繼承了一個廣播,並重寫了onReceive方法。每當時間發生變化都會得到執行,系統每分鍾發出一個這樣的廣播。
觀察onCreat方法。我們班創建了一個IntentFilter的實例。給它添加了一個值 android.intent.action.TIME_TICK 這個值是系統時間發生改變時,發出的廣播的值就是它。也就是說我們想監聽什么廣播,就在這里添加對應的action。
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) } override fun onDestroy() { super.onDestroy() unregisterReceiver(timeChangeReceiver) } inner class TimeChangeReceiver : BroadcastReceiver(){ override fun onReceive(p0: Context?, p1: Intent?) { Toast.makeText(p0,"時間發生改變",Toast.LENGTH_LONG).show() } } }
靜態注冊開機啟動
動態注冊可以自由控制注冊和注銷,有很大的靈活性,但是只能在程序啟動時才可以接收廣播。因為邏輯是寫在onCreate中,如果想在程序未啟動前接收廣播就要用到靜態注冊了。
在Android8.0之后所有的隱式廣播都不允許使用靜態注冊方式來接收了,隱式廣播值得是那些沒有具體指定發送給哪個應用程序的廣播,大多數系統廣播都屬於隱式廣播。但是仍有部分特殊的系統廣播是可以用隱式廣播注冊方式接收。詳情可看連接
建一個廣播,命名MyReceiver,修改代碼如下:
class MyReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"系統開機",Toast.LENGTH_SHORT).show() } }
隨后打開AndroidManifest.xml文件,修改代碼:
<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/AppTheme"> <receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"> <!--添加intente-file如果你是用as創建的廣播,那外面一層應該會自己添加--> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
編輯好所有代碼后重新運行,然后重啟模擬器,就會接收到一個彈窗提升,不要問我為什么用模擬器,因為我用了三台真機都看不到這個toast
真機需要設置電池不優化
發送自定義廣播
標准廣播
創建一個 廣播接收器,用於接收用戶發出的廣播,當接收到廣播時,彈出一個Toast
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(p0: Context?, p1: Intent?) { Toast.makeText(p0,"接收到一個自定義廣播",Toast.LENGTH_SHORT).show() } }
在AndroidManifest中做出如下修改,在靜態注冊的廣播注冊這里我們添加一個 intent-filter,接收一條值為 com.example.broadcasttest.MY_BROADCAST 的廣播。
<receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> </receiver>
在android_main.xml中添加一個按鈕
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btn" android:text="發送廣播" tools:ignore="MissingConstraints" />
最后,在MainActiyty.kt中寫它的點擊事件,代碼很簡單
構建一個 Intent,傳入一個廣播值 com.example.broadcasttest.MY_BROADCAST
調用 Intent 的setPackage()方法,傳入當前應用的包名
最后調用 setBroadcast將廣播發送出去。
之所以需要調用 setPackage()方法,是因為Android 8之后,靜態注冊的廣播無法接收隱式廣播,而我們發送的廣播默認情況下又都是隱式廣播
,因此一定要調用setPackage方法,指定這是哪個程序發出的。
btn.setOnClickListener { val intent = Intent("com.example.broadcasttest.MY_BROADCAST") intent.setPackage(packageName) sendBroadcast(intent) }
運行項目,點擊發送廣播按鈕,效果如下:
有序廣播
發送有序廣播
前面說過,有序廣播是同步執行的廣播,且可以截斷。我們來驗證一下,創建一個 MyBroadcastReceiver2
編輯如下代碼:
class MyBroadcastReceiver2 : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"這是第二個廣播接收器 接收到的自定義廣播", Toast.LENGTH_SHORT).show() } }
在AndroidManifest和剛才的步驟一樣,注冊一個監聽對象
<receiver android:name=".MyBroadcastReceiver2" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST" /> </intent-filter> </receiver>
好,然后來運行一下
不過到現在我們發出的都是標准廣播,現在我們來嘗試發一個有序廣播。
在MainActivty中修改代碼
btn.setOnClickListener { val intent = Intent("com.example.broadcasttest.MY_BROADCAST") intent.setPackage(packageName) sendOrderedBroadcast(intent,null)
}
可以看到,發送有序廣播只用改變一行代碼,將 sendBroadcast方法改為 sendOrderedBroadcast,這個方法接收兩個參數,第一個仍然是Intent第二個則是一個與權限相關的字符串,這里傳入一個nul就可以了。不過現在運行項目后你會發現還是兩個廣播接收器都能接收到這條廣播。好像沒啥區別。不過別忘了他們是又優先級的
設置優先級的方法是在注冊的位置設定。如下,我們在第二個廣播注冊位置 添加 android:priority 將優先級設置為100。確保它一定在 MyBroadcastReceiver 前收到消息。
<receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST" /> </intent-filter> </receiver> <receiver android:name=".MyBroadcastReceiver2" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.example.broadcasttest.MY_BROADCAST" /> </intent-filter> </receiver>
獲得優先級后,我們就可以阻斷廣播繼續傳遞了。修改MyBroadcastReceiver2中的代碼,如下
class MyBroadcastReceiver2 : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"這是第二個廣播接收器 接收到的自定義廣播", Toast.LENGTH_SHORT).show() abortBroadcast() } }
再次運行項目,你會發現只彈出一個Toast
好了,關於kotlin的廣播的基本用法就到這里了,不會再更了