觀察者模式在Android中的應用
阿新 • • 發佈:2019-02-19
觀察者模式在實際使用中是非常方便的,簡單來說就是當一個數據源(即被觀察者)的資料發生了變動,將自動通知到所有對應的觀察者,此時觀察者可以根據接收到的通知資訊針對資料變動作出相應調整。
舉個簡單的在Android上的例子,我使用一個Service在後臺進行時間倒計時,而我需要在多個Activity上同步顯示該倒計時的資訊。那麼,Service上的倒計時功能即為被觀察者(Observable),而這多個Activity則為觀察者(Observer)。
Java自身帶有Observable和Observer的介面,我們也可以自己自定義實現Observable和Observer,但是這就要求我們自己在Observable中維護Observer的列表。
首先,我們定義好觀察者Observer的介面:
package com.vite.testobserver.observer.ifc;
/**
* 觀察者介面
*
* @author trs
*
*/
public interface Observer {
void update(Object data);
}
然後定義被觀察者Observable的介面:
package com.vite.testobserver.observer.ifc; /** * 被觀察者介面 * * @author trs * */ public interface Observable { /** * 新增觀察者 * * @param observer */ public void addObserver(Observer observer); /** * 刪除觀察者 * * @param observer */ public void deleteObserver(Observer observer); /** * 刪除所有觀察者 */ public void deleteObservers(); /** * 通知所有觀察者 * * @param data */ public void notifyObservers(Object data); /** * 通知所有觀察者 */ public void notifyObservers(); /** * 獲取觀察者數量 * * @return */ public int getCountObservers(); }
然後通過繼承Observable的介面,自定義我們自己的被觀察者類:
注意程式碼上面,記錄觀察者Observer的列表使用了static修飾,同時增加了兩各靜態方法GlobalAddObserver和GlobalDeleteObserverpackage com.vite.testobserver.observer; import java.util.ArrayList; import java.util.List; import com.vite.testobserver.observer.ifc.Observable; import com.vite.testobserver.observer.ifc.Observer; /** * 自定義被觀察者 * * @author trs * */ public class TimeCountObservable implements Observable { private static List<Observer> observerList = new ArrayList<Observer>(); public static void GlobalAddObserver(Observer observer) { if (observerList == null) throw new NullPointerException(); if (observer == null) throw new NullPointerException(); synchronized (observerList) { if (!observerList.contains(observer)) observerList.add(observer); } } public static void GlobalDeleteObserver(Observer observer) { if (observerList == null) throw new NullPointerException(); if (observer == null) throw new NullPointerException(); synchronized (observerList) { if (observerList.contains(observer)) observerList.remove(observer); } } @Override public synchronized void addObserver(Observer observer) { // TODO Auto-generated method stub if (observerList == null) throw new NullPointerException(); if (observer == null) throw new NullPointerException(); synchronized (observerList) { if (!observerList.contains(observer)) observerList.add(observer); } } @Override public synchronized void deleteObserver(Observer observer) { // TODO Auto-generated method stub if (observerList == null) throw new NullPointerException(); if (observer == null) throw new NullPointerException(); synchronized (observerList) { if (observerList.contains(observer)) observerList.remove(observer); } } @Override public synchronized void deleteObservers() { // TODO Auto-generated method stub if (observerList == null) throw new NullPointerException(); synchronized (observerList) { observerList.removeAll(observerList); } } @Override public void notifyObservers(Object data) { // TODO Auto-generated method stub if (observerList == null) throw new NullPointerException(); synchronized (observerList) { for (Observer observer : observerList) { observer.update(data); } } } @Override public void notifyObservers() { // TODO Auto-generated method stub notifyObservers(null); } @Override public int getCountObservers() { // TODO Auto-generated method stub if (observerList == null) throw new NullPointerException(); synchronized (observerList) { return observerList.size(); } } }
這是為了在Service以外的地方動態新增和刪除觀察者,寫得比較簡單粗暴,在實際應用過程中我們也可以根據需求進行不同的自定義。
然後,通過對Activity實現觀察者Observer介面中的updata方法,並將自身通過GlobalAddObserver加入到觀察者列表中。
這樣,在後臺Service裡的倒計時功能中呼叫notifyObservers方法,通知所有在觀察者列表中的觀察者,並將資料傳遞到updata方法中,就完成了一次資料更新。
private class TimeCountDownTimer extends CountDownTimer {
public TimeCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
@Override
public void onFinish() {
// TODO Auto-generated method stub
timeCountObservable.notifyObservers("00:00");
if (timer != null)
timer.cancel();
timer = null;
}
@Override
public void onTick(long millisUntilFinished) {
// TODO Auto-generated method stub
Date date = new Date(millisUntilFinished);
timeCountObservable.notifyObservers(df.format(date));
}
}
一般而言這樣就可以了,但是偶爾會遇到一些情況,就是某個觀察者的updata方法中耗時過長,這樣會導致排在該觀察者後面的其餘觀察者的無法及時更新資料。針對這個問題,我們可以用Handler來進行非同步處理。
通過實現Observer介面,我們自定義一個可以非同步處理的TimeCountObserver:
package com.vite.testobserver.observer;
import android.os.Handler;
import com.vite.testobserver.observer.ifc.Observer;
public abstract class TimeCountObserver implements Observer {
private Handler handler;
private Object object;
public TimeCountObserver(Handler handler) {
this.handler = handler;
}
public abstract void onUpdate(Object data);
@Override
public void update(Object data) {
// TODO Auto-generated method stub
object = data;
if (handler == null)
onUpdate(object);
else
handler.post(new LocalRunnable());
}
private class LocalRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
onUpdate(object);
}
}
}
然後在Activity中就無需實現Observer介面,而是例項化TimeCountObserver,並且通過onUpdate方法更新資料:
timeCountObserver = new TimeCountObserver(new Handler()) {
@Override
public void onUpdate(Object data) {
// TODO Auto-generated method stub
content.setText(data.toString());
}
};
TimeCountObservable.GlobalAddObserver(timeCountObserver);
效果如下圖所示:
該例子的下載地址如下: