這次要不是問了同事,感覺陷在裏面無法出來了...
公司的需求是這樣的,根據不同的廣播去做不同的事情,比如廣播A和廣播B同時會接收到很多次,現在的需求就是,接收到廣播A之後,做事情A, 然後上報數據給服務器. 如果後面陸續收到廣播A的廣播,則不用去上傳. 那什麼時候能上傳呢?
當收到廣播B的時候,做事情B, 然後上報數據給服務器. 然後再收到廣播A就可以再上傳一次. 廣播A和B都只是上傳一次數據給服務器,期間接收到重複的廣播則不用上報. 簡單的說就是,廣播A和廣播B數據上報一一對應,就像是拿起碗才能吃飯,不拿碗就沒法吃飯. 也就是即A上報,B上報. A上報,B上報....... 而不是A上報,A上報,B上報.....或者A上報,B上報,B上報.....
我心想好辦啊,就設置了一個boolean標記位, 當接收到廣播A的時候,判斷標記位爲true,則執行上報,然後將標記位設置爲false.當接收到廣播B的時候,判斷標記位爲false,則執行上報,然後將標記位設置爲true.
我以爲沒事了,結果出了很大的問題. 剛開始我判斷是多線程的問題,於是設置了volatile 標記位,設置了synchronize方法, 結果還是會發生這個問題. 會發生廣播A 重複上報的問題,不能和廣播B一一對應,即A上報,B上報. 而不是A上報,A上報,B上報
後來問了一下同事,詢問了這個問題,他對於源碼的理解還是蠻深的,給我講解了,每次接受到廣播的時候,都會初始化一個broadcastReceiver, 我打印了一下hash值, 真的是每次接收到不同的action都會初始化一個broadcastReceiver.
比如說,同時接收到了開機,電量,進入空閒的廣播, 此時會初始化三個broadcastReceiver!!! 那我設置的標記位就無法生效了
於是想了一下,目前能在不同的對象之間交互數據的方式,一個是sharedPreference,一個是數據庫. 由於公司有已有便利的數據庫操作工具類,所以我選擇了數據庫的方式. 這樣,每次執行不同的廣播的時候, 都會去數據庫裏面去查詢,然後判斷. 當然,數據庫是耗時操作,所以我放在了線程中去操作,線程是從線程池中產生的.
以下是線程池的工具類:
public class ThreadPool {
//通過ThreadPoolExecutor的代理類來對線程池的管理
private static ThreadPool.ThreadPollProxy mThreadPollProxy;
public static synchronized ThreadPool.ThreadPollProxy getInstance() {
synchronized (ThreadPool.class) {
if (mThreadPollProxy == null) {
mThreadPollProxy = new ThreadPool.ThreadPollProxy(3, 6, 1000);
}
}
return mThreadPollProxy;
}
//通過ThreadPoolExecutor的代理類來對線程池的管理
public static class ThreadPollProxy {
private ThreadPoolExecutor poolExecutor;
//線程池執行者 ,java內部通過該api實現對線程池管理
private int corePoolSize;
private int maximumPoolSize;
private long keepAliveTime;
public ThreadPollProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
}
//對外提供一個執行任務的方法
public void execute(Runnable r) {
if (poolExecutor == null || poolExecutor.isShutdown()) {
poolExecutor = new ThreadPoolExecutor(
//核心線程數量
corePoolSize,
//最大線程數量
maximumPoolSize,
//當線程空閒時,保持活躍的時間
keepAliveTime,
//時間單元 ,毫秒級
TimeUnit.MILLISECONDS,
//線程任務隊列
new LinkedBlockingQueue<Runnable>(),
//創建線程的工廠
Executors.defaultThreadFactory());
}
poolExecutor.execute(r);
}
}
}
以上問題涉及到的知識點包括: PackageManagerService源碼的理解, 類的初始化及加載,broadcast的理解