This article describes one of Android’s four main components, BroadcastReceiver. The role of broadcast, how to register broadcast, custom broadcast, types of broadcast, and issues to be aware of when using BroadcastReceiver on newer Android systems. Android apps and Android systems and other Android apps can send and receive broadcast messages to and from each other, similar to the publish-subscribe design pattern, and these broadcasts are sent when the events of interest occur.
About System Broadcast
Android, for example, sends broadcasts when various system events occur, such as when the system starts up or the device starts charging. Applications can send custom broadcasts to notify other applications of events they might be interested in (for example, some new data has been downloaded). Applications can register to receive specific broadcasts. Once the broadcast is sent, it is automatically transmitted to the application that agrees to receive it.
The system will automatically send a broadcast when various system events occur. For example, when the system enters and exits airplane mode, the system broadcast will be sent to all applications that agree to receive related events, or the system will also send a low battery broadcast when the phone is low:
Common system broadcasts:
<! --> <action Android :/> <! --> < Action Android :/> <! --> < Action Android :/> <! --> <action Android :/> <! < Action Android :/> <! <data Android :scheme="package"/> <... />Copy the code
System broadcast registration
An application can receive broadcasts in two ways: a broadcast receiver declared by a manifest file and a broadcast receiver registered by context.
Static registration
An AppReceiver is created to receive broadcasts of App installs and uninstalls. This class inherits BroadcastReceiver:
public class AppReceiver extends BroadcastReceiver { private static final String TAG = "AppReceiver"; @override public void onReceive(Context Context, Intent Intent) { Intent.getaction (); // Intent.getAction (); assert action ! = null; Switch (action){case Intent.ACTION_PACKAGE_REMOVED: log. I (TAG, "onReceive: ACTION_PACKAGE_REMOVED "+" app removed "); break; ACTION_PACKAGE_ADDED: log. I (TAG, "onReceive: ACTION_PACKAGE_ADDED "+" App installed "); break; }}}}Copy the code
AndroidManifest.xml
<! Android: Enabled ="true" Android: Exported ="true"> <intent-filter> --> <action Android :/> <! < Action Android :/> <! <data Android :scheme="package"/> </intent-filter> </receiver>Copy the code
During application uninstallation and installation, you can receive the corresponding broadcast:
Dynamic registration
Appreceiver.java is the same as above, but instead of declaring it in androidmanifest.xml, it uses dynamic registration. The following example demonstrates how to dynamically register broadcast receivers created in the Activity:
MainActivity.java
public class MainActivity extends AppCompatActivity { private BroadcastReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create a new broadcast receiver receiver = new AppReceiver(); // Which broadcasts are received IntentFilter IntentFilter = new IntentFilter(); intentFilter.addDataScheme("package"); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); // Register the broadcast receiver registerReceiver(receiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // Unregister broadcast receivers (memory leaks if not cancelled) if(receiver! = null){ unregisterReceiver(receiver); }}}Copy the code
Do not forget to unregister previously registered broadcast receivers when your Activity is destroyed.
Static registration needs to be declared in androidmanifest.xml. As long as the APP is started once, the static registration broadcast will take effect regardless of whether the current APP is stopped or in use. As soon as the corresponding broadcast event occurs, the system iterates through all manifest files, notifies the corresponding broadcast receiver to receive the broadcast, and then invokes the broadcast receiver’s onReceiver method.
Dynamic registration The dynamic registration method depends on the registered component. When the APP is closed, the component object is gone. The dynamically registered code does not exist, and the actions monitored by the dynamic registration will no longer take effect. Statically registered broadcasts propagate much slower than dynamically registered broadcasts.
If both dynamic and static registrations are used, dynamically registered broadcasts take precedence over statically registered broadcasts.
The life cycle of broadcasting
The BroadCastReceiver is created when a broadcast is received and destroyed when the onReceive() method ends
The BroadCastReceiver declaration cycle is very short, so do not create child threads to do time-consuming operations in broadcast receivers. When broadcastReceivers are destroyed, the child becomes empty and can be killed easily
3, As BroadCastReceiver runs on the main thread, time-consuming operations cannot be performed directly in BroadCastReceiver. Otherwise, ANR exceptions will occur, and time-consuming operations should be completed in Service. You can’t use a child thread to solve this problem, because the BroadcastReceiver’s life cycle is very short. The child thread may end the BroadcastReceiver before it ends. Once the BroadcastReceiver ends, In this case, the BroadcastReceiver’s host process is easily killed when the system needs memory. It is an empty process (a process that has no active components). If the host process is killed, the child thread is also killed, so it is not reliable to use child threads to solve the problem.
Custom Broadcast
MainActivity.java
public class MainActivity extends AppCompatActivity { public static final String MY_ACTION = "cn.tim.action.MY_ACTION"; public static final String MY_ACTION_EXTRA_KEY = "input_content"; private EditText etContent; private CustomReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etContent = findViewById(R.id.et_content); TextView tvShow = findViewById(R.id.tv_show); receiver = new CustomReceiver(); receiver.tvShow = tvShow; IntentFilter filter = new IntentFilter(); filter.addAction(MY_ACTION); registerReceiver(receiver, filter); } public void send(View View) {// new Intent Intent = new Intent(MY_ACTION); Intent.putextra (MY_ACTION_EXTRA_KEY, etContent.gettext ().tostring ())); sendBroadcast(intent); } @Override protected void onDestroy() { super.onDestroy(); // Unregister if(receiver! = null){ unregisterReceiver(receiver); }}}Copy the code
CustomReceiver.java
public class CustomReceiver extends BroadcastReceiver { TextView tvShow; @Override public void onReceive(Context context, Intent intent) { if(intent ! = null){ String action = intent.getAction(); if(MainActivity.MY_ACTION.equals(action)){ String inputContent = intent.getStringExtra(MainActivity.MY_ACTION_EXTRA_KEY); tvShow.setText(inputContent); }}}}Copy the code
Use the same code as above to communicate between different applications, as long as you write the same ACTION, then it is OK:
Classification of Broadcast
Broadcast transmission can be divided into orderly broadcast, disorderly broadcast, local broadcast and sticky broadcast.
Orderly broadcast
Ordered broadcast is a broadcast that broadcasts receivers in sequence. The higher the priority of the broadcast receiver, the earlier the broadcast is received. The broadcast with a higher priority receives the broadcast first. After receiving the broadcast, the broadcast can be modified, or the broadcast can be blocked from being transmitted downward.
If the broadcast is terminated in the CReceiver, both A and B with lower priorities will not receive the broadcast.
MainActivity.java
public class MainActivity extends AppCompatActivity { public static final String MY_ACTION = "cn.tim.action.MY_ACTION"; public static final String KEY = "cn.tim.action.MY_ACTION"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent = new Intent(MY_ACTION); Bundle = new Bundle(); bundle.putInt(KEY, 100); intent.putExtras(bundle); //sendBroadcast(intent); // Broadcast sequence. Parameter 2: Permission sendOrderedBroadcast(Intent, NULL); }}Copy the code
Note: If you want to modify the data, the Intent must send the data in a Bundle format.
Public class CReceiver extends BroadcastReceiver {@override public void onReceive(Context Context, Intent intent) { if(intent ! = null){ String action = intent.getAction(); if(MainActivity.MY_ACTION.equals(action)){ Bundle bundle = intent.getExtras(); Toast.makeText(context, "C:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show(); Bundle newBundle = new Bundle(); newBundle.putInt(MainActivity.KEY, 90); setResultExtras(newBundle); }}}} // Priority 1 public class AReceiver extends BroadcastReceiver {@override public void onReceive(Context Context, Intent intent) { if(intent ! = null){ String action = intent.getAction(); if(MainActivity.MY_ACTION.equals(action)){ Bundle bundle = getResultExtras(true); Toast.makeText(context, "A:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show(); Bundle newBundle = new Bundle(); newBundle.putInt(MainActivity.KEY, 80); setResultExtras(newBundle); }}}} // Priority 0 public class BReceiver extends BroadcastReceiver {@override public void onReceive(Context Context, Intent intent) { if(intent ! = null){ String action = intent.getAction(); if(MainActivity.MY_ACTION.equals(action)){ Bundle bundle = getResultExtras(true); Toast.makeText(context, "B:" + bundle.getInt(MainActivity.KEY), Toast.LENGTH_SHORT).show(); }}}}Copy the code
A disorderly radio
An out-of-order broadcast means that all matched receivers receive the broadcast, in no order, until no receivers receive the broadcast.
By default, the system traverses all APP receivers when broadcasts are sent. If you want to protect your APP’s Receiver from external broadcasts, you can add the Android: Exported = “false” attribute to the Receiver node. In this way, the system will not judge and process the APP Receiver when traversing the broadcast receivers of all APP list files.
Local radio
The local broadcast is only broadcast within the APP. Other applications cannot receive the broadcast. The broadcast is secure and does not spread to the outside world. At the same time, because LocalBroadcastManager does not need to use the cross-process mechanism, it is more efficient than BroadcastReceiver. LocalBroadcastManager is used only for dynamic broadcasts. It cannot be used for static broadcasts.
Implementation 'androidx. Localbroadcastmanager: localbroadcastmanager: 1.0.0'Copy the code
MainActivity.java
public class MainActivity extends AppCompatActivity { public static final String MY_NEW_ACTION = "cn.tim.action.MY_NEW_ACTION"; private LocalReceiver localReceiver; private LocalBroadcastManager localBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); / / get LocalBroadcastManager object LocalBroadcastManager = LocalBroadcastManager. GetInstance (this); // Register broadcast localReceiver = new localReceiver (); IntentFilter filter = new IntentFilter(); filter.addAction(MY_NEW_ACTION); localBroadcastManager.registerReceiver(localReceiver, filter); } public void sendLocalBroadcast(View View) {// Send a local broadcast Intent Intent = new Intent(MY_NEW_ACTION); localBroadcastManager.sendBroadcast(intent); } static class LocalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent){ Toast.makeText(context,"Received LocalBroadcast!" ,Toast.LENGTH_SHORT).show(); } } @Override protected void onDestroy() { super.onDestroy(); localBroadcastManager.unregisterReceiver(localReceiver); }}Copy the code
Broadcast is used in the new SDK
As the Android platform evolves, it changes the behavior of the system broadcast from time to time. If you want to use broadcast with Android 7.0 (API level 24) or later SDK, you must note the following changes:
The Android 7.0 API 24
Android 7.0 (API level 24) and later do not send the following system broadcasts:
ACTION_NEW_PICTURE
ACTION_NEW_VIDEO
Copy the code
In addition to Android 7.0 and higher version for the application of the target platform must use this to dynamically register way, not in the listing announcement broadcast receivers, so after all radio and direct all use this to dynamically register, if you use static registration, can send explicit radio, (i.e. specify the package name specified to send again, Intent.addflags (0x01000000); intent.addFlags(0x01000000); intent.addFlags(0x01000000); This allows the broadcast to break through implicit broadcast limits, but static registration is still not recommended, and dynamic registration is better.
The Android 9.0 API 28
Starting with Android 9 (API level 28), NETWORK_STATE_CHANGED_ACTION broadcasts no longer receive information about a user’s location or personally identifiable data. Through the WLAN receiving system radio does not include the SSID, BSSID connection information or scan results, if you want to get these information, you can call WifiManager. GetConnectionInfo ().