Android应用开发基础(一):应用程序组件

Android应用开发基础(一):应用程序组件

Android应用程序使用Java语言编写,然后使用aapt工具将编译后的Java代码和所需的数据及资源文件打包,生成apk文件(apk即Android package的英文缩写)。用户下载并安装到手机的就是这个apk文件,一个apk文件就可以看作是一个应用程序。

每个Android应用程序会以某种形式独立运行:

  • 默认情况下,每个应用程序都在它自己的Linux进程里运行,Android系统会启动这个进程来执行应用程序代码,不需要的时候,Android系统就会终止这个进程,释放系统资源并回收。
  • 每个进程都有自己的Java虚拟机(VM),这样,两个应用程序运行时是互不干扰的。
  • 默认情况下,会为每个应用程序分配一个{wy}的UID(Linux系统用户ID),应用程序内部文件只对这个用户(UID)可见,即便将应用程序A导入到应用程序B,应用程序A的内部文件对应用B也是不可见的。

两个应用程序也可能共享一个UID,这种情况下,两个应用程序的内部文件是互相可见的。为了节省系统资源,拥有同样UID的应用程序也将运行在同一个Linux进程,共享一个VM。

应用程序的组件
Android的重要特征之一就是应用程序A可以使用应用程序B的一部分(但需要应用程序B的授权)。比如,应用程序A需要展示相册图集,正好应用程序B有这个功能,并且允许其它程序调用,A就可以直接调用这个功能而不需再次开发。应用程序A不需要嵌入这段代码,也不需要做链接,只是在需要时启动应用程序B的这个片段即可。

为了实现这个功能,只要应用程序的某个部分被调用,系统都会创建一个进程来启动这个应用程序,并实例化这部分Java对象。这就是Android应用程序与其他系统的{zd0}不同之处,也就是说Android应用程序的入口点并不是{wy}的(而其他系统的应用程序通常会有一个main()函数作为入口点)。Android有4类基础组件,每个基础组件都会在需要时被系统初始化并启动运行。

窗体(Activity)

窗体就是实现某种特定功能的用户界面,比如用户相册功能:界面里会显示一系列菜单项,选择某个菜单会展示相应的照片集。又比如一个短信程序:一个窗体展示通信簿,选择某个联系人后会打开另外一个写消息的窗体,可能还有收件箱窗体、参数设置窗体等。尽管这些窗体(用户界面)相互关联、协同工作,但他们是相互独立的,每个窗体都是一个Activity类的子类。

应用程序由一个或多个窗体组成,前面那个短信程序就是一个多窗体应用的例子。需要多少窗体、每个窗体功能如何,都是根据应用程序的实际来设计的。如果有多个窗体,需要指定其中一个作为应用程序启动时的{dy}个窗体,从一个窗体到另一个的切换是由当前窗体实现的。

每个窗体有一个默认绘图区域,通常是整个屏幕,不过也可能比屏幕小,如浮动在其他窗口上的小窗口。一个窗体可能使用不止一个窗口,比如弹出对话框或者浮动窗口。

可视化窗口由一系列视图对象(视图树)组成,每个视图对象是一个View类的子类,它控制窗口内特定的矩形区域。父视图可以包含子视图,并组织子视图对象的布局,叶视图(即不再包含子视图的视图对象)绘制一个矩形区域,并控制和响应用户在这个区域的操作,即视图是窗体与用户交互的基本元件。例如,视图可以展示一个小图片,用户点击图片时会触发某种动作。Android有一系列可直接使用的内置视图对象,比如按钮、文本框、滚动条、菜单项、复选框等。

窗体通过Activity.setContentView()方法将视图树放置在窗体的窗口内,这里的content view即视图树的根(关于视图和视图树请参考文档的“用户界面”部分)。

服务

服务没有可视化用户界面,并持续运行于后台。例如播放背景音乐的服务,运行于后台而不影响用户其他操作。也可能在后台自动联网并获取数据,或者做某些运算并将结果提供给需要它的窗体。每个服务都是Service基类的子类。

一个典型例子就是音乐播放器软件,该应用程序可能有一个或多个窗体,用户通过窗体选择歌曲并启动播放,而这个音乐播放功能并不一定使用窗体,而是启动一个后台运行的服务,这样用户在关闭播放器窗口后仍能继续听音乐。

应用程序可以连接(或绑定)到某个正在运行的服务(如果这个服务没有运行,会被启动)。连接上之后,应用程序就可以通过暴露出来的接口与这个服务通信,比如音乐服务,暴露出来的接口可以有暂停、回放、停止、重放等功能。

与窗体和其它组件一样,服务运行于应用程序进程的主线程中。由于服务通常再创建其他线程来执行比较耗时的操作(比如音乐播放),因此服务不会阻塞其他组件或用户界面。参看后面“进程与线程”部分。

广播接收器

广播接收器组件只用来接收并响应广播通知。许多广播通常由系统发起,比如时区变更通知、电池电量不足的通知、拍照完成通知、用户变更系统语言的通知,但也有一些广播是由Android应用程序发起,比如数据下载完成通知(其它应用程序得到通知之后会使用这些数据)。

一个应用程序可以有多个广播接收器,用来响应多种不同的通知事件。广播接收器都是BroadcastReceiver类的子类。

广播接收器没有用户界面,当他们接收到通知时会启动一个窗体,或者使用NotificationManager来提醒用户。有多种提醒用户的方法:闪屏、震动、提示音等。另外,通常会在状态栏上显示一个图标,用户点击这个图标就会打开消息。

内容提供器

应用程序通过内容提供器将特定的数据提供给其他应用程序使用,可以是文件、SQLite数据库数据或其它形式的数据。内容提供器都是ContentProvider类的子类,提供器实现了一系列标准方法,其他应用程序通过这些方法存取这些特定类型的数据。应用程序不会直接调用这些方法,而是使用ContentResolver这个对象来调用。ContentResolver对象可以连接任何内容提供器,然后与提供器进行存取数据所需的内部通信操作。

关于内容提供器的更多说明请参看文档的“内容提供器”部分。

只要应用程序中的某个组件被用到,Android就要确保这个应用程序在运行(如果没有运行就会启动它),确保这个组件已被实例化(如果还没有就会创建这个实例)。

组件的xx器:intent

内容提供器会被来自ContentResolver的请求xx,而另外三类组件(窗体、服务和广播接收器)是被称作intent的异步消息xx的,该消息的内容存储在Intent对象中。对于窗体和服务,这类组件会定义一个动作,并指定一个URI来响应这个动作。比如,传递一个展示图片的请求给某个窗体,或者传递一个文本编辑的请求给某个窗体。对于广播接收器,Intent对象会定义一个通知动作,比如用户按下拍照按钮时,它会通知某些的应用程序执行相关的动作。
xx不同类型组件的方法是不一样的:

  • 启动窗体(或者先创建再启动)的方法是传递一个Intent对象给Context.startActivity() 或者 Activity.startActivityForResult()方法,相应的窗体会调用getIntent()来取得这个intent对象。Android也会调用窗体的onNewIntent()方法,将这个intent对象传递给下一个intent。

窗体(A)通常会启动下一个窗体(B),如果A期望获取B返回的结果,窗体A就应该使用startActivityForResult()方法来取代startActivity()方法。例如,窗体A启动了窗体B,用户在窗体B里选择一个图片,这个选择结果就会返回给窗体A。其中的数据传递是通过Intent对象进行的,可以通过窗体A的onActivityResult()方法取得传递的数据。

  • 服务的启动(或传递新参数给正在运行的服务)是通过将Intent对象传递给Context.startService()方法实现的,Android系统会调用服务的onStart()方法,并传递Intent对象给服务。

类似的,传递Intent给Context.bindService()来创建组件和目标服务间的连接,服务会调用onBind()函数来获得Intent对象(如果服务没有运行,bindService()会启动这个服务)。例如,某个窗体会建立与音乐播放服务的连接,以便用户通过这个窗体界面来控制播放器,此时窗体会调用bindService()来创建连接,然后调用相关的方法进行播放、暂停等操作。

后面文档“远程过程调用”会详细介绍服务绑定操作。

应用程序发起广播有以下几种方式:传递Intent对象给Context.sendBroadcast()、Context.sendOrderedBroadcast()或者Context.sendStickyBroadcast()这些方法,Android系统通过onReceive()将Intent对象传递给所有响应此广播的接收器。

更多内容请参看“Intent和Intent过滤器”章节的内容。

停止组件

内容提供器只有在响应来自ContentResolver的请求时被xx,广播接收器则在响应广播消息时被xx,因此这两类组件不必执行显式的停止操作。

窗体即应用中的用户界面,只要会话在持续进行,即使在空闲状态,窗体都会持续运行并保持xx状态。同样,服务也会很长时间持续运行。因此,Android提供了相应方法来停止窗体或者服务。

  • 调用窗体的方法finish()来停止这个窗体,在窗体A里也可以调用finishActivity()方法来停止另外一个窗体B,前提是窗体B是由窗体A通过startActivityForResult()启动的。
  • 调用服务的方法stopSelf()来停止它自己,或者调用Context.stopService()来停止某个服务。

系统也会停止组件,比如某些组件不再使用时,或者Android需要回收内存以用于其他窗体时。后面“组件生命周期”部分会详细讨论这些内容。

清单文件
Android要启动某个应用程序组件,就必须事先识别这些组件。因此,应用程序要在清单文件中声明这些组件,然后这个清单文件和应用程序代码、数据及其它资源文件一起打包进.apk文件。

清单文件就是一个XML文件,通常命名为AndroidManifest.xml,除了声明应用程序组件外,还会处理很多其它事情,比如指明该应用程序引用的类库(即Android默认类库外的类库),设定应用程序权限等。

不过清单文件的基本工作还是标识应用程序组件,比如下面的例子在清单文件中声明了一个窗体:




android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >

. . .


元素的name属性表示这个窗体的Activity子类的名字,icon和label属性则分别表示图标资源文件,和显示在窗体上的标题。
其他组件的声明也类似, 元素分别声明了服务、广播接收器和内容提供器组件。没有在清单文件中声明的窗体、服务和内容提供器对系统是不可见的,因此也不可能会运行。不过,广播接收器则即可以在清单文件中声明,又可以在代码中动态生成(BroadcastReceiver类),然后通过调用Context.registerReceiver()方法注册到系统中。

更多详细内容参看“AndroidManifest.xml文件”章节的内容。

Intent过滤器

Intent对象可以显式指定目标组件,Android会找到这个组件(根据清单文件中的声明)并xx它。如果没有显式的指定目标组件,Android会找到最匹配的组件来响应这个intent,这是通过将Intent对象和潜在目标组件的intent过滤器进行比较实现的。组件通过intent过滤器告知Android它都能处理哪些Intent。和其它组件相关的基本信息一样,intent过滤器也在清单文件中声明。我们对前面清单文件的例子进一步扩展,为窗体增加了2个intent过滤器。




android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >










. . .



例子中的{dy}个过滤器(动作”android.intent.action.MAIN”和类型”android.intent.category.LAUNCHER”的组合)就是常见的一种。它将这个窗体标记为启动窗体,即用户可以在设备中启动的屏幕列表应用。换句话说,这个窗体就是应用程序的入口,即用户启动这个应用程序后见到的{dy}个窗体。

第二个过滤器定义了窗体根据某种特定类型所执行的动作。

一个组件可以有多个intent过滤器,分别定义了不同的能力集。如果没有设置过滤器,这个组件只能被将它作为目标组件的intentxx。

对于在代码中创建和注册的广播接收器,intent过滤器会被直接实例化为IntentFilter对象,除此之外的其他过滤器都在清单文件中设置。

更详细内容请参考“Intent和Intent过滤器”。

标签: , ,

留下回复

郑重声明:资讯 【Android应用开发基础(一):应用程序组件】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——