zoukankan      html  css  js  c++  java
  • Android Content Provider在应用程序之间共享数据的原理分析

           本文參考Android应用程序组件Content Provider在应用程序之间共享数据的原理分析http://blog.csdn.net/luoshengyang/article/details/6967204和《Android系统源码情景分析》,作者罗升阳。

           0、总图流程图例如以下:

           整体类图:



         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通过进程间通信的方式的操作和读取返回结果。

  • 相关阅读:
    自制电脑红外遥控接收器(PC软解码) 转
    .NET Micro Framework介绍
    如何测试移动web?
    自行开发高效精简的二进制序列化库(支持精简框架集) 转
    35个优秀的电子商务网站界面
    .Net Micro Framework中的线程
    《肖申克的救赎》 阅后小记
    分享 MSDN 下载工具(Word/PDF)
    OEA ORM中的分页支持
    OEA 中的多国语言实现
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10870853.html
Copyright © 2011-2022 走看看