Android数据库内容变化的监听

首先介绍内容监测的基本模式

基于uri的内容监测的基本模式被android.content.ContentResolver实现。

它为基于Uri的内容监测的提供了一个平台。(其实如果有必要,我们可以自己实现一个)
ContentResolver为此提供了三个方法:
注册监听器到某个uri
public final void registerContentObserver (Uri uri, boolean notifyForDescendents, ContentObserver observer)

Register an observer class that gets callbacks when data identified by a given content URI changes.

Parameters

uri     The URI to watch for changes. This can be a specific row URI, or a base URI for a whole class of content.

notifyForDescendents     If true changes to URIs beginning with uri will also cause notifications to be sent.

If false only changes to the exact URI specified by uri will cause notifications to be sent.

If true, than any URI values at or below the specified URI will also trigger a match.

observer     The object that receives callbacks when changes occur.
取消被注册的监听器
public final void unregisterContentObserver (ContentObserver observer)

Unregisters a change observer.

参数

observer     The previously registered observer that is no longer needed.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void notifyChange (Uri uri, ContentObserver observer)

Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.

参数

observer     The observer that originated the change, may be null .用以说明observer是第一个发现内容改变的ContentObserver,可为null.
通知所有注册到uri的监听器,告诉他们内容发生了改变。
public void notifyChange (Uri uri, ContentObserver observer, boolean syncToNetwork)

Notify registered observers that a row was updated. To register, call registerContentObserver(). By default, CursorAdapter objects will get this notification.

参数

observer     The observer that originated the change, may be null 用以说明observer是第一个发现内容改变的ContentObserver,可为null

syncToNetwork     If true, attempt to sync the change to the network. 
注1:"基于uri的内容监测的基本模式被android.content.ContentResolver实现",严格来说ContentResolver至少提供了接口。

真正的实现在android.content.ContentService.

其实ContentResolver为基于Uri的内容监测所提供的方法只是调用ContentService相关的方法
注2:"注册监听器到uri"只是说如果notifyChange的uri和registerContentObserver中的uri相匹配,则调用observer的方法onChange。
内容监听器ContentObserver主要有三个方法
public boolean deliverSelfNotifications ()

Returns true if this observer is interested in notifications for changes made through the cursor the observer is registered with.

注:这个函数的使用还是puzzle.
public final void dispatchChange (boolean selfChange)

注:这个是为提供用handler执行onChange的一个接口。所以一般比没必要重载它。
public void onChange (boolean selfChange)

This method is called when a change occurs to the cursor that is being observed.

参数

selfChange     true if the update was caused by a call to commit on the cursor that is being observed.

注1:这个就是我们需要重载的函数,在里面可以实现对内容改变的个性化响应。

关于ContentObserver的更多内容请参阅《内容监听器ContentObserver》。

基本使用是这样的:

首先使用registerContentObserver注册observer监听器到uri,然后在内容发生改变时,就调用notifyChange通知系统所有注册到该uri的监听器,告诉他们内容发生了改变。

这时相应的监听器的dispatchChange方法被调用,在dispatchChange中onChange被调用。

最后如果不想让observer监听器uri相关的内容监听,可以调用unregisterContentObserver来取消注册。

对数据库改变的监测是如何实现的呢?

在providers对数据进行改变后,会通过getContext().getContentResolver().notifyChange的发生相应的uri的内容发生了改变

比如:com.android.providers.contacts中的ContactsProvider2

ContactsProvider2.java文件
public class ContactsProvider2 extends SQLiteContentProvider implements OnAccountsUpdateListener {
-------------------省略------------------
  @Override
    public Uri insert(Uri uri, ContentValues values) {
        waitForAccess();
        return super.insert(uri, values);
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-------------------省略------------------
        waitForAccess();
        return super.update(uri, values, selection, selectionArgs);
    }

@Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        waitForAccess();
        return super.delete(uri, selection, selectionArgs);
    }
}
-------------------省略------------------
    protected void notifyChange() {
        notifyChange(mSyncToNetwork);
        mSyncToNetwork = false;
    }

protected void notifyChange(boolean syncToNetwork) {
        getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null,
                syncToNetwork);
    }
    -------------------省略------------------
}

SQLiteContentProvider.java文件
public abstract class SQLiteContentProvider extends ContentProvider
        implements SQLiteTransactionListener {
   @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri result = null;
        boolean applyingBatch = applyingBatch();
        if (!applyingBatch) {
            mDb = mOpenHelper.getWritableDatabase();
            mDb.beginTransactionWithListener(this);
            try {
                result = insertInTransaction(uri, values);
                if (result != null) {
                    mNotifyChange = true;
                }
                mDb.setTransactionSuccessful();
            } finally {
                mDb.endTransaction();
            }

onEndTransaction();
        } else {
            result = insertInTransaction(uri, values);
            if (result != null) {
                mNotifyChange = true;
            }
        }
        return result;
    }
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        -------------------省略------------------
    }
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        -------------------省略------------------
    }
 -------------------省略------------------
 protected abstract void notifyChange();
 -------------------省略------------------
    protected void onEndTransaction() {
        if (mNotifyChange) {
            mNotifyChange = false;
            notifyChange();
        }
    }
 -------------------省略------------------
}
那么Cursor是如何实现对基于uri的数据库内容变化进行监听呢?

只要把一个监听器ContentObserver对uri使用ContentResolver的registerContentObserver方法进行注册。

如果相应uri的数据库内容变化发变化,先通知ContentObserver,再又让它通知Cursor。

当然为了方便系统把ContentObserver设计成了内部类。

具体可见在Cursor接口的一个实现android.database.AbstractCursor。

AbstractCursor.java文件请见附件1

同时Cursor为我们提供了setNotificationUri(ContentResolver cr, Uri notifyUri)让它内部类的ContentObserver注册到ContentResolver的某个Uri上.

具体代码参见附件1
那么外部如何监听Cursor呢?。
Cursor为外部监测数据库的变化提供了以下接口:

abstract void     registerContentObserver(ContentObserver observer)

Register an observer that is called when changes happen to the content backing this cursor.

注1:当数据库内容变化时通知observer,具体见附件1的onChange(boolean selfChange)函数.

注2:这个监听器observer主要是在setNotificationUri(ContentResolver cr, Uri notifyUri)中notifyUri对应的数据库内容发生变化时被通知的(间接),

abstract void     unregisterContentObserver(ContentObserver observer)

Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).

另外,Cursor还为我们提供了接口,让外部可以通过注册一个DataSetObserver来对Cursor的requery(), deactivate(),
close()行为进行监听。

abstract void     registerDataSetObserver(DataSetObserver observer)

Register an observer that is called when changes happen to the contents of the this cursors data set, for example, when the data set is changed via requery(), deactivate(), or close().

注1:当Cursor发生requery(), deactivate(), or close()时通知DataSetObserver observer

abstract void     unregisterDataSetObserver(DataSetObserver observer)

Unregister an observer that has previously been registered with this cursor via registerContentObserver(ContentObserver).

DataSetObserver的主要方法

Public Methods
void onChanged()

This method is called when the entire data set has changed, most likely through a call to requery() on
Cursor.

void onInvalidated()

This method is called when the entire data becomes invalid, most likely through a call to deactivate() or close() on
Cursor.

那么CursorAdapter是如何实现对基于uri的数据库内容变化进行监听呢?

它当然是借助Cursor来实现的。

但是CursorAdapter与ContentObserver相对应对外提供(可以重载)的接口是:
onContentChanged()

当时CursorAdapter与DataSetObserver相对应对外提供(可以重载)的接口是:
onChanged()->notifyDataSetChanged()//这个消息并完全不是从Cursor传递来,它会在CursorAdapter内手动被调用
onInvalidated()->notifyDataSetInvalidated()//这个消息并不是从Cursor传递来。

具体可以参照附件2的android.widget.CursorAdapter源代码
CursorAdapter的notifyDataSetChanged()和notifyDataSetInvalidated()事件可以继续往外传递

BaseAdapter为此提供了以下系列方法。

void notifyDataSetChanged()

Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

void notifyDataSetInvalidated()

Notifies the attached observers that the underlying data is no longer valid or available.

void registerDataSetObserver(DataSetObserver observer)

Register an observer that is called when changes happen to the data used by this adapter.

void unregisterDataSetObserver(DataSetObserver observer)

Unregister an observer that has previously been registered with this adapter via registerDataSetObserver(DataSetObserver).

android.widget.BaseAdapter的部分源代码如下:

public abstract class BaseAdapter implements ListAdapter,
SpinnerAdapter {

private final DataSetObservable mDataSetObservable = new DataSetObservable();

public boolean hasStableIds() { return false; }

public void registerDataSetObserver(DataSetObserver
observer) { mDataSetObservable.registerObserver(observer); }

public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer);
}

/** * Notifies the attached View that the underlying data has been changed * and it should refresh itself. */

public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); }

public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated();
}

-------------------省略------------------

}

注意:对于BaseAdapter,外部可以强行调用notifyDataSetChanged和notifyDataSetInvalidated来通知DataSetObserver
observer

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://www.cnblogs.com/captainbed

原文地址:https://www.cnblogs.com/siwnchh/p/10234772.html

时间: 2024-08-03 08:56:47

Android数据库内容变化的监听的相关文章

Android开发之使用广播监听网络状态变化

我们经常需要判断网络状态的变化,如有无网络,所以需要监听网络状态的变化,比如网络断开,网络连接给予友好提示.如何监听网络状态的变化呢,最近工作中需要用到这个,于是就用广播机制来实现了网络状态的监听. 使用广播机制来监听网络状态主要涉及到以下几点: 1.需要自己编写个网络广播接收器,该接收器继承BroadcastReceiver类,用来接收系统发出的广播.比如我自己写了个NetStatusReceiver广播接收器.代码如下: package com.log.system; import andr

Android NDK开发(八)——应用监听自身卸载,弹出用户反馈调查

转载请注明出处:http://blog.csdn.net/allen315410/article/details/42521251 监听卸载情景和原理分析 1,情景分析 在上上篇博客中我写了一下NDK开发实践项目,使用开源的LAME库转码MP3,作为前面几篇基础博客的加深理解使用的,但是这样的项目用处不大,除了练练NDK功底.这篇博客,我将讲述一下一个各大应用中很常见的一个功能,同样也是基于JNI开发的Android应用小Demo,看完这个之后,不仅可以加深对NDK开发的理解,而且该Demo也可

Android开机和关机广播监听

Android开机.关机广播监听 一.开机广播的监听 1.在AndroidManifest.xml文件注册接收开机广播 <receiver android:name=".XXXBroadcastReceiver" > <intent-filter> <!-- 开机广播 --> <action android:name="android.intent.action.BOOT_COMPLETED" /> </inte

android的Home键的监听封装工具类(一)

android的Home键的监听封装: 1 package com.gzcivil.utils; 2 3 import android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.content.IntentFilter; 7 8 /** 9 * Home键监听封装 10 * 11 */ 12 public class

Android 通过系统使用NotificationListenerService 监听各种Notification的使用方法

NotificationListenerService是通过系统调起的服务,当有应用发起通知的时候,系统会将通知的动作和信息回调给NotificationListenerService. 在继承NotificationListenerService服务实现自己逻辑之前,需要在配置文件中添加如下代码,获取权限. <service android:name=".NotificationListener" android:label="@string/service_name

PIE SDK图层渲染变化事件监听

1. 功能简介 通过PIE SDK加载图层后,会默认的赋值给数据一个渲染.当用户重新给数据赋值Render或改变数据显示效果时,会触发渲染变化事件. 所谓的事件监听是在事件触发时,将执行用户指定的函数或方法,已实现特定的功能. 2. 功能实现说明 2.1 实现思路及原理说明 第一步 栅格图层接口转换至ILayerEvents 第二步 OnRenderChanged进行事件绑定,以达到监听目的. 2.2  核心接口与方法 接口/类 方法 说明 Carto. ILayerEvents OnRende

Android之EditText文本变化的监听

监听EditText的文本变化需要给EditText控件加一个addTextChangeListener监听器 editText.addTextChangeListener(textWatcher);  这里的textWatcher是一个TextWatcher对象, TextWatcher是一个接口,它有三个抽象方法,具体如下: /** *文本改变之前调用 * @param s 输入框的原内容字符串 * @param start 字符串开始改变的索引位置 * @param count 即将被替换

手机影音第十天,控制屏幕上下滑动改变音量变化,监听物理键改变音量

代码已托管至码云上,有兴趣的小伙伴可以下载看看,IDE是Android studio 2.3.2 https://git.oschina.net/joy_yuan/MobilePlayer 常见的手机播放器,都有屏幕上下滑动改变音量大小的功能,在此也实现下: 原理是: 1.从手指触碰屏幕,到离开屏幕,计算滑动的高度差,然后拿这个高度差与屏幕的高对比,最后结合总音量,得到改变的音量,具体的公式如下 : 改变的音量=(滑动距离差/屏幕总高度)*总音量 结束滑动后的音量=触碰屏幕时的音量+改变的音量

EditText 内容 按键 输入法 监听 示例

内容.输入法.焦点 1.弹出窗口时自动让控件获取焦点,并弹出输入法.注意要在onCreate中法中设置,不能在onResume中设置. et.requestFocus(); new Timer().schedule(new TimerTask() {//Timer是一种定时器工具,用来在一个后台线程计划执行指定任务. //它可以计划执行一个任务一次或反复多次.TimerTask是一个抽象类,它的子类代表一个可以被Timer计划的任务. @Override public void run() {/