mik*_*ehl 16 database sqlite android android-contentresolver
我见过的所有例子registerContentObserver()都是通过ContentProvider界面实现的.但Cursor有一个registerContentObserver()调用,所以我想也许Android人们已经把一些深刻的魔法放在一起,SQLite当活动结果集中的一行改变时,它允许在游标上获得更新.我做错了,或者没有这样的魔法.这是我正在使用的代码,期望是当我点击按钮更新第1行中的值时,我会得到一个onChange()回调.有任何想法吗?
public class MainActivity extends Activity {
private static final String DATABASE_NAME = "test.db";
public static final String TAG = "dbtest";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button make = (Button)findViewById(R.id.btn_make_record);
make.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
MyOpenHelper oh = new MyOpenHelper(v.getContext());
SQLiteDatabase wdb = oh.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("value", String.valueOf(System.currentTimeMillis()));
if (wdb.insert(MyOpenHelper.TABLE_NAME, null, cv) == -1) {
Log.d(TAG, "Unable to insert row");
} else {
Log.d(TAG, "Inserted row ");
}
wdb.close();
}
});
Button update = (Button)findViewById(R.id.btn_update_record);
update.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
MyOpenHelper oh = new MyOpenHelper(v.getContext());
SQLiteDatabase wdb = oh.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("value", String.valueOf(System.currentTimeMillis()));
int count = wdb.update(MyOpenHelper.TABLE_NAME, cv, "_id = ?", new String[] {"1"});
Log.d(TAG, "Updated " + count + " row(s)");
wdb.close();
}
});
MyOpenHelper oh = new MyOpenHelper(this);
SQLiteDatabase rdb = oh.getReadableDatabase();
Cursor c = rdb.query(MyOpenHelper.TABLE_NAME, null, "_id = ?", new String[] {"1"}, null, null, null);
startManagingCursor(c);
contentObserver = new MyContentObserver(new Handler());
c.registerContentObserver(contentObserver);
}
private class MyContentObserver extends ContentObserver {
MyContentObserver(Handler handler) {
super(handler);
}
public boolean deliverSelfNotifications() {
return true;
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "Saw a change in row # 1");
}
}
MyContentObserver contentObserver;
public class MyOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "test";
private static final String TABLE_CREATE =
"CREATE TABLE " + TABLE_NAME + " (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"value TEXT);";
MyOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*ato 21
这实际上是可能的.
你必须在某处定义一个Uri(也许是一个常数).
我建议使用这样的东西:
public static final Uri URI_MY_TABLE =
Uri.parse("sqlite://com.example.<your-app-package>/table");
Run Code Online (Sandbox Code Playgroud)
然后,当您更新数据库数据时,您调用:
context.getContentResolver().notifyChange(Constants.URI_MY_TABLE, null);
Run Code Online (Sandbox Code Playgroud)
从您正在编写的CursorLoader中执行以下操作:
final ForceLoadContentObserver observer;
public MyCursorLoader(final Context context, ...) {
super(context);
// ...
this.observer = new ForceLoadContentObserver();
}
@Override
public Cursor loadInBackground() {
SQLiteDatabase db = this.dbHelper.getReadableDatabase();
final Cursor c = queryDatabase(db);
if (c != null) {
// Ensure the cursor window is filled
c.getCount();
// this is to force a reload when the content change
c.registerContentObserver(this.observer);
// this make sure this loader will be notified when
// a notifyChange is called on the URI_MY_TABLE
c.setNotificationUri(getContext().getContentResolver(),
Constants.URI_MY_TABLE);
}
return c;
}
Run Code Online (Sandbox Code Playgroud)
该ForceLoadContentObserver是内部的公共静态内部类加载器类,如果您使用的是支持库将是android.support.v4.content.Loader.ForceLoadContentObserver
在同一个Loader中,如果数据发生变化,请确保使用forceReload:
@Override
protected void onStartLoading() {
if (this.cursor != null) {
deliverResult(this.cursor);
}
// this takeContentChanged() is important!
if (takeContentChanged() || this.cursor == null) {
forceLoad();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您不知道如何编写CursorLoader,那么这是一个良好的开端:没有ContentProvider的CursorLoader用法
您的CursorAdapter现在应该像这样初始化:
public MyCursorAdapter(Context context, Cursor c) {
super(context, c, 0);
}
Run Code Online (Sandbox Code Playgroud)
该ContentResolver的将在你设置的URI通知观察者的照顾.
这正是ContentProvider的工作原理.
如果您不使用装载机,您可以执行相同的操作,重要的修改是:
这样,当您注册观察者时,您将在底层数据发生变化时收到通知.
mik*_*ehl 15
不接受吧?这是一个很好的借口,可以挖掘自己并弄明白.对于那些可能对我感到好奇的人,如果您下载平台源代码,则需要查看相关文件:
frameworks/base/core/java/android/database/sqlite/SQLiteCursor.java frameworks/base/core/java/android/database/AbstractCursor.java
看起来mContentObservable用于指示程序的不同部分,该程序运行在Cursor中的缓存结果集中,而observable是来自缓存结果集的信号,以便让消费者知道缓存何时被转储/更新.在操作基础数据存储区时,它不会与SQLite实现绑定以触发事件.
并不奇怪,但考虑到我认为可能缺少一些东西的文档.
| 归档时间: |
|
| 查看次数: |
9097 次 |
| 最近记录: |