Detailed broadcast mechanism of Android development

Introduction to Broadcasting Mechanism

Each application in Android can register for the broadcasts that it is interested in, so that the program will only receive the broadcast content that it cares about. These broadcasts may come from the system or from other applications.
Broadcasting in Android can be divided into two types: standard broadcasting and ordered broadcasting.

  • Standard broadcast: It is a completely asynchronous broadcast. After the broadcast is sent, all Broadcast Receivers will receive this broadcast information at almost the same time, so there is no order between them.
  • Orderly broadcast: A synchronously executed broadcast. After the broadcast is sent, only one BroadcastReceiver can receive the broadcast message at the same time. After the logic in the BroadcastReceiver is executed, the broadcast will continue to be delivered. Therefore, the BroadcastReceiver at this time has a sequence. The BroadcastReceiver with high priority can receive the broadcast message first, and the previous BroadcastReceiver can also cut off the broadcast that is being delivered, so that the subsequent BroadcastReceiver cannot receive the broadcast message.

Receive system broadcast

Android has built-in many system-level broadcasts, and we can get various system status information by listening to these broadcasts in the application.
There are generally two ways to register BroadcastReceiver: register in the code and register in AndroidManifest.xml. The former is also called dynamic registration, and the latter is called static registration.

  • Dynamic registration code case
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(){
    //不要在onReceive()方法中添加过多的逻辑或进行任何的耗时操作,因为BroadcastReceiver中是不允许开启线程的,
    //当onReceiver()方法运行了较长时间而没有结束的,程序就会出现错误。
        override fun onReceive(context: Context?, intent: Intent?) {
            TODO("Not yet implemented")
            Toast.makeText(context,"Time has changed",Toast.LENGTH_SHORT).show()
        }
    }
}

The BroadcastReceiver, which is dynamically registered, can freely control registration and cancellation, which has great advantages in flexibility. But it has a shortcoming, that is, the broadcast must be received after the program is started, because the registration logic is written in the onCreate() method. So is there any way that the program can receive broadcasts even when it is not started? This requires the use of static registration.
In fact, theoretically speaking, system broadcasts that can be monitored by dynamic registration, and static registration should also be able to monitor. This is indeed the case in the Android system in the past. However, because a large number of malicious applications use this mechanism to monitor system broadcasts when the program is not started, any application can be frequently awakened from the background, which seriously affects the power and performance of the user’s mobile phone. Therefore, almost every Android system Versions are reducing the function of registering BroadcastReceiver.
After the Android 8.0 system, all implicit broadcasts are not allowed to be received by static registration. Implicit broadcasts refer to broadcasts that are not specifically designated to which application to send. Most system broadcasts are implicit broadcasts, but a few special system broadcasts are still allowed to be received by static registration.
The static BroadcastReceiver must be registered in the AndroidManifest.xml file before it can be used.

  • Static registration code case
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <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:enabled="true"
            android:exported="true"
            android:name=".MainActivity$BootCompleteReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

    class BootCompleteReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            TODO("Not yet implemented")
            Toast.makeText(context,"Boot Complete",Toast.LENGTH_LONG).show()
        }
    }

Send a custom broadcast

Broadcasting is mainly divided into two types: standard broadcasting and ordered broadcasting.

  • Sending a standard broadcast
    Before sending a broadcast, you need to define a BroadcastReceiver to prepare to receive this broadcast, otherwise the song will be white hair. Therefore, create a new MyBroadcastReceiver and add the following code to the onReceiver() method:
    class MyBroadcastReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            TODO("Not yet implemented")
            Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_LONG).show()
        }
    }

<receiver
            android:enabled="true"
            android:exported="true"
            android:name=".MyBroadcastReceiver">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
  val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
  intent.setPackage(packageName)//packageName是getPackageName()的语法糖写法,用于获取当前应用程序的包名。
  sendBroadcast(intent)
  //在Android8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下我们发出的自定义广播恰恰都是隐式广播。因此这里一定要调用setPackage()方法,指定这条广播是发送给哪个应用程序的。从而让它变成一条显式广播,否则静态注册的BroadcastReceiver将无法接收到这条广播。

  • Send an ordered broadcast
  val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
  intent.setPackage(packageName)//packageName是getPackageName()的语法糖写法,用于获取当前应用程序的包名。
  sendOrderedBroadcast(intent,null)//第一个参数仍然式intent;第二个参数是一个与权限相关的字符串,这里传入null就行了。
=======================================
        <receiver
            android:enabled="true"
            android:exported="true"
            android:name=".MainActivity$BootCompleteReceiver">
            <intent-filter
                android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
=======================================

    class BootCompleteReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            TODO("Not yet implemented")
            Toast.makeText(context,"Boot Complete",Toast.LENGTH_LONG).show()
            abortBroadcast()//如果在onReceive方法中调用abortBroadcast方法,就表示将这条广播截断,后面的BroadcastReceiver将无法再接收到这条广播。
        }
    }

Guess you like

Origin blog.csdn.net/qq_36828822/article/details/113829990