5

我有一个 SQLiteDatabase,其数据由内容提供者管理。我正在使用选项卡式布局。第一个选项卡能够向数据库添加行,而第二个选项卡显示数据库中的项目。当我从第一个选项卡将项目添加到数据库时,当我移动到另一个选项卡时,更改应该会反映出来。

数据被正确地添加到数据库中,并且在第一次打开应用程序时,所有当前数据(以及在应用程序的先前版本中添加的任何新数据)都会出现。但是,向数据库添加新项目不会反映在 ListFragment 中。

@Override
    public void onClick(View v) {
        if(v == addSale) {
            Item item = new Item(rn(), null, 100);
            data.add(item);
            total += item.getAmount();
        } else if(v == save) {
            for(Item i: data) {
                ContentValues cv = new ContentValues();
                cv.put(DatabaseProvider.COLUMN_COST, i.getAmount());
                cv.put(DatabaseProvider.COLUMN_ITEM, i.getItem());
                cv.put(DatabaseProvider.COLUMN_PERSON, i.getPerson());
                this.getActivity().getContentResolver().insert(DatabaseProvider.CONTENT_URI, cv);
            }
            total = 0;
            data.clear();
        } else if(v == clear) {
            data.clear();
            total = 0;
        }
        items.notifyDataSetChanged();
        totalView.setText(Item.format(total));
    }

这是我专门使用这些行将项目添加到数据库的地方:

ContentValues cv = new ContentValues();
cv.put(DatabaseProvider.COLUMN_COST, i.getAmount());
cv.put(DatabaseProvider.COLUMN_ITEM, i.getItem());
cv.put(DatabaseProvider.COLUMN_PERSON, i.getPerson());
this.getActivity().getContentResolver().insert(DatabaseProvider.CONTENT_URI, cv);

正如我之前所说,项目被正确地放入数据库中,所以我有理由确定这是正确的。

这是我的 DatabaseProvider 的插入方法

@Override
public Uri insert(Uri uri, ContentValues initialValues) {
    if (sUriMatcher.match(uri) != TABLE) {
        throw new IllegalArgumentException("Invalid URI: " + uri);
    }

    if (initialValues == null) {
        initialValues = new ContentValues();
    }

    SQLiteDatabase db = dbHelper.getWritableDatabase();

    long rowId = db.insert(TABLE_SALES, COLUMN_COST, initialValues);

    if (rowId > 0) {
        Uri newUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
        getContext().getContentResolver().notifyChange(uri, null);
        return newUri;
    }

    throw new SQLException("Failed to insert row into: " + uri);
}

从各种教程和其他 SO 问题中,似乎

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

是让它更新的关键,它就在那里,并且被调用。但没有任何更新。

最后,显示所有数据的列表片段。

package org.worldsproject.android.barcode;

import org.worldsproject.android.barcode.database.DatabaseProvider;

import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;

import com.actionbarsherlock.app.SherlockListFragment;

public class RunningTotal extends SherlockListFragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    public static final String TAG = "Running Total";

    public static final int RUNNING_TOTAL_ID = 1;
    private SimpleCursorAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] uiBindFrom = { DatabaseProvider.COLUMN_PERSON };
        int[] uiBindTo = { R.id.titled };

        adapter = new SimpleCursorAdapter(
                getActivity().getApplicationContext(), R.layout.list_title,
                null, uiBindFrom, uiBindTo,
                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

        setListAdapter(adapter);
        getLoaderManager().initLoader(RUNNING_TOTAL_ID, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
        String[] projection = { DatabaseProvider.COLUMN_ID,
                DatabaseProvider.COLUMN_PERSON};
        return new CursorLoader(getActivity(), DatabaseProvider.CONTENT_URI,
                projection, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
        // TODO Auto-generated method stub
        adapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> arg0) {
        // TODO Auto-generated method stub
        adapter.swapCursor(null);
    }

}

它几乎是http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/的直接克隆,目前只显示数据库中每一行的名称列。它显示以前的条目,但正如我所说,不会更新。我缺少什么步骤来更新它?

4

3 回答 3

13

我认为你的

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

可能没问题。

我看不到您的 DatabaseProvider 的查询函数,但您记得为您在查询函数中返回的光标设置 notificationUri 吗?

在 DatabaseProvider 的 query() 函数中,您应该为游标设置通知 Uri,否则即使您执行 notifyChange(),游标也不会收到通知:

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
   // blah blah
   cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
于 2012-10-23T07:06:53.117 回答
3

我在使用视图寻呼机的 Fragment 上遇到了类似的问题。我意识到我没有注册 ContentObserver,所以我所做的只是将此代码添加到 onResume()

getActivity().getContentResolver().registerContentObserver(sUri, true, myObserver);

并将 myObserver 声明为成员变量:

new ContentObserver(new Handler()) {
    @Override
    public void onChange(boolean selfChange) {
        getActivity().getSupportLoaderManager().restartLoader(); // With appropriate loader args here
    }
});

并确保取消注册在 onPause();

这似乎解决了我的问题,假设 ContentProvider 正确调用了 notifyChange (不过看起来你是这样)。

希望这可以帮助你!

于 2012-10-25T23:00:24.620 回答
-1

我认为错误在这里:

Uri newUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(uri, null);
return newUri;

您应该使用刚刚添加的元素的 uri 调用notifyChange方法,即 newUri。

所以通知变成:

getContext().getContentResolver().notifyChange(newUri, null);
于 2012-10-22T20:45:23.233 回答