GreenDao自带异步操作类简析

转载地址:http://blog.csdn.net/yide55/article/details/50601504


这是一次异步查询操作的流程图

AsyncSession: 
GreenDao提供一个异步操作的统一接口类AsyncSession,它提供了你所需要的所有异步操作方法。 
你可以通过调用DaoSession#startAsyncSession()来获得一个AsyncSession实例。

  public AsyncSession startAsyncSession() {
        return new AsyncSession(this);
    }
       
       
  • 1
  • 2
  • 3

在AsyncSession的构造函数中,会赋值两个全局变量:一个是传参进来的DaoSession,另一个是创建的AsyncOperationExecutor对象。

 public AsyncSession(AbstractDaoSession daoSession) {
        this.daoSession = daoSession;
        this.executor = new AsyncOperationExecutor();
    }
       
       
  • 1
  • 2
  • 3
  • 4

那么AsyncOperationExecutor是什么? 
AsyncOperationExecutor是一条管理着阻塞队列的线程,由它来进行实际的db操作,它的内部实现有点类似于Looper(后面再详解)。AsyncSession作为一个接口类,会将所有异步任务组装发布给AsyncOperationExecutor进行具体的操作。

有异步任务来时,AsyncSession会将异步任务封装成AsyncOperation对象,再将AsyncOperation对象加入到AsyncOperationExecutor对象的阻塞队列中,再走AsyncOperationExecutor的内部逻辑。


private AsyncOperation enqueueDatabaseOperation(OperationType type, Object param, int flags) {
        SQLiteDatabase database = daoSession.getDatabase();
        AsyncOperation operation = new AsyncOperation(type, null, database, param, flags | sessionFlags);
        executor.enqueue(operation);
        return operation;
    }
       
       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这个AsyncOperation包含有下列信息: 
db操作的类型OperationType :增、删、改、查(这里细分的多,会根据具体操作来返回对应的结果); 
SQLiteDatabase 实例; 
操作的参数parameter:sql语句的where判断;

每一个AsyncSession对象都拥有一个AsyncOperationExecutor 实例,,而每一个AsyncOperationExecutor 对象都管理着一个阻塞队列。也就是说,在每个类里头创建的AsyncSession对象将在一条线程中处理一个队列的工作,这样至少能保证当前类中只会创建一条工作线程循环处理非UI操作。

AsyncOperationExecutor中工作流程: 
AsyncOperationExecutor本身运行于线程池生成的某一条线程中,管理着BlockingQueue,在有AsyncOperation添加时,开启任务执行,设置标记executorRunning =true:表示线程为运行状态。AsyncOperationExecutor运行时不停的从BlockingQueue中取出有AsyncOperation进行预定义的增删改查操作(executeOperationAndPostCompleted(),如队列为空则线程阻塞),在操作完成后将结果赋值给有AsyncOperation.result变量(如无则不赋值),再将带任务结果的AsyncOperation返回给监听类。

  //结果返回,回到主线程中执行
  @Override
    public boolean handleMessage(Message msg) {
        AsyncOperationListener listenerToCall = listenerMainThread;
        if (listenerToCall != null) {
            listenerToCall.onAsyncOperationCompleted((AsyncOperation) msg.obj);
        }
        return false;
    }
       
       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
//AsyncOperationExecutor主要逻辑代码
 @Override
    public void run() {
        try {
            try {
                while (true) {
                    AsyncOperation operation = queue.poll(1, TimeUnit.SECONDS);
                    if (operation == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized to be in sync with enqueue(AsyncOperation)
                            operation = queue.poll();
                            if (operation == null) {
                                // set flag while still inside synchronized
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    if (operation.isMergeTx()) {
                        // 等一些时间,看有没有新加入的可在同一事务中执行的任务
                        AsyncOperation operation2 = queue.poll(waitForMergeMillis, TimeUnit.MILLISECONDS);
                        if (operation2 != null) {
                            if (operation.isMergeableWith(operation2)) {
                                mergeTxAndExecute(operation, operation2);
                            } else {
                                // 不能合并事务操作的,就分开执行下,否则在上面代码中合并操作
                                executeOperationAndPostCompleted(operation);
                                executeOperationAndPostCompleted(operation2);
                            }
                            continue;
                        }
                    }
                    executeOperationAndPostCompleted(operation);
                }
            } catch (InterruptedException e) {
                DaoLog.w(Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }
       
       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

AsyncOperationExecutor有一个小操作,在从队列中拿到AsyncOperation处理前会先等待一定时间去获取下一个AsyncOperation,判断是否与其可以进行使用同一事务的合并操作,必竟事务操作代价是比较大的。这里有预先设定合并操作的最大数量,如果有较大的批量操作可能超出限定时,还是建议使用GreenDao提供的其它事务操作方法,必竟这里只是动态的判断是否有可合并的数据库操作,判断与处理的过程中会增加消耗。

下面是简单的异步操作示例:

AsyncSession async = DbMgr.daoSession.startAsyncSession();
        //不关心操作结果时,可不设置lisnter
        async.setListenerMainThread(new AsyncOperationListener() {

            @Override
            public void onAsyncOperationCompleted(AsyncOperation arg0) {

                if (isFinishing())
                    return;
                    //对db结果的UI操作

            }
        });
        async.queryList(builder.build());
       
       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果对操作结果不关心且需进行多项操作时,可以使用这种自动开启事务的方式:

DbMgr.daoSession.startAsyncSession().runInTx(new Runnable() {

            @Override
            public void run() {
                //DELETE
                //DELETE
                //UPDATE

            }
        });
       
       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用过程中碰到: 
“Method may be called only in owner thread, use forCurrentThread to get an instance for this thread” 
问题在于AsyncOperationExecutor 漏了 
((Query) operation.parameter).forCurrentThread().list() 
这个升级到2.1即可解决。

更新一下,附上一张类图: 
这里写图片描述


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值