An overview of the
Broadcast is one of the four components of Android. It is a communication method provided by Android system. The broadcast mechanism in Android allows applications to register only the broadcasts they are interested in, so that applications only receive the broadcasts they care about.
In Android, there are broadcasts from the system, such as battery changes, wifi connection changes and startup completion, as well as from other applications, such as custom broadcasts.
To receive broadcasts on an Android system, you need to use BroadcastReceiver.
Application scenarios of broadcast
- Communication between different components (including within and between applications)
- Multithreaded communication
- Communication between components and systems (such as network changes)
The radio type
- Standard broadcast: a broadcast executed completely asynchronously, after which the receiver of the broadcast event is notified at approximately the same time and may or may not respond to the event
- Ordered broadcast: a synchronous broadcast that can be received by only one receiver at a time after it has been sent. A receiver can choose to continue the broadcast to other receivers after it has been processed or to intercept the broadcast.
Registration way
We mentioned above that the broadcast mechanism in Android allows applications to register only broadcasts they are interested in. There are two types of “registration” :
- Dynamic registration: Register using code
- Static registration: Registers in the manifest file from
Android
As of 8.0, all implicit broadcasts are not allowed to be received using static registration. it is recommended that you do not register broadcast receivers statically in manifest files
Example 1: Receiving a broadcast from the system
For example, when we close or open airplane mode, the system will send an intent.action_airplane_mode_CHANGED message. The implementation of broadcast is basically two steps:
- implementation
BroadcastReceiver
, the rewriteonReceive()
function - registered
BroadcastReceiver
The code for implementing BroadcastReceiver is as follows:
class TestBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context? , intent:Intent?). {
when(intent? .action) { Intent.ACTION_AIRPLANE_MODE_CHANGED -> Toast.makeText(context,"Your flight mode status has changed.", Toast.LENGTH_SHORT).show()
}
}
}
Copy the code
Note: the onReceive() function here is in the main thread and does not handle time-consuming operations. Also, do not start a child thread to perform time-consuming operations, because the Activity will be stopped by the user, or the BroadcastReceiver will end before the child thread ends.
The code for registering BroadcastReceiver is as follows:
class TestBroadcastReceiverActivity : AppCompatActivity() {
private lateinit var mReceiver: TestBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_broadcast_receiver)
mReceiver = TestBroadcastReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(mReceiver, intentFilter)
}
override fun onDestroy(a) {
super.onDestroy()
unregisterReceiver(mReceiver)
}
}
Copy the code
The effect is as follows:
Example 2: Sending custom broadcasts and receiving data
Before sending broadcasts, we also need to implement BroadcastReceiver and override the onReceive() function so that the custom broadcasts we send can be received. The code looks like this:
class TestBroadcastReceiver(private val tv: TextView?) : BroadcastReceiver() {
override fun onReceive(context: Context? , intent:Intent?). {
when(intent? .action) { Intent.ACTION_AIRPLANE_MODE_CHANGED -> Toast.makeText(context,"Your flight mode status has changed.", Toast.LENGTH_SHORT).show()
"com.geely.interview.TEST_BROADCAST_RECEIVER"- > {val data = intent.getStringExtra("content")
Toast.makeText(context, "A custom broadcast was received with data as$data", Toast.LENGTH_LONG).show() tv? .let { it.text =data }
}
}
}
}
Copy the code
In the main constructor, we pass in a TextView to set the value we receive into the interface. We can use the interface, we can write the TestBroadcastReceiver directly into the Activity, and so on. TextView is passed directly from the constructor. Example 5, which follows, was changed to use interfaces to implement setting values into the interface.
To send a broadcast, simply build an Intent object, pass in the value of the broadcast, and call sendBroadcast() to send the broadcast. The specific code is as follows:
class TestSendBroadcastActivity : AppCompatActivity() {
lateinit var mReceiver: TestBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_send_broadcast)
mReceiver = TestBroadcastReceiver(tv_content)
val intentFilter = IntentFilter("com.geely.interview.TEST_BROADCAST_RECEIVER")
registerReceiver(mReceiver, intentFilter)
btn_send.setOnClickListener {
val intent = Intent("com.geely.interview.TEST_BROADCAST_RECEIVER")
intent.putExtra("content", et_content.text.toString())
sendBroadcast(intent)
}
}
override fun onDestroy(a) {
super.onDestroy()
unregisterReceiver(mReceiver)
}
}
Copy the code
The full effect looks like this:
Example 3: Static registration implementation Example 2
In both examples 1 and 2 above we broadcast through dynamic registration, which is the recommended approach, but we need to know how static registration works, so we change example 2 to static registration. First we remove the code for dynamic registration:
class TestSendBroadcastActivity : AppCompatActivity() {
// lateinit var mReceiver: TestBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_send_broadcast)
// mReceiver = TestBroadcastReceiver(tv_content)
// val intentFilter = IntentFilter("com.geely.interview.TEST_BROADCAST_RECEIVER")
// registerReceiver(mReceiver, intentFilter)
btn_send.setOnClickListener {
val intent = Intent("com.geely.interview.TEST_BROADCAST_RECEIVER")
intent.putExtra("content", et_content.text.toString())
sendBroadcast(intent)
}
}
override fun onDestroy(a) {
super.onDestroy()
// unregisterReceiver(mReceiver)}}Copy the code
Then register the BroadcastReceiver statically in androidmanifest.xml as follows:
<receiver android:name=".broadcast.TestBroadcastReceiver">
<intent-filter>
<action android:name="com.geely.interview.TEST_BROADCAST_RECEIVER"/>
</intent-filter>
</receiver>
Copy the code
Prior to Android 8.0, this was fine, but as mentioned earlier, statically registered BroadcastReceivers wouldn’t be able to receive implicit broadcasts after Android 8.0, which is exactly what custom broadcasts are by default.
So we need to call the Intent setPackage() method and pass in the package name of the current application. Sets the broadcast receiver to either display the broadcast or display it via intent.setComponent (the package name, the full class name of the receiving broadcast class).
The code looks like this:
class TestSendBroadcastActivity : AppCompatActivity() {
// lateinit var mReceiver: TestBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_send_broadcast)
// mReceiver = TestBroadcastReceiver(tv_content)
// val intentFilter = IntentFilter("com.geely.interview.TEST_BROADCAST_RECEIVER")
// registerReceiver(mReceiver, intentFilter)
btn_send.setOnClickListener {
val intent = Intent("com.geely.interview.TEST_BROADCAST_RECEIVER")
intent.putExtra("content", et_content.text.toString())
// You can do either of the following
intent.setPackage(packageName)
// intent.component = ComponentName(packageName, "com.xt.interview.broadcast.TestBroadcastReceiver")
sendBroadcast(intent)
}
}
override fun onDestroy(a) {
super.onDestroy()
// unregisterReceiver(mReceiver)}}Copy the code
This allows us to send and receive broadcasts through static registration.
Example 4: Sending and receiving broadcasts between applications
Android BroadcastReceiver not only receives broadcasts from your system and application, but also receives broadcasts from other applications, as long as the customized actions are the same.
Here I made the project complex and changed the package name to a different one. Then install both apps on the phone and call them Demo1 and demo2.
Because the codes of Demo1 and demo2 are exactly the same, the actions of the two custom broadcasts are both “com.geely.interview.TEST_BROADCAST_RECEIVER”, so when I send the broadcast in Demo1, Demo2 can also receive and correctly parse the data carried by the broadcast.
The effect is as follows:
It can be seen that when we send a broadcast in Demo1, Demo2 can also receive it and successfully parse out the data carried by the broadcast.
However, sometimes we do not want our broadcast to be monitored by other apps, because we may carry some implicit data in the broadcast. What should we do in this case? In this case, we can use LocalBroadcastManager to send in-app broadcasts.
App
In-application broadcast can be understood as a kind of local broadcast, in which both sender and receiver belong to the sameApp
.- Compared to global broadcast (normal broadcast),
App
The advantages of in-application broadcasting are: high security & high efficiency
Example 5: Rewrite Example 4 with LocalBroadcastManager
In fact, this rewrite is very simple, just need to rewrite the registration and send these two places.
// Use LocalBroadcastManager to register broadcasts
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, intentFilter)
// Use LocalBroadcastManager to send broadcasts
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
Copy the code
The TestBroadcastReceiver code is as follows:
class TestBroadcastReceiver: BroadcastReceiver() {
private lateinit var tvInteraction: TVInteraction
override fun onReceive(context: Context? , intent:Intent?). {
when(intent? .action) { Intent.ACTION_AIRPLANE_MODE_CHANGED -> Toast.makeText(context,"Your flight mode status has changed.", Toast.LENGTH_SHORT).show()
"com.geely.interview.TEST_BROADCAST_RECEIVER"- > {val data = intent.getStringExtra("content")
Toast.makeText(context, "A custom broadcast was received with data as$data", Toast.LENGTH_LONG).show()
// Determine whether the delayed variable has been initialized
if (::tvInteraction.isInitialized) {
tvInteraction.setText(data)}}}}fun setTVInteractionListener(mtvInteraction: TVInteraction) {
tvInteraction = mtvInteraction
}
// Use the interface to pass data out
interface TVInteraction {
fun setText(content: String?).}}Copy the code
TestSendBroadcastActivity code is as follows:
class TestSendBroadcastActivity : AppCompatActivity(), TestBroadcastReceiver.TVInteraction {
private lateinit var mReceiver: TestBroadcastReceiver
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_send_broadcast)
mReceiver = TestBroadcastReceiver()
val intentFilter = IntentFilter("com.geely.interview.TEST_BROADCAST_RECEIVER")
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, intentFilter)
mReceiver.setTVInteractionListener(this)
btn_send.setOnClickListener {
val intent = Intent("com.geely.interview.TEST_BROADCAST_RECEIVER")
intent.putExtra("content", et_content.text.toString())
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
}
override fun onDestroy(a) {
super.onDestroy()
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver)
}
override fun setText(content: String?).{ content? .let { tv_content.text = it } } }Copy the code
After this rewriting, the broadcast cannot be received by other applications.