Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 中的消息傳遞,詳解廣播機制

Android 中的消息傳遞,詳解廣播機制

編輯:關於Android編程

--------------------------------------廣播機制簡介---------------------------------------------

Android中的廣播機制非常靈活,Android中的每個應用程序都可以對自己感興趣的廣播進行注冊,這個程序也只會收到自己所關心的廣播內容,這些廣播可能是來自於系統的,也可能是來自於其他應用程序的。

Android提供了一套完整的API,允許應用程序自由地發送和接受廣播。

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

標准廣播(Normal broadcasts):標准廣播是一種完全異步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎會在同一時刻接收到這條廣播消息。這種廣播效率比較高,但同時也意味著它是無法被截斷的。

有序廣播(Ordered broadcasts):有序廣播則是一種同步執行的廣播,在廣播發出之後,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢之後,廣播才會繼續傳遞。

-------------------------------------接收系統廣播-----------------------------------------

\

Android內置了很多系統級別的廣播,可以在應用程序中通過監聽這些廣播來得到各種系統的狀態信息。

手機開機完成後會發出一條廣播,電池的電量發生變化會發出一條廣播,時間改變也會發出一條廣播……如果想要接受到這些廣播,就需要使用廣播接收器。

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

注冊廣播的方式一般有兩種,在代碼中注冊和在 AndroidManifest.xml 中注冊,前者被稱為動態注冊,後者被稱為靜態注冊。

創建廣播接收器只需要新建一個類,讓它繼承自BroadcastReceiver,並重寫父類的onReceiver()方法。當有消息通過廣播傳遞過來時,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 = new IntentFilter();
        //為過濾器添加處理規則
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        //注冊廣播接收器
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //動態的廣播接收器最後一定要取消注冊
        unregisterReceiver(networkChangeReceiver);
    }

    //自定義內部類,繼承自BroadcastReceiver
    public class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //實現onReceive()方法的邏輯
            Toast.makeText(context, "網絡狀態改變", Toast.LENGTH_SHORT).show();
        }
    }
}

IntentFilter 的 addAction() 方法中添加了一個值為 android.net.conn.CONNECTIVITY_CHANGE 的 action,用於接收系統對網絡狀態改變而發出的一條廣播。(廣播接收器想要監聽什麼廣播,就在這裡添加相應的action)

調用registerReceiver() 方法對廣播接收器進行注冊,將 BroadcastReceiver 和 IntentFilter 的實例傳遞進去即可。

最後要記得,動態注冊的廣播接收器一定都要取消注冊才行。通過調用unregisterReceiver() 方法取消注冊。

 

修改 NetworkChangeReceiver 的 onReceiver() 方法,使之能夠准確告訴用戶當前網絡狀態:

Android系統規定,如果程序需要訪問系統關鍵信息,必須在配置文件中聲明權限才可以,否則程序直接崩潰。

這裡查詢網絡狀態需要聲明權限,打開AndroidManifest.xml文件,為添加權限(之前),代碼如下:

修改 NetworkChangeReceiver 中的代碼:

    public class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {//connectivityManger是一個系統服務類,專門用於管理網絡連接
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            //調用NetworkInfo的isAvailable()方法判斷是否聯網
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context,"網絡已連接",Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(context,"網絡不可用",Toast.LENGTH_SHORT).show();
            }
        }
    }

靜態注冊實現開機啟動:

動態注冊廣播接收器可以自由地控制注冊與注銷,在靈活性方面有很大優勢。但是它也存在一個缺點,即必須要在程序啟動之後才能接收到廣播,因為注冊的邏輯是寫在onCreate()方法中的。而靜態注冊可以讓程序在未啟動的情況下就能接收到廣播。

這裡我們准備讓程序接收一條開機廣播,當收到這條廣播的時候就可以在onReceive()方法裡執行相應的邏輯,從而實現開機啟動的功能。

新建一個 BootCompleteReceiver 繼承自 BroadcastReceiver,代碼如下所示:

public class BootCompleteReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"程序已啟動",Toast.LENGTH_SHORT).show();
    }
}

這裡不再使用內部類的方式來定義廣播接收器,因為靜態注冊需要在 AndroidManifest中將廣播接收器的類名傳遞進去。

修改 AndroidManifest.xml 文件,代碼如下:




    

    

    
        
            
                

                
            
        

        
            
                
            
        
    

核心代碼:

    
    
        
            
                
                
            
        

將模擬器關閉並重新啟動,在啟動完成之後就會收到開機廣播了。

注意:不要再 onReceive() 方法中添加過多的邏輯或者進行任何耗時的操作,當onReceive()方法運行了較長時間而沒有結束時,程序就會報錯。廣播接收器更多是扮演打開其他組件的角色,比如創建一條狀態欄通知,或者啟動一個服務。

 

-------------------------------------發送自定義廣播-----------------------------------------

\

發送標准廣播:

發送廣播之前的准備工作,定義一個廣播接收器來准備接收此廣播,並在XML中對這個廣播接收器進行注冊:

MyBroadcastReceiver 廣播接收器:

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"Woider 已經收到信息",Toast.LENGTH_SHORT).show();
    }
}

AndroidManifest.xml 對廣播接收器進行注冊:

        
            
                
            
        

修改MainActivity 中的 onCreate()方法,如下所示:

    @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 intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                //調用Context的 sendBroadcast()方法發送廣播
                sendBroadcast(intent);
            }
        });

首先構建一個Intent對象,並把要發送的廣播的值傳入,然後調用 Context 的 sendBroadcast()方法將廣播發送出去,這樣監聽 com.example.broadcasttest.MY_BROADCAST這條廣播的廣播接收器就會收到消息。此時發出去的廣播就是一條標准廣播。

程序運行截圖:

\

另外,由於廣播是使用Intent進行傳遞的,因此你還可以在Intent中攜帶一些數據傳遞給廣播接收器。

發送有序廣播:

廣播是一種可以跨進程的通信方式。因此在我們應用程序內發出的廣播,其他的應用程序也可以收到。

你可以另外新建一個工程,定義一個廣播接收器,接收本程序自定義的廣播。可以驗證得出結論,應用程序發出的廣播是可以被其他應用程序接收到的。

不過目前為止,程序發出的都還是標准廣播,如果需要發送有序廣播,只需要修改一行代碼,即將sendBroadcast()方法改成 sendOrderedBroadcast()方法。

sendOrderedBroadcast()方法接收兩個參數,第一個參數仍然是 Intent,第二個參數是一個與權限相關的字符串。

有序廣播的接收是有先後順序的,前面的廣播接收器還可以將廣播截斷,阻止其繼續傳播。

如果要設定廣播接收器的先後順序,可以在注冊的時候進行設定,在 AndroidManifest 中在元素中,通過android:priority 屬性給廣播接收器設置優先級,數值越大的優先級越高,優先級越高的就可以先收到廣播。

如果在BroadcastReceiver 的子類方法 onReceiver()中調用了abortBroadcast()方法,就表示將這條廣播截斷,後面的廣播接收器將無法再接收到這條廣播。

-------------------------------------使用本地廣播-----------------------------------------

\

系統廣播可以被其他任何程序接收到,這樣就很容易引起安全性的問題。比如我們發送的一些攜帶關鍵性數據的廣播有可能被其他的應用程序截獲,或者其他的程序不停地向我們的廣播接收器裡發送各種垃圾廣播。

為了能夠簡單地解決廣播安全性問題,Android 引入了一套本地廣播機制,使用這個機制發出的廣播只能夠在應用程序的內部進行傳遞,並且廣播接收器也只能接收來自本應用程序發出的廣播,這樣所有的安全性問題就都不存在了。

本地廣播的用法並不復雜,主要就是使用了一個LocalBroadcastManager 來對廣播進行管理,並提供了發送廣播和注冊廣播接收器的方法。

修改 MainActivity 中的代碼,具體實現方法如下:

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);
        //獲取LocalBroadcastManger實例
        localBroadcastManager = localBroadcastManager.getInstance(this);

        TextView textView = (TextView)findViewById(R.id.broadcast);
        textView.setText("廣播地址:\ncom.example.broadcasttest.LOCAL_BROADCAST");
        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");
                intent.putExtra("woider","青春的逝去並不可怕,可怕的是失去了勇敢地熱愛生活的心");
                //發送本地廣播
                localBroadcastManager.sendBroadcast(intent);
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        //注冊本地廣播監聽器
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);


    }

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

    //本地廣播接收器
    class LocalReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String data = intent.getStringExtra("woider");
            Toast.makeText(context,data,Toast.LENGTH_SHORT).show();
        }
    }
}

首先通過LocalBroadcastManager 的getInstance() 方法得到它的一個實例,然後在注冊廣播接收器的時候調用的是LocalBroadcastManager 的registerReceiver()方法,在發送廣播的時候調用的是LocalBroadcastManager 的sendBroadcast() 方法,僅此而已。

運行程序,點擊“發送廣播”,效果如圖所示:

\

可以看到,LocalReceiver成功的收到了這條本地廣播,並通過Toast提示了出來。如果你還有興趣進行實驗,可以嘗試在其他應用程序中去接收 LOCAL_BROADCAST 這條廣播,肯定無法收到,因為這條廣播只會在 BroadcastTest 程序內傳播(但我還是鼓勵你們去嘗試一下的,說不定收到了呢?)

注意:本地廣播是無法通過靜態注冊的方式來接收的。

最後盤點一下使用本地廣播的幾點優勢:

1.  可以明確地知道正在發送的廣播不會離開我們的程序,因此不需要擔心機密數據洩露的問題。

2.  其他的程序無法將廣播發送到我們的程序內部,因此不需要擔心會有安全漏洞的隱患。

3.  發送本地廣播比起發送系統全局廣播將會更加高效。

要推動世界的人,須先自己行動

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved