-1

我遵循了一些教程,这些教程解释了如何将 CursorLoader 与 SQLiteDatabase 一起使用。当我运行我的 ListView 时,没有返回任何结果。我已经确认数据库中有一个使用 Eclipse 插件的条目。

这是我的带有 sqliteopenhelper 实现的 contentprovider

public class DiaryDataProvider extends ContentProvider {

public static final String DATABASE_NAME = "data.db";
public static final int DATABASE_VERSION = 1;

// implementation of SQLiteOpenHelper
private static class DiaryDbHelper extends SQLiteOpenHelper {
    // creating and deleting the database and table
    private static final String TEXT_TYPE = " TEXT";
    private static final String REAL_TYPE = " REAL";
    private static final String INTEGER_TYPE = " INTEGER";
    private static final String COMMA_SEP = ",";

    private static final String SQL_CREATE_ENTRIES = "CREATE TABLE "
            + DiarySchema.TABLE_NAME + " (" + DiarySchema._ID
            + " INTEGER PRIMARY KEY," + DiarySchema.COLUMN_NAME_DIARY_ID
            + TEXT_TYPE + COMMA_SEP + DiarySchema.COLUMN_NAME_DATE
            + TEXT_TYPE + COMMA_SEP + DiarySchema.COLUMN_NAME_TIME
            + TEXT_TYPE + COMMA_SEP + DiarySchema.COLUMN_NAME_SEVERITY
            + TEXT_TYPE + COMMA_SEP + DiarySchema.COLUMN_NAME_LOCATION_LAT
            + REAL_TYPE + COMMA_SEP + DiarySchema.COLUMN_NAME_LOCATION_LONG
            + REAL_TYPE + COMMA_SEP
            + DiarySchema.COLUMN_NAME_LOCATION_DETAIL + TEXT_TYPE
            + COMMA_SEP + DiarySchema.COLUMN_NAME_HAS_FOOD + INTEGER_TYPE
            + COMMA_SEP + DiarySchema.COLUMN_NAME_DETAILS + TEXT_TYPE
            + " )";

    public DiaryDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_ENTRIES);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + DiarySchema.TABLE_NAME);
        onCreate(db);
    }
}

private DiaryDbHelper dbHelper;

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    final int match = DiarySchema.URI_MATCHER.match(uri);
    switch (match) {
    // retrieve diary list
    case DiarySchema.PATH_TOKEN: {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(DiarySchema.TABLE_NAME);
        return db.delete(DiarySchema.TABLE_NAME, selection, selectionArgs);
    }
    default:
        return 0;
    }

}

@Override
public String getType(Uri uri) {
    final int match = DiarySchema.URI_MATCHER.match(uri);
    switch (match) {
    case DiarySchema.PATH_TOKEN:
        return DiarySchema.CONTENT_TYPE_DIR;
    case DiarySchema.PATH_FOR_ID_TOKEN:
        return DiarySchema.CONTENT_ITEM_TYPE;
    default:
        throw new UnsupportedOperationException("URI " + uri
                + " is not supported.");
    }
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int token = DiarySchema.URI_MATCHER.match(uri);
    switch (token) {
    case DiarySchema.PATH_TOKEN: {
        long id = db.insert(DiarySchema.TABLE_NAME, null, values);
        getContext().getContentResolver().notifyChange(uri, null);
        return DiarySchema.CONTENT_URI.buildUpon()
                .appendPath(String.valueOf(id)).build();
    }
    default: {
        throw new UnsupportedOperationException("URI: " + uri
                + " not supported.");
    }
    }
}

@Override
public boolean onCreate() {
    dbHelper = new DiaryDbHelper(getContext());
    return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    final int match = DiarySchema.URI_MATCHER.match(uri);
    switch (match) {
    // retrieve diary list
    case DiarySchema.PATH_TOKEN: {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(DiarySchema.TABLE_NAME);
        return builder.query(db, projection, selection, null, null, sortOrder, null);
    }
    default:
        return null;
    }
}

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    final int match = DiarySchema.URI_MATCHER.match(uri);
    switch (match) {
    // retrieve diary list
    case DiarySchema.PATH_TOKEN: {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(DiarySchema.TABLE_NAME);
        return db.update(DiarySchema.TABLE_NAME, values, selection,
                selectionArgs);
    }
    default:
        return 0;
    }

}
}

这是随之而来的架构

public abstract class DiarySchema implements BaseColumns {
public static final String TABLE_NAME = "diary";
public static final String COLUMN_NAME_DIARY_ID = "diaryid";
public static final String COLUMN_NAME_DATE = "date";
public static final String COLUMN_NAME_TIME = "time";
public static final String COLUMN_NAME_SEVERITY = "severity";
public static final String COLUMN_NAME_LOCATION_LAT = "locationlat";
public static final String COLUMN_NAME_LOCATION_LONG = "locationlong";
public static final String COLUMN_NAME_LOCATION_DETAIL = "locationdetail";
public static final String COLUMN_NAME_DETAILS = "details";
public static final String COLUMN_NAME_HAS_FOOD = "hasfood";

public static final String PATH = "diaries";
public static final int PATH_TOKEN = 100;
public static final String PATH_FOR_ID = "diaries/#";
public static final int PATH_FOR_ID_TOKEN = 200;

public static final String CONTENT_TYPE_DIR = ContentResolver.CURSOR_DIR_BASE_TYPE + "/diaries";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/diaries";

public static final String AUTHORITY = "com.foo.bar.contentproviders";
private static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY);
public static final UriMatcher URI_MATCHER = buildUriMatcher();
public static final Uri CONTENT_URI = BASE_URI.buildUpon().appendPath(PATH)
        .build();

private static UriMatcher buildUriMatcher() {
    final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    final String authority = AUTHORITY;

    matcher.addURI(authority, PATH, PATH_TOKEN);
    matcher.addURI(authority, PATH_FOR_ID, PATH_FOR_ID_TOKEN);

    return matcher;
}

// Prevent anyone from instantiating this class
private DiarySchema() {
};
}

我的 ContentProvider 在 androidmanifest.xml 文件中声明为...

<provider
        android:name="com.foo.bar.contentproviders.DiaryDataProvider"
        android:authorities="com.foo.bar.contentproviders"
        android:exported="false" />

我的 ListFragment 看起来像......

public class FragDiaryEntries extends SherlockListFragment implements
    LoaderManager.LoaderCallbacks<Cursor> {
private static final int URL_LOADER = 0;
private View view;
private Map<Integer, DiaryHolder> diaryHolders = new HashMap<Integer, DiaryHolder>();
CustomAdapter adapter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.frag_diary_entries, container);

    // start the cursor loader getting data to populate diary view
    getLoaderManager().initLoader(URL_LOADER, null, this);

    // Set up adapter
    adapter = new CustomAdapter(getActivity().getApplicationContext(), null);
    setListAdapter(adapter);

    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO different indicator of no data yet
    ((TextView) getListView().getEmptyView()).setText("It's Empty");

    super.onActivityCreated(savedInstanceState);
}



/* Loader callback implemented methods */

@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
    Loader<Cursor> cursorLoader = null;

    // Get all of the diary entries
    switch (loaderId) {
    case URL_LOADER:
        String[] projection = { DiarySchema._ID,
                DiarySchema.COLUMN_NAME_DATE, DiarySchema.COLUMN_NAME_TIME,
                DiarySchema.COLUMN_NAME_SEVERITY,
                DiarySchema.COLUMN_NAME_LOCATION_LAT,
                DiarySchema.COLUMN_NAME_LOCATION_LONG,
                DiarySchema.COLUMN_NAME_LOCATION_DETAIL,
                DiarySchema.COLUMN_NAME_DETAILS,
                DiarySchema.COLUMN_NAME_HAS_FOOD };

        cursorLoader = new CursorLoader(getActivity(),
                DiarySchema.CONTENT_URI, projection, null, null, null);

    }
    return cursorLoader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    adapter.swapCursor(cursor);
}

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

// Custom CursorAdapter
private class CustomAdapter extends CursorAdapter {

    private Cursor cursor;

    public CustomAdapter(Context context, Cursor c) {
        super(context, c, 0);
        this.cursor = c;
    }

    @Override
    public int getCount() {
        return cursor == null ? 0 : cursor.getCount();
    }

    @Override
    public Cursor getCursor() {
        return super.getCursor();
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        int position = cursor.getPosition();

        // Map values from cursor to fields
        TextView created = (TextView) view.findViewById(R.id.diary_created);
        TextView severity = (TextView) view
                .findViewById(R.id.diary_severity);
        TextView location = (TextView) view
                .findViewById(R.id.diary_location);
        CheckBox checkbox = (CheckBox) view
                .findViewById(R.id.diary_item_checked);

        // Create a holder object to store some row details
        if (!diaryHolders.containsKey(position)) {
            // Put the cursor in the correct position
            cursor.moveToPosition(position);

            String date = cursor.getString(cursor
                    .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_DATE));
            String time = cursor.getString(cursor
                    .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_TIME));
            created.setText(date + " at " + time);

            String sev = cursor
                    .getString(cursor
                            .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_SEVERITY));
            severity.setText(sev);

            String loc = cursor
                    .getString(cursor
                            .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_LOCATION_DETAIL));
            location.setText(loc);

            // Other values to put into holder
            long latitude = cursor
                    .getLong(cursor
                            .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_LOCATION_LAT));
            long longitude = cursor
                    .getLong(cursor
                            .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_LOCATION_LONG));
            int hasFood = cursor
                    .getInt(cursor
                            .getColumnIndexOrThrow(DiarySchema.COLUMN_NAME_HAS_FOOD));

            diaryHolders.put(position,
                    new DiaryHolder(position, checkbox.isChecked(),
                            new Diary(date, time, sev, loc, latitude,
                                    longitude, hasFood)));
        } else {

            // Populate from map
            DiaryHolder holder = diaryHolders.get(position);
            Diary diary = holder.getDiaryData();

            created.setText(diary.getDate().concat(diary.getTime()));
            severity.setText(diary.getSeverity());
            location.setText(diary.getLocationDetail());
            checkbox.setChecked(holder.isSelected());
        }

    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup container) {

        // Inflate a new view
        LayoutInflater inflater = LayoutInflater.from(context);
        View view = inflater.inflate(R.layout.diary_list_item, container);
        bindView(view, context, cursor);
        return view;
    }

}

// Holder class for row values
private class DiaryHolder {
    private long rowId;
    private boolean selected;
    private Diary diaryData;

    public DiaryHolder(long rowId, boolean selected, Diary diaryData) {
        this.rowId = rowId;
        this.selected = selected;
        this.diaryData = diaryData;
    }

    public Diary getDiaryData() {
        return diaryData;
    }

    public void setDiaryData(Diary diaryData) {
        this.diaryData = diaryData;
    }

    public long getRowId() {
        return rowId;
    }

    public void setRowId(long rowId) {
        this.rowId = rowId;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

}

}

我知道我的 ContentProvider 的插入部分可以工作,因为我能够插入一条记录。我想要做的是我拉回所有数据并将其显示在我的列表视图中。任何帮助,将不胜感激。

4

2 回答 2

0

我没有看到你setNotificatioUri在返回之前调用光标

看看我知道有效的一种查询方法

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
    sqlBuilder.setTables(CAL_EVENTS_TABLE);

    if (uriMatcher.match(uri) == 1) {
        sqlBuilder.setProjectionMap(mMap);
    } else if (uriMatcher.match(uri) == 2) {
        sqlBuilder.setProjectionMap(mMap);
        sqlBuilder.appendWhere(ID + "=?");
        selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
                new String[] { uri.getLastPathSegment() });
    }
    if (sortOrder == null || sortOrder == "")
        sortOrder = START_DATE + " COLLATE LOCALIZED ASC";
    Cursor c = sqlBuilder.query(db, projection, selection, selectionArgs,
            null, null, sortOrder);
    c.setNotificationUri(getContext().getContentResolver(), uri);
    return c;
}

特别是这里的这段代码

if (sortOrder == null || sortOrder == "")
    sortOrder = START_DATE + " COLLATE LOCALIZED ASC";
Cursor c = sqlBuilder.query(db, projection, selection, selectionArgs,
        null, null, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);

如您所见,我将setNotificationUri其称为文档所说的

Register to watch a content URI for changes. This can be the URI of a specific data row (for example, "content://my_provider_type/23"), or a a generic URI for a content type.

和 ContentResolver 参数说

The content resolver from the caller's context. The listener attached to this resolver will be notified.
于 2013-06-26T16:08:14.080 回答
0

好吧,伙计们,我找到了答案。我已经覆盖了我的 CustomAdapter 的 getCursor() 方法,它正在返回 super.getCursor(); 显然(duh)当我实例化我的适配器对象时,超级的光标被设置为 null 所以它总是返回 null :)

感谢您的所有建议。

于 2013-06-26T17:07:25.067 回答