在android中经常会用到改变数据库内容后再去使用数据库更新的内容,很多人会重新去query一遍,但是这样的问题就是程序会特别占内存,而且有可能会搂关cursor而导致程序内存未释放等等。其实android内部提供了一种ContentObserver的东西来监听数据库内容的变化。
ContentObserver的构造函数需要一个参数Hanlder,因为ContentObserver内部使用了一个实现Runnable接口的内部类NotificationRunnable,来实现数据库内容的变化。需要使用hanlder去post消息。注册ContentObserver的方法是:getContentResolver().registerContentObserver(uri, notifyForDescendents, observer).
上面3个参数为:
uri----Uri类型,是需要监听的数据库的uri.
notifyForDescendents---boolean true的话就会监听所有与此uri相关的uri。false的话则是直接特殊的uri才会监听。一般都设置为true.
observer-----ContentObserver 就是需要的contentobserver.
初始化一个ContentObserver对象,重载onChange(boolean ),在这个方法里去操作数据库的使用,针对变化后的使用。
写了一个小demo,可以参考下。提示这种监听方式必须是contentprovider才能使用,因为contentprovider有uri.简单的那种sqlite数据库没有uri是使用不了的。
下面demo操作的是在一个activityA里点击button跳转至另外一个activityB,在B中点击button往数据库中加数据,加完后关闭B回到A。A的button的文字自动变化设置到数据库中的字符串。
package ty.com.lto; import android.app.Activity; import android.content.Intent; import android.database.ContentObserver; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; public class ListenDataTest extends Activity{ private Button testBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listen_data_test); getContentResolver().registerContentObserver(DataChangeProvider.CONTENT_URI, true, cob); testBtn = (Button)findViewById(R.id.test_btn); testBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Intent in = new Intent(ListenDataTest.this,DataChangeTest.class); startActivity(in); } }); } private ContentObserver cob = new ContentObserver(new Handler()) { @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); testBtn.setText(DataUtils.getChangeName(getApplicationContext())); } }; @Override protected void onDestroy() { super.onDestroy(); getContentResolver().unregisterContentObserver(cob); } }
package ty.com.lto; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.database.ContentObservable; import android.database.ContentObserver; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; public class DataChangeTest extends Activity{ private Button dataBtn; DataSqlite mDataSqlite; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.data_change_test); dataBtn = (Button)findViewById(R.id.data_test_btn); mDataSqlite = new DataSqlite(this); dataBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { ContentValues con = new ContentValues(); con.put("name", "数据变化了"); getContentResolver().insert(DataChangeProvider.CONTENT_URI, con); finish(); } }); } }
package ty.com.lto; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.net.Uri; import android.text.TextUtils; public class DataChangeProvider extends ContentProvider{ private SQLiteOpenHelper mOpenHelper; private static final int ALARMS = 1; private static final int ALARMS_ID = 2; private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH); public static final Uri CONTENT_URI = Uri.parse("content://ty.com.lto/test"); static { sURLMatcher.addURI("ty.com.lto", "test", ALARMS); sURLMatcher.addURI("ty.com.lto", "test/#", ALARMS_ID); } private static class DatabaseHelper extends SQLiteOpenHelper{ private static final String TEST_DATABASE = "test.db"; private static final int VERSION = 1; public DatabaseHelper(Context context) { super(context, TEST_DATABASE, null, VERSION); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE "+"test"+" (" + "_id INTEGER PRIMARY KEY," + "name TEXT "+ ");"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "DROP TABLE IF EXIST "+TEST_DATABASE; db.execSQL(sql); onCreate(db); } } public DataChangeProvider() { } @Override public int delete(Uri url, String where, String[] whereArgs) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; long rowId = 0; switch (sURLMatcher.match(url)) { case ALARMS: count = db.delete("test", where, whereArgs); break; case ALARMS_ID: String segment = url.getPathSegments().get(1); rowId = Long.parseLong(segment); if (TextUtils.isEmpty(where)) { where = "_id=" + segment; } else { where = "_id=" + segment + " AND (" + where + ")"; } count = db.delete("test", where, whereArgs); break; default: throw new IllegalArgumentException("Cannot delete from URL: " + url); } getContext().getContentResolver().notifyChange(url, null); return count; } @Override public String getType(Uri url) { int match = sURLMatcher.match(url); switch (match) { case ALARMS: return "vnd.android.cursor.dir/alarms"; case ALARMS_ID: return "vnd.android.cursor.item/alarms"; default: throw new IllegalArgumentException("Unknown URL"); } } @Override public Uri insert(Uri url, ContentValues initialValues) { if (sURLMatcher.match(url) != ALARMS) { throw new IllegalArgumentException("Cannot insert into URL: " + url); } ContentValues values; if (initialValues != null) { values = new ContentValues(initialValues); } else { values = new ContentValues(); } if (!values.containsKey("name")) values.put("name", ""); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert("test", null, values); if (rowId < 0) { throw new SQLException("Failed to insert row into " + url); } Uri newUrl = ContentUris.withAppendedId(CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(newUrl, null); return newUrl; } @Override public boolean onCreate() { mOpenHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri url, String[] projection, String where, String[] whereArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); int match = sURLMatcher.match(url); switch (match) { case ALARMS: qb.setTables("test"); break; case ALARMS_ID: qb.setTables("test"); qb.appendWhere("_id="); qb.appendWhere(url.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unknown URL " + url); } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor cur = qb.query(db, projection, where, whereArgs,null, null, sortOrder); if (cur != null) { cur.setNotificationUri(getContext().getContentResolver(), url); } return cur; } @Override public int update(Uri url, ContentValues values, String where,String[] whereArgs) { int count; long rowId = 0; int match = sURLMatcher.match(url); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); switch (match) { case ALARMS_ID: { String segment = url.getPathSegments().get(1); rowId = Long.parseLong(segment); count = db.update("test", values, "_id=" + rowId, null); break; } default: { throw new UnsupportedOperationException( "Cannot update URL: " + url); } } getContext().getContentResolver().notifyChange(url, null); return count; } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ty.com.lto" android:versionCode="1" android:versionName="1.0" > <application android:icon="@drawable/icon" android:label="@string/app_name"> <provider android:name="DataChangeProvider" android:authorities="ty.com.lto"/> <activity android:name=".ListenDataTest" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DataChangeTest" android:label="@string/app_name"/> </application> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> </manifest>
转载自:http://dev.10086.cn/cmdn/bbs/viewthread.php?tid=37427&extra=page%3D1%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D67