Android四大组件简析
我们知道,Android应用通常由一个或多个基本组件组成。其中,最基本的四个组件分别就是Activity、Service、BroadcastReceiver以及ContentProvider。下面我来分享一下自己对这四个基本组件的认识。
Activity
Service
BroadcastReceiver
ContentProvider
Activity
Activity是Android应用中负责与用户交互的组件——大致上可以把它看作是Swing编程中的JFrame控件。不过它与JFrame的区别在于:JFrame本身可以设置布局管理器,不断地向JFrame中添加控件,但Activity只能通过setContentView(View)来显示指定的组件。
一般一个Android应用是由多个activity组成的,这多个activity之间可以进行相互跳转。例如,按下一个Button按钮后,可能会跳转到其他的activity,与网页跳转稍微有点不一样的是,activity之间的跳转有可能返回值。例如,从activity A跳转到activity B,那么当activity B运行结束时,有可能会给activity A一个返回值。这样做在很多时候是相当方便的。
Activity为Android应用提供了可视化用户界面,如果该Android应用需要多个用户界面,那么这个Android应用将会包含多个Activity,多个Activity组成Activity栈,当前活动的Activity位于栈顶。
接下来,我们来说一下其生命周期。关于这一点,我之前写过类似的文章,详见拙作:Android之浅谈activity生命周期
需要注意的是,Android中四大组件在使用前都需要注册。Android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity,如:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
四种启动模式(LaunchMode)
先来看实现的代码:
<activity
android:name=".SecondActivity"
android:launchMode="singleInstance"
//四种启动模式都需要在清单文件下的Activity节点下配置,如果不配置,则默认标准standard开启activity
>
</activity>
下面是对其参数进行介绍:
standard:
默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中
singleTop:
如果在任务的栈顶正好存在该Activity,就会重用该实例(会调用实例的onNewIntent()),否则就会创建新的实例放入栈顶(注:即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建实例)
singleTask:
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被转移出栈,如果栈中不存在该示例,将会创建新的实例放入栈中
singleInstance:
在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例,一旦该模式的Activity实例已经存在于某个栈中,任何应用在激活该Activity时都会重用该栈中的实例(会调用实例的onNewIntent())。其效果相当于多个应用共享一个应用,不管谁激活该Activity都会进入同一个应用中
Service
Service 与Activity的地位是并列的,它也代表一个单独的Android组件。Service 与Activity的区别在于:Service 通常位于后台运行,它一般不需要与用户交互,因此Service 组件没有图形用户界面。
与Activity组件需要继承Activity基类相似,Service 组件需要继承Service 基类。一个Service 组件被运行起来之后,它将拥有自己独立的生命周期,Service 组件通常用于为其他组件提供后台服务或监控其他组件的运行状态。
下面介绍关于Service 生命周期的方法:
- IBinder onBind(Intent intent): 该方法是Service子类必须实现的方法。该方法返回的是一个IBinder对象,应用程序可通过该对象与Service组件通信
- void onCreate(): 在该Service第一次被创建后将立即回调该方法
- void onDestroy(): 在该Service被关闭之前将会回调该方法
- void onStratCommand(Intent intent,int flags,int stratld): 每次客户端调用stratService(Intent)方法启动该Service时都会回调该方法
- boolean onUnbind(Intent intent): 当该Service上绑定的所有客户端都断开连接时将会回调该方法
同样地,需要在AndroidManifest.xml文件中配置该Service,如:
<service android:name=".FirstService">
</service>
下面介绍一下Android系统中运行Service的两种方式:
- 通过 Content 的startService()方法 : 通过该方法启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行
- 通过 Content 的bindService()方法 : 使用该方法启动Service,访问者与Service之间绑定在一起,访问者一旦退出,Service也就终止了
无论通过哪种方法启动Service,都可以用stopService()方法将其关闭
为了更好地解读其生命周期,我们来看这张图片:
如果大家想对Service有更深的了解的话,在这里推荐一篇博客,里面有对Service详细的讲解:解读Android之Service(1)基础知识
BroadcastReceiver
BroadcastReceiver是Android应用中另一个重要的组件,顾名思义,BroadcastReceiver代表广播消息接收器。从代码实现的角度看,BroadcastReceiver非常类似于事件编程中的监听器。与普通事件监听器不同的是,普通事件监听器监听的事件源是程序中的对象;而BroadcastReceiver监听的事件源是Android应用中的其他组件。
由于BroadcastReceiver本质上属于一个监听器,因此实现BroadcastReceiver的方法也十分简单,只要重写:
public void onReceive(Context context,Intent intent)方法即可
注意: onReceive方法必须在10秒内完成,如果没有完成,则抛“Application No Response”当广播接收者onReceive方法需要执行很长时间时,最好将此耗时工作通过Intent发送给Service,由Service完成,并且不能使用子线程解决,因为BroadcastReceiver是接收到广播后才创建的,并且生命周期很短,因此子线程可能在没有执行完就已经被杀死了。
此时,如果有通过Context.sendBroadcast(Intent intent)或Context.sendOrderedBroadcast(Intent intent)发送的意图,通过这个语句,能够广播给所有满足条件的组件,比如intent设置了action=”com.xiazdong”,则所有在AndroidManifest.xml中设置过的广播接收者都能够接收到广播。
对于发送广播的一方,通常就是调用Context.sendBroadcast()的程序,而广播接收者就是继承BroadcastReceiver的程序;
通常广播发送方都是通过隐式意图,这样才能发送给多人;
广播发送方分为普通广播和有序广播;
同步广播:发送方发出后,几乎同时到达多个广播接收者处,某个接收者不能接收到广播后进行一番处理后传给下一个接收者,并且无法终止广播继续传播;Context.sendBroadcast(intent);
有序广播:广播接收者需要提前设置优先级,优先级高的先接收到广播,优先级数值为-1000~1000,在AndroidManifest.xml的设置;比如存在3个广播接收者A、B、C,优先级A>B>C,因此A最先收到广播,当A收到广播后,可以向广播中添加一些数据给下一个接收者(intent.putExtra()),或者终止广播(abortBroadcast());Context.sendOrderedBroadcast(intent);
在这里也推荐给大家我学习BroadcastReceiver的博客: Android入门:广播发送者与广播接收者
ContentProvider
对于Android应用而言,它们必须相互独立,各自运行在自己的进程中,如果这些Android应用之间需要实现实时的数据交换——例如,我们开发了一个发送短信的程序,当发送短信时需要从联系人管理应用中读取指定联系人的数据——这就需要多个应用程序之间进行数据交换。
Android系统为这种跨应用的数据交换提供了一个标准:ContentProvider。通常与ContentProvider结合使用的是ContentResolver,一个应用程序使用ContentProvider暴露自己的数据,而另一个应用程序则通过ContentResolver来访问数据。
当用户实现自己的ContentProvider时,同时也需要实现如下的抽象方法:
- insert(Uri,ContentValues):向ContentProvider插入数据
- delete(Uri,ContentValues):删除ContentProvider中指定的数据
- update(Uri,ContentValues,String,String[]):更新ContentProvider中指定的数据
- query(Uri,String[],String,String[],String):从ContentProvider查询数据
同样地,这个组件在使用之前也需要进行配置,如:
<provider
android:authorities=".FirstProvider"
android:name="org.crazyit.providers.firstprovider"
android:exported="true">
</provider>
事实上,当其他应用通过getContentResolver()获取ContentResolver对象来调用query()、insert()、update()、和delete()方法执行数据访问时,实际上就是通过调用指定Uri对应的ContentProvider的query()、insert()、update()、和delete()方法。
这里简单介绍ContentProvider中的Uri:
content://org.crazyit.providers.firstprovider/words
其中可分为三个部分:
- content:// :这个部分是Android的ContentProvider规定的,就像上网的协议默认是http://一样。暴露ContentProvider、访问ContentProvider的协议默认是content://
- org.crazyit.providers.firstprovider :这个部分就是ContentProvider的authorities。系统就是由这个部分来找到操作哪个ContentProvider的。只要访问指定的ContentProvider,这个部分就是固定的。
- words :资源部分(或者说数据部分)。当访问者需要访问不同资源时,这个部分是动态改变的。