Android ContentProvider

2018-08-02


《Android开发艺术探索》9.5章

使用ContentResolver读取联系人
private ArrayList<HashMap<String, String>> readContact() {
   

    String NUM = ContactsContract.CommonDataKinds.Phone.NUMBER;
    String NAME = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;
    Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

    ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
    ContentResolver cr = getContentResolver();
    Cursor cursor = cr.query(uri,new String[]{
   NUM,NAME},null,null,null);
    while (cursor.moveToNext()){
   
        String name = cursor.getString(cursor.getColumnIndex(NAME));
        String phone = cursor.getString(cursor.getColumnIndex(NUM));
        HashMap<String,String> contact = new HashMap<>();
        contact.put("name",name);
        contact.put("phone",phone);
        list.add(contact);
    }
    return list;
工作过程

ContentProvider是一种内容共享型组件,它通过Binder向其他组件乃至其他应用提供数据。当ContentProvider所在的进程启动时,ContentProvider会同时启动并被发布到AMS中。需要注意的是,这个时候ContentProvideronCreate要先于ApplicationonCreate而执行。
当一个应用启动时,入口方法为ActivityThreadmain方法,main方法是一个静态方法,在main方法中会创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThreadattach方法中会远程调用AMSattachApplication方法并将ApplicationThread对象提供给AMSApplicationThread是一个Binder对象,它的Binder接口是IApplicationThread,它主要用于ActivityThreadAMS之间的通信,这一点在前面多次提到。在AMSattachApplication方法中,会调用ApplicationThreadbindApplication方法,注意这个过程同样是跨进程完成的,bindApplication的逻辑会经过ActivityThread中的mH Handler切换到ActivityThread中去执行,具体的方法是handleBindApplication。在handleBindApplication方法中,ActivityThread会创建Application对象并加载ContentProvider。需要注意的是,ActivityThread会先加载ContentProvider,然后再调用ApplicationonCreate方法。
这就是ContentProvider的启动过程,ContentProvider启动后,外界就可以通过它所提供的增删改查这四个接口来操作ContentProvider中的数据源,即insert、delete、update和query四个方法。这四个方法都是通过Binder来调用的,外界无法直接访问ContentProvider,它只能通过AMS根据Uri来获取对应的ContentProviderBinder接口IConentProvider,然后再通过IConentProvider来访问ContentProvider中的数据源。
一般来说,ContentProvider都应该是单实例的。ContentProvider到底是不是单实例,这是由它的android:multiprocess属性来决定的,当android:multiprocessfalse时,ContentProvider是单实例,这也是默认值;当android:multiprocesstrue时,ContentProvider为多实例,这个时候在每个调用者的进程中都存在一个ContentProvider对象。
访问ContentProvider需要通过ContentResolverContentResolver是一个抽象类,通过ContextgetContentResolver方法获取的实际上是ApplicationContentResolver对象,ApplicationContentResolver类继承了ContentResolver并实现了ContentResolver中的抽象方法。当ContentProvider所在的进程未启动时,第一次访问它时就会触发ContentProvider的创建,当然这也伴随着ContentProvider所在进程的启动。通过ContentProvider的四个方法的任何一个都可以触发ContentProvider的启动过程,这里选择query方法。ContentProviderquery方法中,首先会获取IContentProvider对象,不管是通过acquireUnstableProvider方法还是直接通过acquireProvider方法,它们的本质都是一样的,最终都是通过acquireProvider方法来获取ContentProvider。下面是ApplicationContentResolveracquireProvider方法的具体实现:

 @Override
    protected IContentProvider acquireProvider(Context context, String auth) {
   
        return mMainThread.acquireProvider(context,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), true);
    }

ApplicationContentResolveracquireProvider方法并没有处理任何逻辑,它直接调用了ActivityThreadacquireProvider方法,ActivityThreadacquireProvider方法的源码如下:

public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
   
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
   
        return provider;
    }

    // There is a possible race here.  Another thread may try to acquire
    // the same provider at the same time.  When this happens, we want to ensure
    // that the first one wins.
    // Note that we cannot hold the lock while acquiring and installing the
    // provider since it might take a long time to run and it could also potentially
    // be re-entrant in the case where the provider is in the same process.
    ContentProviderHolder holder = null;
    try {
   
        holder = ActivityManager.getService().getContentProvider(
                getApplicationThread(), auth, userId, stable);
    } catch (RemoteException ex) {
   </
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值