BUG fix BroadcastReceiver有序接收廣播,設置標記位失敗及解決

這次要不是問了同事,感覺陷在裏面無法出來了...

公司的需求是這樣的,根據不同的廣播去做不同的事情,比如廣播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的理解

 

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