Android组件之间的通信方式
**学习Android也有一段时间了,有很多总结,一直没整理。想起来的时候懒得整理,想整理的时候又懒得去想。今天总结下四大组件之间的通信方式。如若有不足和错误,欢迎指正补充^_^。
对于Android的组件Activity, Service, ContentProvider和Service,Setter和Getter在这里是没有用的。开发者只能实现其规定的回调接口,组件的创建与销毁都是由系统框架控制的,开发者不能强行干预,更没有办法获取组件的对象。这也决定了,组件之间通信只能用系统支持的Intent。而Intent只能传递基本数据类型和Uri等一些常见的数据类型。Intent只支持传递内置类型和一些限制类型,这就导致了组件之间的数据传递必须都是基本类型,所以枚举类型无法使用。
- Activity之间的回调
这种startActivity或者startActivityForResult通信方式,局限性很大,。
现有两个Activity :A和B,顺序是A->B.传递数据的通信方式就是Intent,没什么好说的,要想从B向A传递数据。需要回调,就是常用的startActivityForResult / onActivityResult / setResult 组合。
提到这类函数组合,相信只要有过一段时间Android开发的来说都很熟悉了,此函数组合主要用于如下场景:用户在A Activity上点击某个按钮,跳转到B Activity,然后用户在B Activity上进行一些具体的操作,待操作完成后返回到A Activity,同时常常将B Activity中操作的一些数据返回到A Activity中。
再如上场景中,A -> B 需要通过startActivityForResult()方式打开。具体方式如下:
在A 中:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(AActivity.this, BActivity.class);
startActivityForResult(intent, 1);
}
});
其中,startActivityForResult第一个参数为Intent,因此,对于需要传递额外参数时,可以通过Intent直接传递。其中Bundle为可选参数。第二个参数为requestCode,即业务请求码。
在B中:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(RESULT_OK, intent);
finish();
}
});
在处理完或相应完用户操作后,自身结束前,需要通过setResult将数据回传给A。
接下来A接手B回传的数据。在A中:
@Override
protected void onActivityResult(int requestCode, int resultCode,Intent intent) {
//获取从B Activity回调的intent数据。
}
- 广播通信方式
广播通信是我们经常用的方式,可以跨应用传递,也是Android里面的标准方法,可以算是观察者模式的一种实现方式。
缺点:无法传递复杂数据,必须通过bundle来传递
主要流程为:
- 1、广播接收者BroadcastReceiver通过Binder机制向AMS(Activity ManagerService)进行注册;
- 2、广播发送者通过binder机制向AMS发送广播;
- 3、AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到
BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中; 4、消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。
使用方式就不罗嗦了
- 基于观察者模式的通信方式
定义对象间的一种一个(Subject)对多(Observer)的依赖关系,当一个对象的状态发送改变时,所以依赖于它的 对象都得到通知并被自动更新
Observer模式要解决的问题为:
建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候, 依赖这个“一”的多也能够同步改变。最常见的一个例子就是:对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。 这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。 Observer模式就是解决了这一个问题。
适用性:
1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面 将这两者封装成独立的对象中以使它们可以各自独立的改变和服用
2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
观察者需要四个对象:
1. Subject(目标)
目标知道它的观察者,可以有任意多个观察者观察同一个目标 提供注册和删除观察者对象的接口
2. Observer(观察者)
为那些在目标发生改变时需获得通知的对象定义个更新的接口
3. ConcreteSubject(具体目标)
将有关状态存入各ConcreteObserver对象,当它的状态发送改变时,向它的各个观察者发出通知
4. ConcreteObserver(具体观察者)
维护一个指向ConcreteObserver对象的引用 存储有关状态,这些状态应与目标的状态保持一致 实现Observer的更新接口是自身状态与目标的状态保持一致
简单示例:
1.定义抽象的观察者接口:
public interface ObserverInterface {
/**
* 根据事件进行数据或者UI的更新
* @param message
*/
public void dispatchChange(String message);
}
2.定义观察者接口实现:
public abstract class Observer implements ObserverInterface{
private Handler mHandler;
public Observer(){
mHandler=new Handler(Looper.getMainLooper());
}
public abstract void onChange(String message);
@Override
public void dispatchChange(String message){
mHandler.post(new NotificationRunnable(message));
}
private final class NotificationRunnable implements Runnable{
private String message;
public NotificationRunnable(String message){
this.message=message;
}
@Override
public void run() {
Observer.this.onChange(message);
}
}
}
3.定义抽象的目标角色,即抽象的被观察者,在其中声明方法(添加、移除观察者,通知观察者):
public interface SubjectInteraface {
/**
* 注册观察者
* @param observer
*/
public void registerObserver(Observer observer);
/**
* 反注册观察者
* @param observer
*/
public void removeObserver(Observer observer);
/**
* 通知注册的观察者进行数据或者UI的更新
*/
public void notifyObserver(String message);
}
4.定义抽象目标接口实现:
public class Subject implements SubjectInteraface {
private List<Observer> mEventObservers=new ArrayList<Observer>();
private static volatile Subject mEventSubject;
private Subject(){
}
public synchronized static Subject getInstance(){
if(mEventSubject ==null){
mEventSubject =new Subject();
}
return mEventSubject;
}
@Override
public void registerObserver(Observer observer) {
synchronized (mEventObservers){
if(observer!=null){
if(mEventObservers.contains(observer)){
return;
}
mEventObservers.add(observer);
}
}
}
@Override
public void removeObserver(Observer observer) {
synchronized (mEventObservers){
int index = mEventObservers.indexOf(observer);
if (index >= 0) {
mEventObservers.remove(observer);
}
}
}
@Override
public void notifyObserver(String message) {
if(mEventObservers!=null && mEventObservers.size()>0 && message!=null){
for(Observer observer:mEventObservers){
observer.dispatchChange(message);
}
}
}
}
5.定义观察者模式的Activity:
/**
* 观察者模式的Activity。
* Created by 2014 on 2015/9/2.
*/
public abstract class BaseActivity extends ActionBarActivity {
private ActivityObserver mActivityObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityObserver=new ActivityObserver(this);
registerObserver(mActivityObserver);
}
@Override
protected void onDestroy() {
super.onDestroy();
removeObserver(mActivityObserver);
}
/**
* 注册为观察者
* @param observer
*/
public void registerObserver(Observer observer) {
final Subject eventSubject=Subject.getInstance();
eventSubject.registerObserver(observer);
}
/**
* 反注册观察者
* @param observer
*/
public void removeObserver(Observer observer) {
final Subject eventSubject=Subject.getInstance();
eventSubject.removeObserver(observer);
}
/**
* 该方法会在具体的观察者对象中调用,可以根据事件的类型来更新对应的UI,这个方法在UI线程中被调用,
* 所以在该方法中不能进行耗时操作,可以另外开线程
* @param message 事件类型
*/
protected abstract void onChange(String message);
private static class ActivityObserver extends Observer {
//添加弱引用,防止对象不能被回收
private final WeakReference<BaseActivity> mActivity;
public ActivityObserver(BaseActivity activity){
super();
mActivity=new WeakReference<BaseActivity>(activity);
}
@Override
public void onChange(String message) {
BaseActivity activity=mActivity.get();
if(activity!=null){
activity.onChange(message);
}
}
}
}
最后贴一个简单的使用示例:
第一个Activity:(被观察者):
public class FirstActivity extends ActionBarActivity {
private Button notifyButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
notifyButton=(Button) findViewById(R.id.NotifyButton);
notifyButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//通知所有观察者,给所有观察者发出消息
Subject sb=Subject.getInstance();
sb.notifyObserver("Hi,this is a message ! ");
}
});
}
}
第二个Activity:(观察者):
public class SecondActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
@Override
protected void onChange(String message) {
System.out.println("SecondActivity Received Message:"+message);
}
}
- 基于 发布/订阅者 模式的通信方式
发布/订阅简称(Pub/Sub)模式,这种模式是观察者observer的一种变体。发布者主要是负责向外发送消息,S订阅者主要是订阅接收消息。主要用于“只负责传递消息,并不关心其他订阅者已经收到这个消息”.和广播通信非常相似。我们常用的发布订阅模式是EventBus框架.
优点:代码简洁优雅,大大降低了耦合性。简化了应用程序内各组件间、组件与后台线程间的通信。
缺点:无法进程间通信,如果一个应用内有多个进程的话就没办法了,无法跨应用传递事件。在组件之间通信非常频繁复杂繁琐的时候,会需要很多不同通信的消息Event实体 , EventBus的缺点也就暴露出来了,此时代码维护也很变得不容易了,显得混乱。
- 1、初始化时注册EventBus.getDefault().register(this);
- 2、用完之后注销EventBus.getDefault().unregister(this);
- 3、中间过程主要就是消息推送和接收,通过EventBus.getDefault().post(param)推送,通onEventMainThread(param),onEventPostThread(param),onEventBackgroundThread(param),onEventAsync(param)接收并处理。
首先定义消息Event实体
public Class MessageEvent{
private int xxx;
private String xxx;
//getter和setter方法
}
发布者:可以在任意组件中发布消息:EventBus.getDefault().post(new MessageEvent());
接收方:要想接受到消息,必须注册:
@Override
public void onCreate(Bundle savedInstanceState) {
EventBus.getDefault().register(this);
}
接受消息处理,有四种ThreadMod:
- PostThread:事件的处理在和事件的发送在相同的进程,这是默认的模式。当事件处理比较简单,不涉及主线程的UI更新时候,推荐使用。如果事件处理需要很长时间,会阻塞主线程也就是发送线程,对应的函数名是onEventPostThread。
- MainThread: 事件的处理会在UI线程中执行。事件处理时间不能太长,否则会阻塞主线程,对应的函数名是onEventMainThread。
- BackgroundThread:事件的处理会在一个后台线程中执行,事件处理是在后台线程,但事件处理时间还是不应该太长,因为如果发送事件的线程是后台线程,会直接执行事件,如果当前线程是UI线程,事件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。对应的函数名是onEventBackgroundThread。
- Async:事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。对应的函数名是onEventAsync。
public void onEventMainThread(MessageEvent mfe) {
String newData = mfe.getXXX();
button.setText(newData );
}
最后在在Ondestory()中取消订阅
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}