Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Content Provider在應用程序之間共享數據的原理分析

Android Content Provider在應用程序之間共享數據的原理分析

編輯:關於Android編程

本文參考Android應用程序組件Content Provider在應用程序之間共享數據的原理分析http://blog.csdn.net/luoshengyang/article/details/6967204和《Android系統源代碼情景分析》,作者羅升陽。

0、總圖流程圖如下:

\

總體類圖:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20140715/20140715085753142.jpg" alt="\">


1、MainActivity進程向AriticlesProvider進程發送IContentProvider.QUERY_TRANSACTION

\


如圖:第一步

~/Android/frameworks/base/core/java/android/content

----ContentProviderNative.java

final class ContentProviderProxy implements IContentProvider {
	......

	public Cursor query(Uri url, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) throws RemoteException {
		//TODO make a pool of windows so we can reuse memory dealers
		CursorWindow window = new CursorWindow(false /* window will be used remotely */);
		BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
		IBulkCursor bulkCursor = bulkQueryInternal(
			url, projection, selection, selectionArgs, sortOrder,
			adaptor.getObserver(), window,
			adaptor);
		if (bulkCursor == null) {
			return null;
		}
		return adaptor;
	}

	......
(1)創建了CursorWindow對象。

(2)創建類BulkCursorToCursorAdaptor對象。
(3)調用bulkQueryInternal。


~/Android/frameworks/base/core/java/android/content

----ContentProviderNative.java

final class ContentProviderProxy implements IContentProvider
{
	......

	private IBulkCursor bulkQueryInternal(
			Uri url, String[] projection,
			String selection, String[] selectionArgs, String sortOrder,
			IContentObserver observer, CursorWindow window,
			BulkCursorToCursorAdaptor adaptor) throws RemoteException {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();

		data.writeInterfaceToken(IContentProvider.descriptor);

		url.writeToParcel(data, 0);
		int length = 0;
		if (projection != null) {
			length = projection.length;
		}
		data.writeInt(length);
		for (int i = 0; i < length; i++) {
			data.writeString(projection[i]);
		}
		data.writeString(selection);
		if (selectionArgs != null) {
			length = selectionArgs.length;
		} else {
			length = 0;
		}
		data.writeInt(length);
		for (int i = 0; i < length; i++) {
			data.writeString(selectionArgs[i]);
		}
		data.writeString(sortOrder);
		data.writeStrongBinder(observer.asBinder());
		window.writeToParcel(data, 0);

		// Flag for whether or not we want the number of rows in the
		// cursor and the position of the "_id" column index (or -1 if
		// non-existent).  Only to be returned if binder != null.
		final boolean wantsCursorMetadata = (adaptor != null);
		data.writeInt(wantsCursorMetadata ? 1 : 0);

		mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);

		DatabaseUtils.readExceptionFromParcel(reply);

		IBulkCursor bulkCursor = null;
		IBinder bulkCursorBinder = reply.readStrongBinder();
		if (bulkCursorBinder != null) {
			bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);

			if (wantsCursorMetadata) {
				int rowCount = reply.readInt();
				int idColumnPosition = reply.readInt();
				if (bulkCursor != null) {
					adaptor.set(bulkCursor, rowCount, idColumnPosition);
				}
			}
		}

		data.recycle();
		reply.recycle();

		return bulkCursor;
	}

	......
}
我們這裡只關注window.writeToParcel(data, 0)。詳細解釋請看對應的博客或者圖書。

如圖:第二步,省略binder_transaction傳輸過程,因為上面已經分析過了。


如圖:第三步

~/Android/frameworks/base/core/java/android/content

----ContentProviderNative.java

abstract public class ContentProviderNative extends Binder implements IContentProvider {
	......

	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
	throws RemoteException {
		try {
			switch (code) {
			case QUERY_TRANSACTION:
				{
					data.enforceInterface(IContentProvider.descriptor);

					Uri url = Uri.CREATOR.createFromParcel(data);

					// String[] projection
					int num = data.readInt();
					String[] projection = null;
					if (num > 0) {
						projection = new String[num];
						for (int i = 0; i < num; i++) {
							projection[i] = data.readString();
						}
					}

					// String selection, String[] selectionArgs...
					String selection = data.readString();
					num = data.readInt();
					String[] selectionArgs = null;
					if (num > 0) {
						selectionArgs = new String[num];
						for (int i = 0; i < num; i++) {
							selectionArgs[i] = data.readString();
						}
					}

					String sortOrder = data.readString();
					IContentObserver observer = IContentObserver.Stub.
						asInterface(data.readStrongBinder());
					CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);

					// Flag for whether caller wants the number of
					// rows in the cursor and the position of the
					// "_id" column index (or -1 if non-existent)
					// Only to be returned if binder != null.
					boolean wantsCursorMetadata = data.readInt() != 0;

					IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
						selectionArgs, sortOrder, observer, window);
					reply.writeNoException();
					if (bulkCursor != null) {
						reply.writeStrongBinder(bulkCursor.asBinder());

						if (wantsCursorMetadata) {
							reply.writeInt(bulkCursor.count());
							reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
								bulkCursor.getColumnNames()));
						}
					} else {
						reply.writeStrongBinder(null);
					}

					return true;
				}
			......
			}
		} catch (Exception e) {
			DatabaseUtils.writeExceptionToParcel(reply, e);
			return true;
		}

		return super.onTransact(code, data, reply, flags);
	}

	......
}
其中,CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);詳細解釋請看博客或者書。


如圖:第四步
~/Android/frameworks/base/core/java/android/content

----ContentProvider.java

public abstract class ContentProvider implements ComponentCallbacks {
	......

	class Transport extends ContentProviderNative {
		......

		public IBulkCursor bulkQuery(Uri uri, String[] projection,
				String selection, String[] selectionArgs, String sortOrder,
				IContentObserver observer, CursorWindow window) {
			......

			Cursor cursor = ContentProvider.this.query(uri, projection,
				selection, selectionArgs, sortOrder);
			......

			return new CursorToBulkCursorAdaptor(cursor, observer,
				ContentProvider.this.getClass().getName(),
				hasWritePermission(uri), window);
		}

		......
	}

	......
}
主要做了以下幾件事:

(1)調用AriticlesProvider的query方法,獲取了SQLiteCursor對象。

(2)由cursor和window對象,形成CursorToBulkCursorAdaptor對象。


如圖,第五步

if (bulkCursor != null) {
	reply.writeStrongBinder(bulkCursor.asBinder());

	if (wantsCursorMetadata) {
		reply.writeInt(bulkCursor.count());
		reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
			bulkCursor.getColumnNames()));
	}
}
傳遞CursorToBulkCursorAdaptor對象,如下圖:
\

如圖:第六步,省略binder_transaction傳輸過程,因為上面已經分析過了。


如圖:第七步

~/Android/frameworks/base/core/java/android/content

----ContentProviderNative.java

IBulkCursor bulkCursor = null;
IBinder bulkCursorBinder = reply.readStrongBinder();
if (bulkCursorBinder != null) {
	bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);

	if (wantsCursorMetadata) {
		int rowCount = reply.readInt();
		int idColumnPosition = reply.readInt();
		if (bulkCursor != null) {
			adaptor.set(bulkCursor, rowCount, idColumnPosition);
		}
	}
}
bulkCursor為BulkCursorProxy對象如下:

\

adaptor.set(bulkCursor, rowCount, idColumnPosition);
把BulkCursorProxy對象放入到BulkCursorToCursorAdaptor對象的句柄變量mBulkCursor中。


如圖:第八步

return new CursorWrapperInner(qCursor, provider);
最後返回了這個對象,qCursor是BulkCursorToCursorAdaptor對象,provider為ContentProviderProxy對象。

至此,我們形成了下圖:

\

進程間通信結束了,下面我們分析如何應用匿名共享內存來傳輸數據。

在前面的一篇文章Android Content Provider的啟動過程源代碼分析http://blog.csdn.net/jltxgcy/article/details/37725749,最後獲取了ContentProviderProxy對象,通過進程間通信來傳遞數據。

public class ArticlesAdapter {
	......

	private ContentResolver resolver = null;

	public ArticlesAdapter(Context context) {
		resolver = context.getContentResolver();
	}

	......

	public Article getArticleByPos(int pos) {
		Uri uri = ContentUris.withAppendedId(Articles.CONTENT_POS_URI, pos);

		String[] projection = new String[] {
			Articles.ID,
			Articles.TITLE,
			Articles.ABSTRACT,
			Articles.URL
		};

		Cursor cursor = resolver.query(uri, projection, null, null, Articles.DEFAULT_SORT_ORDER);
		if (!cursor.moveToFirst()) {
			return null;
		}

		int id = cursor.getInt(0);
		String title = cursor.getString(1);
		String abs = cursor.getString(2);
		String url = cursor.getString(3);

		return new Article(id, title, abs, url);
	}
}

我們不分析詳細過程,首先BulkCursorToCursorAdaptor對象裡面的成員變量mBulkCursor通過進程間通信的方式,找到CursorToBulkCursorAdaptor對象,通過裡面的成員函數mCursor查詢出數據,並且保存在mWindows所指向的匿名共享內存。

而BulkCursorToCursorAdaptor通過成員變量mWindow來訪問相同的匿名共享內存的。這樣MainActivity就獲取了數據。

如果是刪除數據,可能不需要讀寫匿名共享內存,只要通過mBulkCursor通過進程間通信的方式的操作和讀取返回結果。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved