In The Android operating system, Broadcast is a mechanism to transmit data between components. These components can be located in different processes for inter-process communication
BroadcastReceiver is a component that filters, receives, and responds to Broadcast. First, the message to be sent and the information used for filtering (Action, Category) are loaded into an Intent object. The Intent object is then broadcast by calling context.sendbroadcast () and sendOrderBroadcast(). Once the broadcast is sent, the registered BroadcastReceiver checks whether the registered IntentFilter matches the Intent sent, and calls the BroadcastReceiver’s onReceiver() method if it does
So when we define a BroadcastReceiver, we need to implement the onReceiver() method. The BroadcastReceiver has a very short life cycle and is only valid when the onReceiver() method is executed. Once the execution is complete, the life cycle of the BroadcastReceiver ends
There are two types of broadcast in Android, standard broadcast and ordered broadcast
- Standard broadcast. Standard broadcast is a completely asynchronous broadcast. After the broadcast is sent, all receivers receive the broadcast at the same time. It has high efficiency and cannot be truncated
- Orderly broadcast. Orderly broadcast is a kind of synchronous execution, on the radio after the same time only a radio receiver can receive priority radio receiver would receive priority, when the high priority onReceiver radio receivers () method after the operation, the radio will continue to pass, and in front of the radio receiver can choose truncated radio, So the radio receiver behind can’t pick up the broadcast
One, static registration
Static registration is to register the BroadcastReceiver in the manifest file, declare it with the **< Receiver >** tag, and set the filter in the tag with the < intent-filter > tag. The life cycle of a BroadcastReceiver follows the entire application. If you are dealing with system broadcasts, the BroadcastReceiver can receive the broadcasts regardless of whether the application is running
1. Send standard broadcasts
First, inherit the BroadcastReceiver class to create a Receiver for receiving standard broadcasts, fetching the string passed by the Intent in the onReceive() method
public class NormalReceiver extends BroadcastReceiver {
private static final String TAG = "NormalReceiver";
public NormalReceiver(a) {}@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("Msg"); Log.e(TAG, msg); }}Copy the code
The BroadcastReceiver declared in the manifest file must contain the action attribute of the NORMAL_ACTION string in order for the BroadcastReceiver to receive the broadcasts issued in the following code
The sendBroadcast(Intent) method is invoked to send a standard broadcast
public class MainActivity extends AppCompatActivity {
private final String NORMAL_ACTION = "com.example.normal.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendBroadcast(View view) {
Intent intent = new Intent(NORMAL_ACTION);
intent.putExtra("Msg"."Hi"); sendBroadcast(intent); }}Copy the code
Register the BroadcastReceiver in the manifest file
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".NormalReceiver">
<intent-filter>
<action android:name="com.example.normal.receiver" />
</intent-filter>
</receiver>
</application>
Copy the code
2. Send an ordered broadcast
First, inherit the BroadcastReceiver class to create three receivers for receiving ordered broadcasts, named OrderReceiver_1, OrderReceiver_2, and OrderReceiver_3. In addition, since the Receiver receives broadcasts in a sequential order, in addition to receiving data from the Intent used to send the broadcast, the higher-priority Receiver can also transmit the processing results to the lower-priority Receiver after processing the operation
public class OrderReceiver_1 extends BroadcastReceiver {
private final String TAG = "OrderReceiver_1";
public OrderReceiver_1(a) {}@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "OrderReceiver_1 was called");
// Retrieve the data passed in the Intent
String msg = intent.getStringExtra("Msg");
Log.e(TAG, "Value received by OrderReceiver_1:" + msg);
// Pass data to the Receiver of the next priority
Bundle bundle = new Bundle();
bundle.putString("Data"."(Hello)"); setResultExtras(bundle); }}Copy the code
public class OrderReceiver_2 extends BroadcastReceiver {
private final String TAG = "OrderReceiver_2";
public OrderReceiver_2(a) {}@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "OrderReceiver_2 was called");
// Fetch the data passed by the previous priority Receiver
String data = getResultExtras(true).getString("Data");
Log.e(TAG, "Data passed from the previous priority Receiver --" + data);
// Pass data to the Receiver of the next priority
Bundle bundle = new Bundle();
bundle.putString("Data"."(Leaves should be leaves)"); setResultExtras(bundle); }}Copy the code
public class OrderReceiver_3 extends BroadcastReceiver {
private final String TAG = "OrderReceiver_3";
public OrderReceiver_3(a) {}@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "OrderReceiver_3 was called");
// Fetch the data passed by the previous priority Receiver
String data = getResultExtras(true).getString("Data");
Log.e(TAG, "Data passed from the previous priority Receiver --"+ data); }}Copy the code
Register three receivers in the manifest file and specify the same action attribute value. The priority between receivers is determined using the priority attribute. The higher the value, the higher the priority
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".OrderReceiver_1">
<intent-filter android:priority="100">
<action android:name="com.example.order.receiver" />
</intent-filter>
</receiver>
<receiver android:name=".OrderReceiver_2">
<intent-filter android:priority="99">
<action android:name="com.example.order.receiver" />
</intent-filter>
</receiver>
<receiver android:name=".OrderReceiver_3">
<intent-filter android:priority="98">
<action android:name="com.example.order.receiver" />
</intent-filter>
</receiver>
</application>
Copy the code
The sendOrderedBroadcast(Intent, String) method is invoked to send an ordered broadcast. The value of String is used when you define permissions, as described below
public class MainActivity extends AppCompatActivity {
private final String NORMAL_ACTION = "com.example.normal.receiver";
private final String ORDER_ACTION = "com.example.order.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendBroadcast(View view) {
Intent intent = new Intent(NORMAL_ACTION);
intent.putExtra("Msg"."Hi");
sendBroadcast(intent);
}
public void sendOrderBroadcast(View view) {
Intent intent = new Intent(ORDER_ACTION);
intent.putExtra("Msg"."Hi");
sendOrderedBroadcast(intent, null); }}Copy the code
The run result is
02-20 22:52:30.135 6714-6714/ / com. Example. Zy. Myapplication E OrderReceiver_1: OrderReceiver_1 is invoked02-20 22:52:30.135 6714-6714/ / com. Example. Zy. Myapplication E OrderReceiver_1: OrderReceiver_1 receives the value: Hi02-20 22:52:30.143 6714-6714/ / com. Example. Zy. Myapplication E OrderReceiver_2: OrderReceiver_2 is invoked02-20 22:52:30.143 6714-6714/ com. Example. Zy. Myapplication E/OrderReceiver_2: from a priority on the Receiver transmit data - (Hello)02-20 22:52:30.150 6714-6714/ / com. Example. Zy. Myapplication E OrderReceiver_3: OrderReceiver_3 is invoked02-20 22:52:30.150 6714-6714/ / com. Example. Zy. Myapplication E OrderReceiver_3: from a priority on the Receiver transmit data - (leaf should be)Copy the code
It can be seen that the Receiver receives broadcasts not only because of the order of “priority” attribute, but also because of data transfer between receivers
In addition, the BroadcastReceiver can call the abortBroadcast() method to truncate the broadcast so that lower priority broadcast receivers cannot receive the broadcast
Second, dynamic registration
To register a BroadcastReceiver dynamically, you define and set up an IntentFilter object in your code, and then call the context.registerReceiver () method where you want to register it. Calling Context. UnregisterReceiver () method to cancel the registration, at the moment there is no need to register the Receiver in the manifest file
This takes the form of registering a broadcast receiver in the Service and outputs logs when registering a broadcast receiver, unregistering a broadcast receiver, and receiving a broadcast
public class BroadcastService extends Service {
private BroadcastReceiver receiver;
private final String TAG = "BroadcastService";
public BroadcastService(a) {}@Override
public void onCreate(a) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MainActivity.ACTION);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "BroadcastService receives broadcast"); }}; registerReceiver(receiver, intentFilter); Log.e(TAG,"BroadcastService registered receiver");
super.onCreate();
}
@Override
public void onDestroy(a) {
super.onDestroy();
unregisterReceiver(receiver);
Log.e(TAG, "BroadcastService unregister receiver");
}
@Override
public IBinder onBind(Intent intent) {
return null; }}Copy the code
Provides methods for starting, stopping, and broadcasting services
public class MainActivity extends AppCompatActivity {
public final static String ACTION = "com.example.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startService(View view) {
Intent intent = new Intent(this, BroadcastService.class);
startService(intent);
}
public void sendBroadcast(View view) {
Intent intent = new Intent(ACTION);
sendBroadcast(intent);
}
public void stopService(View view) {
Intent intent = new Intent(this, BroadcastService.class); stopService(intent); }}Copy the code
The result is as follows
02-20 23:55:20.967 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService registered receivers02-20 23:55:22.811 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:23.179 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:23.461 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:23.694 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:23.960 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:24.282 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:24.529 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService received radio02-20 23:55:24.916 22784-22784/ / com. Example. Zy. Myapplication E BroadcastService: BroadcastService cancel registered receiversCopy the code
Local broadcasting
All broadcasts sent and received are global broadcasts of the system. That is, broadcasts sent and received by other applications can be received by other applications, which may cause insecurity
Therefore, in some cases, a local broadcast mechanism can be used, where broadcasts issued by this mechanism can only be transmitted within the application, and the broadcast receiver can only receive broadcasts issued within the application itself
LocalBroadcastManager is used to manage broadcasts
function | role |
---|---|
LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter) | Registered Receiver |
LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver); | The cancellation of the Receiver |
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent) | Sending asynchronous broadcast |
LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent) | Send synchronous broadcast |
First, you create a BroadcastReceiver to receive local broadcasts
public class LocalReceiver extends BroadcastReceiver {
private final String TAG = "LocalReceiver";
public LocalReceiver(a) {}@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "Local broadcast received."); }}Copy the code
Then it is time to register and unregister LocalReceiver using LocalBroadcastManager
private LocalBroadcastManager localBroadcastManager;
private LocalReceiver localReceiver;
private final String LOCAL_ACTION = "com.example.local.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localReceiver = new LocalReceiver();
IntentFilter filter = new IntentFilter(LOCAL_ACTION);
localBroadcastManager.registerReceiver(localReceiver, filter);
}
@Override
protected void onDestroy(a) {
super.onDestroy();
unregisterReceiver(batteryReceiver);
localBroadcastManager.unregisterReceiver(localReceiver);
}
public void sendLocalBroadcast(View view) {
Intent intent = new Intent(LOCAL_ACTION);
localBroadcastManager.sendBroadcast(intent);
}
Copy the code
It is important to note that local broadcasts cannot be received through static registration, because static registration is mainly used to receive broadcasts without the application being started, while local broadcasts are sent by the application itself, which must be started
Use private permissions
The problem with using a dynamically registered broadcast Receiver is that any application within the system can listen and trigger our Receiver. Normally we don’t want that
One solution is to add an Android: Exported =”false” attribute to the < Receiver > tag in the manifest file indicating that the Receiver is for internal use only. In this way, other applications in the system cannot access the Receiver
Alternatively, you can choose to create your own usage permissions by adding a < Permission > tag to the manifest file to declare custom permissions
<permission
android:name="com.example.permission.receiver"
android:protectionLevel="signature" />
Copy the code
The protectionLevel attribute value must be specified at the same time. The system determines the user mode of the user-defined permission based on this attribute value
Attribute values | Limited way |
---|---|
normal | The default value. Low-risk permissions that pose the least risk to other applications, systems, and users. The system automatically grants this type of permission to applications when they are installed and does not require explicit user approval (although users can always choose to view these permissions before installation). |
dangerous | High-risk permissions. Applications requesting this type of permission can access users’ private data or control devices, which may adversely affect users. Because this type of license introduces potential risks, the system may not automatically grant it to the requested application. For example, the system could show the user any hazardous licenses requested by the application and require confirmation before proceeding, or it could take some other approach to avoid automatic permission by the user |
signature | The system grants the permission only when the application requesting the permission uses the same certificate signature as the application claiming the permission. If the certificate matches, the system automatically grants permission without notifying the user or requiring explicit approval |
signatureOrSystem | The system only grants applications in the Android system image that use the same certificate signature as the applications that claim permissions. Avoid this option. The “Signature” level is sufficient for most requirements, and the “signatureOrSystem” permission is used for some special cases |
First, create a new project, create a custom permission in its manifest file, and declare it. ProtectionLevel property value set to “signature”
<permission
android:name="com.example.permission.receiver"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.permission.receiver" />
Copy the code
Then, send a Broadcast with the permission declaration. In this way, only applications that use the same certificate signature and claim the permission can receive the Broadcast
private final String PERMISSION_PRIVATE = "com.example.permission.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendPermissionBroadcast(View view) {
sendBroadcast(new Intent("Hi"), PERMISSION_PRIVATE);
}
Copy the code
Go back to the previous project and first declare permissions in the manifest file
<uses-permission android:name="com.example.permission.receiver" />
Copy the code
Create a BroadcastReceiver
public class PermissionReceiver extends BroadcastReceiver {
private final String TAG = "PermissionReceiver";
public PermissionReceiver(a) {}@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "Private privilege broadcast received."); }}Copy the code
Then register the broadcast receiver. Since Android Studio uses the same certificate to sign each App during debugging, the PermissionReceiver outputs a Log after a previously newly installed App sends a broadcast
private final String PERMISSION_PRIVATE = "com.example.permission.receiver";
private PermissionReceiver permissionReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter1 = new IntentFilter("Hi");
permissionReceiver = new PermissionReceiver();
registerReceiver(permissionReceiver, intentFilter1, PERMISSION_PRIVATE, null);
}
@Override
protected void onDestroy(a) {
super.onDestroy();
unregisterReceiver(permissionReceiver);
}
Copy the code
Five, actual combat
1. Monitor network status changes
First you need a utility class to monitor the current state of the network
/** * Created by leaves should be leaves on 2017/2/21. */
public class NetworkUtils {
/** * Marks the current network status, namely: mobile data, Wifi, unconnected, network status announced */
public enum State {
MOBILE, WIFI, UN_CONNECTED, PUBLISHED
}
/** * A flag bit that is used to cache the status of the network before a new broadcast is received */
private static State tempState;
/** * Get the current network connection status **@param context Context
* @returnNetwork status */
public static State getConnectState(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
State state = State.UN_CONNECTED;
if(networkInfo ! =null && networkInfo.isAvailable()) {
if (isMobileConnected(context)) {
state = State.MOBILE;
} else if(isWifiConnected(context)) { state = State.WIFI; }}if (state.equals(tempState)) {
return State.PUBLISHED;
}
tempState = state;
return state;
}
private static boolean isMobileConnected(Context context) {
return isConnected(context, ConnectivityManager.TYPE_MOBILE);
}
private static boolean isWifiConnected(Context context) {
return isConnected(context, ConnectivityManager.TYPE_WIFI);
}
private static boolean isConnected(Context context, int type) {
//getAllNetworkInfo() is deprecated in API 23
//getAllNetworks() was added in API 21
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
NetworkInfo[] allNetworkInfo = manager.getAllNetworkInfo();
for (NetworkInfo info : allNetworkInfo) {
if (info.getType() == type) {
returninfo.isAvailable(); }}}else {
Network[] networks = manager.getAllNetworks();
for (Network network : networks) {
NetworkInfo networkInfo = manager.getNetworkInfo(network);
if (networkInfo.getType() == type) {
returnnetworkInfo.isAvailable(); }}}return false; }}Copy the code
Then declare a BroadcastReceiver and output the current network state with Log in the onReceive() method
public class NetworkReceiver extends BroadcastReceiver {
private static final String TAG = "NetworkReceiver";
public NetworkReceiver(a) {}@Override
public void onReceive(Context context, Intent intent) {
switch (NetworkUtils.getConnectState(context)) {
case MOBILE:
Log.e(TAG, "Currently connected to mobile data");
break;
case WIFI:
Log.e(TAG, "Currently connected to Wifi");
break;
case UN_CONNECTED:
Log.e(TAG, "No network connection at present");
break; }}}Copy the code
Registered in the manifest file radio receiver, “android.net.conn.CONNECTIVITY_CHANGE” is the predefined action value system, as long as the system state changes, network NetworkReceiver will receive the broadcast
<receiver android:name=".NetworkReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Copy the code
Also, ask for permission to view network status
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Copy the code
2. Monitor the change of electric quantity
Since the system states that broadcast receivers that listen for power changes cannot be registered statically, dynamic registration is the only option
private final String TAG = "MainActivity";
private BroadcastReceiver batteryReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
batteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Current power
int currentBattery = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
/ / total power
int totalBattery = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
Log.e(TAG, "Current battery :" + currentBattery + "- Total electric quantity:"+ totalBattery); }}; registerReceiver(batteryReceiver, intentFilter); }@Override
protected void onDestroy(a) {
super.onDestroy();
unregisterReceiver(batteryReceiver);
}
Copy the code
The Intent value in onReceive(Context, Intent) contains some additional information to extract the current and total charge
To make it easy to see the power changes, you can actively change the simulator’s power in the “Extended Controls” panel of the simulator to view the Log output
3, application installation update uninstall listener
First, create the BroadcastReceiver
public class AppReceiver extends BroadcastReceiver {
private final String TAG = "AppReceiver";
public AppReceiver(a) {}@Override
public void onReceive(Context context, Intent intent) {
// Determine the type of broadcast
String action = intent.getAction();
// Get the package name
Uri appName = intent.getData();
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
Log.e(TAG, "Installed:" + appName);
} else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
Log.e(TAG, "Updated:" + appName);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
Log.e(TAG, "Unloaded:"+ appName); }}}Copy the code
Register broadcast receiver
<receiver android:name=".train.AppReceiver">
<intent-filter>
<! -- Install the app -->
<action android:name="android.intent.action.PACKAGE_ADDED" />
<! Update app -->
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<! -- Uninstall the app -->
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<! -- Carrying bag name -->
<data android:scheme="package" />
</intent-filter>
</receiver>
Copy the code