在下載模塊中經(jīng)常要用到的一個(gè)模式就是觀察者模式了,這是為了提高用戶體驗(yàn)所決定的。
但用戶在下載頁(yè)面點(diǎn)擊了下載之后,肯定希望除了這個(gè)下載頁(yè)面能看到下載進(jìn)度之外還能在其他地方看到,如通知欄等地方。
這時(shí)我們需要把下載任務(wù)進(jìn)度實(shí)時(shí)更新到各個(gè)組件或者頁(yè)面,如下載詳情頁(yè),應(yīng)用頁(yè),通知欄等地方。
實(shí)時(shí)更新下載進(jìn)度有多種方法,
1、使用廣播,在每次更新進(jìn)度的時(shí)候發(fā)廣播,當(dāng)時(shí)比較耗電
2、使用handler,在要更新進(jìn)度的時(shí)候發(fā)送message
3、使用觀察者模式,注冊(cè)觀察者,在更新進(jìn)度的時(shí)候提醒每個(gè)觀察者。
當(dāng)然,其中handler是可以結(jié)合起來(lái)使用的,因?yàn)閔andler可是實(shí)現(xiàn)線程間通信。
使用觀察者模式能夠較為便捷的通知組件更新進(jìn)度,那么改怎么使用它呢?
-
首先一個(gè)存儲(chǔ)信息的DownloadInfo類,代碼如下:
public class DownloadInfo { private int progress; public int getProgress() { return progress; } public void setProgress(int progress) { this.progress = progress; } }
這個(gè)類并不復(fù)雜,主要是存儲(chǔ)和取出下載信息
-
其次要?jiǎng)?chuàng)建觀察者接口,也就是觀察者想要得到哪些信息,在這里,觀察者要得到的信息是下載狀態(tài),觀察者接口代碼如下:
public interface DownloadObserver { // 下載進(jìn)度發(fā)生變化 public void onDownloadProgressChanged(int progress); } -
第三步是要注冊(cè)和注銷觀察者,注冊(cè)即哪個(gè)組件需要得到進(jìn)度發(fā)生改變的信息,注銷即這一個(gè)觀察者不在得到改變的信息。當(dāng)然得到觀察者對(duì)象我們要將其保存到一個(gè)集合之中,這時(shí)我們才能用for循環(huán)統(tǒng)一的通知觀察者,代碼如下:
public class DownLoadTask { private DownloadInfo info; public DownLoadTask(DownloadInfo info) { this.info = info; } private ArrayList<DownloadObserver> observers = new ArrayList<>(); public void registerObserver(DownloadObserver Observer) { if (Observer != null) { observers.add(Observer); } } public void unregisterObserver(DownloadObserver Observer) { if (Observer != null) { observers.remove(Observer); } } public void notifyAllObserver() { if (observers != null) { for (Iterator<DownloadObserver> iterator = observers.iterator(); iterator.hasNext();) { DownloadObserver observer = iterator.next(); observer.onDownloadProgressChanged(info.getProgress()); } } } }
在上面,我們將觀察者對(duì)象存到ArrayList集合中,然后在notifyAllObserver()通過(guò)遍歷的方式通知所有的觀察者對(duì)象,這時(shí)就能讓所有的觀察者獲得進(jìn)度改變的信息
這樣一來(lái),我們的觀察者的工具類已經(jīng)準(zhǔn)備好了,只需要我們調(diào)用registerObserver()注冊(cè)好觀察者,觀察者就會(huì)添加進(jìn)觀察者的集合mObservers中,當(dāng)有了觀察者的數(shù)據(jù)之后,想獲取通知就調(diào)用notifyDownloadStateChanged()或者notifyDownloadProgressChanged(),這兩個(gè)方法就將信息傳給了DownloadObserver觀察者對(duì)象中。
然后調(diào)用的時(shí)候我們僅僅是獲取了更新的數(shù)據(jù),但是我們并不知道要更新哪一個(gè)控件,這就需要一個(gè)具體的觀察者來(lái)實(shí)現(xiàn)了。
我們創(chuàng)建了三個(gè)簡(jiǎn)單的實(shí)現(xiàn)類,當(dāng)獲得進(jìn)度更新的時(shí)候就輸出進(jìn)度到控制臺(tái)上,代碼如下:
實(shí)現(xiàn)類1:
public class DeskShow implements DownloadObserver{
@Override
public void onDownloadProgressChanged(int progress) {
System.out.println("桌面顯示進(jìn)度: " + progress);
}
}
實(shí)現(xiàn)類2:
public class NotionShow implements DownloadObserver{
@Override
public void onDownloadProgressChanged(int progress) {
System.out.println("通知欄顯示進(jìn)度 : " + progress);
}
}
一切準(zhǔn)備好之后,就可以在主方法中使用它們了,主方法代碼如下:
public class Download {
public static void main(String[] args) {
// 創(chuàng)建三個(gè)觀察者對(duì)象
DeskShow deskShow = new DeskShow();
NotionShow notionShow = new NotionShow();
OtherShow otherShow = new OtherShow();
DownloadInfo info = new DownloadInfo();
DownLoadTask downLoadTask = new DownLoadTask(info);
// 注冊(cè)觀察者對(duì)象到集合中
downLoadTask.registerObserver(deskShow);
downLoadTask.registerObserver(notionShow);
downLoadTask.registerObserver(otherShow);
new Thread() {
public void run() {
int progress = 0;
while (true) {
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 每隔0.5秒更改一次DownloadInfo的信息
progress = progress + 1;
info.setProgress(progress);
// 更改信息之后通知觀察者
downLoadTask.notifyAllObserver();
}
};
}.start();
}
}
這樣整個(gè)觀察者的模型就已經(jīng)完成了,在外部傳入DownloadInfo的進(jìn)度值之后,直接調(diào)用downLoadTask的notifyAllObserver(),就可以通知所有的觀察者當(dāng)前的進(jìn)度。
探究觀察者模式的本質(zhì),就是java中回調(diào)的使用方式,獲得具體的信息,把不確定的信息設(shè)置為一個(gè)方法,歸由子類實(shí)現(xiàn)。
總結(jié)
或許大家看完這個(gè)模型,對(duì)于觀察者模式還有一點(diǎn)疑惑,那么我們來(lái)總結(jié)一下使用觀察者模式的步驟吧!
1、創(chuàng)建一個(gè)類,這個(gè)類是用于保存動(dòng)態(tài)的需要改變的數(shù)據(jù)(被觀察者),在本文表示DownloadInfo類;
2、創(chuàng)建一個(gè)接口類,這個(gè)類用于觀察對(duì)象狀態(tài)的改變(觀察者),在本文表示DownloadObserver類;
3、創(chuàng)建一個(gè)注冊(cè)和注銷觀察者的任務(wù)類(DownLoadTask),這個(gè)類擁有注冊(cè)和注銷觀察者,并且在被觀察這信息發(fā)送改變時(shí)通知所有的觀察者。
4、實(shí)現(xiàn)DownloadObserver類,這些實(shí)現(xiàn)類實(shí)現(xiàn)接收到DownloadInfo類信息發(fā)生改變的時(shí)候要實(shí)現(xiàn)的功能,在本文即是DeskShow類,輸出進(jìn)度語(yǔ)句。
這樣一個(gè)觀察者的模型就組件好了!
最后就是在主方法中注冊(cè)觀察者,然后傳入改變的數(shù)據(jù),通知所有的觀察者。