四大組件之廣播接收者

  • 爲什麼需要 廣播接收者 BroadcastReceiver

    • 有一些未知時間會執行的事件。需要等待系統的通知。
    • 參與者: 電臺、頻道、收音機

廣播接收者案例 Ip撥號器

<action android:name="android.intent.action.NEW_OUTGOING_CALL" />,權限 PROCESS_OUTGOING_CALL

  • 需求:當用戶打電話的時候,自動的在號碼前添加 17951 前綴

  • 創建廣播

    1. 繼承 BroadcastReceiver
    2. 覆寫生命週期方法。廣播接收者只有onReceive這一個生命週期方法
    3. 在清單文件註冊
  • 廣播使用的上下文是從 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);
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章