Android四大组件的作用及多进程的开启

2018-05-14  本文已影响39人  wuchao226

一、Android四大组件

Android四大组件除了BroadcastReceiver以外,其他三种组件都必须在AndroidManifest中注册,对于BroadcastReceiver来说,既可以在AndroidManifest中注册,也可以通过代码来注册。在调用方式上,Activity、Service和BroadcastReceiver需要借助Intent,而ContentProvider无须借助Intent。

二、Activity

Activity 是一种展示型组件,其作用就在于向用户直接展示一个界面,并且接收用户操作信息从而进行交互。Activity 是唯一一种可以直接感知的组件,可以说,在用户看来 Activity 就是一个Android应用的全部。

1. 启动方式

Activity 启动方式有两种,显式启动和隐式启动

Intent intent=new Intent(this,SampleActivity.class);
startActivity(intent);
Intent intent=new Intent("com.wuc.sampleActivity");
startActivity(intent);
<activity android:name=".SampleActivity">
    <intent-filter>
        <action android:name="com.wuc.sampleActivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
2. 生命周期

(1)正常情况下,Activity 会经历如下生命周期

下图详细的描述了 Activity 各种生命周期的切换过程:

Activity 的生命周期切换过程.png

三、Service

Service主要用于在后台执行一系列计算任务,耗时的后台任务,需要单独的线程去完成,因为Service本身是运行在主线程的。Service不与用户产生UI交互,其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。
1. Context.startService()启动
被启动的服务的生命周期:onCreate -> onStartCommand -> onDestroy

2.bindService
被绑定的服务的生命周期:onCreate-> onBind-> onUnbind->onDestory()

3. startService和bindService混合使用
需求场景:在activity中要得到service对象进而能调用对象的方法,但同时又不希望activity finish的时候service也被destory了。

1、先调用startService,后调用bindService。服务的执行过程为:

onCreate —》onStartCommand —》onStart —》onBind  —》(onServiceConnected)

2、先unBindService,后stopService。服务结束的执行过程:

onUnbind —》onDestroy

注意:unBindService会执行到onUnbind,stopService会执行到onDestroy。
3、先stopService,后unBindService。服务结束的执行过程:

onUnbind —》onDestroy

注意:stopService不会执行任何操作,unBindService会执行到onUnbind—》onDestroy。

1、先调用startService,后调用bindService。服务的执行过程为:

onCreate —》onBind  —》(onServiceConnected) —》onStartCommand —》onStart

2、先unBindService,后stopService。服务结束的执行过程:

onUnbind —》onDestroy

注意:unBindService会执行到onUnbind,stopService会执行到onDestroy。
3、先stopService,后unBindService。服务结束的执行过程:

onUnbind —》onDestroy

注意:stopService不会执行任何操作,unBindService会执行到onUnbind—》onDestroy。

总结:
1、若被停止的服务依然有ServiceConnection 与其绑定,则服务不能销毁,直至我们把所有ServiceConnection 解绑
2、当所有ServiceConnection 解绑后,系统会自动销毁服务。(不包括同时用startService()启动的情况。此时,我们不得不再调用一次stopService来销毁它)
3、多次bindService时,服务本身的onBind不会被多次执行。
4、bind上一个Service后,执行一次unBindService就够了。不然会出错。
5、一个App里,同一个Activity多次bind一个服务,除了第一次,后面的bind不会有任何onBind、onServiceConnected打印。
一个App里,不同的Activity去bind一个服务,第一次bind有onBind、onServiceConnected打印,后面的bind只会有onServiceConnected打印。
6、一个Activity bind上一个Service后,如果Activity finish前没有调用unBind,App会崩溃

四、BroadcastReceiver

主要用于在不同的组件乃至不同的应用之间传递消息,不与用户产生交互,工作在系统内部。
注册的两种方式:
1、静态注册
静态注册是在AndroidManifest.xml文件中配置的

<receiver android:name=".MyReceiver">  
     <intent-filter>  
            <action android:name="android.intent.action.MY_BROADCAST"/>  
            <category android:name="android.intent.category.DEFAULT" />  
     </intent-filter>  
</receiver> 

配置了以上信息之后,只要是android.intent.action.MY_BROADCAST这个地址的广播,MyReceiver都能够接收的到。注意,这种方式的注册是常驻型的,也就是说当应用关闭后,如果有广播信息传来,MyReceiver也会被系统调用而自动运行。
2、动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播

MyReceiver receiver = new MyReceiver();  
          
IntentFilter filter = new IntentFilter();  
filter.addAction("android.intent.action.MY_BROADCAST");  
          
registerReceiver(receiver, filter); 

注意,registerReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,所以可以直接调用。在实际应用中,我们在Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作:

@Override  
protected void onDestroy() {  
    super.onDestroy();  
    unregisterReceiver(receiver);  
}

注意,这种注册方式与静态注册相反,不是常驻型的,也就是说广播会跟随程序的生命周期。
当注册完成之后,这个接收者就可以正常工作了。我们可以用以下方式向其发送一条广播:

Intent intent = new Intent("android.intent.action.MY_BROADCAST");  
intent.putExtra("msg", "hello receiver.");  
sendBroadcast(intent);

注意,sendBroadcast也是android.content.ContextWrapper类中的方法,它可以将一个指定地址和参数信息的Intent对象以广播的形式发送出去。

五、ContentProvider

ContentProvider是一种数据共享型组件,用于向其他组件乃至其他应用共享数据

实现一个 ContentProvider 时需要实现以下几个方法:

注意:
1、onCreate() 默认执行在主线程,别做耗时操作,query() 也最好异步执行
2、上面的 4 个增删改查操作都可能会被多个线程并发访问,因此需要注意线程安全

ContentProvider 与 URI

ContentProvider 使用 URI 标识要操作的数据,这里的内容 URI 主要包括两部分:
1、authority:整个提供程序的符号名称
2、path:指向表的名称/路径
内容 URI 统一的形式就是:

content://authority/path

如:

content://user_dictionary/words

当调用 ContentResolver 方法来访问 ContentProvider 中的表时,需要传递要操作表的 URI。

在通过 ContentResolver 进行数据请求时(比如 contentResolver.insert(uri, contentValues);), 系统会检查指定 URI 的 authority 信息,然后将请求传递给注册监听这个 authority 的 ContentProvider 。这个 ContentProvider 可以监听 URI 想要操作的内容,Android 中为我们提供了 UriMatcher 来解析 URI。

六、开启多进程

在Android中使用多进程的方法,那就是在AndroidManifest中给四大组件(Activity,Service,Receiver,ContentProvider)指定android:process属性
process属性的值可以随便设置

<activity   
      android:name="com.wuc.sample.SecondActivity"  
      android:process=":second" />  
<activity   
      android:name="com.wuc.sample.ThirdActivity"  
      android:process="com.wuc.sample.third" /> 

假设包名是:com.wuc.sample
1、":"的含义是指要在当前的进程名前面附加上当前的包名,对于SecondActivity来说,它的完整的进程名为"com.wuc.sample:second"。对于ThirdActivity中的声明方式,它是一种完整的命名方式,不会附加包名信息;
2、以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中;而进程名不以":"开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。

Android系统为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据。两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以。在这种情况下,它们可以互相访问对方的私有数据,比如data目录,组件信息等。
如果它们跑在同一个进程中,那么除了能共享data目录,组件信息,还可以共享内存数据等等

多进程模式的运行机制

SecondActivity运行在一个单独的进程中,Android为每一个应用程序分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上 有不同的地址空间,这就会导致在不同的虚拟机中访问同一类的对象会产生多份副本。在一个进程中修改某个值只会影响当前进程,对其他进程不会造成任何影响。
所有运行在不同进程中的四大组件,只要它们之间如要通过内存来共享数据,都会失败,这也是多进程所带来的主要影响。

一般来说,使用多进程会造成如下几方面的问题:

上一篇 下一篇

猜你喜欢

热点阅读