編輯:關於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通過進程間通信的方式的操作和讀取返回結果。
NavigationView+DrawerLayout實現側拉抽屜效果
先上效果圖: NavigationView是android-support-design包下的一個控件,在使用NavigationView時需要引入design
基於Android實現ListView圓角效果
本文演示如何在Android中實現ListView圓角效果。無論是網站,還是APP,人們都愛看一些新穎的視圖效果。直角看多了,就想看看圓角,這幾年刮起了一陣陣的圓角設計風
miui8應用鎖怎麼設置 miui8應用鎖設置使用教程
小米miui8應用鎖怎麼設置呢?小米miui8應用鎖怎麼使用呢?還不知道的朋友一起隨小編看看下文的miui8應用鎖設置使用教程吧!首先打開手機系統設置,點擊
OkHttp框架從入門到放棄,解析圖片使用Picasso裁剪,二次封裝OkHttpUtils,Post提交表單數據
我們這片博文就來聊聊這個反響很不錯的OkHttp了,標題是我惡搞的,本篇將著重詳細的分析,探索OkHttp這個框架的使用和封裝一.追其原理 Android系統提供了兩種