1. 程式人生 > >觀察者模式在Android中的應用

觀察者模式在Android中的應用

觀察者模式在實際使用中是非常方便的,簡單來說就是當一個數據源(即被觀察者)的資料發生了變動,將自動通知到所有對應的觀察者,此時觀察者可以根據接收到的通知資訊針對資料變動作出相應調整。

舉個簡單的在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的介面,自定義我們自己的被觀察者類:
package 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();
		}
	}
}
注意程式碼上面,記錄觀察者Observer的列表使用了static修飾,同時增加了兩各靜態方法GlobalAddObserverGlobalDeleteObserver

這是為了在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);

效果如下圖所示:


該例子的下載地址如下: