Android数据库内容变化的监听

首先介绍内容监测的基本模式
基<wbr style="line-height:25px">于<span style="color:#ff0000; line-height:25px">uri</span><span style="color:#003366; line-height:25px">的内容监测的基本模式被</span><span style="color:#ff6600; line-height:25px">android.content.ContentResolver</span><span style="color:#003366; line-height:25px">实现</span><wbr style="line-height:25px">。<br style="line-height:25px"> 它为基于Uri的内容监测的提供了一个平台。(其实如果有必要,我们可以自己实现一个)<br style="line-height:25px"><span style="color:#ff00ff; line-height:25px">ContentResolver</span>为此提供了三个方法:<br style="line-height:25px"><wbr style="line-height:25px"><span style="color:#003366; line-height:25px">注册监听器到某个</span><span style="color:#339966; line-height:25px">uri</span><wbr style="line-height:25px"><br style="line-height:25px"><span style="color:#993300; line-height:25px">publicfinalvoid</span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">registerContentObserver</wbr></span><wbr style="line-height:25px">(Uriuri,booleannotifyForDescendents,ContentObserverobserver)<br style="line-height:25px"> RegisteranobserverclassthatgetscallbackswhendataidentifiedbyagivencontentURIchanges.<br style="line-height:25px"> Parameters<br style="line-height:25px"> uriTheURItowatchforchanges.ThiscanbeaspecificrowURI,orabaseURIforawholeclassofcontent.<br style="line-height:25px"> notifyForDescendentsIftruechangestoURIsbeginningwithuriwillalsocausenotificationstobesent.<br style="line-height:25px"> IffalseonlychangestotheexactURIspecifiedbyuriwillcausenotificationstobesent.<br style="line-height:25px"> Iftrue,thananyURIvaluesatorbelowthespecifiedURIwillalsotriggeramatch.<br style="line-height:25px"> observerTheobjectthatreceivescallbackswhenchangesoccur.<br style="line-height:25px"><wbr style="line-height:25px"><span style="color:#003366; line-height:25px">取消被注册的监听器</span><wbr style="line-height:25px"><br style="line-height:25px"><span style="color:#993300; line-height:25px">publicfinalvoid</span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">unregisterContentObserver</wbr></span><wbr style="line-height:25px">(ContentObserverobserver)<br style="line-height:25px"> Unregistersachangeobserver.<br style="line-height:25px"> 参数<br style="line-height:25px"> observerThepreviouslyregisteredobserverthatisnolongerneeded.<br style="line-height:25px"><span style="color:#003366; line-height:25px">通知所有注册到uri的监听器,告诉他们内容发生了改变。</span><br style="line-height:25px"><span style="color:#993300; line-height:25px">publicvoid</span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">notifyChange</wbr></span><wbr style="line-height:25px"><span style="line-height:25px"></span>(Uriuri,ContentObserver<span style="color:#339966; line-height:25px">observer</span>)<br style="line-height:25px"> Notifyregisteredobserversthatarowwasupdated.Toregister,callregisterContentObserver().Bydefault,CursorAdapterobjectswillgetthisnotification.<br style="line-height:25px"> 参数<br style="line-height:25px"> observerTheobserverthatoriginatedthechange,maybenull .用以说明<span style="color:#339966; line-height:25px">observer</span>是第一个发现内容改变的ContentObserver,可为null.<br style="line-height:25px"><span style="color:#003366; line-height:25px">通知所有注册到uri的监听器,告诉他们内容发生了改变。</span><br style="line-height:25px"><span style="color:#993300; line-height:25px">publicvoid</span><span style="color:#ff6600; line-height:25px"><span style="line-height:25px"></span><wbr style="line-height:25px">notifyChange</wbr></span><wbr style="line-height:25px">(Uriuri,ContentObserverobserver,booleansyncToNetwork)<br style="line-height:25px"> Notifyregisteredobserversthatarowwasupdated.Toregister,callregisterContentObserver().Bydefault,CursorAdapterobjectswillgetthisnotification.<br style="line-height:25px"> 参数<br style="line-height:25px"> observerTheobserverthatoriginatedthechange,maybenull用以说明<span style="color:#339966; line-height:22px">observer</span>是第一个发现内容改变的ContentObserver,可为null<br style="line-height:25px"> syncToNetworkIftrue,attempttosyncthechangetothenetwork.<br style="line-height:25px"><span style="line-height:25px">注1</span>:"基于uri的内容监测的基本模式被android.content.ContentResolver实现",严格来说ContentResolver至少提供了接口。<br style="line-height:25px"> 真正的实现在android.content.ContentService.<br style="line-height:25px"> 其实ContentResolver为基于Uri的内容监测所提供的方法只是调用ContentService相关的方法<br style="line-height:25px"><span style="line-height:25px">注2</span>:<span style="color:#000080; line-height:25px">"注册监听器到</span><span style="color:#339966; line-height:25px">uri</span><span style="color:#000080; line-height:25px">"只是说如果</span><span style="color:#ff6600; line-height:25px">notifyChange</span><span style="color:#000080; line-height:25px">的</span><span style="color:#339966; line-height:25px">uri</span><span style="color:#000080; line-height:25px">和</span><span style="color:#ff6600; line-height:25px">registerContentObserver</span><span style="color:#000080; line-height:25px">中的</span><span style="color:#339966; line-height:25px">uri</span><span style="color:#000080; line-height:25px">相匹配,则调用</span><span style="color:#ff9900; line-height:25px">observer</span><span style="color:#000080; line-height:25px">的方法</span><span style="color:#008000; line-height:25px">onChange</span><span style="color:#000080; line-height:25px">。</span><br style="line-height:25px"><span style="color:#003366; line-height:25px">内容监听器</span><span style="color:#ff00ff; line-height:25px">ContentObserver</span><span style="color:#003366; line-height:25px">主要有三个方法</span><br style="line-height:25px"><span style="color:#993300; line-height:25px">publicboolean</span><wbr style="line-height:25px"><span style="color:#ff6600; line-height:25px">deliverSelfNotifications<wbr style="line-height:25px">()</wbr></span><br style="line-height:25px"> Returnstrueifthisobserverisinterestedinnotificationsforchangesmadethroughthecursortheobserverisregisteredwith.<br style="line-height:25px"> 注:这个函数的使用还是puzzle.<br style="line-height:25px"><span style="color:#993300; line-height:25px">publicfinalvoid</span><wbr style="line-height:25px"><span style="color:#ff6600; line-height:25px">dispatchChange</span><wbr style="line-height:25px">(booleanselfChange)<br style="line-height:25px"> 注:这个是为提供用handler执行onChange的一个接口。所以一般比没必要重载它。<br style="line-height:25px"><span style="color:#993300; line-height:25px">publicvoid</span><span style="color:#ff6600; line-height:25px">o<wbr style="line-height:25px">nChange</wbr></span><wbr style="line-height:25px">(booleanselfChange)<br style="line-height:25px"> Thismethodiscalledwhenachangeoccurstothecursorthatisbeingobserved.<br style="line-height:25px"> 参数<br style="line-height:25px"> selfChangetrueiftheupdatewascausedbyacalltocommitonthecursorthatisbeingobserved.<br style="line-height:25px"> 注1:这个就是我们需要重载的函数,在里面可以实现对内容改变的个性化响应。<br style="line-height:25px"> 关于ContentObserver的更多内容请参阅《<strong><a title="阅读全文" target="_blank" href="http://hubingforever.blog.163.com/blog/static/171040579201010154221692/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">内容监听器ContentObserver</a></strong>》。<br style="line-height:25px"> 基本使用是这样的:<br style="line-height:25px"> 首先使用<wbr style="line-height:25px"><span style="color:#ff00ff; line-height:25px">registerContentObserver</span><span style="color:#000080; line-height:25px">注册</span><span style="color:#339966; line-height:25px">observer</span><span style="color:#000080; line-height:25px">监听器到</span><span style="color:#99cc00; line-height:25px">uri</span><wbr style="line-height:25px">,然后在内容发生改变时,就调用<wbr style="line-height:25px"><span style="color:#339966; line-height:25px">notifyChange</span>通知系统所有注册到该<span style="color:#808000; line-height:25px">uri</span>的监听器<wbr style="line-height:25px">,告诉他们内容发生了改变。<br style="line-height:25px"> 这时相应的监听器的dispatchChange方法被调用,在dispatchChange中onChange被调用。<br style="line-height:25px"> 最后如果不想让<span style="color:#339966; line-height:25px">observer</span>监听器<span style="color:#808000; line-height:25px">uri</span>相关的内容监听,可以调用<wbr style="line-height:25px"><span style="color:#ff00ff; line-height:25px">unregisterContentObserve</span>r来取消注册<wbr style="line-height:25px">。<br style="line-height:25px"><br style="line-height:25px"> 对数据库改变的监测是如何实现的呢?<br style="line-height:25px"> 在providers对数据进行改变后,会通过<span style="color:#0000ff; line-height:25px">getContext().getContentResolver().<wbr style="line-height:25px">notifyChange</wbr></span><wbr style="line-height:25px">的发生相应的uri的内容发生了改变<br style="line-height:25px"> 比如:com.android.providers.contacts中的ContactsProvider2<br style="line-height:25px"> ContactsProvider2.java文件<br style="line-height:25px"><span style="color:#993300; line-height:25px">publicclass</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px">ContactsProvider2</span><span style="color:#993300; line-height:25px">extends</span><span style="color:#3366ff; line-height:25px">SQLiteContentProviderimplementsOnAccountsUpdateListener{</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">@Override</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicUriinsert(Uriuri,ContentValuesvalues){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">waitForAccess();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">returnsuper.insert(uri,values);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">@Override</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">waitForAccess();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">returnsuper.update(uri,values,selection,selectionArgs);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#808080; line-height:25px">@Override</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicintdelete(Uriuri,Stringselection,String[]selectionArgs){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">waitForAccess();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">returnsuper.delete(uri,selection,selectionArgs);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#993300; line-height:25px">protectedvoid</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">notifyChange<wbr style="line-height:25px">()</wbr></wbr></span><span style="color:#3366ff; line-height:25px"><span style="line-height:25px"></span>{</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">notifyChange(mSyncToNetwork);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mSyncToNetwork=false;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#993300; line-height:25px">protectedvoid</span><span style="color:#3366ff; line-height:25px"></span><wbr style="line-height:25px"><span style="color:#ff6600; line-height:25px">notifyChange</span><wbr style="line-height:25px"><span style="color:#3366ff; line-height:25px">(booleansyncToNetwork){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI,null,</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">syncToNetwork);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"> SQLiteContentProvider.java文件<br style="line-height:25px"><span style="color:#993300; line-height:25px">publicabstractclass</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px">SQLiteContentProvider</span><span style="color:#993300; line-height:25px">extends</span><span style="color:#3366ff; line-height:25px">ContentProvider</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">implementsSQLiteTransactionListener{</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">@Override</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicUriinsert(Uriuri,ContentValuesvalues){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">Uriresult=null;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">booleanapplyingBatch=applyingBatch();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">if(!applyingBatch){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mDb=mOpenHelper.getWritableDatabase();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mDb.beginTransactionWithListener(this);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">try{</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">result=insertInTransaction(uri,values);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">if(result!=null){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mNotifyChange=true;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mDb.setTransactionSuccessful();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}finally{</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mDb.endTransaction();</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#0000ff; line-height:25px"><wbr style="line-height:25px">onEndTransaction<wbr style="line-height:25px">();</wbr></wbr></span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}else{</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">result=insertInTransaction(uri,values);</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">if(result!=null){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mNotifyChange=true;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">returnresult;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs){</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">publicintdelete(Uriuri,Stringselection,String[]selectionArgs){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#993300; line-height:25px">protectedabstractvoid</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">notifyChange<wbr style="line-height:25px">();</wbr></wbr></span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#993300; line-height:25px">protectedvoid</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">onEndTransaction<wbr style="line-height:25px">()</wbr></wbr></span><span style="color:#3366ff; line-height:25px">{</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><span style="color:#993300; line-height:25px">if</span><span style="color:#3366ff; line-height:25px">(mNotifyChange){</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">mNotifyChange=false;</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px"></span><wbr style="line-height:25px"><strong></strong><span style="color:#0000ff; line-height:25px">notifyChange</span><span style="color:#0000ff; line-height:25px"><wbr style="line-height:25px">();</wbr></span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span><br style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span><br style="line-height:25px"><span style="color:#003366; line-height:25px">那么Cursor是如何实现对基于uri的数据库内容变化进行监听呢?<br style="line-height:25px"> 只要把一个监听器ContentObserver对uri使用ContentResolver的</span><span style="color:#ff00ff; line-height:25px">registerContentObserver</span><span style="color:#003366; line-height:25px">方法进行注册。<br style="line-height:25px"> 如果相应</span><span style="color:#808000; line-height:25px">uri</span><span style="color:#003366; line-height:25px">的数据库内容变化发变化,先通知</span><span style="color:#ff9900; line-height:25px">ContentObserver</span><span style="color:#003366; line-height:25px">,再又让它通知Cursor。</span><br style="line-height:25px"> 当然为了方便系统把ContentObserver设计成了<wbr style="line-height:25px"><span style="color:#0000ff; line-height:25px">内部类</span><wbr style="line-height:25px">。<br style="line-height:25px"> 具体可见在Cursor接口的一个实现<span style="color:#0000ff; line-height:25px">android.database.AbstractCursor</span>。<br style="line-height:25px"> AbstractCursor.java文件请见<a target="_blank" href="http://hubingforever.blog.163.com/blog/static/1710405792010101541737347/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">附件1</a><br style="line-height:25px"> 同时Cursor为我们提供了<span style="color:#ff00ff; line-height:25px"><wbr style="line-height:25px">setNotificationUri</wbr></span><wbr style="line-height:25px">(ContentResolvercr,UrinotifyUri)让它内部类的<wbr style="line-height:25px"><span style="color:#000080; line-height:25px">ContentObserver</span>注册<wbr style="line-height:25px">到ContentResolver的某个<wbr style="line-height:25px"><span style="color:#808000; line-height:25px">Uri</span><wbr style="line-height:25px">上.<br style="line-height:25px"> 具体代码参见<a target="_blank" href="http://hubingforever.blog.163.com/blog/static/1710405792010101541737347/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">附件1</a>。<br style="line-height:25px"><span style="color:#003366; line-height:25px">那么外部如何</span><span style="color:#ff00ff; line-height:25px">监听Cursor</span><span style="color:#003366; line-height:25px">呢?。</span><br style="line-height:25px"><span style="color:#ff00ff; line-height:25px">Cursor</span>为外部监测数据库的变化提供了以下接口:<br style="line-height:25px"> abstractvoid<span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">registerContentObserver</wbr></span><wbr style="line-height:25px">(ContentObserverobserver)<br style="line-height:25px"> Registeranobserverthatiscalledwhenchangeshappentothecontentbackingthiscursor.<br style="line-height:25px"> 注1:当数据库内容变化时通知observer,具体见<a target="_blank" href="http://hubingforever.blog.163.com/blog/static/1710405792010101541737347/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">附件1</a>的onChange(booleanselfChange)函数.<br style="line-height:25px"> 注2:这个监听器observer主要是在<span style="color:#0000ff; line-height:25px">setNotificationUri(ContentResolvercr,UrinotifyUri)</span>中notifyUri对应的数据库内容发生变化时被通知的(间接),<br style="line-height:25px"> abstractvoid<span style="color:#ff6600; line-height:25px"><wbr style="line-height:25px">unregisterContentObserver</wbr></span><wbr style="line-height:25px">(ContentObserverobserver)<br style="line-height:25px"> UnregisteranobserverthathaspreviouslybeenregisteredwiththiscursorviaregisterContentObserver(ContentObserver).<br style="line-height:25px"><div style="line-height:25px"> <div style="line-height:25px">另外,<span style="color:#ff00ff; line-height:25px">Cursor</span><span style="color:#003366; line-height:25px">还为我们提供了接口,让外部可以通过注册一个</span><span style="color:#ff6600; line-height:25px">DataSetObserver</span><span style="color:#003366; line-height:25px">来对Cursor的</span><span style="color:#0000ff; line-height:25px">requery(),deactivate(), close()</span><span style="color:#003366; line-height:25px">行为进行监听。</span> </div> <div style="line-height:25px">abstractvoid<span style="line-height:22px"><span style="color:#ff6600; line-height:22px"><wbr style="line-height:22px">registerDataSetObserve<span style="line-height:25px">r</span></wbr></span></span><wbr style="line-height:22px">(DataSetObserverobserver)<br style="line-height:22px"> Registeranobserverthatiscalledwhenchangeshappentothecontentsofthethiscursorsdataset,forexample,whenthedatasetischangedviarequery(),deactivate(),orclose().<br style="line-height:22px"> 注1:当Cursor发生requery(),deactivate(),orclose()时通知DataSetObserverobserver</wbr> </div> <div style="line-height:25px">abstractvoid<span style="line-height:22px"><span style="color:#ff6600; line-height:22px"><wbr style="line-height:22px">unregisterDataSetObserver</wbr></span></span><wbr style="line-height:22px">(DataSetObserverobserver)<br style="line-height:22px"> UnregisteranobserverthathaspreviouslybeenregisteredwiththiscursorviaregisterContentObserver(ContentObserver).</wbr> </div> <div style="line-height:25px"> <span style="color:#ff00ff; line-height:25px">DataSetObserver</span><span style="color:#003366; line-height:25px">的主要方法</span><br style="line-height:25px"><div style="line-height:25px"> <span style="line-height:normal; color:rgb(51,51,51); font-family:arial,sans-serif; font-size:13px"></span> <table id="pubmethods" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:1em; margin-left:1em; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; font-size:0.9em; border-collapse:collapse; empty-cells:show; width:933px"><tbody style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <th colspan="12" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:rgb(222,232,241)"> Public Methods</th> </tr> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; background-color:rgb(246,246,246)"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/database/DataSetObserver.html#onChanged()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">onChanged</a></span>()</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> This method is called when the entire data set has changed, most likely through a call to<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/database/Cursor.html#requery()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">requery()</a></code>on a<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/database/Cursor.html" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">Cursor</a></code>.</div> </td> </tr> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/database/DataSetObserver.html#onInvalidated()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">onInvalidated</a></span>()</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> This method is called when the entire data becomes invalid, most likely through a call to<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/database/Cursor.html#deactivate()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">deactivate()</a></code>or<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/database/Cursor.html#close()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">close()</a></code>on a<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/database/Cursor.html" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">Cursor</a></code>.</div> </td> </tr> </tbody></table> </div> </div> </div> </wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
那么 CursorAdapter 是如何实现对基于 uri 的数据库内容变化进行监听呢?
它当然是<wbr style="line-height:25px"><span style="color:#000080; line-height:25px">借助Cursor</span><wbr style="line-height:25px">来实现的。<br style="line-height:25px"> 但是<span style="color:#ff00ff; line-height:25px">CursorAdapter</span>与<span style="color:#339966; line-height:25px">ContentObserver</span>相对应对外提供(可以重载)的接口是:<br style="line-height:25px"><span style="color:#0000ff; line-height:25px"><wbr style="line-height:25px">onContentChanged<wbr style="line-height:25px">()</wbr></wbr></span><br style="line-height:25px"> 当时<span style="color:#ff00ff; line-height:25px">CursorAdapter</span>与<span style="color:#008000; line-height:25px">DataSetObserver</span>相对应对外提供(可以重载)的接口是:<br style="line-height:25px"><wbr style="line-height:25px"><span style="color:#0000ff; line-height:25px">onChanged()-&gt;notifyDataSetChanged<wbr style="line-height:25px">()</wbr></span><span style="color:#808080; line-height:25px">//这个消息并完全不是从Cursor传递来,它会在CursorAdapter内手动被调用</span><br style="line-height:25px"><wbr style="line-height:25px"><span style="color:#0000ff; line-height:25px">onInvalidated()-&gt;notifyDataSetInvalidated()</span><wbr style="line-height:25px"><span style="color:#0000ff; line-height:25px">//这个消息并不是从Cursor传递来。</span><br style="line-height:25px"> 具体可以参照<a target="_blank" href="http://hubingforever.blog.163.com/blog/static/1710405792010101541844916/" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">附件2</a>的android.widget.CursorAdapter源代码<br style="line-height:25px"><wbr style="line-height:25px"><span style="color:#ff00ff; line-height:25px">CursorAdapter</span>的<span style="color:#339966; line-height:25px">notifyDataSetChanged<wbr style="line-height:25px">()</wbr></span>和<wbr style="line-height:25px"><span style="color:#008000; line-height:25px">notifyDataSetInvalidated()</span>事件<wbr style="line-height:25px">可以<span style="color:#333399; line-height:25px">继续往外传递</span> <div style="line-height:25px"> <span style="color:#ff00ff; line-height:25px">BaseAdapter</span>为此提供了以下系列方法。<br style="line-height:25px"><span style="line-height:normal; color:rgb(51,51,51); font-family:arial,sans-serif; font-size:13px"></span> <table id="pubmethods" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:1em; margin-left:1em; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; font-size:0.9em; border-collapse:collapse; empty-cells:show; width:933px"><tbody style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/widget/BaseAdapter.html#notifyDataSetChanged()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">notifyDataSetChanged</a></span>()</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.</div> </td> </tr> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; background-color:rgb(246,246,246)"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/widget/BaseAdapter.html#notifyDataSetInvalidated()" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">notifyDataSetInvalidated</a></span>()</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> Notifies the attached observers that the underlying data is no longer valid or available.</div> </td> </tr> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/widget/BaseAdapter.html#registerDataSetObserver(android.database.DataSetObserver)" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">registerDataSetObserver</a></span>(<a rel="nofollow" href="http://developer.android.com/reference/android/database/DataSetObserver.html" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">DataSetObserver</a>observer)</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> Register an observer that is called when changes happen to the data used by this adapter.</div> </td> </tr> <tr style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; background-color:rgb(246,246,246)"> <td style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:right; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px">void</nobr> </td> <td width="100%" style="line-height:21px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:6px; padding-right:12px; padding-bottom:6px; padding-left:12px; border-top-width:1px; border-right-width:1px; border-bottom-width:1px; border-left-width:1px; border-style:initial; border-color:initial; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-color:rgb(204,204,204); border-right-color:rgb(204,204,204); border-bottom-color:rgb(204,204,204); border-left-color:rgb(204,204,204); text-align:left; vertical-align:top; background-color:inherit"> <nobr style="line-height:21px"><span style="line-height:21px; margin-right:2px"><a rel="nofollow" href="http://developer.android.com/reference/android/widget/BaseAdapter.html#unregisterDataSetObserver(android.database.DataSetObserver)" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">unregisterDataSetObserver</a></span>(<a rel="nofollow" href="http://developer.android.com/reference/android/database/DataSetObserver.html" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">DataSetObserver</a>observer)</nobr><div style="line-height:25px; margin-top:0px; margin-right:0px; margin-bottom:0px; margin-left:0px; padding-top:3px; padding-right:1em; padding-bottom:0px; padding-left:1em; border-top-width:0px; border-right-width:0px; border-bottom-width:0px; border-left-width:0px; border-style:initial; border-color:initial; border-style:initial; border-color:initial"> Unregister an observer that has previously been registered with this adapter via<code style="line-height:1em; color:rgb(0,112,0); font-family:monospace"><a rel="nofollow" href="http://developer.android.com/reference/android/widget/Adapter.html#registerDataSetObserver(android.database.DataSetObserver)" style="color:rgb(0,102,153); line-height:21px; text-decoration:none">registerDataSetObserver(DataSetObserver)</a></code>.</div> </td> </tr> </tbody></table> <span style="color:#0000ff; line-height:25px">android.widget.BaseAdapter</span>的部分源代码如下:<br style="line-height:25px"> </div> <div style="line-height:25px"> <div style="line-height:25px"> <span style="color:#993300; line-height:25px">public abstract class</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#ff6600; line-height:25px">BaseAdapter</span><span style="color:#3366ff; line-height:25px"></span><span style="color:#993300; line-height:25px">implements</span><span style="color:#3366ff; line-height:25px">ListAdapter, SpinnerAdapter {</span> </div> <div style="line-height:25px"> <span style="color:#993300; line-height:25px">private final</span><span style="color:#ff6600; line-height:25px">DataSetObservable mDataSetObservable = new DataSetObservable();</span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">public boolean hasStableIds() { return false; }</span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px">public void</span><span style="color:#993300; line-height:25px"></span><span style="color:#ff6600; line-height:25px">registerDataSetObserver</span><span style="color:#3366ff; line-height:25px">(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); }</span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px">public void</span><span style="color:#ff6600; line-height:25px">unregisterDataSetObserver</span><span style="color:#3366ff; line-height:25px">(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); }</span> </div> <div style="line-height:25px"><span style="color:#808080; line-height:25px">/** * Notifies the attached View that the underlying data has been changed * and it should refresh itself. */</span></div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px">public void</span><span style="color:#ff6600; line-height:25px">notifyDataSetChanged()</span><span style="color:#3366ff; line-height:25px">{ mDataSetObservable.notifyChanged(); }</span> </div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px">public void</span><span style="color:#ff6600; line-height:25px">notifyDataSetInvalidated()</span><span style="color:#3366ff; line-height:25px">{ mDataSetObservable.notifyInvalidated(); }</span> </div> <div style="line-height:25px"><span style="color:#808080; line-height:25px">-------------------省略------------------</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span></div> <div style="line-height:25px">注意:对于<span style="line-height:25px; color:rgb(0,0,255)">BaseAdapter,</span>外部可以强行调用<span style="color:#008000; line-height:25px">notifyDataSetChanged</span>和<span style="color:#008000; line-height:25px">notifyDataSetInvalidated</span>来通知DataSetObserver observer</div> </div> </wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值