一:前言
最近在遇到了Android的开发中常用到的设计模式之观察者模式,观察者模式,所谓的模式就是一种设计思想,可以按照某种模式,写出更合理,简单,有效的代码。可以用在Android开发中,也可以用在Java,C#等等开发中,就类似单例模式,代理模式,模版等等。
二:什么是观察者模式
个人理解所谓的观察者模式,打个比喻,就好比,老师在教室上课,学生在教室听课,这里的老师就是被观察者,而这时候的在听课的学生就是观察者,老师通过说话,来传递知识,老师每说一个知识,学生都会实时做出相应的反映。这就是所谓的观察者模式,也有人理解为事件的订阅,再以事件的订阅打个比喻,假设现在有个Android授课老师在讲课,有想学习Android的学生想实时的学习到新的Android知识,那怎么办,没错那就是必须的关注这个老师,你才能实时的获取到最新的Android知识,这里的关注就是,关注的过程就是事件的订阅。(个人理解,有什么不的对的地方,欢迎指教)
三:举例说明
我们这里用实际的需求来说明下.
需求:现在有学生A(也就是Activity) 去回答老师提出的问题,最后有老师,告诉学生是否回答正确,如果回答正确的学生,开心的笑了,不正确学生表现很沮丧。(也就是跳转到B Activity,去回答问题,最后提交,服务器将答题结果发布,A Activity接收结果,根据结果做出一些操作)
四:具体代码实现
1.这里我们先定义一个被观察者,也就是老师类。
package com.zhang.zs.zhangtest;
import java.util.Observable;
/**
* Created by zs on 2016/11/12.
* 老师类,老师就是给自己的学生传播知识,让自己的学生收益。
* 这里老师就好像是一个消息的发送者,可以认为,老师就是被观察者
* 这里继承系统的Observable类
* name_ok.由于在同一时间段,只能有一个老师给学生传递知识,所以我们要把老师类(被观察者,事件发送源)
* 对象设计成单例模式
*/
public class Teacher extends Observable {
private Teacher() {
}
private static Teacher teacher = null;
public static Teacher getInstance() {
if (teacher == null) {
synchronized (Teacher.class) {
if (teacher == null) {
teacher = new Teacher();
}
}
}
return teacher;
}
public void postMessage(String eventtype) {
setChanged();
notifyObservers(eventtype);
}
}
这里Teacher类就是被观察者,设计成单例模式,就是为了让整个系统中只存在一个消息的发送者。
2.现在新建一个EventType类。这里定义了一些,老师具体发送了一些什么信息,
package com.zhang.zs.zhangtest;
/**
* Created by zs on 2016/11/12.
* 定义一些事件常量
*
*/
public class EventType {
public static final String RESPONSE_SUCESS="resposeok"; //回答正确
public static final String RESPONSE_FAIL="responseno"; //回答错误
}
3.老师发送消息,学生怎能接受的到呢,到底是那个学生接受到呢,就好比我是哈佛校长(校长也是老师)发布的内部消息,当然只有,哈佛学校的学生才能接受消息把,这里是有关联的,如果你想接受哈佛的消息怎么办,想办法加入哈佛呗,这里的观察者也是一样的。首先将我们的A Activity 注册到 我们的消息的发送者中。让他知道有你这个学生。在一般开发中我们都会定义一个基类,这里我们也定义一个基类,(观察者多的话,一个一个添加多麻烦)。基类如下
package com.zhang.zs.zhangtest;
import android.app.Activity;
import android.os.Bundle;
import java.util.Observable;
import java.util.Observer;
/**
* Created by zs on 2016/11/12.
*/
public class BaseActivity extends Activity implements Observer{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(this instanceof Observer){
//将要接收消息的学生添加
Teacher.getInstance().addObserver(this);
}
}
//接受到消息的回调方法,就是学生接受到消息后做出的反映
@Override
public void update(Observable observable, Object data) {
}
}
4.这时候我们来定义一个学生,(A activity)
功能:一个按钮,一个显示图片的控件,点击按钮,转到B activity ,图片控件,显示根据老师公布学生答题的对错的结果去显示相应的图片,
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="reply"
android:text="我要回答问题" />
<ImageView
android:id="@+id/image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
/>
</RelativeLayout>
Activity 代码;
package com.zhang.zs.zhangtest;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import java.util.Observable;
public class MainActivity extends BaseActivity {
private ImageView image;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image);
}
public void reply(View v) {
//跳转也去答题
startActivity(new Intent(this, ReplayActivity.class));
}
/**
* 根据接收到的消息去做相关的功能
* @param observable
* @param data
*/
@Override
public void update(Observable observable, Object data) {
if (data instanceof String) {
String message = (String) data;
// 接收到成功消息就显示成功的图片 ,失败就显示失败的图片
if (EventType.RESPONSE_SUCESS.equals(message)) {
image.setBackgroundResource(R.drawable.name_ok);
} else if (EventType.RESPONSE_FAIL.equals(message)) {
image.setBackgroundResource(R.drawable.name_err);
}
}
}
}
5.这里定义答题activity,根据答题结果,老师(被观察者)发出相应的消息。
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="题目一:1+1=?"
android:textSize="19sp" />
<RadioGroup
android:id="@+id/anser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<RadioButton
android:id="@+id/two"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2"
android:textSize="19sp" />
<RadioButton
android:id="@+id/three"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="3"
android:textSize="19sp" />
<RadioButton
android:id="@+id/four"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="4"
android:textSize="19sp" />
<RadioButton
android:id="@+id/five"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="5"
android:textSize="19sp" />
</RadioGroup>
<Button
android:layout_marginTop="20dp"
android:text="提交"
android:onClick="response"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
想用activity代码:
package com.zhang.zs.zhangtest;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioGroup;
import android.widget.Toast;
public class ReplayActivity extends BaseActivity {
private RadioGroup anser;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_replay);
anser = (RadioGroup) findViewById(R.id.anser);
}
//根据消息发送消息
public void response(View view) {
int checkId = anser.getCheckedRadioButtonId();
if (checkId == R.id.two) {
// 老师发送答题成功的消息
Teacher.getInstance().postMessage(EventType.RESPONSE_SUCESS);
} else if (checkId == R.id.three || checkId == R.id.four || checkId == R.id.five) {
// 老师发送答题失败的消息
Teacher.getInstance().postMessage(EventType.RESPONSE_FAIL);
} else {
Toast.makeText(this, "请回答这个问题", Toast.LENGTH_SHORT).show();
return;
}
finish();
}
}
项目源码地址:https://github.com/sdsjk/Observable
到现在,整个需求就做完了,在重复一下,点击mainActivity中的按钮去跳转到 Bactivity去答题,答完题,点击提交按钮,会根据你的答案发送出不同的消息,这时候,Mainactivity就会接受到消息,做出相应的处理。如图