这次要不是问了同事,感觉陷在里面无法出来了...
公司的需求是这样的,根据不同的广播去做不同的事情,比如广播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的理解