Broadcast组件简析

本文学习拜读自罗升阳老师的《Android系统源代码情景分析》

涉及Binder

一 概述

在Android系统中,广播(Broadcast)是一种在组件之间进行消息传递的方式。这些组件可以运行在同一个进程中,也可以运行在不同的进程中。当两个不在同一个进程中的组件通过广播机制来传递消息的时候,广播机制就有点类似Binder进程间通信机制。事实上,广播机制就是在Binder机制的基础上实现的。

既然如此,Android系统为什么还需要广播机制呢?我们知道,在Binder进程间通信机制中,Client组件在好Service组件通信之前,必须要先获得它的一个代理对象,即Client组件实现要知道Service组件的存在。然而,在广播机制中,广播发送者事先并不需要知道广播接收者的存在,这样就可以降低广播发送者和广播接收者之间的耦合度,进而提高系统的可扩展性。因此, Android系统需要提供广播机制。

广播机制是一种基于消息发布和订阅的事件驱动模型,即广播发送者负责发布消息,而广播接受者需要先订阅消息,然后才能接收到消息。Android系统将广播接收者抽象为一种Boradcast Receiver组件,它是Android应用程序的四大组件之一。同时,Android应用程序的另外两种组件,即Activity组件和Service组件被赋予了发送广播的能力。因此,在Android系统中,使用广播机制在组件之间传递消息是很方便的。

广播机制存在一个注册中心,它是由ActivityManagerService来担当的。广播接收者订阅消息的表现形式就是将自己注册到ActivityManagerService中,并且指定要接收的广播类型。当广播发送者向广播接收者发送一个广播时,这个广播首先发送到ActivityManagerService然后ActivityManagerService根据这个广播的类型找到相应的广播接收者,最后将这个广播发送给他们处理。

广播接收者的的注册方式分为静态注册和动态注册两种方式。在静态注册方式中,用来描述广播接收者的Boradcast Receiver组件必须要在配置文件 AndroidManifest.xml中注册他们所感兴趣的广播类型,以便ActivityManagerService可以找到他们。在动态注册方式中。我们需要在代码中手动的调用 Context接口的成员函数registerReceiver将Boradcast Receiver组件注册到 ActivityManagerService中,Activity组件和Service组件都实现了Context接口,因此,我们可以方便的在一个Activity组件或者Service组件中注册一个Boradcast Receiver组件。同等情况下,动态注册的广播接收者要比静态注册的广播接收者优先接收到广播。

广播的发送方式分为有序和无序两种。我们在注册广播接收者时,可以指定它们的优先级。当ActivityManagerService接收有序
广播时,它就会先将这个有序广播发送给符合条件的,优先级较高的广播接收者处理,然后再发送给符合条件的,优先级较低的广播接收者处理,而当 ActivityManagerService 接收无序广播时,他就会忽略广播接收者的优先级,并行的将无序广播发送给所有符合条件的广播接收者处理。

二 广播机制应用实例

在前面的 Service组件分析实例中,我们开发了一个应用程序 Counter,它由一个Activity组件Counter和一个Service组件
CounterService组成。Counter组件在启动CounterService组件的计数器时,需要指定一个计数器回调接口 ICounterCallback,
以便 CounterService组件可以将计数器的当前计数实时的更新到Counter组件的用户界面上。这种数据更新方式存在一定的缺陷,因为这会使得CounterService组件依赖于Counter组件提供的计数器回调接口ICounterCallback。

本文开发一个名称为 Broadcounter的应用程序,它实现的功能与应用程序Counter是一样的,不过它使用广播机制来代替计数器回调接口ICounterCallback,使得CounterService组件不必依赖于Counter组件

应用程序Broadcounter的目录结构如下:

Android/packages/apps/Broadcounter

------AndroidManifest.xml
------Android.mk
------src
	------com/android/broadcounter
			------ICounterService.java
			------CounterService.java
			------Broadcounter.java
------res
	------layout
			------main.xml
	------values
			------strings.xml
	------drawable
			------icon.png

ICounterService

定义一个计数器接口ICounterService,用来启动和停止计数器。在启动计数器的时候,我们只需要指定计数器的初始值即可
而不必指定计数器回调接口。

package com.android.broadcounter;

public interface ICounterService {
	
	public void startCounter(int initVal);
	public void stopCounter();
}

CounterService.java

package com.android.broadcounter;
	 
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class CounterService extends Service implements ICounterService {
	
private final static String LOG_TAG = "com.android.broadcounter.CounterService";

public final static String BROADCAST_COUNTER_ACTION = "com.android.broadcounter.COUNTER_ACTION";
public final static String COUNTER_VALUE = "com.android.broadcounter.counter.value";

private boolean stop = false;
private final IBinder binder = new CounterBinder();

public class CounterBinder extends Binder {
		public CounterService getService() {
				return CounterService.this;
			}
	}
	
public IBinder onBind(Intent intent) {
		return binder;
	}
	
@Override
public void onCreate() {
		super.onCreate();
		Log.i(LOG_TAG, "Counter Service Created");
	}
	
public void startCounter(int initVal) {
		
		AsyncTask task = new AsyncTask (){
				@Override
				protected Integer doInBackground(Integer... vals) {
						Integer initCounter = vals[0];
						
						stop = false;
						while(!stop){
								publishProgress(initCounter);
								
								try{
										Thread.sleep(1000);
									}catch(InterruptedException e) {
											e.printStackTrace();
									}
										
									initCounter++;	
							}
							
							return initCounter;
					}
					
				@Override	
				protected void onProgressUpdate(Integer... values){
						super.onProgressUpdate(values);
						
						int counter = values[0];
						Intent intent = new Intent(BROADCAST_COUNTER_ACTION);
						intent.putExtra(COUNTER_VALUE, counter);
						sendBroadcast(intent);
					}
				
				@Override	
				protected void onPostExecute(Integer val){
						int counter = val;
						Intent intent = new Intent(BROADCAST_COUNTER_ACTION);
						intent.putExtra(COUNTER_VALUE, counter);
						
						sendBroadcast(intent);
					}
				
			};
			
			task.execute(initVal);
}	
	
	public void stopCounter() {
			stop = true;
		}
}

该部分实现了一个CounterService组件,他也是通过异步任务(AsyncTask)来提供计数功能,并且该CounterService组件是通过
广播的形式将计数器的当前计数实时的更新打到Counter组件的用户界面上的。

在计数器的执行过程中,即在异步任务task的成员函数onProgressUpdate()函数中,CounterService组件会先将计数器的当前
计数值写入到一个类型为 BROADCAST_COUNTER_ACTION 的广播中,接着再调用其父类ContextWrapper的成员函数sendBroadcast()将这个广播发送出去,以便Counter组件可以接收到这个广播,并且获得里面的计数值。

同样,在计数器停止执行时,即在异步任务task的成员函数onPostExecute()中,CounterService组件也会先将计数器的最后计数值写入到一个类型为BROADCAST_COUNTER_ACTION 的广播中,接着再调用其父类ContextWrapper的成员函数sendBroadcast()将这个广播发送出去,以便Counter组件可以接收到这个广播,并且获得里面的计数值。

Broadcounter.java

package com.android.broadcounter;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Broadcounter extends Activity implements OnClickListener {
	private final static String LOG_TAG = "com.android.broadcounter.Broadcounter";

private Button startButton = null;
private Button stopButton = null;
private TextView counterText = null;

private ICounterService counterService = null;

@Override	
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	
	startButton = (Button)findViewById(R.id.button_start);	
	stopButton = (Button)findViewById(R.id.button_stop);	
	counterText = (TextView)findViewById(R.id.textview_counter);
	
	startButton.setOnClickListener(this);
	stopButton.setOnClickListener(this);
	
	startButton.setEnabled(true);
	stopButton.setEnabled(false);
	
	Intent bindIntent = new Intent(Broadcounter.this, CounterService.class);
	bindService(bindIntent,ServiceConnection , Context.BIND_AUTO_CREATE);
	
	Log.i(LOG_TAG, "Broadcounter Activity Created");
		
	}
	
@Override		
public void onResume(){
	super.onResume();
	IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);
	registerReceiver(counterActionReceiver, counterActionFilter);
}	

@Override		
public void onPause(){
	super.onPause();
	unregisterReceiver(counterActionReceiver);
}	
	
	
@Override	
public void onClick(View v) {
	
	if(v.equals(startButton)) {
			if(counterService != null) {
					counterService.startCounter(0);
					startButton.setEnabled(false);
					stopButton.setEnabled(true);
				}
		}else if(v.equals(stopButton)) {
			if(counterService != null) {
					counterService.stopCounter();
					startButton.setEnabled(true);
					stopButton.setEnabled(false);
					
				}
			}
	}	
	
private ServiceConnection ServiceConnection  = new ServiceConnection() {
	
		public void onServiceConnected(ComponentName className, IBinder service) {
				counterService = ((CounterService.CounterBinder)service).getService();
				
				Log.i(LOG_TAG, "Counter Service Connected");
			}
			
		public void onServiceDisconnected(ComponentName className) {
			counterService = null;
			Log.i(LOG_TAG, "Counter Service Disconnected");
			}
	};
	
	
private BroadcastReceiver counterActionReceiver = new BroadcastReceiver() {
	public void onReceive(Context context, Intent intent) {
			int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);
			String text = String.valueOf(counter);
			counterText.setText(text);
		}
		
	};

}

此处代码实现了一个 Broadcounter组件,它在启动时,回调用bindService()来绑定 CounterService组件,以便可以获得它的
一个访问接口。并且这个Broadcounter组件是通过一个广播接收者来获得 CounterService组件内部的计数器的当前计数值。

Broadcounter组件在内部定义了一个广播接收者 counterActionReceiver,它是用来接收类型为 BROADCAST_COUNTER_ACTION 的广播的,以便可以获得CounterService组件的计数器的当前计数值,并且将它显示在用户界面上。

当 Broadcounter组件被激活时,即在它的成员函数onResume()中,它会调用其父类 ContextWrappe的成员函数registerReceiver()将广播接收者 counterActionReceiver 注册到 ActivityManagerService中,并且指定要接收的广播类型为 BROADCAST_COUNTER_ACTION

当Boradcounter组件被中止时,即在他的成员函数 onPause() 中,他会调用其父类 ContextWrappe的成员函数unregisterReceiver()来注销前面所注册的广播接收者counterActionReceiver,这亚航他就不会再接收到类型为 BROADCAST_COUNTER_ACTION的广播了。

main.xml






		    
			
			
			
			
			
						
		
				
		

strings.xml



	Broadcounter
	Counter:
	0
	Start Counter
	Stop Counter

AndroidManifest.xml



	
	
			
		
			
				
				
			
		
		
		
		
		
	

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := My_Broadcounter
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

build/target/product/core.mk 中添加 My_Broadcounter

mmm packages/apps/Broadcounter/

Broadcast组件简析_第1张图片

你可能感兴趣的:(Android系统分析篇)