【android教程】Android应用程序基础(Application Fundamentals)1

2012-11-07 01:08 阅读 714 次 评论关闭

Android应用程序是用java语言写的,通过aapt工具把应用程序所需要的任何 数据、资源文件打包成apk文件,这个文件是一个将应用安装到手机上的一个载 体。
有很多方式,每个android应用程序存在于不同的世界:
(1)默认的,每个应用在他自己的Linux进程中运行,当应用中的任何代码 需要执行时android就启动相应的进程,当不需要执行时并且系统资源被其他应 用请求时android就关闭相应的进程。
(2)每个进程都有他自己的虚拟机对象(VM),所以应用程序代码与其他的 应用运行是彼此隔离的。
(3)默认的,每个应用被分配一个唯一的Linux user ID,都被设置权限以 便应用程序的文件只对用户可见或者只对应用自己可见。
安排两个应用程序共享一个user ID是可能的,这种情况下他们彼此之间是可 以看见对方的文件的,为了保护系统资源,拥有相同ID的应用也能被安排运行在 一个相同的Linux进程中,共享相同的VM。
1、应用组件(Application Components)
Android一个核心的特点就是一个应用能使用另一个应用的元素(如果另一个 应用允许的话),你的应用不需要包含你用到的另一个应用的代码也不需要你连 接这些代码,相反的,只是当应用需要这些代码时,就启动另一个应用相应的代 码(不是让另一个应用全部启动)
为了这个能工作,当一个应用的任何部分被需要时系统必须能启动这个应用 进程,并且将这个部分实例化成java对象,因此,和其他大多数系统不同的是, android应用程序没有一个单独的程序入口(例如:没有main()函数),相反 的,android应用有必要的组件以便当需要时系统能实例化并运行它,android中 有四种组件:
(1)Activity
一个Activity是一个可见的用户可以使用的用户界面,如果一个应用中有多 个Activity,虽然彼此结合形成一个应用在一起工作,但是每个Activity是彼此 独立的,每个都是Activity的一个子类。
一个应用程序可能由一个或多个Activity组成,这些Activity这么样显示, 需要多少个Activity,依赖于这个应用的设计者,一般的,有一个Activity应该 被标记成当这个应用启动时第一个呈现出来给用户的。
每个Activity默认的被给予一个窗口来绘制,一般的,这个窗口占满整个屏 幕,但是他可以比屏幕小并且浮在另一个窗口的上面。
一个窗口中的可见的内容是由一些具有层次关系的view组成的,都是继承自 View类的,每个view都控制一个窗口中的特定的矩形框,parent view 包含 children view和组织children view的布局,leaf view(那些在继承层次最底 层的view)绘制在他们所控制的矩形框中,并且对用户的动作做出直接的回应, 因此view就是Activity和用户交互的地方,android有很多已经做好的view你可 以使用,包括buttons,text fields,scroll bars,menu items,check boxes 等等
一个view hierarchy是通过Activity.setContentView()方法被放到一个 Activity的window中的,content view是view hierarchy中最顶端的那个view。
(2)Services
一个service不是一个用户可见的组件,在不确定的一段时间内运行在后台, 每个service都继承自Service类。
你可以连接(connect)或者绑定(bind)到一个正在运行的service(如果 这个service还没运行的话就启动它),当连接到service后,你可以通过一个 service暴露出来的接口和这个service交流,对music service来说,这个接口 可以是允许用户暂停,后退,停止,重新播放。
和Activity或者其他组件一样,service运行在这个应用进程的主线程中,所 以他不会阻塞其他的组件或者用户界面,他们经常为那些耗时长的任务单独开一 个线程。

(3)Broadcast receivers
一个broadcast receiver这样一个组件,他只是接收广播并作出反应,在系 统中有很多已有的广播,比如反应时区变化(timezone)的,电池变化 (battery)的,用户修改了系统语言时的广播,应用程序也可以自己定义广播 ,比如定义这样一个广播,让其他的应用知道某些数据已经下载完毕了可以使用 了。
一个应用可以有任意多个broadcast receiver来对他所关心的广播进行监听 并作出反应。所有的receiver都继承自BroadcastReceiver类。
BroadcastReceiver不显示在用户界面上,然而,他们可以启动一个Activity 来作为他们接收到的信息一种反应,或者他们可以使用NotificationManager来 提示用户,Notifications可以通过不同的方式获得用户的注意,比如点亮呼吸 灯,震动电话,播放一个声音等等,他们一般放一个图标在状态栏上,来让用户 可以打开获得这些信息。
(4)Content providers
Content providers是一个应用程序数据的集合,来让其他的应用可以访问这 些数据,这些数据可以被存在文件系统中,SQLite数据库中,或者其他可以存数 据的地方,Content providers是一个基本的方法集合来使其他的应用可以获得 和存储这些数据,然而应用不直接调用这些方法,而是使用一个 ContentResolver对象来调用这些方法,一个ContentResolver可以和任何的 Content providers交流,他和provider协作来管理系统中任何进程间的通信。
无论何时一个请求都应该由一个特定的组件来处理,android系统来确保包含 这个组件的应用进程运行,如果需要就启动它,如果需要就为这个组件创造一个 实例,确保这个组件的一个适当的实例可以被得到。
2、启动组件:intent
当有一个来自于content resolver的请求指向Content provider时,content provider启动,其他的三个组件(Activity,service,broadcast receiver) 是通过一个叫做intent的异步的消息来启动的,一个intent持有一个message的 内容,对Activity和service来说,他是一个被要求的动作(action)和在该动 作上的数据的URI,对broadcast receiver来说,intent对象是一个被广播的动 作。
针对每种组件分别有对应的方法来启动它:
(1)一个Activity是通过传递一个Intent对象到Context.startActivity() 或者Activity.startActivityForResult()来启动的(或者去做一些新的任务) ,被启动的这个Activity可以通过getIntent()来获得导致他启动的那个 intent的。
(2)一个service是通过传递一个Intent对象到Context.startService()来 启动的(或者给一些新的命令给正在运行的service),android调用service的 onStart()方法,并且把Intent对象传递给他,同样的,一个Intent可以传递 到Context.bindService()方法里来建立一个介于正在运行的service和调用他的 组件之间的连接,这个service通过onBind()方法来接收这个Intent对象,( 如果这个service还没有运行,bindservice()能选择性的启动它),在后面的 部分,关于绑定service的更多详细的信息请查看远程调用。
(3)一个应用可以通过传递一个Intent对象给像Context.sendBroadcast(), Context.sendOrderedBroadcast(), Context.sendStickyBroadcast()这样的方 法来开始一个广播,android通过调用对应的onReceive()方法将intent传递给 所有对这个广播感兴趣的broadcast receiver。
3、关闭组件(Shutting down components)
当对来自于content resolver的请求作出回应时content provider就启动了 ,当有一个感兴趣的broadcast message被广播时,broadcast receiver启动, 所以我们需要知道怎么关闭这些组件。
(1)Activity可以通过调用它自己的finish()方法来关闭,一个Activity 也可以通过调用finishActivity()来关闭另一个Activity(这个Activity是通过 调用startActivityForResult()来启动的)。
(2)一个service可以通过调用自己的stopSelf(),或者 Context.stopService()来关闭。
当组件不再使用时或者android为了更多组件能运行而回收内存时,android 系统是关闭这些组件的,在后面的部分,可以在组件的生命周期中看到更多更详 细的介绍。

4、Activities and Tasks
一个Activity可以启动另一个Activity,即使这个Activity是定义在另一个 应用里的,比如说,你想展示给用户一条街的地图,现在已经有一个Activity可 以做这件事,那么现在你需要做的就是将你请求的信息放进一个Intent对象里, 并且通过startActivity()传递给他,这个地图就可以显示出来了,但用户按 下BACK键时,你的Activity又重新出现在屏幕上。
对用户来说,显示地图的Activity和你的Activity好像在一个应用中的,即 使是他们是定义在不用的应用中的,运行在各自的应用进程中,android将两个 Activity放进一个task里,一个task是一组彼此联系的Activity,被安排在一个 堆栈中,堆栈中的根Activity就是开辟这个task的,一般的,他是用户选择应用 后首先启动的那个Activity,堆栈顶部的Activity是当前正在运行的Activity, 当一个Activity启动另一个Activity时,新的Activity被压进堆栈中,成为运行 的Activity,当用户按下BACK键,当前的Activity弹出堆栈,先前的Activity恢 复成为运行的Activity。
一个task就是一组Activity的堆栈,不是在manifest文件里的一个类,一个 元素,所以没有方法来为一个task里的Activity独立的设置值,对task设置值是 在root Activity里设置的。
一个task里的所有Activity组成一个单元,整个task(整个Activity堆栈) 可以在前台,也可以在后台(应用程序的切换就是task的前后台的切换),假设 ,当前的task有四个Activity在堆栈里,用户按下HOME键,去开启另一个应用( 实际上是一个新的task),那么当前的task就退到后台运行,新开启的应用的 root Activity此时就显示出来了,然后,过了一段时间,用户回到主界面,又 重新选择了以前的那个应用(先前的那个task),那么先前的那个task此时又回 到了前台了,当用户按下BACK键时,屏幕不是显示刚刚关闭的那个应用,而是移 除回到前台的这个task堆栈栈顶Activity,将下一个Activity显示出来。
刚才描述的情况是Activity和task默认的行为,但是有很多的方法来对几乎 所有的方面进行修改,如Activity和task的联系。task里Activity的行为,是受 启动它的Intent对象的flag和在manifest文件中的Activity的属性集合共同影响 的。
Flag:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
<activity>属性:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
5、Affinities and new tasks
默认的,一个应用里的所有Activity都有联系,所有都是属于一个task的, 然而,可以通过<activity>下的taskAffinity属性来为每个Activity单独 的设置属性关系,定义在不同应用中的Activity可以共享一种关系(affinity) ,或者定义在同一个应用中的Activity可以分配不同的关系(affinity)。这种 关系在两种情况下生效,当启动Activity的 Intent对象包含有 FLAG_ACTIVITY_NEW_TASK标志,一个Activity的allowTaskReparenting属性设置 为true。
FLAG_ACTIVITY_NEW_TASK
一个Activity调用startActivity()启动一个新的Activity时,新的 Activity会压入到相同的task中的,如果传递给startactivity()的Intent对 象含有FLAG_ACTIVITY_NEW_TASK标志,系统就会寻找一个新的task来装这个新的 Activity,然而,也不总是这么做,如果已经有一个task和这个新的的Activity 有相同的关系,那么就把这个新的Activity放进这个task里,如果没有,就启动 一个新的task。
allowTaskReparenting属性
如果一个Activity的allowTaskReparenting属性设置为true,这个Activity 就可以从启动时的那个task移动到一个和他有关系的当前在前台的一个task里, 比如,假设现在有一个天气预报的Activity被定义在一个旅行的应用里,他和这 个应用里的其他Activity有相同的关系(默认的关系),并且他允许 reparenting,现在你自己应用有一个Activity启动这个天气预报的Activity, 那么天气预报Activity就会移动到你的Activity所在的task里,当旅行的应用又 回到前台时,天气预报Activity重新回到以前的那个task并显示。(个人观点: 如果说没有设置这个属性,或者这个属性设置为false,那么一个应用里的 Activity调用另一个应用里的Activity时,系统是为另一个应用里的Activity创 建一个实例,然后放到同一个task里,但是如果设置了allowTaskReparenting为 true,那么另一个应用里的Activity是可以在不同的task间来回移动的,那个 task在前台就移动到那个task里)

6、启动方式
<activity>下的launchMode属性可以设置四种启动方式:
"standard" (the default mode)
"singleTop"
"singleTask"
"singleInstance"
这些不同的方式可以从下面的四点来说:
(1)对一个Intent作出回应时哪个task应该去持有这个Activity。
对standard和singleTop方式来说,新的Activity和通过startActivity调用 他的Activity处在同一个task中,如果调用时Intent对象里含有 FLAG_ACTIVITY_NEW_TASK标志,那么就像前面讲的那样的寻找一个新的task。
相反的,singTask和singleInstance方式,总是标志Activity为task的root Activity,他们不会进入到其他的task中。
(2)一个Activity是否可以有多个实例。
一个standard或者singleTop属性的Activity可以实例化多次,他们可以属于 多个不同的task。
相反的,singleTask或者singleInstance属性的Activity只能有一个实例( 单例)。
(3)实例是否能允许在task里有其他的Activity。
一个singleInstance属性的Activity单独的在他自己的task里,并且这个 task里只能有他自己一个Activity,如果他启动了另一个Activity,那个 Activity会根据启动模式来启动并装进一个不同的task里。其他的方面, singleInstance和singleTask一样的。
其他三个方式允许有多个Activity在一个task里,一个singleTask属性的 Activity总是一个task里的root Activity,但是他可以启动另外的Activity并 且将这个新的Activity装进同一个task里,standard和singleTop属性的 Activity可以出现在task的任何地方。
(4)一个类(Activity)的对象是否可以被启动来处理一个新的Intent。
对默认的standard方式,会实例化一个对象来处理每一个新的Intent,每个 实例处理一个新的Intent,对singleTop方式,如果一个已经存在的实例是在 task的栈顶,那么就重用这个实例来处理这个新的Intent,如果这个实例不在栈 顶,那就不复用他,而是重新创建一个实例来处理这个新的Intent并且将这个实 例压入堆栈。
例如现在有一个task堆栈ABCD,A是root Activity,D是栈顶Activity,现在 有一个启动D的Intent来了,如果D是默认的standard方法,那么就会创建一个新 的实例来处理这个Intent,所以这个堆栈就变为ABCDD,然而如果D是singleTop 方式,这个已经存在的栈顶的D就会来处理这个Intent,所以堆栈还是ABCD。D此 时调用onNewIntent(),此时D可以调用getIntent()来获得最初的Intent, 或者调用setIntent()来更新这个Intent。
如果现在有一个Intent来启动B,不管B是standard还是singleTop(因为现在 B不在栈顶),都会创建一个新的实例,所以堆栈变为ABCDB
在一个task里,对singleTask和singleInstance属性的Activity只能有一个 实例。所以这仅有的一个会来处理所以的Intent,一个singleInstance属性 Activity总在栈顶(因为task里就只有他一个Activity),所以他会处理所以的 Intent,但是一个singleTask属性的Activity必须是task的root Activity(也 就是必须在栈底),不能确定他的上面是否还有其他的Activity,如果没有,就 可以处理,如果还有其他的Activity,那么如果现在有一个Intent来启动这个 singleTask属性的Activity,这个Intent将会被丢掉(即使是这个Intent被丢掉 ,他的到来还是会导致这个task回到前台)。
当创建一个类(Activity)的实例来处理一个新的Intent时,用户可以按下 BACK键回到上一个Activity,但是如果是用已经存在的栈顶的Activity来处理 Intent的话,按下BACK键是不能回到以前的状态的(没处理这个Intent之前)。

版权声明:本文著作权归原作者所有,欢迎分享本文,谢谢支持!
转载请注明:【android教程】Android应用程序基础(Application Fundamentals)1 | 猎微网

评论已关闭!