Android : Content Provider 一次添加两行

Android : Content Provider adds two rows at a time

我在 Content Providers 上关注了这个 tutorial,它运行良好。 我自己尝试了一些东西并使用 Loaders 加载数据。而且我无法实现以下目标:

因此,每次我单击 发送消息 按钮时,它都会添加两行。 这是 logcat 文件。

07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 1, , 1468526093018
07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 2, , 1468526093018
07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 3, , 1468526292717
07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 4, , 1468526292717
07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 5, , 1468696845898
07-17 02:57:18.307 11619-11619/poketpixels.reminder D/DB: 6, , 1468696845898

注意BODY没有文字显示,两行的时间戳是相等的。如此自然,同时创建。

以下是 activity 文件:

public class ActivityChat extends AppCompatActivity
    implements LoaderManager.LoaderCallbacks<Cursor> {

private static final int URL_LOADER = 0;
String URL = "content://something/messages";
Button sendMessage;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);

    sendMessage = (Button)findViewById(R.id.btnSend);

    getLoaderManager().initLoader(URL_LOADER, null, this);

    sendMessage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SendMessage();
        }
    });

}



public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    CursorLoader loader = new CursorLoader(
            this,
            Uri.parse(URL),
            null,
            null,
            null,
            null);

    return loader;
}



public void onLoadFinished(
        Loader<Cursor> loader,
        Cursor c) {

 // LOADS ALL ROWS 
    if (c.moveToFirst()) {
        do {
            Log.d("DB",
                    c.getString(c.getColumnIndex(MessageProvider._ID)) +
                            ", " + c.getString(c.getColumnIndex(MessageProvider.BODY)) +
                            ", " + c.getString(c.getColumnIndex(MessageProvider.CREATED_AT)) + "\n"
            );
        } while (c.moveToNext());
    }

}


@Override
public void onLoaderReset(Loader<Cursor> loader) {

}

public void SendMessage() {

    // Add a new message record
    ContentValues values = new ContentValues();

    values.put(MessageProvider.BODY,
            ((EditText)findViewById(R.id.eTmessageBody)).getText().toString());

    values.put(MessageProvider.CREATED_AT,
            (System.currentTimeMillis()));

    Log.d("DB", "SENT ALREADY");
    Uri messages = Uri.parse(URL);

    Cursor c = getContentResolver().query(messages, null, null, null, "created_at");

    //loads only the last row
    c.moveToLast();
    Log.d("LAST ROW",c.getString(c.getColumnIndex(MessageProvider._ID)) +
            ", " +  c.getString(c.getColumnIndex( MessageProvider.BODY)) +
            ", " + c.getString(c.getColumnIndex( MessageProvider.CREATED_AT)) );

}

}

MessageProvider.java

public class MessageProvider extends ContentProvider {

static final String PROVIDER_NAME = "something";
static final String URL = "content://" + PROVIDER_NAME + "/messages";
public static final Uri CONTENT_URI = Uri.parse(URL);

public static final String _ID = "_id";
public static final String BODY = "body";
public static final String CREATED_AT = "created_at";

private static HashMap<String, String> MESSAGES_PROJECTION_MAP;

static final int MESSAGES = 1;
static final int MESSAGE_ID = 2;

static final UriMatcher uriMatcher;
static {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(PROVIDER_NAME, "messages", MESSAGES);
    uriMatcher.addURI(PROVIDER_NAME, "messages/#", MESSAGE_ID);
}


/**
 * Database specific constant declarations
 */
private SQLiteDatabase db;
static final String DATABASE_NAME = "test";
static final String MESSAGES_TABLE_NAME = "message";
static final int DATABASE_VERSION = 1;
static final String CREATE_DB_TABLE =
        " CREATE TABLE " + MESSAGES_TABLE_NAME +
                " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                " body TEXT NOT NULL, " +
                " created_at TEXT NOT NULL);";

/**
 * Helper class that actually creates and manages
 * the provider's underlying data repository.
 */
private static class DatabaseHelper extends SQLiteOpenHelper {
    DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

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

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

@Override
public boolean onCreate() {
    Context context = getContext();
    DatabaseHelper dbHelper = new DatabaseHelper(context);

    /**
     * Create a write able database which will trigger its
     * creation if it doesn't already exist.
     */
    db = dbHelper.getWritableDatabase();
    return (db == null) ? false : true;
}

@Override
public Uri insert(Uri uri, ContentValues values) {

    final long objectId = db.insertOrThrow(MessageProvider.MESSAGES_TABLE_NAME, null, values);
    final Uri newObjectUri = ContentUris.withAppendedId(CONTENT_URI, objectId);
    getContext().getContentResolver().notifyChange(newObjectUri, null);

    /**
     * Add a new message record
     */
    long rowID = db.insert(MESSAGES_TABLE_NAME, "", values);

    /**
     * If record is added successfully
     */

    if (rowID > 0) {
        Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
        getContext().getContentResolver().notifyChange(_uri, null);
        return _uri;
    }
    throw new SQLException("Failed to add a record into " + uri);
}

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


    switch (uriMatcher.match(uri)) {
        case MESSAGES:
            qb.setProjectionMap(MESSAGES_PROJECTION_MAP);
            break;

        case MESSAGE_ID:
            qb.appendWhere(_ID + "=" + uri.getPathSegments().get(1));
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }

    if (sortOrder == null || sortOrder == "") {
        /**
         * By default sort on time
         */
        sortOrder = CREATED_AT;
    }
    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

    /**
     * register to watch a content URI for changes
     */
    c.setNotificationUri(getContext().getContentResolver(), uri);
    return c;
}


@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    int count = 0;


    //public int delete(String table, String whereClause, String[] whereArgs) {

    final long objectId = db.delete(MessageProvider.MESSAGES_TABLE_NAME, null, null);
    final Uri newObjectUri = ContentUris.withAppendedId(CONTENT_URI, objectId);
    getContext().getContentResolver().notifyChange(newObjectUri, null);


    switch (uriMatcher.match(uri)) {
        case MESSAGES:
            count = db.delete(MESSAGES_TABLE_NAME, selection, selectionArgs);
            break;

        case MESSAGE_ID:
            String id = uri.getPathSegments().get(1);
            count = db.delete(MESSAGES_TABLE_NAME, _ID + " = " + id +
                    (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }

    getContext().getContentResolver().notifyChange(uri, null);
    return count;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    int count = 0;


    final long objectId = db.insertOrThrow(MessageProvider.MESSAGES_TABLE_NAME, null, values);
    final Uri newObjectUri = ContentUris.withAppendedId(CONTENT_URI, objectId);
    getContext().getContentResolver().notifyChange(newObjectUri, null);


    switch (uriMatcher.match(uri)) {
        case MESSAGES:
            count = db.update(MESSAGES_TABLE_NAME, values, selection, selectionArgs);
            break;

        case MESSAGE_ID:
            count = db.update(MESSAGES_TABLE_NAME, values, _ID + " = " + uri.getPathSegments().get(1) +
                    (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return count;
}

@Override
public String getType(Uri uri) {
    switch (uriMatcher.match(uri)) {
        /**
         * Get all message records
         */
        case MESSAGES:
            return "vnd.android.cursor.dir/vnd.poketpixels.reminder.messages";

        /**
         * Get a particular message
         */
        case MESSAGE_ID:
            return "vnd.android.cursor.item/vnd.poketpixels.reminder.messages";

        default:
            throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
}
}

所以这两个问题是 :

编辑:

第二个问题解决了。 但是,我仍然无法显示字符串。在 logcat.

中显示空值

您在插入方法中插入了两次记录。

one by using :     final long objectId = db.insertOrThrow(MessageProvider.MESSAGES_TABLE_NAME, null, values);


Another by :  long rowID = db.insert(MESSAGES_TABLE_NAME, "", values);

从 class MessageProvider 的插入方法中删除上述行之一。