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的理解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值