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掉你
非常容易使用。