观察者模式是一种使用非常多,也非常有用的一种设计模式。该模式有2种对象,一种是被观察者,一种是观察者。被观察者是唯一的,观察者可以有多个,是一种一对多的关系。举个例子,好比我们去追一部正在更新的电视剧,这部电视剧就是我们被观察者而追电视剧的人就是观察者,如何在电视剧更新的时候追电视剧的人第一时间知道就是观察者模式需要解决的这类问题。在安卓中使用观察中是非常简单的,因为这两种对象Google已经帮我们分装好类了,我们只需要直接用就可以了,下面是分装好的两个类及常用的方法。
Observer(观察者),是一个接口类,只需要重写update方法就可以了,该方法在被观察者通知观察者数据改变时调用。
Observerable(被观察者),是一个类,常用的方法如下:
setChanged():数据改变时调用。
addObserver():添加观察者时调用。
下面我们就来使用者两个类演示一个示例,示例的效果是这样的,我们用观察者去观察一个图片下载的过程,如果图片下载完成就通知观察者去更新imageview上面的图片。
首先新建一个类继承Observerable类,里面代码如下:
~~~
public class MyObserverable extends Observable {
// 数据改变时调用
@Override
protected void setChanged() {
super.setChanged();
Log.e("", "数据改变了!");
}
// 添加观察者时调用
@Override
public void addObserver(Observer observer) {
super.addObserver(observer);
Log.e("", "新增加了一个观察者!");
}
}
~~~
MainActivity类实现Observer接口,重写update方法,update里的代码如下:
~~~
@Override
public void update(Observable observable, Object data) {
// 将下载的图片显示到ImageView上面
imgv.post(new Runnable() {
@Override
public void run() {
imgv.setImageBitmap(bm);
}
});
}
~~~
Activity布局文件如下:
~~~
<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:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下载图片" />
<ImageView
android:id="@+id/imgv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/btn"
android:scaleType="centerInside"
android:src="@drawable/ic_launcher" />
</RelativeLayout>
~~~
给按钮添加一个监听事件,代码如下:
~~~
// 下载图片
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setReadTimeout(5 * 1000);
conn.setConnectTimeout(5 * 1000);
// 将输入流转换为图片
bm = BitmapFactory.decodeStream(conn.getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 设置数据改变
observerable.setChanged();
// 通知观察者
observerable.notifyObservers();
}
}).start();
}
});
~~~
点击按钮去下载一张图片,记得添加网络访问权限,在oncreate方法里面我们做如下工作:
~~~
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化observerable对象
observerable = new MyObserverable();
// 将自己添加到观察队列中
observerable.addObserver(this);
init();
}
~~~
完整的MainActivity代码如下:
~~~
public class MainActivity extends Activity implements Observer {
private ImageView imgv;
private Button btn;
private MyObserverable observerable;
private Bitmap bm;
private String url = "http://cdn.duitang.com/uploads/item/201409/05/20140905015324_zvwG2.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化observerable对象
observerable = new MyObserverable();
// 将自己添加到观察队列中
observerable.addObserver(this);
init();
}
private void init() {
imgv = (ImageView) findViewById(R.id.imgv);
btn = (Button) findViewById(R.id.btn);
// 下载图片
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setReadTimeout(5 * 1000);
conn.setConnectTimeout(5 * 1000);
// 将输入流转换为图片
bm = BitmapFactory.decodeStream(conn.getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 设置数据改变
observerable.setChanged();
// 通知观察者
observerable.notifyObservers();
}
}).start();
}
});
}
@Override
public void update(Observable observable, Object data) {
// 将下载的图片显示到ImageView上面
imgv.post(new Runnable() {
@Override
public void run() {
imgv.setImageBitmap(bm);
}
});
}
}
~~~
MainActivity类实现观察者接口,将自己添加到观察队列中,点击按钮下载图片,下载完成使用被观察者通知观察者更新UI,下面来看运行效果:
![](https://box.kancloud.cn/2016-03-18_56eb6b9d6dc9f.jpg)
**输出的Log:**
![](https://box.kancloud.cn/2016-03-18_56eb6b9d98cce.jpg)
最后有一个注意的问题,update方法并不是运行在主线程中而是在notifyObservers调用的线程中运行。附上下载demo:[demo](http://download.csdn.net/detail/qq379454816/9333855)