Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android四大組件--Broadcast Receiver詳解

Android四大組件--Broadcast Receiver詳解

編輯:關於Android編程

本文主要講述了:

一、BroadcastReceiver概述:

二、BroadcastReceiver事件分類

三、BroadcastReceiver事件的編程流程

四、兩類BroadcastReceiver

五、普通廣播和有序廣播

六、Service與BroadcastReceiver如何交互?

七、開機自動運行service

八、BroadcastReceiver的生命周期


一、BroadcastReceiver概述:

1、廣播接收器是一個專注於接收廣播通知信息,並做出對應處理的組件。很多廣播是源自於系統代碼的──比如,通知時區改變、電池電量低、拍攝了一張照片或者用戶改變了語言選項。應用程序也可以進行廣播──比如說,通知其它應用程序一些數據下載完成並處於可用狀態。
2、應用程序可以擁有任意數量的廣播接收器以對所有它感興趣的通知信息予以響應。所有的接收器均繼承自BroadcastReceiver基類。
2、廣播接收器沒有用戶界面。然而,它們可以啟動一個activity來響應它們收到的信息,或者用NotificationManager來通知用戶。通知可以用很多種方式來吸引用戶的注意力──閃動背燈、震動、播放聲音等等。一般來說是在狀態欄上放一個持久的圖標,用戶可以打開它並獲取消息。


二、BroadcastReceiver事件分類

1、系統廣播事件,比如:ACTION_BOOT_COMPLETED(系統啟動完成後觸發),ACTION_TIME_CHANGED(系統時間改變時觸發),ACTION_BATTERY_LOW(電量低時觸發)等等。

2、用戶自定義的廣播事件。


三、BroadcastReceiver事件的編程流程

1、注冊廣播事件:注冊方式有兩種,

一種是靜態注冊,就是在 AndroidManifest.xml文件中定義,注冊的廣播接收器必須要繼承BroadcastReceiver類;

在AndroidManifest.xml中用標簽生命注冊,並在標簽內用標簽設置過濾器。

    //繼承BroadcastReceiver,重寫onReceiver方法


        


       //使用過濾器,接收指定action廣播


      


  

另一種是動態注冊,是在程序中使用 Context.registerReceiver注冊,注冊的廣播接收器相當於一個匿名類。兩種方式都需要IntentFIlter。

IntentFilter intentFilter = new IntentFilter();


intentFilter.addAction(String);   //為BroadcastReceiver指定action,使之用於接收同action的廣播


registerReceiver(BroadcastReceiver,intentFilter);

  一般:在onStart中注冊,onStop中取消unregisterReceiver

  指定廣播目標Action:Intent intent = new Intent(actionString);

  並且可通過Intent攜帶消息 :intent.putExtra("msg", "hello,我通過廣播發送消息了");

  發送廣播消息:Context.sendBroadcast(intent )


2、發送廣播事件:通過Context.sendBroadcast來發送,由Intent來傳遞注冊時用到的Action。

3、 接收廣播事件:當發送的廣播被接收器監聽到後,會調用它的onReceive()方法,並將包含消息的Intent對象傳給它。onReceive中代碼的執行時間不要超過5s,否則Android會彈出超時dialog。

四、兩類BroadcastReceiver

1、正常廣播 Normal broadcasts(用 Context.sendBroadcast()發送)是完全異步的。它們都運行在一個未定義的順序,通常是在同一時間。這樣會更有效,但意味著receiver不能包含所要使用的結果或中止的API。
2、有序廣播 Ordered broadcasts(用 Context.sendOrderedBroadcast()發送)每次被發送到一個receiver。所謂有序,就是每個receiver執行後可以傳播到下一個receiver,也可以完全中止傳播——不傳播給其他receiver。 而receiver運行的順序可以通過matched intent-filter 裡面的android:priority來控制,當priority優先級相同的時候,Receiver以任意的順序運行。


PS:

下面舉例說明了4種情況的廣播事件:靜態注冊的系統廣播事件、靜態注冊的用戶自定義廣播事件、動態注冊的系統廣播事件和動態注冊的用戶自定義廣播事件。

1、創建廣播接受者

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

public class MyReceiver extends BroadcastReceiver {
	
	private static final String TAG = "MyReceiver";
	
	@Override
	public void onReceive(Context context, Intent intent) {
		String msg = intent.getStringExtra("msg");
		Log.i(TAG, msg);
	}

}
2、廣播注冊

1)靜態注冊
靜態注冊是在AndroidManifest.xml文件中配置的,我們就來為MyReceiver注冊一個廣播地址:


        	
        		
        		
        	
        
配置了以上信息之後,只要是android.intent.action.MY_BROADCAST這個地址的廣播,MyReceiver都能夠接收的到。


2)動態注冊
動態注冊需要在代碼中動態的指定廣播地址並注冊,通常我們是在Activity或Service注冊一個廣播,下面我們就來看一下注冊的代碼:

MyReceiver receiver = new MyReceiver();
        
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST");
        
registerReceiver(receiver, filter);

3)發送廣播

    public void send(View view) {
    	Intent intent = new Intent("android.intent.action.MY_BROADCAST");
    	intent.putExtra("msg", "hello receiver.");
    	sendBroadcast(intent);
    }

PS:

下面簡單介紹下系統廣播

下面是android系統中定義了很多標准的Broadcast Action來響應系統的廣播事件(只列出一部分)

①ACTION_TIME_CHANGED(時間改變時觸發)
②ACTION_BOOT_COMPLETED(系統啟動完成後觸發)--比如有些程序開機後啟動就是用這種方式來實現的
③ACTION_PACKAGE_ADDED(添加包時觸發)
④ACTION_BATTERY_CHANGED(電量低時觸發)

/**
 * 系統靜態注冊廣播消息接收器
 * 
 * @author zuolongsnail
 * 
 */
public class SystemReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW)) {
			Log.e("SystemReceiver", "電量低提示");
			Toast.makeText(context, "您的手機電量偏低,請及時充電", Toast.LENGTH_SHORT).show();
		}
	}
}



	
		
			
				
				
			
		
		
		
			
				
			
		
	

五、普通廣播和有序廣播

上面的例子只是一個接收者來接收廣播,如果有多個接收者都注冊了相同的廣播地址,又會是什麼情況呢,能同時接收到同一條廣播嗎,相互之間會不會有干擾呢?

這就涉及到普通廣播和有序廣播的概念了。

1、Normal Broadcast(普通廣播):Normal Broadcast是完全異步的,可以在同一時刻(邏輯上)被所有接收者接收到,消息傳遞的效率比較高。但缺點是接受者不能將處理結果傳遞給下一個接收者,並且無法終止Broadcast Intent的廣播。

2、Ordered Broadcast(有序廣播):Ordered Broadcast的接收者將按預先聲明的優先級依次接受Broadcast。如:A的級別高於B、B的級別高於C,那麼Broadcast先傳給A,再傳給B,最後傳給C。優先級別聲明在元素的android:priority屬性中,數越大優先級別越高,取值范圍為-1000-1000,優先級別也可以調用IntentFilter對象的setPriority()進行設置。OrderedBroadcast接收者可以終止Broadcast Intent的傳播,BroadcastIntent的傳播一旦終止,後面的接收者就無法接收到Broadcast。另外,OrderedBroadcast的接收者可以將數據傳遞給下一個接收者。如:A得到Broadcast後,可以往它的結果對象中存入數據,當Broadcast傳給B時,B可以從A的結果對象中得到A存入的數據。

3、context提供的如下兩個方法用於發送廣播:
  sendBroadcast():發送Normal Broadcast
sendOrderedBroadcast():發送OrderedBroadcast。

4、對於OrderedBroadcast而言,系統會根據接收者生命的優先級別順序逐個執行接收者,優先接收到Broadcast的接收者可以終止Broadcast,調用BroadcastReceiver的abortBroadcast()方法即可終止Broadcast。如果Broadcast被前面的接收者終止,後面的接收者就再也無法獲取到Broadcast。

5、不僅如此,對於OrderBroadcast而言,優先接收到Broadcast的接收者可以通過setResultExtras(Bundle)方法將處理結果存入Broadcast中,然後傳給下一個接收者,下一個接收者通過代碼: Bundle bundle=getResultExtras(true)可以獲取上一個接收者存入的數據。

實例:點擊按鈕,兩個Receiver接收同一條廣播,在logcat中打印出數據(按照Receiver的優先順序,Receiver2先,Receiver1後)

Manifest:




    

    
        
            
                

                
            
            
        
        
            
                
            
        
        
            
                
            
        
    


activity代碼:

//發送廣播,bundle綁上key為a的數據
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class C48_BroadcastActivity extends Activity {
    /** Called when the activity is first created. */
	Button button;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        button=(Button)findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent=new Intent("com.song.123");
				Bundle bundle=new Bundle();
				bundle.putString("a", "aaa");
				intent.putExtras(bundle);
				//有序廣播
				sendOrderedBroadcast(intent, null);
			}
		});
        
    }
}
Receiver2

package com.song;
//優先接到廣播,bundle綁上key為b的數據
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class MyReceiver2 extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		System.out.println("receiver2");
//		context.getSystemService(name);
		Bundle bundle=intent.getExtras();
		bundle.putString("b", "bbb");
		System.out.println("a="+bundle.get("a"));
		setResultExtras(bundle);
		//切斷廣播
//		abortBroadcast();     
	}

}

Receiver1

package com.song;
//接收從receiver2傳來的廣播,包含key為a和b的數據
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class MyReceiver1 extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		System.out.println("receiver1");
		//要不要接受上一個廣播接收器receiver2傳來的的數據
		Bundle bundle=getResultExtras(true);
		System.out.println("a="+bundle.getString("a")+",b="+bundle.getString("b"));
	}

}

根據上面的配置可以看出,該程序包括兩個receiver,其中Receiver2高,Receiver1低。如果Receiver2中的Receiver2zhabortBroadcast()注釋了,那麼程序Receiver1中將可以看到完整的信息了。


六、Service與BroadcastReceiver如何交互?

我們之前都是先啟動了一個Activity,然後在Activity中啟動服務。如果是這樣,在啟動服務時必須要先啟動一個Activity。在很多時候這樣做有些多余,我們現在可以利用Broadcast Receiver在Android系統啟動時運行一個Activity。也許我們會從中得到一些啟發,既然可以在Broadcast Receiver中啟動Activity,為什麼不能啟動Service呢?說做就做,現在讓我們來驗證一下這個想法。

先編寫一個服務類,這個服務類沒什麼特別的,仍然使用前面兩節編寫的MyService類即可。在AndroidManifest.xml文件中配置MyService類的代碼也相同。

下面來完成最關鍵的一步,就是建立一個BroadcastReceiver,代碼如下:

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
 
public class StartupReceiver extends BroadcastReceiver  
{  
    @Override  
    public void onReceive(Context context, Intent intent)  
    {  
        //  啟動一個Service  
        Intent serviceIntent = new Intent(context, MyService.class);          
        context.startService(serviceIntent);          
        Intent activityIntent = new Intent(context, MessageActivity.class);  
        //  要想在Service中啟動Activity,必須設置如下標志  
        activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
        context.startActivity(activityIntent);  
    }  
} 

在StartupReceiver類的onReceive方法中完成了兩項工作:啟動服務和顯示一個Activity來提示服務啟動成功。

AndroidManifest.xml文件的完整代碼。

 
 
     
         
                              
                 
             
         
         
             
                 
                 
             
         
         
     
     
     
 


PS:

開機自動運行service

我們經常會有這樣的應用場合,比如消息推送服務,需要實現開機啟動的功能。要實現這個功能,我們就可以訂閱系統“啟動完成(BOOT_COMPLETED)”這條廣播,接收到這條廣播後我們就可以啟動自己的服務了;

上面實例其實和開機啟動服務差不多了,下面我們在說說開機啟動服務。
Receiver :

public class BootCompleteReceiver extends BroadcastReceiver {
	
	private static final String TAG = "BootCompleteReceiver";
	
	@Override
	public void onReceive(Context context, Intent intent) {
		Intent service = new Intent(context, MsgPushService.class);
		context.startService(service);
		Log.i(TAG, "Boot Complete. Starting MsgPushService...");
	}

}


Service :

public class MsgPushService extends Service {

	private static final String TAG = "MsgPushService";
	
	@Override
	public void onCreate() {
		super.onCreate();
		Log.i(TAG, "onCreate called.");
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(TAG, "onStartCommand called.");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
}
AndroidManifest
        
        
        	
        		
        		
        		
        	
        
        
        

PS:

最後在說說Broadcast的生命周期

  1、一個BroadcastReceiver 對象只有在被調用onReceive(Context, Intent)的才有效的,當從該函數返回後,該對象就無效的了,結束生命周期。

  因此從這個特征可以看出,在所調用的onReceive(Context, Intent)函數裡,不能有過於耗時的操作,不能使用線程來執行。對於耗時的操作,請start service來完成。因為當得到其他異步操作所返回的結果時,BroadcastReceiver 可能已經無效了。

2、一個Broadcast receiver只有一個回調方法:

void onReceive(Context curContext, Intent broadcastMsg)

當Broadcast receiver接收到一條廣播信息,android會調用它的onReceive()方法,並傳遞給它一個包含廣播信息的intent對象。當Broadcast receiver在執行這個方法時可以認為它是活動的,onReceive()方法返回時,它便終止了。

一個包含活動Broadcast receiver的進程會被系統保護以避免被終止。但是如果進程不包含任何活動組件,那麼當它占用的內存要用於其它進程時,系統任何時候都可以終止運行該進程。

當應答一條廣播信息十分耗時,而另一個線程必須執行某個任務時會出現一個問題。試想一下,如果onReceive()方法產生一個線程然後返回,那麼整個進程,包括新的線程會被認為是不活動的(除非在進程中還有其它活動的組件),該進程就有被系統終止運行的危險。解決這個問題的辦法就是在onReceive()方法中啟動一個服務,讓這個服務做那樣的工作,這樣系統就會知道進程中有活動的組件而不會停止進程。


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