1、Android中廣播分為靜態注冊和動態注冊
2、下面是一個簡單靜態注冊的例子
- 創建一個繼承
BroadcastReceiver
的子類
public class DeviceBootReceiver extends BroadcastReceiver {
private static final String TAG = DeviceBootReceiver.class.getName();
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "開機了:" + intent.getAction());
}
}
該類的功能用於接收手機開機的廣播。
- 在
AndroidManifest.xml
中注冊該組件
<receiver android:name=".DeviceBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
action
標簽中的值用於匹配廣播的類型,這里是開機廣播。
這樣當手機開機時,便會收到來自系統的消息。
同樣,我們也可以監聽應用安裝,應用卸裝,USB插拔等系統廣播。只是action
的值稍有不同。
<receiver android:name=".OtherStateReceiver">
<intent-filter>
<!--電量過低-->
<action android:name="android.intent.action.BATTERY_LOW" />
<!--USB連接-->
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<!--USB斷開-->
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
<!--軟件包安裝-->
<action android:name="android.intent.action.PACKAGE_ADDED" />
<!--軟件包卸裝-->
<action android:name="android.intent.action.PACKAGE_REMOVED" />
</intent-filter>
</receiver>
上面除了開機廣播,其他廣播這樣注冊能成功的前提是 API Level < 26(Android8.0以下)
。Google為了防止接收者程序常駐內存消耗資源,禁止了一些Manifest declared receiver
。我們想要繼續監聽,就要使用動態注冊的方式。
3、下面是一個動態注冊的例子:
public class SystemBroadcastReceiverActivity extends AppCompatActivity {
private SystemBroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_system_broadcast_receiver);
IntentFilter filter = new IntentFilter();
//USB連接
filter.addAction(Intent.ACTION_POWER_CONNECTED);
//USB斷開
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
receiver = new SystemBroadcastReceiver();
registerReceiver(receiver, filter);
}
private class SystemBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println(intent.getAction());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}
然后在AndroidManifest.xml
注冊該Activity
即可。
4、自定義廣播
前面說的都是接收系統廣播,我們也可以發送自定義的廣播,然后在同一個應用或不同應用中接收。
下面是一個靜態注冊的自定義廣播:
- 建立一個
Activity
,提供一個Button
,點擊后發送廣播
public class CustomSenderActivity extends AppCompatActivity {
public static final String BROADCAST_ACTION = "com.hncj.android.manifest.CustomSenderActivity";
public static final String BROADCAST_CONTENT = "broadcast_content";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_sender);
}
@SuppressLint("WrongConstant")
public void sendBroadcast(View view) {
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
intent.putExtra(BROADCAST_CONTENT, "我發送了廣播,你看收沒收到?");
//解決API26及以上的Android靜態注冊的Receiver收不到廣播
//第一種解決方案:設置標志 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
intent.addFlags(0x01000000); //不論是一個應用自己發自己收還是一個應用發一個應用收,都可以實現效果
//第二種解決方案:指定包名(這里是一個應用,自己發,自己收,都在一個包下)
//intent.setPackage(getPackageName()); //如果是給另一個應用發廣播 則寫成intent.setPackage("另一個項目應用接收者的包名");
//第三種解決方案: 明確指定包名,類名
//intent.setComponent(new ComponentName(this, CustomReceiver.class)); //如果是給另一個應用發廣播 則寫成 intent.setComponent(new ComponentName("另一個應用接收者包名", "另一個應用接收者類名"));
//發送廣播
sendBroadcast(intent);
}
}
- 布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="40dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendBroadcast"
android:background="#008080"
android:textSize="30dp"
android:text="發送廣播"></Button>
</LinearLayout>
- 接收者
public class CustomReceiver extends BroadcastReceiver {
private static final String TAG = CustomReceiver.class.getName();
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "我收到了來自" + action + "的廣播");
}
}
AndroidManifest.xml
文件
<activity android:name=".manifest.CustomSenderActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".manifest.CustomReceiver">
<intent-filter>
<action android:name="com.hncj.android.manifest.CustomSenderActivity" />
</intent-filter>
</receiver>
這里的一個接收者是在當前項目,還有一個接收者在另一個項目,代碼基本是一致的。
相關的API:
發送有序廣播:
<!--廣播中攜帶數據-->
Bundle bundle = new Bundle();
bundle.putString("username", "nacy");
sendOrderedBroadcast(intent, null, null, null, Activity.RESULT_OK, null, bundle);
為接收者設置優先級:(-1000-1000),即定義哪個接收者先收到,優先級越大,越早收到廣播
<receiver android:name=".manifest.CustomReceiver">
<!--priority可以設置優先級-->
<intent-filter android:priority="9">
<action android:name="com.hncj.android.manifest.CustomSenderActivity" />
</intent-filter>
</receiver>
終止廣播:
<!--廣播不再向下傳遞-->
abortBroadcast();
取出廣播中的數據:
//取出Bundle對象,類似於一個map
Bundle bundle = getResultExtras(true);
設置接收者權限:(誰能收到)
- 先在發送方
AndroidManifest.xml
中聲明一個權限(包名+權限名)
<permission android:name="com.hncj.android.RECEIVER_PERMISSION" />
- 發送時定義接收者需要擁有的權限:
sendOrderedBroadcast(intent, Manifest.permission.RECEIVER_PERMISSION, null, null, Activity.RESULT_OK, null, bundle);
- 接收者需要在
AndroidManifest.xml
使用權限:
<uses-permission android:name="com.hncj.android.RECEIVER_PERMISSION" />
設置發送者權限:(誰能給我發)
- 先在接收方
AndroidManifest.xml
聲明一個權限
<permission android:name="com.hncj.android.SENDER_PERMISSION" />
- 在Receiver標簽中說明發送者要擁有的權限:
<receiver android:name=".manifest.CustomReceiver" android:permission="com.hncj.android.SENDER_PERMISSION">
<intent-filter android:priority="9">
<action android:name="com.hncj.android.manifest.CustomSenderActivity" />
</intent-filter>
</receiver>
- 在發送方
AndroidManifest.xml
中使用權限
<uses-permission android:name="com.hncj.android.SENDER_PERMISSION" />
還有動態注冊的自定義廣播,與上面提到的動態注冊的例子差不多,只是自定義action的內容。