android getContentResolver().notifyChange() 没有重启我的加载器

android getContentResolver().notifyChange() does not restart my loader

代码:

首先是我的 Uris

public static final String PACKAGE    = "my.url.contentprovider";

public static final String TABLE_NAME = "NetworkTransaction";

public static final String AUTHORITY  = PACKAGE + ".NetTransContentProvider";

public static final Uri BASE_URI = Uri.parse("content://"+AUTHORITY);

public static final Uri CONTENT_URI_ANY_OBSERVER  = Uri.withAppendedPath(BASE_URI,TABLE_NAME+"/*");

public static final Uri CONTENT_URI_FIND_BY_ID  = Uri.withAppendedPath(BASE_URI,TABLE_NAME+"/FIND/ID");

public static final Uri CONTENT_URI_INSERT_OR_REPLACE_BY_ID    = Uri.withAppendedPath(BASE_URI,TABLE_NAME+"/INSERT/REPLACE/ID"); 

public static final Uri CONTENT_URI_INSERT_BY_ID   = Uri.withAppendedPath(BASE_URI,TABLE_NAME+"/INSERT/ID"); 

我的加载程序来自 activity 代码:

@Override
protected void onResume() {
    super.onResume();
getSupportLoaderManager().restartLoader(NET_TRANS_LOADER_ID,mBundle,this).forceLoad();

}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
    Uri uri = null;
    CursorLoader cl=null;
    switch (id) {
    case NET_TRANS_LOADER_ID:
        uri = NetTransContentProvider.CONTENT_URI_FIND_BY_ID;
        cl  = new CursorLoader(ChoosingUserNameActivity.this, uri, NetTransDbUtils.allColumns,
                NetTransDbUtils.COLUMN_ID + " = ? ",
                new String[]{String.valueOf(bundle.getLong(EXTRA_TRANSACTION_ID,-1))}, null);

        break;
    default:
        break;
    }
    return cl;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    final int loaderId = loader.getId();
    switch (loaderId) {
    case NET_TRANS_LOADER_ID:
        if(mTransactionId != null){
            NetTrans netTrans = NetTransDbUtils.cursorToNetTrans(cursor);
            if(netTrans != null && netTrans.getStatus() != null 
                                && !netTrans.getStatus().equals(NetTrans.STATUS_PENDING)){
                EventBus.getDefault().post(new NetTransMsg(true, mTransactionId, netTrans.getMessage()));
            }
        }
        break;
    default:
        break;
    }
}

并且在我调用

的已启动服务中运行在ExecutorService上的可运行对象

mContext.getContentResolver().insert(NetTransContentProvider.CONTENT_URI_INSERT_OR_REPLACE_BY_ID, cv );

插入的值但加载器不调用:

@Override
public Uri insert(Uri uri, ContentValues values) {
    int uriType = sUriMatcher.match(uri);
    switch (uriType) {

    case INSERT_OR_REPLACE_BY_ID:
        mDatabase.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
        break;

    case INSERT_BY_ID:
        mDatabase.insert(TABLE_NAME, null, values);
        break;

    default:
        break;
    }

    getContext().getContentResolver().notifyChange(CONTENT_URI_ANY_OBSERVER, null);
    return null;
}
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) {
        Cursor cursor = mDatabase.query(TABLE_NAME,projection,selection, selectionArgs, null, null, null);
        cursor.setNotificationUri(getContext().getContentResolver(), CONTENT_URI_ANY_OBSERVER);
        return cursor;
    }

我的问题是getContext().getContentResolver().notifyChange(CONTENT_URI_ANY_OBSERVER, null);在插入方法中无法使我的加载程序重新启动。


更新

我创建了一个sample project,你按下按钮,一个新的NetTrans对象被创建并写入数据库,然后线程休眠5000毫秒并覆盖那个值(模拟网络操作)。但在那之后装载机不会重新启动。我的错误在哪里?

如果您希望在 CONTENT_URI_ANY_OBSERVER 上注册的观察者在 CONTENT_URI_FIND_BY_ID 上发生更改时得到通知,您需要确保两件事。

  • 首先,CONTENT_URI_ANY_OBSERVER 需要是 CONTENT_URI_FIND_BY_ID 的父级。如果您将其视为文件系统上的文件夹,'CONTENT_URI_ANY_OBSERVER' 应该在其子文件夹之一中包含“CONTENT_URI_FIND_BY_ID”。

  • 其次,在注册您的内容观察器时,您必须为 notifyDescendants 参数传递 true。

Android尝试寻找匹配的内容观察者时没有通配符的考虑(评论中提供的link仅适用于UriMatcher)。因此,要解决您的问题,您应该从 CONTENT_URI_ANY_OBSERVER 中删除 /* 并且它应该开始匹配。您可以看到 my.url.contentprovider/NetworkTransaction 现在如何成为 my.url.contentprovider/NetworkTransaction/INSERT/REPLACE/ID 的父 "folder",而之前您有 my.url.contentprovider/NetworkTransaction/*

编辑 1

查看您的示例项目后,我发现了您的问题所在的其他方面。当您使用游标加载器时,游标由加载器拥有。这意味着除了遍历其数据之外,您不应该以任何方式更改它。在您的 NetTransDbUtils.cursorToNetTrans(cursor) 方法中,您正在关闭游标,这将阻止 CursorLoader 能够有效地监视对游标数据的更改。

简单回答:不要在 NetTransDbUtils.cursorToNetTrans(cursor); 中为此用例调用关闭 cursor.close()

用简单的解析替换你的 Uris:

public static final Uri CONTENT_URI_ANY_OBSERVER = Uri
        .parse(BASE_URI + "/" + TABLE_NAME);
public static final Uri CONTENT_URI_FIND_BY_ID = Uri
        .parse(BASE_URI + "/" + TABLE_NAME + "/FIND/ID");
public static final Uri CONTENT_URI_INSERT_OR_REPLACE_BY_ID = Uri
        .parse(BASE_URI + "/" + TABLE_NAME + "/INSERT/REPLACE/ID");
public static final Uri CONTENT_URI_INSERT_BY_ID = Uri
        .parse(BASE_URI + "/" + TABLE_NAME + "/INSERT/ID");

在您的 RestService class 中,使用回调处理程序:

private Handler mHandler;

@Override
public void onCreate() {
    ...
    mHandler = new Handler();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    ...
    mHandler.post(task);
    ...
}