爲什麼需要 廣播接收者 BroadcastReceiver
- 有一些未知時間會執行的事件。需要等待系統的通知。
- 參與者: 電臺、頻道、收音機
廣播接收者案例 Ip撥號器
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />,權限 PROCESS_OUTGOING_CALL
需求:當用戶打電話的時候,自動的在號碼前添加 17951 前綴
創建廣播
- 繼承 BroadcastReceiver
- 覆寫生命週期方法。廣播接收者只有onReceive這一個生命週期方法
- 在清單文件註冊
廣播使用的上下文是從 onReceive 方法的參數裏傳過來的
- 廣播接收者代碼
// 1. 繼承 BroadcastReceiver public class DialReceiver extends BroadcastReceiver { @Override // 2. 覆寫生命週期方法。廣播接收者只有onReceive這一個生命週期方法 public void onReceive(Context context, Intent intent) { // 獲取撥出的電話 String number = getResultData();//有序廣播可以用getResultData()方法 System.out.println("DialReceiver.onReceive,number="+number); // 獲取用戶配置的Ip前綴 SharedPreferences preferences = context.getSharedPreferences("config", Context.MODE_PRIVATE); String prefix = preferences.getString("number", ""); // 更新電話號碼 setResultData(prefix+number); } }
清單文件代碼
<!-- 3.在清單文件註冊 -->
<receiver android:name="com.itheima.dail.DialReceiver">
<intent-filter >
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
- 主界面代碼
// 獲取用戶輸入的前綴,並保存到配置文件
public void click(View view) {
String number = et_number.getText().toString();
// 保存
SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
Editor editor = preferences.edit();
editor.putString("number", number);
editor.commit();// 千萬要提交啊!!!!!
}
廣播接收者案例 SD卡狀態監聽
action:MEDIA_MOUNTED 和 MEDIA_UNMOUNTED,<data android:scheme="file" />
- 廣播接收者代碼
// 1. 繼承 BroadcastReceiver
public class SDCardStatusReceiver extends BroadcastReceiver {
@Override
// 2. 處理生命週期方法
public void onReceive(Context context, Intent intent) {
System.out.println("SDCardStatusReceiver.onReceive,action"+intent.getAction());
if ("android.intent.action.MEDIA_MOUNTED".equals(intent.getAction())) {
Toast.makeText(context, "SD卡已加載", 0).show();
}
}
}
- 清單文件代碼
<!-- 3. 清單文件註冊 -->
<receiver android:name="com.itheima.sdcard.SDCardStatusReceiver">
<intent-filter >
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<data android:scheme="file" />
</intent-filter>
</receiver>
廣播接收者案例 短信監聽器
action 爲 android.provider.Telephony.SMS_RECEIVED,因爲安全問題 IDE 裏不提示,直接手動複製。權限 RECEIVE_SMS
- 廣播接收者代碼
// 1.繼承 BroadcastReceiver
public class SMSListenerReceiver extends BroadcastReceiver {
@Override
// 2. 覆寫 生命週期方法
public void onReceive(Context context, Intent intent) {
// System.out.println("SMSListenerReceiver.onReceive,action="+intent.getAction());
// 獲取數據
Object[] objs = (Object[]) intent.getExtras().get("pdus");
// 解析短信信息
for (Object object : objs) {
byte[] bytes = (byte[]) object;
SmsMessage pdu = SmsMessage.createFromPdu(bytes);
System.out.println("SMSListenerReceiver.onReceive,sender="+pdu.getOriginatingAddress()+";body="+pdu.getMessageBody());
}
}
}
- 清單文件
<!-- 3. 清單文件註冊 -->
<receiver android:name="com.itheima.sms.SMSListenerReceiver">
<intent-filter >
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
不同版本廣播的特點
- 廣播的生存時長,只在 onReceive 方法執行的時候,一般是 6 秒
- 在4.0以上,沒有桌面圖標的應用不能接收廣播。
- 廣播不需要打應用就能接收,關閉進程還能接收。
- 在 2.3 上從系統設置關閉後還能接收,在4.0上從系統設置關閉就不能再接收。
廣播接收者案例 卸載安裝
action 爲 PACKAGE_INSTALL、PACKAGE_REMOVED、PACKAGE_ADDED,<data android:scheme="package"/>
- 廣播代碼
// 1. 繼承BroadcastReceiver
public class AppStatusReceiver extends BroadcastReceiver {
@Override
// 2. 覆寫生命週期方法
public void onReceive(Context context, Intent intent) {
Uri data = intent.getData();
System.out.println("AppStatusReceiver.onReceive,intent="+intent);
}
}
- 清單代碼
<!-- 3.清單文件註冊 -->
<receiver android:name="com.itheima.appstatus.AppStatusReceiver">
<intent-filter >
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
廣播接收者案例 開機啓動 – 在廣播裏開啓 Activity
action 爲 BOOT_COMPLETED,權限 RECEIVE_BOOT_COMPLETED。廣播裏打開 Activity需要設置標記 Intent.FLAG_ACTIVITY_NEW_TASK
從 Activity 以外的地方,調用 startActivity 必須使用FLAG_ACTIVITY_NEW_TASK 來生成新的任務棧
07-27 03:40:54.066: E/AndroidRuntime(1439): Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
廣播代碼
// 1. 繼承 BroadcastReceiver
public class BootReceiver extends BroadcastReceiver {
@Override
// 2. 覆寫生命週期方法
public void onReceive(Context context, Intent intent) {
System.out.println("BootReceiver.onReceive,action="+intent.getAction());
// 打開主界面
Intent intentMain = new Intent(context, MainActivity.class);
// 從 Activity 以外的地方,調用 startActivity 必須使用這個 flag 來生成新的任務棧
intentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentMain);
}
}
- 清單文件代碼
<!-- 3.清單文件註冊 -->
<receiver android:name="com.itheima.boot.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
有序廣播和無序廣播
無序廣播:就像電臺-頻道-收音機機制,接收者是沒有順序,只要頻道正確,就可以任意接收。
- 發送廣播
// 發送無序廣播 public void click(View view) { // 創建意圖 Intent intent = new Intent(); intent.setAction("com.itheima.custom"); intent.putExtra("msg", "手機要炸了"); // 發送廣播 sendBroadcast(intent); }
- 接收廣播
// 1. 繼承 BroadcastReceiver public class OrderLessReceiver extends BroadcastReceiver { @Override // 2. 覆寫生命週期方法 public void onReceive(Context context, Intent intent) { // 解耦合 String msg = intent.getStringExtra("msg"); System.out.println("OrderLessReceiver.onReceive,msg="+msg); } }
- 清單文件
<!-- 3. 清單文件註冊 --> <receiver android:name="com.itheima.orderlessreceiver.OrderLessReceiver"> <intent-filter > <action android:name="com.itheima.custom"/> </intent-filter> </receiver>
有序廣播:就像政府部門下發文件,按照權利大小的順序,依次接收。
- 有序廣播,可以在接收的順序鏈上修改廣播裏的數據
- 有廣播,可以被終止。
- 有序廣播,可以設置一個最終的接收者,用來驗證數據。即使廣播被終止,也會調用最終的接收者。
發送廣播
// 發送有序廣播
public void click(View view) {
// 創建意圖
Intent intent = new Intent();
intent.setAction("com.itheima.shuai");
intent.putExtra("msg", "你太帥了!!");
// 參數一 意圖
// 參數二 接收者需要聲明的權限
// 參數三 廣播的最終接收者
// 參數四 無視他就行
// 參數五 可以向接收者傳遞一個 int 值
// 參數六 可以向接收者傳遞一個 String 值
// 參數七 可以向接收者傳遞一個 Bundle 值,可以封裝任意多的數據
sendOrderedBroadcast(intent , null, new FinalReceiver(), null, 1, "習大大賞你 200 塊錢", null);
}
- 接收廣播
public class ShiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("省.onReceive,msg="+intent.getStringExtra("msg"));
// 獲取廣播數據
String data = getResultData();
System.out.println("市.onReceive,data="+data);
// 修改數據
// setResultData("習大大賞你10塊錢");
// 終止廣播
abortBroadcast();
}
}
- 註冊廣播
<receiver android:name="com.itheima.moneyreceiver.ShengReceiver">
<intent-filter android:priority="1000"> <!-- priority 範圍 0 -1000,並且數字越大,優先級越高 -->
<action android:name="com.itheima.shuai"/>
</intent-filter>
</receiver>
<receiver android:name="com.itheima.moneyreceiver.ShiReceiver">
<intent-filter android:priority="999">
<action android:name="com.itheima.shuai"/>
</intent-filter>
</receiver>
<receiver android:name="com.itheima.moneyreceiver.HaorenReceiver">
<intent-filter android:priority="0">
<action android:name="com.itheima.shuai"/>
</intent-filter>
</receiver>
特殊廣播接收者
action 爲 SCREEN_OFF和 SCREEN_ON,
在 Java 代碼裏註冊廣播,一定要記得將它反註冊掉
07-27 07:50:35.454: E/ActivityThread(6913): Activity com.itheima.screen.MainActivity has leaked IntentReceiver com.itheima.screen.ScreenStatusReceiver@b5674950 that was originally registered here. Are you missing a call to unregisterReceiver()?
清單文件註冊無效
<!-- 在清單文件註冊。響應頻繁的廣播,不能在清單文件註冊-->
<!-- <receiver android:name="com.itheima.screen.ScreenStatusReceiver">
<intent-filter >
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver> -->
- 在 java 代碼理動態註冊廣播
“`java
public class MainActivity extends Activity {
private ScreenStatusReceiver statusReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*<intent-filter >
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>*/
// 特殊的廣播接收者。響應頻繁的廣播,必須要在 Java 代碼裏註冊,這樣的話,只有應用被打開的時候才能接受廣播
// 創建意圖過濾器
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
// 動態的註冊廣播
statusReceiver = new ScreenStatusReceiver();
registerReceiver(statusReceiver, filter);
}
@Override
// 生命週期方法,當界面被銷燬時會執行
protected void onDestroy() {
super.onDestroy();
// 反註冊,廣播接收者
unregisterReceiver(statusReceiver);
}
}