2012/03/05

Android:AsyncQueryHandlerでクエリ発行時のエラーをハンドリングする方法


AsyncQueryHandlerを使ってクエリを非同期実行する場合に、実行したクエリがディスク
フル等による要因でエラーとなることがあります。
クライアント側でこれを受け取る方法としてAsyncQueryHandler.WorkerHandlerが提供さ
れています。

下記はそのサンプルソースです。

private QueryHandler query;

@Override
protected void onResume() {
    super.onResume();
    query = new QueryHandler(this);
    query.startQuery(10, null, Browser.BOOKMARKS_URI,
            new String[] {"_id"}, null, null, null);
}

private static class QueryHandler extends AsyncQueryHandler {
    public QueryHandler(Context context) {
        super(context.getContentResolver());
    }

    private class ErrorHandler extends AsyncQueryHandler.WorkerHandler {
        public ErrorHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        try {
            super.handleMessage(msg);
        } catch (Exception e) {
            // do something.
        }
    }

    @Override
    protected Handler createHandler(Looper looper) {
        return new ErrorHandler(looper);
    }

    @Override
    protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
        DatabaseUtils.dumpCursor(cursor);
    }
}

AsyncQueryHandlerでのクエリ実行は、AsyncQueryHandlerに内包されているHandlerThread
上で行われます。
このHandlerThreadのLooperはWorkerHandlerと紐付けられており、WorkerHandler.handleMessage
でクエリの問合せが行われます。

WorkerHandlerはAsyncTaskQuery.createHandler(Looper)で生成されるHandlerインスタン
スとなります。
createHandlerメソッドはpublicとなっており、サブクラスがこれをオーバーライドする
ことで、独自のWorkerHandlerを定義することが可能です。

先ほどの例では、ErrorHAndlerのhandleMessage内で呼び出されるsuper.handleMessage(msg);
内でクエリが問合せされます。
ここでtry-catch節を組むことで、WorkerHandlerが発行するクエリの例外を拾えるという
仕組みです。
# 実際catchする例外はExceptionではなくSQLiteDiskIOExceptionやSQLiteFullExceptionに
# なるでしょう。

以上です。