Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 安卓四大組件之廣播,安卓四大組件

安卓四大組件之廣播,安卓四大組件

編輯:關於android開發

安卓四大組件之廣播,安卓四大組件


      廣播是一種廣泛運用的在應用程序之間傳輸信息的機制,Android 為了將系統運行時的各種“事件”通知給其他應用,因此內置了多種廣播。廣播機制最大的特點就是發送方並不關心接收方是否接到數據,也不關心接收方是如何處理數據的。Android 中的每個應用程序都可以對自己感興趣的廣播進行注冊,這樣該程序就只會接收到自己所關心的廣播內容,這些廣播可能是來自於系統的,也可能是來自於其他應用程序的,前者是系統廣播,後者是自定義廣播。廣播在具體的項目中應用場景並不多,但一旦使用會使得程序變得精簡很多,因此本片文章就簡單介紹一下安卓系統的廣播機制。

      首先,簡單的介紹一下安卓的廣播機制。BroadCastReceiver是對發送出來的Broadcast 進行過濾接受並響應的一類組件,是Android四大組件之一,主要用於接收系統或者app發送的廣播事件。在我們的項目中經常使用廣播接收者接收系統通知,比如開機啟動、sd掛載、低電量、外播電話、鎖屏等。 如果我們做的是播放器,那麼監聽到用戶鎖屏後我們應該將我們的播放之暫停等。android的四大組件本質上就是為了實現移動或者說嵌入式設備上的MVC架構,它們之間有時候是一種相互依存的關系, 有時候又是一種補充關系,引入廣播機制可以方便幾大組件的信息和數據交互。廣播有利於程序間互通消息,例如在自己的應用程序內監聽系統來電。 

       BroadCastReceiver的一般編寫步驟:

        1. 寫一個類繼承BroadCastReceiver;

        2. 重寫oncreat()方法;

        3. 注冊廣播。動態注冊和靜態注冊,前者在java代碼中實現,後這在清單文件中編寫。動態注冊需要寫BroadCastReceiver的實現類和過濾器,靜態注冊除了寫過濾器外還要在receiver標簽的name屬性上添加包名和類名。

       按照廣播的屬性來分,廣播分兩種:有序廣播和無序廣播。

      無序廣播:又叫普通廣播,完全異步,不會被某個廣播接收者終止,邏輯上可以被任何廣播接收者接收到,在廣播發出之後,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先後順序可言。優點是效率較高。缺點是一個接收者不能將處理結果傳遞給下一個接收者,並無法終止廣播intent的傳播。Context.sendBroadcast() 發送的是普通廣播,所有訂閱者都有機會獲得並進行處理。

      有序廣播:按照被接收者的優先級順序,在被接收者中依次傳播。比如有三個廣播接收者A,B,C,優先級是A > B > C。那這個消息先傳給A,再傳給B,最後傳給C。,因此通常需要在AndroidManifest.xml 中進行注冊,優先級別聲明在intent-filter 元素的android:priority 屬性中,數越大優先級別越高,取值范圍:-1000 到1000,優先級別也可以調用IntentFilter 對象的setPriority()進行設置。有序廣播的接收者可以終止廣播的傳播,廣播的傳播一旦終止,後面的接收者就無法接收到廣播,有序廣播的接收者可以將數據傳遞給下一個接收者,如:A 得到廣播後,可以往它的結果對象中存入數據,當廣播傳給B 時,B 可以從A 的結果對象中得到A 存入的數據。Context.sendOrderedBroadcast() 發送的是有序廣播。Bundlebundle = getResultExtras(true))可以獲取上一個接收者存入在結果對象中的數據。

      對於有序廣播有一個小細節,那就是優先級高的廣播可以終結一個廣播。終止一個有序廣播:abortBroadcast()。終止有序廣播只需要一句代碼,該代碼是BroadCastReceiver 類中的方法,因此這裡可以直接使用。這裡需要注意的是如果abortBroadCast 是在一個無序廣播中執行的,那麼就會報如下異常:

          java.lang.RuntimeException:

          BroadcastReceiver trying to return result during a non-ordered broadcast

      在低版本的手機上比如Android2.3 上是不會報這樣的異常的,安卓工程師認為終止無序廣播是不合法的操作,因此在Android2.3之後的版本,終止無序廣播都是非法操作。為了防止我們終止一個無序廣播導致報異常,我們可以先判斷接收到的廣播類型。優化後的代碼如下:

       if (isOrderedBroadcast()) {

              abortBroadcast();

       }

       isOrderedBroadcast 方法是BroadCastReceiver 類提供的,用於判斷當前的廣播類型。返回true 為有序廣播,返回false 為無序廣播。

       之後,再來講一下廣播的注冊機制。廣播注冊方式有兩種,動態注冊和靜態注冊。在清單文件中注冊廣播接收者稱為靜態注冊,在代碼中注冊稱為動態注冊。靜態注冊的廣播接收者只要app在系統中運行則一直可以接收到廣播消息,動態注冊的廣播接收者當注冊的Activity或者Service銷毀了那麼就接收不到廣播了。

       靜態注冊:在清單文件中進行如下配置

<receiver android:name="包名+類名" > 
   <intent-filter>
       <action android:name="android.intent.action.CALL" > </action> 
   </intent-filter> 
</receiver>

 

      動態注冊:在代碼中進行如下注冊

//廣播發送者:
Intent intent = new Intent();
intent.setAction(Uri);
intent.putExtra("packname", packname);
sendBroadcast(intent);

//自定義廣播接受中:
receiver = new BroadcastReceiver();
  IntentFilter intentFilter = new IntentFilter(); 
intentFilter.addAction(Uri);
context.registerReceiver(receiver, intentFilter);

        

        按照廣播的編寫方式來分,又可以分為系統廣播和自定義廣播兩種。

       系統廣播的應用較為普遍,比如文章開頭所講的:系統電量的改變、屏幕的鎖屏、網絡狀態的改變、接收到新的短信、撥打電話事件、sdcard 的掛載和移除、應用的安裝和卸載等等。比如我們開發的在線播放視頻類的APP,那麼我們就有必要監聽網絡轉態改變的事件廣播,如果用戶的網絡狀態從wifi 改變為了4G 上網,那麼應該提示用戶是否使用4G 網絡繼續播放視頻,如果不提示用戶,那麼就可能導致用戶流量被大量使用,一會兒功夫,用戶可能就要停機了。這些都是通過系統廣播完成。Android給許多系統服務廣播Intent。你可以使用這些基於系統事件的消息來給自己的工程增添一些功能,這些事件如時區變更、數據連接狀態、SMS消息或電話呼叫。系統廣播的編寫也較為簡單,通過查看底層源碼獲取相關的action節點及其他參數,然後把這些寫在清單文件中或動態寫在java代碼中,就可以在BroadCastReceiver的實現類中接受廣播了。文章最後給出一個屏幕點亮和熄滅的案例,再次就不在贅述。       

       給出幾種常用的系統廣播監聽事件中清單文件的寫法。當然若是動態注冊,只需要在java代碼中添加過濾器即可,節點參數類似。

<--!監聽SD卡狀態的receiver節點:-->
<receiver android:name="包名+類名" > 
<intent-filter> 
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/> 
<data android:scheme="file"></data> 
</intent-filter> 
</receiver>


<--!開機監聽:-->
<receiver android:name="包名+類名"> 
<intent-filter>
 <action android:name="android.intent.action.BOOT_COMPLETED" > </action>
</intent-filter>
 </receiver>

<--!電話監聽:-->
<receiver android:name="包名+類名"> 
  <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
   </intent-filter> 
</receiver>

<--!程序安裝和卸載的監聽:-->
<receiver android:name="包名+類名"> 
  <intent-filter >
    <action android:name="android.intent.action.PACKAGE_ADDED"/> 
   <action android:name="android.intent.action.PACKAGE_REMOVED"/> 
    <data android:scheme="package"></data> 
  </intent-filter> 
</receiver>


<--!短信監聽:-->
<receiver android:name="包名+類名" >
    <intent-filter android:priority="1000" >
      <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
    </intent-filter>
 </receiver>

 

        上面列出來的是幾種較為常見的系統廣播的參數寫法,當然還有一些並未寫出,比如,電量低、日期更改等等,因此可以在需要編寫時查閱相關的底層源碼獲取。

        再來講一下自定義廣播。

        自定義廣播的應用場景通常是,兩個程序間發送數據。例如,用看門狗程序實現程序鎖,當密碼登錄界面上密碼輸入正確時,立即通知看門狗程序跳過輪訓,這樣就可以進入程序。自定義的廣播同樣可以分為有序關播和無序廣播兩種,下面分別給出自定義的無序廣播和自定義的有序廣播兩個案例。

       自定義無序廣播,定義兩個程序,利用廣播機制發送數據。

       廣播發送者:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    /**
     * 發送關播
     * @param view
     */
    public void click(View view){
        Intent intent = new Intent();
        intent.setAction("com.example.sendbroadcast.mysend");  //可以自定義action的值
        intent.putExtra("data", "用廣播傳遞的數據");
        sendBroadcast(intent);
    }
}

         廣播接受者:

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;

public class MainActivity extends Activity {
    private myReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//         兩種注冊的方式,在java代碼中和清單文件中
        receiver = new myReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.example.sendbroadcast.mysend");
        registerReceiver(receiver, filter);
    }

    class myReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            System.out
                    .println("收到廣播發送者發來的數據: " + intent.getStringExtra("data"));
        }
    }
    /**
     * 程序關閉時銷毀廣播
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
        receiver = null;
    }
}

         上述程序還可以在清單文件中注冊。

        <receiver android:name="com.example.receivebroadcast.MyBroadcastReceiver" >
            <intent-filter>
                <action android:name="com.example.sendbroadcast.mysend" />
            </intent-filter>
        </receiver>

 

         自定義有序廣播。本文給出的案例是一個消息傳遞機制,有消息發布者發布一個消息,一次傳遞給四個人,優先級高的接受者修改消息。

         消息發布者:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    public void click(View view){
        Intent intent = new Intent();
        intent.setAction("com.example.sendordermessage");
        //new MyReceiver()是一個監視程序,監聽最後廣播的數據
        sendOrderedBroadcast(intent, null, new MyReceiver(), null, 1, "我是消息發布者, 我發布的消息是: 街上有一只狼", null);
    }
}

        另外在廣播發布者中,寫一個監視程序,查看最後一個廣播接受者接受到的數據。

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
         System.out.println("我是內線程序,我收到的消息是: " + getResultData());
    }
}

 

        第一個廣播接受者:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class FirstReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
          System.out.println("我是第一個消息接受者,我聽說" + getResultData());
          setResultData("街上有5只狼");
    }
}

 

      第二個廣播接受者:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class SecondReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
          System.out.println("我是第二個消息接受者,我聽說" + getResultData());
          setResultData("街上有10只猴");
    }
}

       第三個廣播接受者:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class ThirldReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
          System.out.println("我是第三個消息接受者,我聽說" + getResultData());
          setResultData("街上有20只狼");
    }
}

       第四個廣播接受者:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class FourthReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
          System.out.println("我是第四個消息接受者,我聽說" + getResultData());
    }
}

       廣播接受者的清單文件的配置

        <receiver android:name="com.example.receiverorder.FirstReceiver" >
            <intent-filter android:priority="1000" >
                <action android:name="com.example.sendordermessage" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.example.receiverorder.SecondReceiver" >
            <intent-filter android:priority="500" >
                <action android:name="com.example.sendordermessage" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.example.receiverorder.ThirldReceiver" >
            <intent-filter android:priority="0" >
                <action android:name="com.example.sendordermessage" />
            </intent-filter>
        </receiver>
        <receiver android:name="com.example.receiverorder.FourthReceiver" >
            <intent-filter android:priority="-1000" >
                <action android:name="com.example.sendordermessage" />
            </intent-filter>
        </receiver>

 

      工程的目錄結構:

                  

          成果展示:

               

        最後補充一個小內容。在Android 中一些操作比較頻繁的事件,比如鎖屏解屏和電量的變化,也會發送特定的廣播。但是此類廣播的注冊是無法注冊在AndroidManifest.xml 中,只能在代碼中進行注冊。也就是說對於鎖屏解屏和電量變化的監聽只能通過動態注冊。亮屏和息屏的操作經常用於省電處理中,當屏幕熄滅時可以關閉掉一些耗時的服務,當屏幕點亮時再啟動服務。這樣既保證了用戶的使用體驗,同時減少了手機的耗電量,對於產品優化大有裨益。下面給出屏幕廣播監視案例,寫一個內部類繼承BroadcastReceiver,在該類中接受關播信息。

        

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

public class MainActivity extends Activity {

    private myReceiver myreceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        myreceiver = new myReceiver();
        registerReceiver(myreceiver, filter);
    }
    /**
     * 廣播實現類
     *
     */
    class myReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            System.out.println(intent.getAction().toString());
        }
    }
    
    /**
     * 反注冊廣播
     * 
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(myreceiver);
        myreceiver = null;
    }
}

        自此,廣播的內容全部講解完畢。

 

 

 

 

 

 

 

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