このチュートリアル からContentProviders
とローダーの使用方法を調査しました
見方:Activity
とListView
、SimpleCursorAdapter
、CursorLoader
があります。 ContentProvider
も実装します。
Activity
では、ボタンをクリックすることでgetContentResolver().insert(URI, contentValues);
を呼び出すことができます。
ContentProvider
の実装では、insert()
メソッドの最後にgetContentResolver().notifyChange(URI, null);
を呼び出し、CursorLoader
はデータをリロードする必要があるというメッセージを受け取ります。 UIを更新します。また、SimpleCursorAdapter
で_FLAG_REGISTER_CONTENT_OBSERVER
_を使用すると、メッセージも受信され、そのメソッドonContentChanged()
が呼び出されます。
したがって、データを挿入、更新、または削除すると、ListViewが更新されます。
Activity.startManagingCursor(cursor);
は非推奨であり、cursor.requery()
は非推奨であるため、cursor.setNotificationUri()
からの実践的な意味はわかりません。
setNotificationUri()
メソッドのソースコードを調べたところ、メソッド内でmContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver)
が呼び出されていることがわかりました。また、CursorLoader
も同じことをします。最後に、cursorはメッセージを受信し、次のメソッドがCursor内で呼び出されます。
_protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange, null);
// ...
}
}
_
しかし、私はこれを理解することはできません。
だから私の質問は:なぜ私たちのContentProvider
実装のcursor.setNotificationUri()
メソッドでquery()
を呼び出す必要があるのですか?
Cursor.setNotificationUri()
を呼び出すと、カーソルは何のために作成されたかを認識しますContentProvider Uri.
CursorLoader
は、独自のForceLoadContentObserver
(ContentObserver
を拡張する)を、Context
を呼び出すときに指定したURIのContentResolver
のsetNotificationUri
に登録します。
したがって、ContentResolver
がURIのコンテンツが変更されたことを認識すると変更 [これはContentProvider
のgetContext().getContentResolver().notifyChange(uri, contentObserver);
、insert()
、およびupdate()
メソッド内でdelete()
を呼び出すと発生します] CursorLoaderのForceLoadContentObserver
を含むすべてのオブザーバーに通知します。
次に、ForceLoadContentObserver
は、ローダーのmContentChangedをtrueとしてマークします
CursorLoader
は、カーソルのオブザーバーnotをURIに登録します。
以下を調べてください CursorLoaderのソースコード 。 CursorLoader
がcontentObserver
をcursor
に登録することに注意してください。
_/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
}
mCancellationSignal = new CancellationSignal();
}
try {
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
mSelectionArgs, mSortOrder, mCancellationSignal);
if (cursor != null) {
try {
// Ensure the cursor window is filled.
cursor.getCount();
cursor.registerContentObserver(mObserver);
} catch (RuntimeException ex) {
cursor.close();
throw ex;
}
}
return cursor;
} finally {
synchronized (this) {
mCancellationSignal = null;
}
}
_
Cursor
はメソッドsetNotificationUri()
を呼び出して、mSelfObserver
をuri
に登録する必要があります。
_//AbstractCursor.Java
public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) {
synchronized (mSelfObserverLock) {
mNotifyUri = notifyUri;
mContentResolver = cr;
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
mSelfObserver = new SelfContentObserver(this);
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle); // register observer to the uri
mSelfObserverRegistered = true;
}
}
_
contentProvider
のinsert
、update
、delete
メソッド内で、getContext().getContentResolver().notifyChange(uri, null);
を呼び出してuri
オブザーバー。
したがって、cursor#setNotificationUri()
を呼び出さない場合、そのCursorLoader
の基になるデータが変更されても、uri
は通知を受け取りません。
カーソルアダプターに1つのURIを使用します。
_@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = new Bundle();
Uri uri = TemperatureContract.SensorEntry.buildSensorID0AddressUri(mDeviceAddress);
args.putParcelable("URI", uri);
getSupportLoaderManager().initLoader(0, args, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (args != null) {
Uri mUri = args.getParcelable("URI");
return new CursorLoader(this,
mUri,
null, // projection
null, // selection
null, // selectionArgs
null); // sortOrder
} else {
return null;
}
}
_
別のクラスでは、I 別のURIを使用してデータベースの内容を変更します。ビューを更新するには、データプロバイダーのupdate
メソッドのdefault実装を変更する必要がありました。デフォルトの実装は、同じURIのみを通知します。別のURIに通知する必要があります。
結局、データプロバイダークラスのupdate
メソッドでnotifyChange()
を2回呼び出しました。
_@Override
public int update(
Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int rowsUpdated;
switch (match) {
case ...:
break;
case SENSOR_BY_ID_AND_ADDRESS:
String sensorId = TemperatureContract.SensorEntry.getSensorIdFromUri(uri);
String sensorAddress = TemperatureContract.SensorEntry.getSensorAddressFromUri(uri);
rowsUpdated = db.update(
TemperatureContract.SensorEntry.TABLE_NAME, values, "sensorid = ? AND address = ?", new String[]{sensorId, sensorAddress});
if (rowsUpdated != 0) {
Uri otheruri = TemperatureContract.SensorEntry.buildSensorID0AddressUri(sensorAddress);
getContext().getContentResolver().notifyChange(otheruri, null);
}
break;
case ...:
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsUpdated;
_
insert
メソッドとdelete
メソッドについても同じことをしました。