Android四大组件对Android开发者开说再熟悉不过了,他们是ActivityServiceBroadcastReceiverContentProvider。当具有一定开发实践后会发现很多情况情况下,只有对Android体系结构有一定认识,在实际开发中才能写出更加优秀的代码,否者总是只知其表,不知其里,难免有一种雾里看花的感觉。


 1.四大组件的运行状态

        Android四大组件中BroadcastReceiver既可以在AndroidMenifest.xml中也可以通过java代码完成注册,两者分别称为静态注册和动态注册。而其他三者必须在AndroidMenifest.xml中完成注册。从调用方式来讲,ActivityServiceBroadcastReceiver都需要借助Intent,而ContentProvider不需要借助Intent

        Activity的调用分为显示和隐式两种,显式调用无非就是使用startActivity方法,可以明确地指向一个Activity组件,简单易用不再介绍。隐式调用具体实现在《AndroidIntentFilter的匹配规则》中已有详细描述,不在赘述。但隐式Intent指向一个或多个Activity组件,当然也可能没有Activity符合筛选规则。Activity组件的主要作用是展示一个界面并和用户交互,它扮演的其实是一个前台界面的角色。

       Service是一种计算型组件,用于在手机后台执行一系列计算任务。Service有两种状态,分为启动状态和绑定状态两种,两者的不同之处在于后者情况下外界可以很方便的和Service组件进行通信,而前者的Service不需要和外界有直接的交互。但需要注意一点,Service本身是处于主线程的,所以耗时的后台计算仍然需要放到单独的线程中完成。

       BroadcastReceiver是一种消息型组件,用于在不同的组件乃至不同的应用之间传递消息,他事实上工作在系统内部。静态注册的广播不需要应用启动就可以接收相应的广播。动态广播需要通过Context.registerReceiver()来实现,并且在不需要时使用Context.unRegisterReceiver()来解除广播,这种形式的广播必须启动应用才能完成注册并接收广播。发送和接收过程的匹配通过广播接收者的完成。可以发现,广播其实是一种低耦合的观察者模式,也不适合做耗时的操作。

       ContentProvider是一种数据共享型的组件,用于向其他组件或者其他应用提供数据。ContentProvider提供增删改查四个方法,内部维持一个数据集合,这个集合可以使用数据库实现,也可以使用其他任何类型,没有什么要求。因为这四个方法是在Binder线程池中被调用的,所以处理好线程同步是很重要的。

 

2.Activity的工作过程

        ActivitystartActivity()有好几种重载方式,这在我们调用它的时候就会发现,但该方法内部都会调用startActivityForReult方法。下面是截取该方法的部分代码

public void startActivityForResult(Intent intent , int requestCode, @Nullable Bundle options)

{

    If(mParent == null){

       Instrumentation.ActivityResult ar =

            mInstrumentation.execStartActivity(......);

       .......

     }

     .......

}

         mParent代表的是ActivityGroup,API 13之后基本使用Fragment取代ActivityGroup了。下面再看exceStartActivity方法,该方法有一个ApplicationThread类型的参数,而ApplicationThread实际上是ActivityThread的一个内部类,了解Activity启动模式的朋友就会发现ApplicationThreadActivityThreadActivity的启动过程中多么重。在该方法中有两句重要的代码:

......

int result = ActivityManagerNative.getDefault().startActivity(.......);

checkStartActivityResult(result,intent);

......

        第二句很明显是检查启动Activity的结果,如果无法正确的启动一个Activity就会抛出异常错误。启动Activity的时候有一个常见错误“Unable to find explicit activity class;have you declared this activity int your AndroidMenifest.xml”,就是从这抛出的,看到这有疑惑的朋友你是不是豁然开朗了。

   既然启动Activity是上面的第一句代码完成的,ActivityManagerNative.getDefault()的具体实现的ActivityManagerService(简称AMS),所以查看一下AMSstartActivity方法即可。在该方法中又绕了一大圈,最终回到AplicationThreadscheduleLaunchActivity()启动ActivityscheduleLaunchActivity方法中发送一个启动Activity的消息交给Handler处理,这个Handler的名字很简洁,叫H。后面介绍其他三个组件的启动时都会用到H。处理这个启动消息的的时候会先判断是否Application已经创建过了,如果已经创建过了就不会重复创建了,这也就揭示了为什么一个应用只会有一个ApplicationApplication创建完毕后,系统紧接着调用ApplicationonCreate方法。接着会通过Activityattach方法来完成一些重要数据的初始化,完成Window的创建并关联Activity,这样当Window接收到外部事件后就可以将事件传递给Activity。最后就是调用ActivityonCreate方法,完成整个启动过程。

 

3.Service的启动过程

        Service有启动和绑定两种状态,值得注意的是,这两种状态是可以共存的,也就是说Service可以同时处于启动和绑定状态

启动一个Service如下所示:

Intent intentService = new Intent(this,oneService.class);

startService(intentService);

通过绑定的方式启动一个Service

Intent intentService = new Intent(this,oneService.class);

bindService(intentService,mServiceConnection,BIND_AUTO_CREATE);

         Service的启动从ContextWrapperstartService方法开始,该方法又调用了ContextImplstartService方法。之前已经说过Context的具体实现交给了ContextImpl来完成,ContextImplstartService源码很复杂,分析Service的启动过程没必要一句一句代码的深究。Activity的启动类似,最终都是发送消息给Handler H来完成启动。H通过ActivityThreadhandleCreateService完成Service的启动。

         handleCreateService主要完成下面几件事:

1.通过类加载器创建Service实例;

2.创建Application对象,并调用ApplicationonCreate方法,当然Application只能创建一次;

3.创建ConTextImpl并通过Serviceattach建立两者的关系,注意ServiceActvity都是一个Context

4.最后调用ServiceonCreate方法,并将Service对象保存到ActivityThread的一个ArrayMap列表中。到这里Service已经启动了,下面就是Service的绑定过程。

          Service的绑定同样是从ContextWrapper开始的,再最终调用ContextImplbandServiceCommon方法。这个方法主要做了下面的两件事:

 · ServiceConnection对象转化为ServiceDiapatcher.InnerConnection。这是因为服务的绑定可能是跨进程的,所以ServiceConnection必须借助Binder才能让远程服务端回调自己的方法,InnerConnection正好充当Binder这个角色。在ServiceDiapatcher中保存了ServiceConnectionInnerConnection对象。

·  bindServiceCommon通过AMSbindService完成具体的绑定过程。AMS通过一系列的调用,最终调用了ApplicationThreadSchedualBindServiceApplicationThread中一系列由schedule开头的方法都是通过Handler H来中转的,这次也不例外。在H内部,会交给ActivityThreadhandleBindService处理,首先根据Servicetoken取出Service对象,然后调用ServiceonBind方法,onBind方法会返回一个Binder对象给客户端使用。这个时候客户端并不知道已经成功连接Service了,所以需要调用客户端中ServiceConnectiononServiceConnected方法。到这里,Service的绑定过程就算完成了。

 

4.BroadcastReceiver的工作过程

   先回顾一下BroadcastReceiver的使用方法,首先要定义广播的接收者,只需要继承BroadcastReceiver并重写onReceiver方法即可。比如:

 

public class oneReceiver extends BroadcastReceiver{

   @Override

   public void onReceiver(Context context,Intent intent){

       //onReceiver不能做耗时的工作

      Log.e(“......”,intent.getAction()+””);

   }

}

 

定义过接收者后,还需要注册广播接收者

·静态注册

  

      

           

      

  

·动态注册

  IntentFilter filter = new IntentFilter();

  filter.addAction(“com.ryg.receiver.LAUNCH”);

  registerReceiver(new oneReceiver(),filter);

·发送广播

  Intent intent = new Intent();

  intent.setAction(“com.rgy.receiver.LAUNCH”);

  sendBroadcast(intent);

         当使用send方法发送广播时,AMS会查找出匹配的广播接收者并把广播发送给他们处理。广播分为普通广播、有序广播和粘性广播。最普遍的还是普通广播。

   广播的发送和接受实质是一个过程的两个阶段。在Ansroid5.0中,默认情况不会发送广播给已经停止的应用,实际上在Android3.0就为Intent添加了两个标志位,分别是:

·FLAG_INCLUDE_STOPPED_PACKAGES,表示广播会发送给已经停止的应用

·FLAG-EXCLUDE_STOPPED_PACKAGES,表示广播不会发送给已经停止的应用

  系统默认为Intent添加了第二种标志位,以免广播无意间或者唤起不必要的应用。如果确实要唤起已经停止的应用,为广播添加上面的第一种标志位即可。当两种标志位共存时,广播会发送给已经停止的应用。而最终广播发送的实现还是在前面提到过的Handler H类中完成。

 

5.ContentProvider的工作过程

        ContentProvider是一种内容共享型组件,他通过Binder向其他组件乃至其他应用提供数据。ContentProvider所在的进程启动时,ContentProvider会同时启动,并且要注意ContentProvideronCreate是优先于ApplicationonCreate执行的。这和前面介绍的三个组件是完全不同的。

   当一个应用启动时,入口方法为ActivityThreadmain方法,在main方法中会创建ActivityThread的实例并创建主线程的消息队列。在ActivityThreadhandleBandApplication方法中,ActivityThread会创建Application对象并加载ContentProvider。这里要注意的是,ActivityThread会先加载ContentProvider再调用ApplicationonCreate方法。流程图如下:

 

 

        ContentProvider是否是单实例是由他的multiprocess属性决定的。androidmultiprocessfalseContentProvider是单实例的,当他是true的时候,ContentProvider就是多实例。多实例是指每个调用者的进程都会有一个ContentProvider对象,但这样会带来进程间通信的开销,所以大部分还是使用单实例。

   当ContentProvider所在进程还未启动时,第一次访问他会出发ContentProvider的创建,当然也伴随着ContentProvider所在进程的启动。ContentProvider四个方法中的任何一个都会触发启动ContentProvider,下面以查询query为例。

   在query方法中会调用ActivityThreadacquireProvider方法,该方法会先从ActivityThread中查找是否已经存在目标ContentProvider了,如果存在直接返回。如果目前ContentProvider还没启动,那么久发送一条进程间请求给AMS让其启动ContentProvider。启动ContentProvider的时候会先启动它所在的进程(也可以理解为是应用),然后再启动当前进程的ContentProviderAMS会把ContentProvider存储在ProviderMap,这样一来调用者就可以直接从AMS中获取ContentProvider了。

更多相关文章

  1. android之listview使用方法(一)
  2. 从头到尾给你讲明白Android(安卓)View实现原理
  3. 对于android中自定义组件属性的理解
  4. android充当server服务器
  5. android 应用内悬浮框,并在指定页面显示
  6. 新书内容连载(1):自定义Android组件之带图像的TextView
  7. Android(安卓)应用设置全局Exception处理事件的方法
  8. [置顶] Android(安卓)实现 WheelView
  9. Android(安卓)四大组件

随机推荐

  1. android 优化之字节对齐
  2. Android中AsyncTask(异步执行任务)的使用
  3. android AsyncTask使用总结
  4. android 数据备份
  5. android -- 小功能 DownloadManager——A
  6. Android如何监听蓝牙耳机的按键事件
  7. 将Android通讯录导入iphone的方法
  8. [置顶] 介绍下什么是android呢?
  9. Android开发黄金搭档:Android(安卓)Studio
  10. 一步步探索学习Android(安卓)Touch事件分