入職小白隨筆之Android四大組件——廣播詳解(broadcast)


Broadcast

廣播機制簡介

Android中的廣播主要可以分為兩種類型:標准廣播有序廣播

  • 標准廣播:是一種完全異步執行的廣播,在廣播發出之后,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先后順序可言。這種廣播的效率會比較高,但同時也意味着它是無法截斷的。
  • 有序廣播:是一種同步執行的廣播,在廣播發出之后,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢后,廣播才會繼續傳遞。所以此時的廣播接收器是有先后順序的,優先級高的廣播接收器就可以先收到廣播消息,並且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣后面的廣播接收器就無法收到廣播消息了。

接收系統廣播

Android內置了很多系統級別的廣播,我們可以在應用程序中通過監聽這些廣播來得到各種系統的狀態信息。比如手機開機完成后會發出一條廣播,電池的電量發生變化會發出一條廣播,時間或時區發生改變也會發出一條廣播,等等。如果想要接收到這些廣播,就需要使用廣播接收器,下面我們來介紹一下它的具體用法。

1.動態注冊監聽網絡變化

廣播接收器可以自由地對自己感興趣的廣播進行注冊,這樣當有相應地廣播發出時,廣播接收器就能夠收到該廣播,並在內部處理相應的邏輯。注冊廣播的方式一般有兩種。

  • 動態注冊:在代碼中注冊。
  • 靜態注冊:在AndroidManifest.xml中注冊。
    那么該如何創建一個廣播接收器呢?其實只需要新建一個類,讓它繼承自BroadcastReceiver,並重寫父類的onReceive()方法就可以了。這樣當有廣播到來時,onReceive()方法就會得到執行,具體的邏輯就可以在這個方法中處理。
    現在我們就先通過動態注冊的方式編寫一個能夠監聽網絡變化的程序,借此學習一下廣播接收器的基本用法。新建一個BroadcastTest項目,然后修改MainActivity中的代碼,如下所示:
public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
        }

    }

}

可以看到,我們在MainActivity中定義了一個內部類NetworkChangeReceiver,這個類是繼承自BroadcastReceiver的,並重寫了父類的onReceive()方法。這樣每當網絡狀態發生變化時,onReceive()方法就會得到執行,這里只是簡單地使用Toast提示了一段文本信息。
然后觀察onCreate()方法,首先我們創建了一個IntentFilter的實例,並給它添加了一個值為android.net.conn.CONNECTIVITY_CHANGE的action,為什么要添加這個值呢?因為當網絡狀態發生變化時,系統發出的正是一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就是說我們的廣播接收器想要監聽什么廣播,就在這里添加相應的action。接下來創建了一個NetworkChangeReceiver的實例,然后調用registerReceiver()方法進行注冊,將NetworkChangeReceiver的實例和IntentFilter的實例都傳了進去,這樣NetworkChangeReceiver就會收到所有值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就實現了監聽網絡變化的功能。
最后要記得,動態注冊的廣播接收器一定都喲啊取消注冊才行,這里我們是在onDestroy()方法中通過調用unregisterReceiver()方法來實現的。
首先你會在注冊完成的時候收到一條廣播,然后按下home鍵回到主界面(注意不能按back鍵,否則onDestroy()方法會執行),接着打開Settings程序——>Data usage進入到數據使用詳情界面,然后嘗試着開關Cellular data按鈕來啟動和禁用網絡,你就會看到有Toast提醒你網絡發生了變化。
不過,只是提醒網絡發生了變化還不夠人性化,最好是能夠准確地告訴用戶當前是有網絡還是沒有網絡,因此我們還需要對上面的代碼進行進一步的優化。修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
            } else  {
                Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();

            }
        }

    }

}

在onReceive()方法中,首先通過getSystemService()方法得到了ConnectivityManager的實例,這是一個系統服務類,專門用於管理網絡連接的。然后調用它的getActiveNetworkInfo()方法可以得到NetworkInfo的實例,接着調用NetworkInfo的isAvailable()方法,就可以判斷出當前是否有網絡了,最后我們還是通過Toast的方式對用戶進行提示。
另外,這里有非常重要的一點需要說明,Android系統為了保護用戶設備的安全和隱私,作了嚴格的規定:如果程序需要進行一些對用戶來說比較敏感的操作,就必須在配置文件中聲明權限才可以,否則程序將會直接崩潰。比如這里訪問系統的網絡狀態及時需要聲明權限的。打開AndroidManifest.xml文件,在里面加入如下權限就可以訪問系統網絡狀態了:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">

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

2.靜態注冊實現開機啟動

動態注冊的廣播接收器可以自由地控制注冊與注銷,在靈活性方面有很大的優勢,但是它也存在這一個缺點,即必須在程序啟動之后才能接收到廣播,因為注冊的邏輯是寫在onCreate()方法中的。那么有沒有辦法可以讓程序在未啟動的情況下就能接收到廣播呢?這就需要使用靜態注冊的方式了。
這里我們准備讓程序接收一條開機廣播,當收到這條廣播時就可以在onReceive()方法里執行相應地邏輯,從而實現開機啟動的功能。可以使用Android Studio提供的快捷方式來創建一個廣播接收器,右擊com.example.broadcasttest包—>Other—>Broadcast Receiver,我們將廣播接收器命名為BootCompleteReceiver。修改其中的代碼:

public class BootCompleteReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
       // throw new UnsupportedOperationException("Not yet implemented");
        Toast.makeText(context,"Boot Complete",Toast.LENGTH_LONG).show();
    }
}

代碼非常簡單,我們只是在onReceive()方法中使用Toast彈出一段提示信息。
另外,靜態的廣播接收器一定要在AndroidManifest.xml文件中注冊才可以使用,不過由於我們是使用Android Studio的快捷方式創建的廣播接收器,因此注冊這一步已經被自動完成了。打開AndroidManifest.xml文件瞧一瞧,代碼如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">

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

    <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=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
        </receiver>
       
    </application>

</manifest>

可以看到, 標簽內出現了一個新的標簽 ,所有靜態的廣播接收器都是在這里進行注冊的。它的用法其實和 標簽非常類似,也是通過android:name來制定具體注冊哪一個廣播接收器,而enabled和exported屬性則是根據我們剛才勾選的狀態自動生成的。
不過目前BootCompleteReceiver還是不能接收到開機廣播的,我們還需要對AndroidManifest.xml文件進行修改才行,如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">

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

    <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=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
       
    </application>

</manifest>

由於Android系統啟動完成后會發出一條值為android.intent.action.BOOT_COMPLETED的廣播,因此我們在 標簽里添加了相應的action。另外,監聽系統開機廣播也是需要聲明權限的,可以看出,我們使用了 標簽又加入了一條android.permission.RECEIVE_BOOT_COMPLETED權限。
需要注意的是: 不要在onReceive()方法中添加過多的邏輯或者進行任何的耗時操作,因為在廣播接收器中是不允許開啟線程的,當onReceive()方法運行了較長時間而沒有結束時,程序就會報錯。因此廣播接收器更多的是扮演一種打開程序其他組件的角色,比如創建一條狀態欄通知,或者啟動一個服務等。

發送自定義廣播

現在你已經學會了通過廣播接收器來接收系統廣播,接下來我們就要學習一下如何在應用程序中發送自定義的廣播。前面介紹過,廣播分為兩種類型:標准廣播和有序廣播,接下來我們就將通過實踐的方式來看一下這兩種廣播具體的區別。

發送標准廣播

在發送廣播之前,我們還是需要先定義一個廣播接收器來准備接收此廣播才行,不然發出去也是白發。因此新建一個MyBroadcastReceiver,代碼如下所示:

public class MyBroadcastReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        //throw new UnsupportedOperationException("Not yet implemented");
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

這里當MyBroadcastReceiver收到自定義的廣播時,就會彈出"received in MyBroadcastReceiver"的提示。然后在AndroidManifest.xml中對這個廣播接收器進行修改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">

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

    <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=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

可以看到,這里讓MyBroadcastReceiver接收一條值為com.example.broadcasttest.MY_BROADCAST的廣播,因此待會兒在發送廣播的時候,我們就需要發出這樣的一條廣播。接下來修改activity_main.xml中的代碼,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Broadcast"
        />

</LinearLayout>

這里在布局文件中定義了一個按鈕,用於作為發送廣播的觸發點。然后修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendBroadcast(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
            } else  {
                Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();

            }
        }

    }

}

可以看到,我們在按鈕的點擊事件里面加入了發送自定義廣播的邏輯。首先構建出了一個Intent對象,並把要發送的廣播的值傳入,然后調用了Context的sendBroadcast()方法將廣播發送出去,這樣所有監聽com.example.broadcasttest.MY_BROADCAST這條廣播的廣播接收器就會收到消息。此時發出去的廣播就是一條標准廣播。

發送有序廣播

廣播是一種可以跨進程的通信方式,這一點從前面接收系統廣播的時候就可以看出來了。因此我們應用程序內發出的廣播,其他的應用程序應該也是可以收到的。為了驗證這一點,我們需要再新建一個BroadcastTest2項目。在這個項目下定義一個廣播接收器,用於接收上一小節中的自定義廣播。新建AnotherBroadcastReceiver,代碼如下所示:

public class AnotherBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
       // throw new UnsupportedOperationException("Not yet implemented");
        Toast.makeText(context,"received in AnotherBroadcastReceiver",Toast.LENGTH_SHORT).show();
    }
}

這里仍然是在廣播接收器的onReceive()方法中彈出了一段文本信息。然后再AndroidManifest.xml中對這個廣播接收器進行修改,代碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest2">

    <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=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

可以看到,AnotherBroadcastReceiver同樣接收的是com.example.broadcasttest.MY_BROADCAST這條廣播。現在重新回到BroadcastTest項目的主界面,並點擊一下Send Broadcast按鈕,就會分別碳儲量此提示信息了。這樣就強有力的證明了,我們的應用程序發出的廣播時可以被其他的應用程序接收到的。
不過到目前為止,程序里發出的都還是標准廣播,現在我們來嘗試一下發送有序廣播。重新回到BroadcastTest項目中,然后修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendOrderedBroadcast(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
            } else  {
                Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();

            }
        }

    }

}

可以看到,發送有序廣播只需要改動一行代碼,即將sendBroadcast()方法改成sendOrderedBroadcast()方法。sendOrderedBroadcast()方法接收兩個參數,第一個參數仍然是Intent,第二個參數是一個與權限相關的字符串,這里傳入null即可。現在重新運行程序,並點擊按鈕,你會發現,兩個應用程序仍然都可以接收到這條廣播。看上去好像和標准廣播沒什么區別,不過別忘了,這個時候的廣播接收器是有先后順序的,而且前面的廣播接收器還可以將廣播截斷,以阻止繼續傳播。
那么該如何設定廣播接收器的先后順序呢?當然是在注冊的時候進行設定了,修改AndroidManifest.xml中的代碼,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">

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

    <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=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

可以看到,我們通過android:priority屬性給廣播接收器設置了優先級,優先級比較高的廣播接收器就可以先收到廣播。這里將MyBroadcastReceiver的優先級設成了100,以保證它一定會在AnotherBroadcastReceiver之前收到廣播。
既然已經獲得了接收廣播的優先權,那么MyBroadcastReceiver就可以選擇是否允許廣播繼續傳遞了。修改MyBroadcastReceiver中的代碼,如下所示:

public class MyBroadcastReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        //throw new UnsupportedOperationException("Not yet implemented");
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

如果在onReceive()方法中調用了abortBroadcast()方法,就表示將這條廣播截斷,后面的廣播接收器將無法再接收到這條廣播。現在重新運行程序,並點擊以下Send Broadcast按鈕,你會發現,只有MyBroadcastReceiver中的Toast信息能夠彈出,說明了這條廣播經過MyBroadcastReceiver之后確實是中止傳遞了。

使用本地廣播

前面我們發送和接收的廣播全部屬於系統全局廣播,即發出的廣播可以被其他任何應用程序接收到,並且我們也可以接收來自於其他任何程序的廣播。這樣就很容易引起安全性問題,比如說我們發送的一些攜帶關鍵性數據的廣播有可能唄其他的應用程序截獲,或者其他的程序不停地向我們的廣播接收器發送各種垃圾廣播。
為了能夠簡單的解決廣播的安全性問題,Android引入了一套本地廣播機制,使用這個機制發出的廣播只能夠在應用程序的內部進行傳遞,並且廣播接收器也只能來自本應用程序發出的廣播,這樣所有的安全性問題就都不存在了。
本地廣播的用法並不復雜,主要就是使用了一個LocalBroadcastManager來對廣播進行管理,並提供了發送廣播和注冊廣播接收器的方法。下面我們就通過具體的實例來嘗試一下它的用法,修改MainActivity中的代碼,如下所示:

package com.example.broadcasttest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;

    private LocalReceiver localReceiver;

    private LocalBroadcastManager localBroadcastManager;

    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);
                //Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                //sendBroadcast(intent);
                //sendOrderedBroadcast(intent,null);
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);
        //intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        //networkChangeReceiver = new NetworkChangeReceiver();
        //registerReceiver(networkChangeReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        localBroadcastManager.unregisterReceiver(localReceiver);
        //unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
            } else  {
                Toast.makeText(context,"network is unavailable",Toast.LENGTH_SHORT).show();

            }
            //Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
        }

    }
    class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"received local broadcast",Toast.LENGTH_SHORT).show();
        }
    }
}


首先通過LocalBroadcastManager的getInstance()方法得到了它的一個實例,然后在注冊廣播接收器的時候調用的是LocalBroadcastManager的registerReceiver()方法,在發送廣播的事后調用的是LocalBroadcastManager的sendBroadcast()方法,僅此而已。這里我們在按鈕的點擊事件里面發出了一條com.example.broadcasttest.LOCAL_BROADCAST廣播,然后再LocalReceiver里去接收這條廣播。重新運行程序,並點擊Send Broadcast按鈕。可以看到,LocalReceiver成功接收到了這條本地廣播,並通過Toast提示了出來。
另外還有一點需要說明:本地廣播是無法通過靜態注冊的方式來接收的。其實這也完全可以理解,因為靜態注冊主要就是為了讓程序在未啟動的情況下也能收到廣播,而發送本地廣播時,我們的程序肯定是已經啟動了,因此也完全不需要使用靜態注冊的功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM