簡単探索ContentProviderOperation
36421 ワード
前の記事でContentProviderOperationを使用しましたが、ContentProviderOperationがどのように機能しているのかを見てみましょう.
1.ContentProviderOperationではParcelableが実装されており、コンストラクタはプライベートであるため、オブジェクトを直接作成することはできません.コードは次のとおりです.
RUID操作のためのいくつかの方法が提供され、コードは以下の通りである.
その中で理解しにくいのがnewAssertQueryメソッドで、このメソッドはデータをクエリーするためのものではなく、ブレークポイントクエリーとして理解できます.つまり、クエリーに条件を満たすデータがあるかどうか、ない場合はOperationApplicationException異常が投げ出されます.
以上のonClick()メソッドの役割はversion=3のデータにuri対応のテーブルが3つあるかどうかを調べることです.null、逆にOperationApplicationException異常が投げ出されます.その他の使用状況はhttp://blog.sina.com.cn/s/blog_a387d6d2010114mp.htmlを参照してください.
2.ContentProviderOperationを使用する場合、通常はこのような方法を採用しています.
builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); その後、このbuilderにいくつかの条件を追加し、最後に彼のbuild()メソッドを呼び出してContentProviderOperationオブジェクトを返すことができます.見てみろ
new ContentProviderOperation()メソッドで付与された操作が見られる.
3.最後にgetContentResolver()を呼び出す.applyBatch(ContactsContract.AUTHEORITY,operationList)がバッチ処理を行うことは、以前ContentProviderOperationを構築するプロセスがSQL文を組み合わせるようなものであり、applyBatchはSQL文を実行することに相当することを理解できる.具体的な流れは:ContentResolver.java(applyBatch())--> ContentProviderClient.java(applyBatch()) --> ContentProvider.JAva,ContentProviderのapplyBatch()メソッドは次のとおりです.
ループが使用されていますが、最終的に呼び出されたのはContentProviderOperationのapplyメソッドです.
まずresolveValueBackReferences()メソッドを呼び出し、mValuesまたは加工後のmValuesを返します.
mValuesBackReferences==nullという判断を理解するために、まず一つの問題を知っておく必要があります.前の文章では、2番目のContentProviderOperationからbuilderを使用しています.withValueBackReference(Email.RAW_CONTART_ID,rawContactIndex)は、mValuesBackReferencesに値を付与します.コードは次のとおりです.
この方法はTYPE_には使えないことがわかりますDELETE.
引き続きresolveValueBackReferencesメソッドを参照してください.mValuesBackReferences==nullの場合、mValuesに直接戻ります.mValuesは、withValues()メソッドで入力した値によって組み立てられたContentValueオブジェクトです.たとえば、更新または挿入する値などです.mValuesBackReferences!=null、それでは前のContentProviderResultのuriの中のidを取り出してEmailに割り当てます.RAW_CONTACT_ID、builder.withValueBackReference(Email.RAW_CONTART_ID,rawContactIndex)の最初の変数は、withValueBackReferenceメソッドの役割も明らかになった.具体的には、http://blog.sina.com.cn/s/blog_a387d6d2010114mp.html参照
引き続きapply()メソッドを見ます.
ContentProviderOperationのapply()メソッドこそRUID操作を本格的に実行する場所であることが分かった.
また、上記のコードではトランザクションの使用は見つかりません.操作に失敗した場合にロールバックする必要がある場合は、トランザクションを追加する必要があります.上記の分析を経て、自分のContentProviderでappltBatch()メソッドを書き換え、トランザクションを追加すると、ContactsProviderを分析する専門的な文章が表示されます.実は連絡先のContactsProciderで採用されているのがこの考え方です.
1.ContentProviderOperationではParcelableが実装されており、コンストラクタはプライベートであるため、オブジェクトを直接作成することはできません.コードは次のとおりです.
1 public class ContentProviderOperation implements Parcelable {
2 /** @hide exposed for unit tests */
3 public final static int TYPE_INSERT = 1;
4 /** @hide exposed for unit tests */
5 public final static int TYPE_UPDATE = 2;
6 /** @hide exposed for unit tests */
7 public final static int TYPE_DELETE = 3;
8 /** @hide exposed for unit tests */
9 public final static int TYPE_ASSERT = 4;
10
11 private final int mType;
12 private final Uri mUri;
13 private final String mSelection;
14 private final String[] mSelectionArgs;
15 private final ContentValues mValues;
16 private final Integer mExpectedCount;
17 private final ContentValues mValuesBackReferences;
18 private final Map<Integer, Integer> mSelectionArgsBackReferences;
19 private final boolean mYieldAllowed;
20
21 private final static String TAG = "ContentProviderOperation";
22 private ContentProviderOperation(Builder builder) {
23 mType = builder.mType;
24 mUri = builder.mUri;
25 mValues = builder.mValues;
26 mSelection = builder.mSelection;
27 mSelectionArgs = builder.mSelectionArgs;
28 mExpectedCount = builder.mExpectedCount;
29 mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
30 mValuesBackReferences = builder.mValuesBackReferences;
31 mYieldAllowed = builder.mYieldAllowed;
32 }
RUID操作のためのいくつかの方法が提供され、コードは以下の通りである.
1 public static Builder newInsert(Uri uri) {
2 return new Builder(TYPE_INSERT, uri);
3 }
4
5 /**
6 * Create a {@link Builder} suitable for building an update
7 * {@link ContentProviderOperation}.
8 * @param uri The {@link Uri} that is the target of the update.
9 * @return a {@link Builder}
10 */
11 public static Builder newUpdate(Uri uri) {
12 return new Builder(TYPE_UPDATE, uri);
13 }
14
15 /**
16 * Create a {@link Builder} suitable for building a delete
17 * {@link ContentProviderOperation}.
18 * @param uri The {@link Uri} that is the target of the delete.
19 * @return a {@link Builder}
20 */
21 public static Builder newDelete(Uri uri) {
22 return new Builder(TYPE_DELETE, uri);
23 }
24
25 /**
26 * Create a {@link Builder} suitable for building a
27 * {@link ContentProviderOperation} to assert a set of values as provided
28 * through {@link Builder#withValues(ContentValues)}.
29 */
30 public static Builder newAssertQuery(Uri uri) {
31 return new Builder(TYPE_ASSERT, uri);
32 }
その中で理解しにくいのがnewAssertQueryメソッドで、このメソッドはデータをクエリーするためのものではなく、ブレークポイントクエリーとして理解できます.つまり、クエリーに条件を満たすデータがあるかどうか、ない場合はOperationApplicationException異常が投げ出されます.
1 public void onClick(View v) {
2 final ArrayList<ContentProviderOperation> operationList =
3 new ArrayList<ContentProviderOperation>();
4 ContentProviderOperation.Builder builder = null;
5 int rawContactIndex = 0;
6
7 builder = ContentProviderOperation
8 .newAssertQuery(RawContacts.CONTENT_URI);
9 builder.withSelection("version=?", new String[]{String.valueOf(3)})
10 .withExpectedCount(3);
11 operationList.add(builder.build());
12
13 try {
14 ContentProviderResult[] res = getContentResolver().
15 applyBatch(ContactsContract.AUTHORITY, operationList);
16 Log.e(TAG, "res.length = " + res.length);
17 for (int i = 0; i < res.length; i++) {
18 Log.e(TAG, i + "res.toString() = " + res[i].toString());
19 Log.e(TAG, i + "res.uri = " + res[i].uri);
20 }
21 } catch (RemoteException e) {
22 } catch (OperationApplicationException e) {
23 }
24 }
以上のonClick()メソッドの役割はversion=3のデータにuri対応のテーブルが3つあるかどうかを調べることです.null、逆にOperationApplicationException異常が投げ出されます.その他の使用状況はhttp://blog.sina.com.cn/s/blog_a387d6d2010114mp.htmlを参照してください.
2.ContentProviderOperationを使用する場合、通常はこのような方法を採用しています.
builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); その後、このbuilderにいくつかの条件を追加し、最後に彼のbuild()メソッドを呼び出してContentProviderOperationオブジェクトを返すことができます.見てみろ
build() , :
1 /** Create a ContentProviderOperation from this {@link Builder}. */
2 public ContentProviderOperation build() {
3 if (mType == TYPE_UPDATE) {
4 if ((mValues == null || mValues.size() == 0) &&
5 (mValuesBackReferences == null ||
6 mValuesBackReferences.size() == 0)) {
7 throw new IllegalArgumentException("Empty values");
8 }
9 }
10 if (mType == TYPE_ASSERT) {
11 if ((mValues == null || mValues.size() == 0) &&
12 (mValuesBackReferences == null ||
13 mValuesBackReferences.size() == 0) &&
14 (mExpectedCount == null)) {
15 throw new IllegalArgumentException("Empty values");
16 }
17 }
18 return new ContentProviderOperation(this);
19 }
new ContentProviderOperation()メソッドで付与された操作が見られる.
3.最後にgetContentResolver()を呼び出す.applyBatch(ContactsContract.AUTHEORITY,operationList)がバッチ処理を行うことは、以前ContentProviderOperationを構築するプロセスがSQL文を組み合わせるようなものであり、applyBatchはSQL文を実行することに相当することを理解できる.具体的な流れは:ContentResolver.java(applyBatch())--> ContentProviderClient.java(applyBatch()) --> ContentProvider.JAva,ContentProviderのapplyBatch()メソッドは次のとおりです.
1 public ContentProviderResult[] applyBatch(
2 ArrayList<ContentProviderOperation> operations)
3 throws OperationApplicationException {
4 final int numOperations = operations.size();
5 final ContentProviderResult[] results =
6 new ContentProviderResult[numOperations];
7 for (int i = 0; i < numOperations; i++) {
8 results[i] = operations.get(i).apply(this, results, i);
9 }
10 return results;
11 }
ループが使用されていますが、最終的に呼び出されたのはContentProviderOperationのapplyメソッドです.
1 public ContentProviderResult apply(ContentProvider provider,
2 ContentProviderResult[] backRefs, int numBackRefs) throws OperationApplicationException {
3 ContentValues values =
4 resolveValueBackReferences(backRefs, numBackRefs);
まずresolveValueBackReferences()メソッドを呼び出し、mValuesまたは加工後のmValuesを返します.
1 public ContentValues resolveValueBackReferences(ContentProviderResult[] backRefs, int numBackRefs) {
2 if () {
3 return mValues;
4 }
5 final ContentValues values;
6 if (mValues == null) {
7 values = new ContentValues();
8 } else {
9 values = new ContentValues(mValues);
10 }
11 for (Map.Entry<String, Object> entry :
12 mValuesBackReferences.valueSet()) {
13 String key = entry.getKey();
14 Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
15 if (backRefIndex == null) {
16 Log.e(TAG, this.toString());
17 throw new IllegalArgumentException("
18 values backref " + key + " is not an integer");
19 }
20 values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
21 }
22 return values;
23 }
mValuesBackReferences==nullという判断を理解するために、まず一つの問題を知っておく必要があります.前の文章では、2番目のContentProviderOperationからbuilderを使用しています.withValueBackReference(Email.RAW_CONTART_ID,rawContactIndex)は、mValuesBackReferencesに値を付与します.コードは次のとおりです.
1 public Builder withValueBackReference(String key, int previousResult) {
2 if (mType != TYPE_INSERT && mType != TYPE_UPDATE
3 && mType != TYPE_ASSERT) {
4 throw new IllegalArgumentException("only inserts, updates, and asserts can have value back-references");
5 }
6 if (mValuesBackReferences == null) {
7 mValuesBackReferences = new ContentValues();
8 }
9 mValuesBackReferences.put(key, previousResult);
10 return this;
11 }
この方法はTYPE_には使えないことがわかりますDELETE.
引き続きresolveValueBackReferencesメソッドを参照してください.mValuesBackReferences==nullの場合、mValuesに直接戻ります.mValuesは、withValues()メソッドで入力した値によって組み立てられたContentValueオブジェクトです.たとえば、更新または挿入する値などです.mValuesBackReferences!=null、それでは前のContentProviderResultのuriの中のidを取り出してEmailに割り当てます.RAW_CONTACT_ID、builder.withValueBackReference(Email.RAW_CONTART_ID,rawContactIndex)の最初の変数は、withValueBackReferenceメソッドの役割も明らかになった.具体的には、http://blog.sina.com.cn/s/blog_a387d6d2010114mp.html参照
引き続きapply()メソッドを見ます.
1 public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
2 int numBackRefs) throws OperationApplicationException {
3 ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
4 String[] selectionArgs =
5 resolveSelectionArgsBackReferences(backRefs, numBackRefs);
6
7 if (mType == TYPE_INSERT) {
8 Uri newUri = provider.insert(mUri, values);
9 if (newUri == null) {
10 throw new OperationApplicationException("insert failed");
11 }
12 return new ContentProviderResult(newUri);
13 }
14
15 int numRows;
16 if (mType == TYPE_DELETE) {
17 numRows = provider.delete(mUri, mSelection, selectionArgs);
18 } else if (mType == TYPE_UPDATE) {
19 numRows = provider.update(mUri, values, mSelection, selectionArgs);
20 } else if (mType == TYPE_ASSERT) {
21 // Assert that all rows match expected values
22 String[] projection = null;
23 if (values != null) {
24 // Build projection map from expected values
25 final ArrayList<String> projectionList = new ArrayList<String>();
26 for (Map.Entry<String, Object> entry : values.valueSet()) {
27 projectionList.add(entry.getKey());
28 }
29 projection = projectionList.toArray(new String[projectionList.size()]);
30 }
31 final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
32 try {
33 numRows = cursor.getCount();
34 if (projection != null) {
35 while (cursor.moveToNext()) {
36 for (int i = 0; i < projection.length; i++) {
37 final String cursorValue = cursor.getString(i);
38 final String expectedValue = values.getAsString(projection[i]);
39 if (!TextUtils.equals(cursorValue, expectedValue)) {
40 // Throw exception when expected values don't match
41 Log.e(TAG, this.toString());
42 throw new OperationApplicationException("Found value " + cursorValue
43 + " when expected " + expectedValue + " for column "
44 + projection[i]);
45 }
46 }
47 }
48 }
49 } finally {
50 cursor.close();
51 }
52 } else {
53 Log.e(TAG, this.toString());
54 throw new IllegalStateException("bad type, " + mType);
55 }
56
57 if (mExpectedCount != null && mExpectedCount != numRows) {
58 Log.e(TAG, this.toString());
59 throw new OperationApplicationException("wrong number of rows: " + numRows);
60 }
61
62 return new ContentProviderResult(numRows);
63 }
ContentProviderOperationのapply()メソッドこそRUID操作を本格的に実行する場所であることが分かった.
また、上記のコードではトランザクションの使用は見つかりません.操作に失敗した場合にロールバックする必要がある場合は、トランザクションを追加する必要があります.上記の分析を経て、自分のContentProviderでappltBatch()メソッドを書き換え、トランザクションを追加すると、ContactsProviderを分析する専門的な文章が表示されます.実は連絡先のContactsProciderで採用されているのがこの考え方です.