Broadcast 使用詳解

極力推薦文章:歡迎收藏
Android 乾貨分享 java

閱讀五分鐘,每日十點,和您一塊兒終身學習,這裏是程序員Android

本篇文章主要介紹 Android 開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:android

  1. 廣播的生命週期
  2. 四大組件之一,必須在Androidmainfest.xml中註冊
  3. 廣播的註冊(靜態廣播、動態廣播)
  4. 廣播的發送(正常、有序、持續)
  5. 廣播接收(系統廣播、自定義廣播)

Broadcast Android 四大組件之一,是一種普遍運用在應用程序之間異步傳輸信息的機制。
Broadcast 本質上是一個Intent 對象,差異在於 Broadcast 能夠被多個 BroadcastReceiver 處理。BroadcastReceiver 是一個全局監聽器,經過它的 onReceive() 能夠過濾用戶想要的廣播,進而進行其它操做。程序員

1. BroadcastReceiver簡介

BroadcastReceiver繼承關係

BroadcastReceiver 默認是在主線程中執行,若是onReceiver() 方法處理事件超過10s,則應用將會發生ANR(Application Not Responding),此時,若是創建工做線程並不能解決此問題,所以建議:如處理耗時操做,請用 Service 代替。微信

BroadcastReceiver繼承關係 以下:網絡

java.lang.Object
   ↳    android.content.BroadcastReceiver

BroadcastReceiver 的主要聲明週期方法onReceiver(),此方法執行完以後,BroadcastReceiver 實例將被銷燬。併發

2.四大組件之一,必須在Androidmainfest.xml中註冊

<receiver
            android:name="ReceiverMethod"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="String....." />
            </intent-filter>
        </receiver>

注意:
如不註冊,將致使沒法接收處理廣播消息app

3.廣播的註冊(靜態註冊、動態註冊)

廣播的註冊分兩種,一種在ndroidMfest.xml中靜態註冊,另外一種是在Java代碼中動態註冊。異步

1.靜態註冊

一些系統發送的廣播須要在Androidmainfest.xml 中靜態註冊,例如 開機廣播,apk狀態改變廣播,電量狀態改變廣播等。這些靜態註冊的廣播,一般在Androidmainfest.xml 中攔截特定的字符串。ide

靜態註冊廣播的方法以下:學習

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.programandroid"
    android:versionCode="1"
    android:versionName="1.0" >
         ... ...
        <receiver
            android:name="com.programandroid.BroadcastReceiver.NotificationReceived"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="Notification_cancel" />
                <action android:name="Notification_music_pre" />
                <action android:name="Notification_music_play" />
                <action android:name="Notification_music_next" />
            </intent-filter>
        </receiver>
        ... ...

1.靜態註冊開機廣播方法

開機廣播比較特殊,須要在Androidmainfest.xml 中添加權限。不然,沒法獲取開機廣播。

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

//靜態註冊廣播的方法
        <receiver
            android:name=".component.BroadcastReceiver.BootReceiverMethod"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

2.動態註冊廣播

在Java中動態註冊廣播,一般格式以下:

//動態註冊廣播
  registerReceiver(BroadcastReceiver, IntentFilter);

動態註冊 監聽滅屏、點亮屏幕的廣播

在廣播中動態註冊廣播請注意必定要使用context.getApplicationContext(),防止context 爲空 ,引發空指針異常。

public class ScreenOnOffReceiver {

    public static void ReceiverScreenOnOff(Context context) {
        IntentFilter screenOffFilter = new IntentFilter();
        screenOffFilter.addAction(Intent.ACTION_SCREEN_OFF);
        screenOffFilter.addAction(Intent.ACTION_SCREEN_ON);
        BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                // TODO Auto-generated method stub
                String action = intent.getAction();
                if (action.equals(Intent.ACTION_SCREEN_OFF)) {

                    Toast.makeText(context, "接收屏幕熄滅廣播", Toast.LENGTH_SHORT).show();

                }
                if (action.equals(Intent.ACTION_SCREEN_ON)) {

                    Toast.makeText(context, "接收屏幕點亮廣播", Toast.LENGTH_SHORT).show();
                }


            }

        };
        /**
         * context.getApplicationContext()
         * 在廣播中註冊廣播時候須要注意,防止context 爲空 ,引發空指針異常
         * **/
// 2.動態註冊廣播的方法
        context.registerReceiver(mScreenOnOffReceiver, screenOffFilter);

    }
}

4.廣播的發送(無序、有序、持續)

1.發送無序廣播的方法

發送無序廣播在Android 中很常見,是一種一對多的關係,主要經過 sendBroadcast(intent);發送廣播。

發送自定義廣播案例

廣播說白了就是一個帶Action等字符串標記的Intent。發送自定義廣播舉例以下:

Intent customIntent=new Intent();
        customIntent.setAction("SendCustomBroadcast");
        sendBroadcast(customIntent);

接收自定義廣播的方法

當用戶對某些廣播感興趣的話,此時能夠獲取此廣播,而後在onReceive方法中處理接收廣播的一下操做。

public class CustomBroadcast extends BroadcastReceiver {
    public CustomBroadcast() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals("SendCustomBroadcast")){
            Toast.makeText(context,"自定義廣播接收成功:Action:SendCustomBroadcast",Toast.LENGTH_SHORT).show();
        }
    }
}
注意自定義廣播是在 Androidmanfest.xml 中靜態註冊的。

2.發送有序廣播

廣播在Android是有優先級的,優先級高的廣播能夠終止或修改廣播內容。發送有序廣播的方法以下sendOrderedBroadcast(intent,"str_receiver_permission");

例如:發送自定義有序廣播

Intent customOrderIntent=new Intent();
        customOrderIntent.setAction("SendCustomOrderBroadcast");
        customOrderIntent.putExtra("str_order_broadcast","老闆說:公司每人發 10 個 月餅");
        sendOrderedBroadcast(customOrderIntent,"android.permission.ORDERBROADCAST");

廣播屬於四大組件,必定要在AndroidMainfest.xml 中註冊。

有序廣播靜態註冊

接收有序廣播的靜態註冊方法以下:

<receiver
            android:name=".component.BroadcastReceiver.CustomHightBrodcast"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter android:priority="1000">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>

        <receiver
            android:name=".component.BroadcastReceiver.CustomMiddleBroadcast"
            android:enabled="true"
            android:exported="true"
          >
            <intent-filter android:priority="500">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".component.BroadcastReceiver.CustomLowerBroadcast"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter android:priority="100">
                <action android:name="SendCustomOrderBroadcast" />
            </intent-filter>
        </receiver>
    1. 有序廣播,高優先級廣播能夠優先處理
public class CustomHightBrodcast extends BroadcastReceiver {
    public CustomHightBrodcast() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            Toast.makeText(context, intent.getStringExtra("str_order_broadcast"), Toast.LENGTH_SHORT).show();
            Bundle bundle=new Bundle();
            bundle.putString("str_order_broadcast","經理說:公司每人發 5 個 月餅");
//            修改廣播傳輸數據
            setResultExtras(bundle);
        }
    }
}
    1. 中優先級的廣播後序處理
public class CustomMiddleBroadcast extends BroadcastReceiver {
    public CustomMiddleBroadcast() {
    }
    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            Toast.makeText(context, getResultExtras(true).getString("str_order_broadcast"), Toast.LENGTH_SHORT).show();
            Bundle bundle=new Bundle();
            bundle.putString("str_order_broadcast","主管說:公司每人發 2 個 月餅");
            setResultExtras(bundle);
        }
    }
}
    1. 低優先級廣播最後處理
public class CustomLowerBroadcast extends BroadcastReceiver {
    public CustomLowerBroadcast() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("SendCustomOrderBroadcast")) {
            String notice= getResultExtras(true).getString("str_order_broadcast");
            Toast.makeText(context,notice, Toast.LENGTH_SHORT).show();
//          終止廣播繼續傳播下去
            abortBroadcast();
        }
    }
}

注意 :
有序廣播須要聲明並使用權限

  • 1.聲明使用權限
<!-- 申請使用自定義 有序廣播的權限 -->
 <uses-permission >   android:name="android.permission.ORDERBROADCAST" />
  • 2.聲明權限
<!-- 自定義 有序廣播的權限 -->
 <permission>
android:name="android.permission.ORDERBROADCAST"/>

在有序廣播中高優先級的廣播接收廣播,能夠修改數據,而後傳給低優先級的廣播。

3.發送持續廣播(已經被棄用)

粘性廣播會在Android 系統中一直存在,不過隨着 Android系統的不斷更新,此方法逐漸被拋棄,使用方法以下:sendStickyBroadcast(intent);

5.廣播接收(系統廣播、自定義廣播)

當廣播發出後,如何接收廣播呢,下面將介紹接收廣播的方法。
接受廣播類 主要繼承 BroadcastReceiver,而後在onReceive方法,過濾廣播Action中攜帶的Intent,而後進行相關處理。

接收開機廣播的方法

1. 實現BootReceiverMethod 繼承 BroadcastReceiver

p ublic class BootReceiverMethod extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //   接收開機廣播處理事情,好比啓動服務
        Intent mStartIntent = new Intent(context, StartServiceMethods.class);
        context.startService(mStartIntent);
    }
}

2.在Androidmainfest.xml 聲明組件信息,並過濾開機完成 Action

<receiver
            android:name=".component.BroadcastReceiver.BootReceiverMethod"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

3.聲明接收開機廣播完成的權限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

極力推薦文章:歡迎收藏
Android 乾貨分享

閱讀五分鐘,每日十點,和您一塊兒終身學習,這裏是程序員Android

本篇文章主要介紹 Android 開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:

  1. Service 簡介
  2. 四大組件之一,必須在Androidmainfest.xml 中註冊
  3. 啓動模式啓動服務
  4. 綁定模式綁定服務
  5. 前臺服務
  6. AIDL遠程服務

Service Android 四大組件之一(Activity 活動,Service 服務,ContentProvider 內容提供者,BroadcastReceiver 廣播),與Activity相比,Activity 是運行在前臺,用戶能夠看得見,Service 則是運行在後臺,無用戶界面,用戶沒法看到。

Service主要用於組件之間交互(例如:與ActivityContentProviderBroadcastReceiver進行交互)、後臺執行耗時操做等(例以下載文件,播放音樂等,但Service在主線程運行時長不能超過20s,不然會出現ANR,耗時操做通常建議在子線程中進行操做)。

1.Service 簡介

在瞭解Service 的生命週期的以前,咱們先了解一下Service 的繼承關係,方便咱們更好的瞭解Service

Service 繼承關係以下:

java.lang.Object
   ↳    android.content.Context
        ↳    android.content.ContextWrapper
             ↳    android.app.Service

Service 的兩種啓動模式

Service 有兩種不一樣的啓動模式 ,不一樣的啓動模式對應不一樣生命週期.
Service 啓動模式主要分兩種: 1. 啓動模式。 2. 綁定模式。

1.啓動模式

此模式經過 startService()方法啓動,此服務能夠在後臺一直運行,不會隨啓動組件的消亡而消亡。只能執行單一操做,沒法返回結果給調用方,經常使用於網絡下載、上傳文件,播放音樂等。

2.綁定模式

此模式 經過綁定組件(Activity等)調用 bindService() 啓動,此服務隨綁定組件的消亡而解除綁定。

若是此時沒有其它經過startService()啓動,則此服務會隨綁定組件的消亡而消亡。
多個組件不只能夠同時綁定一個Service,並且能夠經過進程間通訊(IPC)執行跨進程操做等。

3.兩種服務能夠同時運行

啓動模式與綁定模式的服務能夠同時運行,在銷燬服務時,只有兩種模式都不在使用Service時候,才能夠銷燬服務,不然會引發異常。

4. 兩種 Service 模式的生命週期

兩種 Service 模式的生命週期以下:

兩種 Service 模式生命週期圖

2.四大組件之一,必須在Androidmainfest.xml 中註冊

Service 註冊方法以下:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ServiceMethods" />
      ...
  </application>
</manifest>

注意:

Service 如不註冊 ,不會像Activity 那樣會致使App CrashService 不註冊 不會報異常信息,可是服務會起不來,如不注意很容易迷惑。

3.啓動模式

經過啓動模式啓動的Service ,如不主動關閉,Service會一直在。

啓動模式啓動服務的方法

Intent  mBindIntent = new Intent(ServiceMethods.this, BindServiceMethods.class);
        startService(mStartIntent);

啓動模式啓動服務的生命週期

下面是驗證啓動模式啓動服務的生命週期的方法,詳細生命週期請查看上方Service的生命週期圖。

01-03 17:16:36.147 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onCreate----
01-03 17:16:36.223 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onStartCommand----
01-03 17:16:38.174 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onDestroy----

啓動模式 啓動服務案例

此案例功能:啓動服務,在服務中建立通知

// Service 建立方法
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }
    // Service  啓動方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "----onStartCommand----");
        // 獲取NotificationManager實例
        notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        // 實例化NotificationCompat.Builder並設置相關屬性
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this)
        // 設置小圖標
                .setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(
                        BitmapFactory.decodeResource(getResources(),
                                R.drawable.ic_launcher))
                // 設置通知標題
                .setContentTitle("我是經過StartService服務啓動的通知")
                // 設置通知不能自動取消
                .setAutoCancel(false).setOngoing(true)
                // 設置通知時間,默認爲系統發出通知的時間,一般不用設置
                // .setWhen(System.currentTimeMillis())
                // 設置通知內容
                .setContentText("請使用StopService 方法中止服務");

        // 經過builder.build()方法生成Notification對象,併發送通知,id=1
        notifyManager.notify(1, builder.build());

        return super.onStartCommand(intent, flags, startId);
    }
    // Service  銷燬方法
    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        notifyManager.cancelAll();
        super.onDestroy();
    }

4. 綁定模式啓動綁定服務

綁定模式啓動的服務會隨着綁定逐漸的消亡而解除Service綁定,若是此時Service沒有經過啓動模式啓動,則此服務將會被銷燬。

綁定模式啓動綁定服務的方法

綁定模式,是經過其餘組件啓動的Service

啓動綁定模式服務的方法

// 啓動綁定服務處理方法
    public void BtnStartBindService(View view) {
        // 啓動綁定服務處理方法
        bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        isBindService = true;
        Toast.makeText(ServiceMethod.this, "啓動 " + mBindCount + " 次綁定服務",
                Toast.LENGTH_SHORT).show();
    }

    
    public void BtnSopBindService(View view) {
        if (isBindService) {
            // 解除綁定服務處理方法
            unbindService(serviceConnection);
            Toast.makeText(ServiceMethod.this, "解除 " + mUnBindCount + " 次綁定服務",
                    Toast.LENGTH_SHORT).show();
            isBindService = false;
        }

    }

綁定服務 隨綁定組件的消亡而消亡

綁定模式 生命週期回調代碼以下:

// Service 建立方法
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }

    // Service 綁定方法
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "----onBind----");

        MyBinder myBinder = new MyBinder();
        return myBinder;
    }

    // Service 解除綁定方法
    @Override
    public boolean onUnbind(Intent intent) {

        Log.i(TAG, "----onUnbind----");
        return super.onUnbind(intent);

    }

    // Service 銷燬方法
    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        super.onDestroy();
    }

綁定服務的生命週期代碼打印Log信息以下:

01-03 20:32:59.422 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onCreate----
01-03 20:32:59.423 13306-13306/com.android.program.programandroid I/BindService wjwj:: -----onBind-----
01-03 20:33:09.265 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onUnbind----
01-03 20:33:09.266 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onDestroy----

綁定服務案例

功能:獲取綁定模式啓動 綁定服務及解除綁定服務的次數

綁定服務類

package com.android.program.programandroid.component.Service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class BindServiceMethods extends Service {
    private static final String TAG = "BindService wjwj:";

    public BindServiceMethods() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "----onCreate----");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "----onBind----");

        MyBinder myBinder = new MyBinder();
        return myBinder;
    }


    @Override
    public boolean onUnbind(Intent intent) {

        Log.i(TAG, "----onUnbind----");
        return super.onUnbind(intent);

    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "----onDestroy----");
        super.onDestroy();
    }
}
  • 組件與綁定服務類之間的交互
//    啓動綁定服務處理方法
    public void BtnStartBindService(View view) {

        bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        isBindService = true;
        Toast.makeText(ServiceMethods.this,"啓動 "+mBindCount+" 次綁定服務",Toast.LENGTH_SHORT).show();
    }

    //    解除綁定服務處理方法
    public void BtnSopBindService(View view) {
        if (isBindService) {
            unbindService(serviceConnection);
            Toast.makeText(ServiceMethods.this,"解除 "+mUnBindCount+" 次綁定服務",Toast.LENGTH_SHORT).show();
            isBindService=false;
        }

    }
  • 組件之間交互所需的 Binder 接口類
/**
* 該類提供 綁定組件與綁定服務提供接口
* */
public class MyBinder extends Binder {
   private int count = 0;

    public int getBindCount() {
        return ++count;
    }
    public int getUnBindCount() {
        return count> 0 ? count-- : 0;
    }
}

5. 提升服務的優先級

服務默認啓動方式是後臺服務,可是能夠經過設置服務爲前臺服務,提升服務的優先級,進而避免手機內存緊張時,服務進程被殺掉。

設置前臺服務的兩種方法

1.設置爲前臺服務

//設置爲前臺服務
startForeground(int, Notification)

2.取消前臺服務

//取消爲前臺服務
stopForeground(true);

startForeground 前臺服務案例

功能:前臺服務綁定通知信息,提升服務進程優先級,不然取消通知信息

package com.android.program.programandroid.component.Service;

import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;

import com.android.program.programandroid.R;

public class MyStartForcegroundService extends Service {

    public MyStartForcegroundService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent.getAction().equals("start_forceground_service")) {

//        獲取NotificationManager實例
            NotificationManager notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//        實例化NotificationCompat.Builder並設置相關屬性
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
//                設置小圖標
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
//                設置通知標題
                    .setContentTitle("我是經過startForeground 啓動前臺服務通知")
//                設置通知不能自動取消
                    .setAutoCancel(false)
                    .setOngoing(true)
//                設置通知時間,默認爲系統發出通知的時間,一般不用設置
//                .setWhen(System.currentTimeMillis())
//               設置通知內容
                    .setContentText("請使用stopForeground 方法改成後臺服務");

            //經過builder.build()方法生成Notification對象,併發送通知,id=1
//        設置爲前臺服務
            startForeground(1, builder.build());

        } else if (intent.getAction().equals("stop_forceground_service")) {
            
            stopForeground(true);
        }

        return super.onStartCommand(intent, flags, startId);
    }
}

6. 使用AIDL接口實現遠程綁定

因爲內容較多,後續另開一篇詳細介紹。

至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

微信關注公衆號:  程序員Android,領福利

相關文章
相關標籤/搜索