古人已用三冬足,年少今开万卷余。这篇文章主要讲述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
a
Cursor . | ||||||||||
void |
onInvalidated()This method is called when the entire data becomes invalid, most likely through a call to
deactivate()
or
close()
on
a
Cursor . |
它当然是借助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虚拟机体系结构
- Android 简单的语音播报
- Android8.0通知
- Android动态自动匹配输入框
- 安卓手机传递文件到Windows系统电脑
- Cordova????????????App?????? - ??????
- Twitter数据挖掘(使用Python进行大数据分析的指南)
- 迁移旧数据而不用担心
- HDFS教程,适用于陷入关系数据库的数据分析师