Android中很多内部数据都是保存在数据库中,例如 短信,通讯录,文件信息等。这些数据可以通过它们的Uri来查询,
常用的数据类型及其对应的数据库文件路径如下表。
数据类型 | 数据库路径 |
---|---|
通讯录 | /data/data/com.android.providers.contacts/databases/contacts2.db |
短信 | /data/data/com.android.providers.telephony/databases/mmssms.db |
文件信息 | /data/data/com.android.providers.media/databases/external.db |
查询方法为:
Context.getContentResolver().query(Uri uri,
String[] projection, String selection,
String[] selectionArgs, String sortOrder)
query方法包含五个参数,分别解析如下。
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String columns[] = new String[] {MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA};
String selection = IMAGE_BUCKET_DISPLAY_NAME + " IN (?,?,?)";
String[] selectionArgs = {"Screenshots", "Camera", "Download"};
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
mContext.getContentResolver().query(uri, columns, selection, selectionArgs, sortOrder);
其对应的SQL语句为
SELECT MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA
FROM MediaStore.Images.Media.EXTERNAL_CONTENT_URI
WHERE IMAGE_BUCKET_DISPLAY_NAME IN ("Screenshots", "Camera", "Download")
ORDER BY MediaStore.Images.Media.DATE_ADDED DESC
在查询数据库中信息时需要指定查询的Uri。
常用的数据类型及其查询Uri如下表。
数据类型 | 查询Uri |
---|---|
通讯录 | content://com.android.contacts/data |
短信 | content://sms/ 全部信息 |
文件信息 | content://media/external/images/media 图片数据 |
虽然可以通过query方法来查询数据库获取信息,但如果数据库中的信息发生了改变,那么获取到的信息也就随之失效。例如某次使用query方法查询到在Download目录中有一个图片,文件名为photo.jpg。但过段时间后可能这张图片被删除或重命名了。如果这时再去使用原先查询到的信息去读取这张图片,就会找不到文件。
因此,需要能够在数据库内容发生改变时通知应用去更新数据。
在Android中可以通过ContentObserver来监听数据库变化。
其使用方法为:
1、定义一个类继承自ContentObserver类
派生类中必须重写其构造方法和onChange()方法。
构造方法的原型为
public ContentObserver(Handler handler) { mHandler = handler;
}
参数handle用来向创建handler的线程发送消息。当ContentObserver对象收到数据库变化的消息后,如果handler为null,会直接调用onChange()方法,这时onChange()是在非UI线程中执行的。如果handler不为null,那么ContentObserver对象会调用handler的post方法将消息发送到创建handler的线程去执行onChange()方法。所以如果需要在onChange()中去执行查询数据库之类比较耗时的操作,则可以传入null handler。如果需要在onChange中更新UI界面,则必须在UI线程中new一个handler,并作为参数传入。
onChange()有两个重载的方法,其原型为
public void onChange(boolean selfChange) {}
public void onChange(boolean selfChange, Uri uri) {}
在低于API level 16 的系统中,会调用第一种不带Uri参数的onChange函数。在大于等于API level 16 的系统中,会调用带Uri参数的onChange函数。为了兼容性,两种onChange函数都需要重写。
Android SDK给出的建议实现方式为
public void onChange(boolean selfChange) {
onChange(selfChange,null);
}
public void onChange(boolean selfChange, Uri uri) {
....
}
即不带Uri参数的onChange方法直接调用带参数的onChange方法,并传入null作为Uri。onChange在处理时需要对Uri为null的情况做判断。
2、 注册监听某个数据库表格的变化
注册监听的方法为:
Context.getContentResolver().registerContentObserver(Uri uri,
boolean notifyForDescendents,
ContentObserver observer)
registerContentObserver方法包含三个参数。
3、解除监听
必须确保registerContentObserver和unregisterContentObserver的成对调用。在不需要监听时,调用unregisterContentObserver来解除监听。方法为:
mContext.getContentResolver().unregisterContentObserver(observer);
通常的做法是在Activity的onResume中调用registerContentObserver,在Activity的onPause中调用unregisterContentObserver。如果没有调用unregisterContentObserver,则会造成内存泄漏,相关的资源无法被回收。
使用ContentObserver监听图片数据库变化代码如下
public class ImageDataChangeObserver extends ContentObserver {
public ImageDataChangeObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.i("listview1", uri.toString());
}
}
private ImageDataChangeObserver mObserver;
public void registerContentObserver(Context context) {
mObserver = new ImageDataChangeObserver(null);
context.getContentResolver().registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, observer);
}
通过以上代码,可以监听图片数据库发生的改变。当图片数据库发生改变时会自动调用observer的onChange方法,通知监听对象更新数据和界面。