GreenDao自带异步操作类简析

来源:互联网 发布:智能视频分析软件 编辑:程序博客网 时间:2024/06/03 09:24

转载地址: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即可解决。

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


0 0
原创粉丝点击