26設計模式之觀察者模式


觀察者模式是一種使用非常多,也非常有用的一種設計模式。該模式有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,下面來看運行效果:

輸出的Log:


掃描關注我的微信公衆號:



最後有一個注意的問題,update方法並不是運行在主線程中而是在notifyObservers調用的線程中運行。附上下載demo:demo


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章