本篇为大家介绍一下观察者模式。
这里不会再画那些无聊的关系图,类图。因为观察者模式非常简单,那些图网上到处都是,连百度百科都已经有很长的内容了。
简单的说一下逻辑:当某事件(Event)被任何地方触发的时候,这个事件的所有监听者(Listener),都会触发监听器。
当然,这个事件也可能没有一个监听者,但他并不关心这个。
先来看看公共处理逻辑类
package com.chenjian.observer;
import android.content.Intent;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ChenJian
* 2016.8.3 16:48:48.
*/
public class SystemEvent {
private static Map<SystemEventConst, ArrayList<SoftReference<EventListener>>> mEventMap = new HashMap<>();
public static void release() {
if (mEventMap != null) {
for (Map.Entry<SystemEventConst, ArrayList<SoftReference<EventListener>>> entry : mEventMap.entrySet()) {
if (entry.getValue() != null) {
entry.getValue().clear();
}
}
mEventMap.clear();
mEventMap = null;
}
}
public interface EventListener {
void onEvent(SystemEventConst eventType, Intent data);
}
public synchronized static boolean addListener(SystemEventConst eventType, EventListener eventListener) {
if (mEventMap == null) {
return false;
}
ArrayList<SoftReference<EventListener>> list = mEventMap.get(eventType);
if (list == null) {
list = new ArrayList<>();
}
for (SoftReference<EventListener> softListener : list) {
if (softListener != null) {
EventListener sEventListener = softListener.get();
if (sEventListener != null && sEventListener == eventListener) {
return false;
}
}
}
SoftReference<EventListener> listener = new SoftReference<>(eventListener);
list.add(listener);
mEventMap.put(eventType, list);
return true;
}
public synchronized static void removeListener(SystemEventConst eventType, EventListener listener) {
ArrayList<SoftReference<EventListener>> list = mEventMap.get(eventType);
if (null == list) {
return;
}
for (int i = 0; i < list.size(); i++) {
EventListener l = list.get(i).get();
if (l == listener) {
list.remove(i);
break;
}
}
}
public synchronized static void removeListener(SystemEventConst eventType) {
mEventMap.remove(eventType);
}
public synchronized static void fireEvent(SystemEventConst eventType, Intent data) {
ArrayList<SoftReference<EventListener>> list = mEventMap.get(eventType);
if (list != null) {
for (int i = 0; i < list.size(); i++) {
EventListener listener = list.get(i).get();
if (listener != null) {
listener.onEvent(eventType, data);
}
}
}
}
public synchronized static void fireEvent(SystemEventConst eventType) {
fireEvent(eventType, null);
}
}
这个类中,保存着一个map,key为事件类型,value是这个事件所对应的监听器列表。
本类中也包含了一些添加删除监听器的方法,同样也有触发事件的方法。
触发事件时,可以不带参数,带参数的话,这里选择的是Intent类型,我不用Map而用Intent,因为个人感觉Intent更符合Android的数据传递思想。
再来看看事件类型,SystemEventConst类
package com.chenjian.observer;
/**
* Created by ChenJian
* 2016.8.3 16:48:48.
*/
public enum SystemEventConst {
/**
* 总金额变化
*/
EVENT_TOTAL_MONEY_CHANGE,
}
是一个枚举类型,里面可以定义自己想要的事件。
再来看看使用
主界面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/tv_main_money"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/money" />
<Button
android:id="@+id/btn_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="@string/button" />
</LinearLayout>
代码
package com.chenjian.observer;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements SystemEvent.EventListener {
private TextView mMoneyTextView;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findView();
setListener();
}
@Override
protected void onDestroy() {
super.onDestroy();
SystemEvent.removeListener(SystemEventConst.EVENT_TOTAL_MONEY_CHANGE, this);
}
private void findView() {
mMoneyTextView = (TextView) findViewById(R.id.tv_main_money);
mButton = (Button) findViewById(R.id.btn_main);
}
private void setListener() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, OtherActivity.class));
}
});
SystemEvent.addListener(SystemEventConst.EVENT_TOTAL_MONEY_CHANGE, this);
}
@Override
public void onEvent(SystemEventConst eventType, Intent data) {
switch (eventType) {
case EVENT_TOTAL_MONEY_CHANGE:
mMoneyTextView.setText(data.getAction());
break;
}
}
}
TextView上显示金额,按钮点击后跳转到另一个界面。
这里使用到了观察者模式,在一开始的时候,注册了监听器,在事件发生的时候,改变金额的值。
要非常注意的是:在监听者被销毁不再使用的时候,要把自己从监听器列表中删除掉
再来看看OtherActivity
package com.chenjian.observer;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
/**
* 作者: ChenJian
* 时间: 2016.12.28 10:42
*/
public class OtherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent("$110");
SystemEvent.fireEvent(SystemEventConst.EVENT_TOTAL_MONEY_CHANGE, intent);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
}
触发事件,并带上金额的参数,三秒后退出。
看看前后界面显示
Android中观察者模式还是相对常用的,比如本例,在主界面或者其它页面都可能显示着用户的个人信息,金额昵称之类的,在详情页或者修改页去做修改后,通知相关页面做出修改。如果使用BrocastReceiver或者全局变量,就显得非常的麻烦。
源码下载点击打开链接