从线程更改数据源时通知AsyncTaskLoader

时间:2014-07-06 21:41:06

标签: android multithreading

我是android的新手,我不确定我是否正在寻找可能,是否有可能从一个线程更新装载程序管理器处理的listview内容?如果可以,请告诉我如何?

下面有更多详细信息,为简洁起见,我删除了很多行,如果您需要更多详细信息,请与我们联系

我正在使用的HandlerThread就是这个,我需要通知加载器有关更改列表视图内容的更改

    public void syncWithBackend(Context context) {
    //Connect to the server over HTTP and get the latest data after receiving 
    //the GCM tickle message then save the result in DB

    dbhelper.saveFm(id, artno, comment );

//Here is where I need to notify the loader or the list about the new change 
// to view the new saved data
     context.getContentResolver().notifyChange(uri, null);


}

我正在使用的URI是belwo,

 Uri uri = Uri.parse("sqlite://com.pack.android.and/posts"); 

我的LoaderCallbacks就是这个

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    return new FeedListCursorLoader(getActivity());
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    cCursorAdapter adapter = new cCursorAdapter(getActivity(), 
            (fCursor) cursor);
    setListAdapter(adapter);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    setListAdapter(null);
}

我的意图服务就是这个

    protected void onHandleIntent(Intent intent) {

//Here I got the GCM message, call the thread to sync with the backend

        hanlder1.queueHttp(this);

}

我的AsyncTaskLoader是这个

public abstract class SQLiteCursorLoader extends AsyncTaskLoader<Cursor> {
    private Cursor cCursor;

    public SQLiteCursorLoader(Context context) {
        super(context);
    }
//I'm overriding this from the Fragment to get the cursor after querying sqlite DB 
    protected abstract Cursor loadCursor();

    @Override
    public Cursor loadInBackground() {
        Cursor cursor = loadCursor();
        if (cursor != null) {
            cursor.getCount();
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

             }
        return cursor;
    }

    @Override
    public void deliverResult(Cursor data) {
        Cursor oldCursor = cCursor;
        cCursor = data;

        if (isStarted()) {
            super.deliverResult(data);
        }

        if (oldCursor != null && oldCursor != data && !oldCursor.isClosed()) {
            oldCursor.close();
        }
    }

    @Override
    protected void onStartLoading() {
      ...
    }

    @Override
    protected void onStopLoading() {
      ...
    }

    @Override
    public void onCanceled(Cursor cursor) {
      ...    
    }

    @Override
    protected void onReset() {
       ...      
    }

1 个答案:

答案 0 :(得分:1)

是的,但并不像你期望的那样。

您不会更新光标,您将替换它。事实上,LoaderManager会自动为您完成。它几乎令人难以置信的简单

创建游标时,为响应Loader的请求,将其注册为特定URI的侦听器:

cursor.setNotificationUri(getContext().getContentResolver(), uri);

URI可以是您想要的任何内容。它代表(是?的“名称”)数据。

Loader运行LoaderManager时,LoaderManager会在回调中获得Loader返回的光标,然后再将其传递给您。 它在该光标上注册为侦听器。

如果在此之后的某个时刻,您宣布在该URI所代表的数据中发生了更改,请执行以下操作:

getContext().getContentResolver().notifyChange(uri, null);

将通知光标(在该URI上注册为侦听器)。当通知光标时,将通知LoaderManager(在光标上注册为监听器),它将自动重新运行Loader!

在你的情况下,你会在另一个线程上做通知......

如果您的onLoadFinished方法只是换出旧光标并换入新光标,那么ListView将通过魔法更新。

Android的某些部分非常棒。

编辑添加示例代码:

以下是一些示例代码,用于演示其工作原理。 db是对SQLiteOpenHelper的引用。方法insertquery分别是简单的数据库插入和查询。

首先是插入代码:

db.insert();
getContentResolver().notifyChange(DbHelper.URI, null);

然后是装载机:

private static class MagicLoader extends AsyncTaskLoader<Cursor> {
    private final DbHelper db;
    private volatile Cursor cursor;
    private final ContentObserver obs = new ContentObserver(new Handler()) {
        @Override public boolean deliverSelfNotifications() { return true; }
        @Override public void onChange(boolean selfChange) { onContentChanged(); }
    };

    public MagicLoader(Context ctxt, DbHelper db) {
        super(ctxt);
        this.db = db;
    }

    @Override
    protected void onStartLoading() {
        if (null == cursor) { forceLoad(); }
        else { deliverResult(cursor); }
    }

    @Override
    public Cursor loadInBackground() {
        cursor = db.query();
        if (cursor != null) {
            try {
                cursor.setNotificationUri(
                    getContext().getContentResolver(),
                    DbHelper.URI);
                cursor.getCount();
                cursor.registerContentObserver(obs);
            }
            catch (RuntimeException ex) {
                cursor.close();
                throw ex;
            }
        }
        return cursor;
    }
};

请注意,如果您只使用ContentProvider,这将更容易。