android四大组件的运行状态

android四大组件:Activity,Service,BroadcastReceiver和ContentProvider.

一、异同点

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

二、Activity的相关介绍

Activity是一种展示组件,用于向用户直接的展示一个界面,并且可以接收用户输入的信息来进行交互。

1、什么是Activity?

Activity是一个负责与用户交互的组件,Activity中所有操作都与用户密切相关,可以通过setContentView(View)来显示指定控件。

在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。

2、请描述一下Activity生命周期。

onCreate(Bundle savedInstanceState):

创建activity时调用。设置在该方法中,还以Bundle的形式提供对以前储存的任何状态的访问!

onStart():

activity变为在屏幕上对用户可见时调用。

onResume():

activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法

总是被调用的)。

onPause():

activity被暂停或收回cpu和其他资源时调用,该方法用于保存活动状态的,也

是保护现场,压栈吧!

onStop():

activity被停止并转为不可见阶段及后续的生命周期事件时调用。

onRestart():

重新启动activity时调用。该活动仍在栈中,而不是启动新的活动。

onDestroy():

activity被完全从系统内存中移除时调用,该方法被调用

3、如何退出Activity?如何安全退出已调用多个Activity的Application?

在Android中退出程序比较麻烦,尤其是在多个Activity的程序中,在2.2之前可以采用如下代码退出程序:

1. ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);

2. am.restartPackage(getPackageName());

此种方法是一种最方便和最简单的退出程序的办法,但是在2.2和2.2之后就不能用了,一种常用的方法是自定义一个Activity的栈,在程序退出时将栈中的所有的Activity进行finish。

还有一些其他的方式,在这http://alex-yang-xiansoftware-com.iteye.com/blog/1099207可查看。

4、如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?

答:重写onSaveInstanceState()方法,在此方法中保存需要保存的数据,该方法将会在activity被回收之前调用。通过重写onRestoreInstanceState()方法可以从中提取保存好的数据

5、 activity在屏幕旋转时的生命周期

答:不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。

6、 activity的启动模式有哪些?是什么含义?

答:在android里,有4种activity的启动模式,分别为:

“standard” (默认)

“singleTop”

“singleTask”

“singleInstance”

当应用运行起来后就会开启一条线程,线程中会运行一个任务栈,当Activity实例创建后就会放入任务栈中。Activity启动模式的设置在AndroidManifest.xml文件中,通过配置Activity的属性android:launchMode=""设置。

1. Standared模式(默认)

我们平时直接创建的Activity都是这种模式的Activity,这种模式的Activity的特点是:只要你创建了Activity实例,一旦激活该Activity,则会向任务栈中加入新创建的实例,退出Activity则会在任务栈中销毁该实例。

2. SingleTop模式

这种模式会考虑当前要激活的Activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,否则会在任务栈中创建新的实例。

3. SingleTask模式

如果任务栈中存在该模式的Activity实例,则把栈中该实例以上的Activity实例全部移除,调用该实例的newInstance()方法重用该Activity,使该实例处於栈顶位置,否则就重新创建一个新的Activity实例。

4. SingleInstance模式

当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,此时使用的都是同一个Activity实例,它都会处于任务栈的栈顶。此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity。

7、跟activity和Task 有关的 Intent启动方式有哪些?其含义?核心的Intent Flag有:

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_SINGLE_TOP

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

FLAG_ACTIVITY_NEW_TASK

如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相同的次序。这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。

FLAG_ACTIVITY_CLEAR_TOP

如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。

FLAG_ACTIVITY_SINGLE_TOP

如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

如果设置这个标志,这个activity不管是从一个新的栈启动还是从已有栈推到栈顶,它都将以the front door of the task的方式启动。这就讲导致任何与应用相关的栈都讲重置到正常状态(不管是正在讲activity移入还是移除),如果需要,或者直接重置该栈为初始状态。

三、Service

Service是一种计算型组件,用于在后台执行一系列的计算任务。由于在后台,所以用户无法直接感知到他的存在。Service和activity组件略有不同,activity组件只有一种运行模式,即activity处于启动状态,而Service却有两种状态:启动和绑定状态。

1、android 关于service生命周期的onCreate()和onStart()说法正确的是(ad)(多选题)

A、当第一次启动的时候先后调用onCreate()和onStart()方法

B、当第一次启动的时候只会调用onCreate()方法

C、如果service已经启动,将先后调用onCreate()和onStart()方法

D、如果service已经启动,只会执行onStart()方法,不在执行onCreate()方法

2、Service是如何启动

A. 通过startService;Service会经历onCreate->onStart;stopService的时候直接onDestroy;如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的话,Service会一直在后台运行,下次TestServiceHolder再起来可以stopService。

B. 通过bindService;Service只会运行onCreate,这个时候TestServiceHolder和TestService绑定在一起,TestServiceHolder退出了,Srevice就会调onUnbind->onDestroyed,所谓绑定在一起就共存亡了。

3、Service用在哪个线程

默认情况下Service是运行在启动该Service的应用主线程的,如果Service中的操作占用大量的CPU资源或有阻断操作(比如播放MP3或者访问网络)会影响应用主线程的响应性能,甚至会造成“应用程序无响应(ANR)”问题。

4、简单介绍服务

服务是没有界面的长生命周期的代码。一个很好的例子是媒体播放器从列表中播放歌曲。在一个媒体播放器程序中,大概要有一个或多个活动(activity)来供用户选择歌曲并播放它。然而,音乐的回放就不能使用活动(activity)了,因为用户希望他导航到其他界面时音乐继续播放。这种情况下,媒体播放器活动(activity)要用Context.startService()启动一个服务来在后台运行保持音乐的播放。系统将保持这个音乐回放服务的运行直到它结束。注意一下,你要用Context.bindService()方法连接服务(如果它没有运行,要先启动它)。当连接到服务后,你可以通过服务暴露的一个接口和它通信。对于音乐服务,它允许你暂停、倒带,等等。

5、service和Thread区别?

1).Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2).Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。

四、BroadcastReceiver

BroadcastReceiver是一种消息型组件,用于在不同的组件中和不同的应用之间传递消息。同样无法被用户指甲感知到,因为他工作在系统内部。

在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。

1、用途:

实现了不同的程序之间的数据传输与共享,因为只要是和发送广播的action相同的接受者都能接受这个广播。典型的应用就是android自带的短信,电话等等广播,只要我们实现了他们的action的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等

起到了一个通知的作用,比如在service中要通知主程序,更新主程序的UI等

因为service是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接受者专门用来接受service发过来的数据和通知了

2、使用场景:

同一app内部的同一组件内的消息通信(单个或多个线程之间);

同一app内部的不同组件之间的消息通信(单个进程);

同一app具有多个进程的不同组件之间的消息通信;

不同app之间的组件之间消息通信;

Android系统在特定情况下与App之间的消息通信。

3、实现原理:

从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:

广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;

广播发送者通过binder机制向AMS发送广播;

AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;

消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

4、注册方式

有俩种注册方式分别是静态注册和动态注册

静态注册

在AndroidManifest.xml 中:    . . .android:exported —— 此broadcastReceiver能否接收其他App的发出的广播(其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。)android:name  —— 此broadcastReceiver类名;android:permission  ——如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收;android:process  ——broadcastReceiver运行所处的进程。默认为app的进程。可以指定独立的进程(Android四大基本组件都可以通过此属性指定自己的独立进程)

动态注册

无须在AndroidManifest中注册组件。直接在代码中通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver。registerReceiver的定义形式如下:

registerReceiver(BroadcastReceiverreceiver,IntentFilterfilter)或:registerReceiver(BroadcastReceiverreceiver,IntentFilterfilter,StringbroadcastPermission,Handlerscheduler)

5、俩种注册方式的区别

静态注册即使app退出,任然能接收到广播

动态注册时,当activity退出,就接收不到广播了

但是 静态注册即使app退出,任然能接收到广播 这种说法自Android 3.1开始有可能不再成立。

Android 3.1开始系统在Intent与广播相关的flag增加了参数:

A. FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)

B. FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包

自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。

由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。

但是对于自定义的广播,可以通过复写此flag为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。

Intent intent = new Intent();

intent.setAction(BROADCAST_ACTION);

intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);

intent.putExtra("name", "qqyumidi");

sendBroadcast(intent);

替代方案: 通过将Service与App本身设置成不同的进程已经成为实现此类需求的可行替代方案。

6、其他

有序广播

有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其的主要发送方式变为:sendOrderedBroadcast(intent, receiverPermission, ...)。

对于有序广播,其主要特点总结如下:

1>多个具当前已经注册且有效的BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。

2>先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。

应用内广播

Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,所以安全隐患如下:

其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;

其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。

7、增加安全性的方案:

对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;

在广播发送和接收时,都增加上相应的permission,用于权限验证;

发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

相比于全局广播,App应用内广播优势体现在:

安全性更高;

8、Android引入广播机制的用意?

答:

a : 从MVC的角度考虑(应用程序内) ,其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。

b:程序间互通消息(例如在自己的应用程序内监听系统来电)

c:效率上(参考UDP的广播协议在局域网的方便性)

d:设计模式上(反转控制的一种应用,类似监听者模式)


五、ContentProvider

ContentProvider是一种数据共享组件,用于向其他组件和其他应用共享数据。同样无法直接被用户感知。

1、ContentProvider的URI的配置?

清单文件之指定URI或者代码里面指定URI,contentProvider通过URI访问数据

2、contentprovider怎么实现数据共享?

一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content providers是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。要想使应用程序的数据公开化,可通过2种方法:创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。

3、如何通过一套标准及统一的接口获取其他应用程序暴露的数据?

Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。

4、ContentProvider和SQL的区别

Sql只能在该工程的内部共享数据,ContentProvider能在工程之间实现数据共享。

5、Android如何访问自定义ContentProvider

第一:得到ContentResolver类对象:ContentResolver cr = getContentResolver();

第二:定义要查询的字段String数组。

第三:使用cr.query();返回一个Cursor对象。

第四:使用while循环得到Cursor里面的内容


补充:

1、Intent的原理

intent是连接Activity, Service, BroadcastReceiver, ContentProvider四大组件的信使,,可以传递八种基本数据类型以及string, Bundle类型,以及实现了Serializable或者Parcelable的类型。

2、Intent可以划分成显式意图和隐式意图:

显式意图:调用Intent.setComponent()或Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意图明确指定了Intent应该传递给哪个组件。

隐式意图:没有明确指定组件名的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。

3、IntentService有何优点?

Acitivity的进程,当处理Intent的时候,会产生一个对应的Service

Android的进程处理器现在会尽可能的不kill掉你

非常容易使用。

推荐阅读更多精彩内容