Android进阶之四大组件综述

本篇文章概述分析Android四大组件的机制,插入本人其他的博客链接方便阅读,以及为接下来写四大组件的内部工作过程铺垫。

1 Android四大组件的运行状态

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

1.1 四大组件都可以开启多进程

1.1.1 如何开启并查看多进程

Android四大组件都可以开启多进程,需要在AndroidManifest.xml里面添加android:process="",process的值可以自由设置,没有指定process属性运行在默认进程中,默认进程名是包名。例子如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.seniorlibs.ipc">

    <application
        android:name=".MyApplication"
        <activity
            android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 当前应用的私有进程(常用) -->
        <activity
            android:name=".SecondActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name"
            // 以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。
            android:process=":remote" />
       
        <!-- 全局进程 -->
        <activity
            android:name=".ThirdActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name"
            // 以"."开头的进程属于全局进程,其他应用的组件可以通过sharedUserId方式和它跑在同一个进程中。
            android:process="com.seniorlibs.ipc.remote" />
    </application>
</manifest>

可以在DDMS视图中查看进程信息,还可以用shell来查看,命令为:adb shell ps 或者 adb shell “ps | grep com.seniorlibs.ipc”。(注意:adb shell 之后的内容要用引号引起来,就不会报adb ‘grep’ 不是内部或外部命令错误。)

$ adb shell "ps | grep com.seniorlibs.ipc"
u0_a85    6768  1349  1417592 50864 SyS_epoll_ 00000000 S com.seniorlibs.ipc
u0_a85    6839  1349  1413888 49096 SyS_epoll_ 00000000 S com.seniorlibs.ipc:remote 
u0_a85    6858  1349  1413888 48884 SyS_epoll_ 00000000 S com.seniorlibs.ipc.remote
1.1.2 多进程造成的问题

(1)静态成员和单例模式完全失效。因为每个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,导致在不同的虚拟机访问同一个类的对象会产生多份副本,所以进程间不可以通过内存来共享数据。
(2)线程同步机制完全失效。类似1,既然不在同一块内存,不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象。
(3)SharePreferences的可靠性下降。因为SharePreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失。
(4)Application会多次创建。因为系统在创建新的进程同时分配独立的虚拟机,其实是启动一个应用的过程(相当于重新启动),就会创建新的Application。所以,在Application初始化第三方sdk时需要判断是否是“主进程”正在执行。

public class Application extends BaseApplication {
    private final static String LOG_TAG = "Application ";
    private static String PROCESS_MAIN = "com.main";           // 主进程名称
    private static String PROCESS_MESSAGE = "com.h:message";   // 消息进程名称
  
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    @Override
    protected void init() {
        String curProcessName = ProcessUtils.getCurProcessName(this);
        initData(curProcessName);
    }

    @Override
    protected void unInit() {
        String curProcessName = ProcessUtils.getCurProcessName(this);
        unInitData(curProcessName);
    }

    /**
     * 初始化数据
     */
    private void initData(String curProcessName) {
        if (PROCESS_MAIN.equals(curProcessName)) {
            // 初始化线程池
            // 初始化HTTP请求管理
		    // 初始化广告sdk
            // 初始化自定义生命周期回调
            this.registerActivityLifecycleCallbacks(new CustomActivityLifecycleCallback());
        }
            
        if (PROCESS_MAIN.equals(curProcessName) || PROCESS_MESSAGE.equals(curProcessName)) {
            PushUtils.initPush(this);  // 初始化推送
        }
    }

    /**
     * 反初始化数据
     */
    private void unInitData(String curProcessName) {
        if (PROCESS_MAIN.equals(curProcessName) || PROCESS_MESSAGE.equals(curProcessName)) {
            // 释放线程池资源  
            // 释放HTTP请求资源
        }
    }
}

1.2 Provider相关???

1.2.1 利用ShareUserID共享数据(私有暴露)

在Android里面每个app都有一个唯一的linux user ID,则这样权限就被设置成该应用程序的文件只对该用户可见,只对该应用程序自身可见。用到SharedUserId让两个apk使用相同的userID,这样它们共享一个虚拟机,就可以看到对方的文件。
注意:打包时签名文件必须相同。除非使用一个系统自带软件的ShareUID,例如Contact,那么无须第三方签名。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.mythou.serviceID"
	android:versionCode="1"
	android:versionName="1.0"
	android:sharedUserId="com.mythou.share">

//第二个应用程序的menifest文件代码如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.mythou.clientID"
	android:versionCode="1"
	android:versionName="1.0"
	android:sharedUserId="com.mythou.share">
//从package=“com.mythouclientID”的程序获取package="com.mythou.serviceID"的程序的context:
Context context = this.createPackageContext("com.mythou.serviceID", Context.CONTEXT_IGNORE_SECURITY);
String str = context.getString(R.string.appname);
1.2.2 利用StartActivity启动其他应用的组件(完全暴露)

android:exported=”true”的作用,而一旦设置了intentFilter之后,exported就默认为true,除非强制设为false。没有设置intentFilter时,它的exported属性默认仍然是false,也就不会暴露数据。

exported=”true”:provider需要提供给其他application,甚至是第三方application使用;
exported=”false”:provider只有自己的application或者同一个UID的application使用。

另外组件是Provider时:当Android sdk的最小版本为16或者更低时它的默认值是true,如果是17和以上的版本默认值是false。可以通过Android:exported=“fasle” 和 permission来限制当前应用Provider是否会被其它应用获取。

2 Activity机制

2.1 定义与作用

(1)Activity主要作用是:展示一个界面并和用户交互,它扮演的是一种前台界面的角色。
(2)Activity是一种展示型组件,主要是向用户展示一个界面,并且可以接收用户的输入信息从而和用户进行交互。对用户来说,Activity就是Android应用的全部,因为其他三大组件对用户来说是不可感知的。
(3)Activity只有一种运行模式–启动状态,它的启动由Intent触发,其中Intent分为显式启动和隐式启动,显式启动明确地指向一个Activity,隐式启动则指向一个或多个目标Activtity组件。详细阅读:Android基础之IntentFilter匹配规则与隐式启动Activity

2.2 内容详解

Android基础之Activity生命周期+Activity难点

Android基础之Activity四种启动模式和task相关

2.4 内部工作过程

Android系统分析之Activity的启动流程

3 Service机制

3.1 定义与作用

(1)Service组件的主要作用是:在后台执行计算任务,执行任务的结果可以和外界进行通信。
(2)Service是一种计算型组件,用于在后台执行一系列计算任务。由于Service组件工作在后台,因此用户无法直接感知到它的存在。Activity组件只有一种运行模式-启动状态,但是Service组件却有两种状态:启动状态和绑定状态。①通过startService启动的服务处于启动状态,它的内部可以执行一些后台计算,并且不需要和外界有直接的交互。②通过bindService启动的服务处于绑定状态,Service内部同样也可以执行后台计算,但是处于这种状态的Service可以通过ServiceConnection和外界进行通信。

3.2 内容详解

Android基础之四大组件-详解Service

4 BroadcastReceiver机制

4.1 定义与作用

(1)BroadcastReceiver组件的主要作用是:消息的传递,该消息的传递可以在应用内,也可以在应用之间,它的角色是一个消息的传递者。
(2)BroadcastReceiver是一种消息型组件,用于在不同组件乃至不同应用之间传递消息。BroadcastReceiver同样无法被用户所感知,因为它工作在系统内部。BroadcastReceiver也叫做广播,广播的注册方式有两种:静态注册和动态注册。静态注册指在AndroidManifest中注册广播,这种广播在应用安装时被系统解析,此种形式的广播不需要应用启动就可以接收到相应的广播。动态广播需要通过Context.registerReceiver()来实现,并且在不需要的时候通过Context.unRegisterReceiver()解除广播,此种形态的广播必须要应用启动才能注册并接收广播。在实际开发中通过Context的一系列send方法来发送广播,被发送的广播会被系统(Activity Manager Service)发送给合适的广播接受者,依据是intent-filter/permission。由此发现,BroadcastReceiver可以用来实现低耦合的观察者模式,一般来说不需要停止,也没有停止的概念。由于BroadcastReceiver运行在主线程,所以它不适合用来执行耗时操作。

4.2 内容详解

Android基础之四大组件-BroadcastReceiver解析

5 ContentProvider机制

5.1 定义与作用

(1)ContentProvider组件的主要作用是:作为一个平台,提供数据的共享,并且提供数据的增删改查功能。主要应用于应用之间的数据共享场景。
(2)ContentProvider是一种数据共享型组件,用于向其他组件乃至其他应用共享数据。同样的,它也无法被用户所感知。对于ContentProvider组件来说,它的内部需要实现增删改查这四种操作,在它的内部维持了一份数据集合,这个数据集合既可以通过数据库来实现,也可以采用其他任何类型来实现,比如List和Map。需要注意的是,ContentProvider内部的insert、delete、update和query方法需要处理好线程同步,因为这几个方法都是在Binder线程池中被调用的。ContentProvider组件不需要手动停止。

5.2 内容详解

Android基础之四大组件-深入理解ContentProvider

6 参考资料

《Android开发艺术探索》

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

Android四大组件的作用

Android中startActivity中的permission检测与UID机制

Android ShareUserId 使用总结

android:exported 属性详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值