1. 程式人生 > >《第一行程式碼Android》學習總結第五章 詳解廣播機制

《第一行程式碼Android》學習總結第五章 詳解廣播機制

一、廣播機制簡介

        Android提供了一系列API,允許程式自由的傳送和接收廣播,同時每個程式都可以對自己感興趣的廣播進行註冊,該程式便可以只接受來自於系統或其他應用程式的自己關心的廣播內容。

標準廣播:

        一種完全非同步執行的廣播,在廣播發出後,所有廣播接收器會在同一時間接收到該廣播訊息。它們之間沒有任何先後順序,因此這種廣播的效率很高,但無法被截斷。

有序廣播:

        一種同步執行的廣播,廣播發出後,同一時間只會有一個廣播接收器接收到該廣播,當這個廣播接收器執行的邏輯完畢後才會繼續傳遞。它們之間是有先後順序的,優先順序高的廣播接收器先收到廣播,同時前面的廣播接收器還可以截斷正在傳遞的廣播。

廣播接收器(Broadcast Receiver):

       廣播接收器可以自由的對感興趣的廣播進行註冊,這樣當有相應的廣播發出時,廣播接收器就能夠收到該廣播,並在內部處理響應的邏輯。註冊廣播接收器只需新建一個類,繼承自BroadcastReceiver類,並重寫父類的onReceive()方法。當有廣播來時,onReceive()方法會自動執行。

二、接收系統廣播

        Android內建了許多系統級的廣播,我們可以通過監聽系統廣播來得到各種系統的狀態變化。

1)動態註冊——實現監聽網路變化

        動態註冊主要是在java程式碼中註冊。

1、修改MainActivity中程式碼註冊廣播,並在MainActivity中定義內部類NetworkChangeReceiver繼承自BroadcastReceiver類,並重寫父類的onReceive()方法。

  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例項,並將需要那種廣播的action新增進來
        intentFilter = new IntentFilter();
//當系統網路變化時發出的廣播
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
//建立NetworkChangeReceiver例項,並註冊廣播
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
//動態註冊的廣播一定要登出
        unregisterReceiver(networkChangeReceiver);
    }

class NetworkChangeReceiver extends BroadcastReceiver{
//每當網路狀態發生變化時都會執行onReceive()方法
        @Override
        public void onReceive(Context context, Intent intent) {
//系統服務類,用於專門管理網路連線
            ConnectivityManager connectivityManager = (ConnectivityManager) 
getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
//判斷當前是否有網路,對使用者進行Toast提示是否有網路
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context,"network is available",Toast.LENGTH_SHORT).show();
            }
            else{
                Toast.makeText(context,"network is not 
available",Toast.LENGTH_SHORT).show();
            }
        }
   }
}

2、在AndroidManifest.xml中新增網路相關許可權

        如果程式中需要進行一些對使用者來說比較敏感的操作時,就必須在配置檔案中宣告許可權才行,否則程式會直接崩潰。

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

2)靜態註冊——實現監聽開機啟動

        靜態註冊主要是通過AndroidManifest.xml註冊。

        動態註冊的廣播接收器可以自由的控制註冊和登出,有很大的靈活性,但存在一個缺點,必須在程式啟動時才能接收到廣播。而靜態註冊可以讓程式在未啟動的情況下接收到廣播。

1、使用AndroidStudio提供的快捷方式建立廣播接收器,右擊com.launcher.broadcasttest包→New→Other→Broadcast Receiver。

        設定廣播接收器名為 BootCompleteMyReceiver,

Exported屬性表示是否允許這個廣播接收器接受本程式以外的廣播。

Enabled屬性表示是否啟用這個廣播接收器。

2、修改BootCompleteMyReceiver中onReceive()方法。

public class BootCompleteMyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"boot complete",Toast.LENGTH_LONG).show();
    }
}

3、靜態的廣播接收器只有在AndroidManifest.xml中註冊才能使用,建立時這步AndroidStudio已經幫我們做好了。

<receiver
     android:name=".BootCompleteMyReceiver"
     android:enabled="true"
     android:exported="true">
</receiver>

4、<receiver>標籤中新增<intent-filter>標籤,並在其中設定相應的action。

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

5、在AndroidManifest.xml中新增開機相關許可權。

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

注意:不要在onReceive()方法中新增過多邏輯或進行任何耗時操作,因為廣播接收器中是不允許開啟執行緒的,當onReceive()方法執行較長時間並沒有結束時,程式就會報錯。

三、使用本地廣播

        系統全域性廣播中發出的廣播可以被其他任何應用程式接收到,也可以收到來自其他任何應用程式的廣播。會存在安全性問題。

        本地廣播機制,這個機制發出的廣播只能在應用程式內部進行傳遞,而且廣播接收器也只能接受來自於本應用程式發出的廣播,可以一定程度上解決安全性問題。

        本地廣播主要使用了一個LocalBroadcastManager對廣播進行管理,與動態註冊很類似。

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
// getInstance()方法獲取LocalBroadcastManager例項
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.launcher.localbroadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
// localBroadcastManager的registerReceiver()方法註冊本地廣播
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            Intent intent = new Intent("com.launcher.localbroadcasttest.LOCAL_BROADCAST");
//localBroadcastManager的sendBroadcast()方法傳送本地廣播
            localBroadcastManager.sendBroadcast(intent);
            }
        });

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

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

        本地廣播無法通過靜態註冊的方式來接受。

四、廣播相關設定與使用

        廣播是一種跨程序的通訊方式,因此一個應用程式中發出的廣播在其他應用程式中通過action包名識別也可以接受。

1)傳送自定義廣播

1、新建MyBroadcastReceiver類,定義一個廣播接收器。

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

2、在AndroidManifest.xml中修改接受自定義廣播action,這裡為靜態註冊廣播接收器。

<receiver
     android:name=".MyBroadcastReceiver"
     android:enabled="true"
     android:exported="true">
       <intent-filter>
                <action android:name="com.launcher.broadcasttest.MY_BROADCAST"/>
       </intent-filter>
</receiver>

3、修改activity_main,定義一個Button作為廣播的觸發點。

<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>

4、修改MainActivity,建立併發送自定義廣播。

public class MainActivity extends AppCompatActivity {
    @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 view) {
                Intent intent = new Intent();
                intent.setAction("com.launcher.broadcasttest.MY_BROADCAST");
//傳送自定義廣播,所有監聽com.launcher.broadcasttest.MY_BROADCAST廣播的廣播接收器都會收到訊息。
                sendBroadcast(intent);
            }
        });
    }
}

2)傳送有序廣播

       Intent intent = new Intent("com.launcher.broadcasttest.MY_BROADCAST");
       sendOrderBroadcast(intent,null);

第一個引數為Intent。

第二個引數為一個與許可權相關的字串,一般為null。

3)設定廣播優先順序

<intent-filter android:priority=”100”>
       <action android:name="com.launcher.broadcasttest.MY_BROADCAST"/>
</intent-filter>

4)將廣播截斷

abortBroadcast();

        將廣播截斷後,後面的廣播接收器將無法再收到這條廣播。