Android的应用程序组件---四大组件

Android的一个核心特性就是一个应用程序可作为其他应用程序中的元素,可为其他应用程序提供数据。例如,如果程序需要用某些控件来加载一些图片,另一个程序已经开发出了此项功能,且可供其他程序使用,就可以直接使用跨进程通信方式调用那个程序的功能,而不是自己再开发一个。为了实现这样的功能,Android系统必须能够在需要应用程序中的任何一部分时启动它的进程,并且实例化那部分的Java对象。所以,不像大多数其他系统中的程序,Android程序不是只有单一的进入点,而是它们拥有系统实例化和运行必须的组件,Android中提供了4大组件;Android中的四大组件除了BroadcastReceiver之外,Activity、Service、ContentProvider都要必须在AndroidManifest.xml中注册,而BroadcastReceiver可以在AndroidManifest.xml文件中注册,也可以在Java代码或者kotlin代码中注册;在Android 8.0后,在AndroidManifest.xml文件中静态注册广播接收失效,是因为官方对耗电量的优化,避免APP滥用广播的一种处理方式。

1、Activity
Activty是一种展示型组件,Activity为用户提供了一个可视的用户界面。例如,一个拨打电话程序可能有一个Activity用来显示可以拨打电话的联系人,第二个Activity用来新建联系人写信息,其他的Activity用来查看具体的联系人,或者更改联系人信息,虽然应用程序中的各个Activity所提供的用户界面聚合性很强,但是每个Activity都独立于其他的Activity,每一个实例化的Activity都是Activity的子类,Intent可触发了Activity的启动,Intent可分为显式Intent触发和隐式Intent触发;显式Intent触发可明确的指向Activity组件,用如下代码表示:

   Intent in = new Intent(this,SecondActivity.class)
   MainActivity.this.startActivity(in)

隐式Intent触发是指向一个或者2个以上的Activity的目标组件,它也可以没有目标Activity,它的隐式触发用如下代码表示:

Intent intent = new Intent();
intent.setPackage("com.xe.launchmode");
intent.setAction("com.xe.actoin.MAP");
intent.addCategory("android.intent.category.APP_MAPS");
MainActivity.this.startActivity(intent);

2、Service
Service是一种后台处理任务型组件,它一直在后台运行,用于后台处理一系列的计算任务或者处理其他事情的时候播放背景音乐等,每个service都扩展自Service类;Service组件和Activity组件的开启是不同的,Activity只有一种启动状态,用如下代码表示:

Intent in = new Intent(this,SecondActivity.class)
startActivity(in)

而Service的开启却有2种,当处于启动状态时,它可以做一些后台任务,不需要和用户界面交互,它的生命周期和应用程序一样长,多媒体播放器播放音乐是应用Service的一个非常好的例子。多媒体播放器程序可能包含一个或者多个Activity,用户通过这些Activity选择并播放音乐。然而音乐回放并不需要一个Activity来处理,因为用户可能会希望音乐一直播放下去,即使退出了播放器去执行其他应用程序也不停止。为了让音乐一直播放,多媒体播放器Activity可能会启动一个Service在后台播放音乐。Android系统会使音乐回放Service一直运行,即使在启动这个Service的Activity退出之后。它的启动可用如下代码表示:

Intent in = new Intent(this,SecondActivity.class)
MainActivity.this.startService(in)

当它处于绑定状态时,它即可以做一些后台任务,也可以和用户界面做交互,它的生命周期和用户界面一样长,它的绑定可用如下代码表示:

ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    
Intent intent = new Intent(mContext, MyService.class);   
MainActivity.this.bindService(intent,new ServiceConnection(),Context.BIND_AUTO_CREATE);

以上2中开启,不管是哪一种都不可以直接在Service中做耗时操作,因为它是运行在主线程中的,如果非要做耗时操作,应该开一个工作线程给它去执行。

3、BroadcastReceiver
一般不执行任何任务,仅仅是接收并相应广播通知一类的组件。大部分广播通知是由系统产生的,例如改变时区、闹钟提醒、用户选择了一幅图片或者用户改变了语言首选项。应用程序同样也可以发送广播通知,例如通知其他应用程序某些数据已经下载到设备上可以使用;一个应用程序的BroadcastReceiver来响应它的通知,所有的BroadcastReceiver的实现类都扩展自BroadcastReceiver类。BroadcastReceiver适合用于不同的组件以及不同的进程之间进行通信,它是没有用户界面的,是因为它在系统内部工作。下面介绍它的2种注册方式,首先是静态注册,它是在AndroidManifest.xml文件中完成的,安装应用时会被应用解析,不启动应用也能接收广播,用如下监听wifi状态改变的代码表示:

<receiver android:name=".myapplication.receiver.WifiReceiver">
    <intent-filter>
          <action android:name="android.net.wifi.RSSI_CHANGED" />
          <action android:name="android.net.wifi.STATE_CHANGE" />
          <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     </intent-filter>
</receiver>

从以上代码可以发现,接收过程的匹配是通过<intent-filter>来描述的,可以总结出广播是一个低耦合的观察者模式这样的结论。
另外一种方式就是动态注册,需要启动应用程序才可以接收到广播,是通过在Java代码中完成注册的,用如下代码表示它的动态注册:

public class MyBroadcastReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent){
            
        }
 }
 
 
 MyBroadcastReceiver receiver = new MyBroadcastReceiver();
 IntentFilter filter=new IntentFilter();
 filter.addAction("com.xe.intent.action.ACTION_1");
 filter.addAction("com.xe.intent.action.ACTION_2");
 SecondActivity.this.registerReceiver(receiver,filter);

发送广播可用如下代码来实现:

Intent intent = new Intent();
intent.setAction("com.xe.intent.action.ACTION_2");
MainActivity.this.sendBroadcast(intent);

以上2种广播的注册方式中广播的接收是不可以做耗时操作的,因为接收广播的方法是在主线程中被调用的。

4、ContentProvider
ContentProvider是一种共享数据型组件,应用程序可以通过ContentProvider来访问其他应用程序的数据,包括其他应用程序的私有数据;和Service一样,它是没有用户界面的,它的内部需要实现insert、update、delete和query方法,它在内部使用一份数据集合并且对数据集合没有要求。ContentProvider是跨进程通信的,当Android系统收到一个需求某个组件进行处理的请求的时候,Android会确保处理此请求的组件的宿主进程是否已经在运行,如果没有,则立即启动这个进程。ContentProvider是提供一个外部接口ContentResolver给其他进程访问数据的,下面一部分代码简单的表示query方法的使用过程:

Uri bookUri = Uri.parse("content://com.zyb.provider/data");
ContentResolver cr = ContentProviderActivity.this.getContentResolver();
Cursor bookCursor = cr.query(bookUri,new String[]{"_id","name"},null,null,null);
while (bookCursor.moveToNext()) {
   int id = bookCursor.getInt(0);
   String name = bookCursor.getString(1);
}

以上代码,首先要创建要访问数据的Uri,然后通过应用程序获取ContentResolver接口,通过该接口获取数据集合Cursor对象,最后通过Cursor对象查找索引获取到最终所需的数据。好了,本章内容就写到这里,由于本人技术有限,文章难免会出现错误,还望批评指正;后面我会找个时间写一下Android四大组件工作过程的源码分析,谢谢大家的阅读。