《Android开发进阶:从小工到专家》——第1章,第1.1节Activity

简介:

本节书摘来自异步社区《Android开发进阶:从小工到专家》一书中的第1章,第1.1节Activity,作者 何红辉,更多章节内容可以访问云栖社区“异步社区”公众号查看

第1章 Android的构成基石—四大组件
Android开发进阶:从小工到专家
由于本书的目标读者是有一定Android基础的开发人员,因此,本章不再介绍Android系统的架构、历史等知识,而是直接切入主题,从讲解Android的四大组件开始,然后一步一步深入学习开发中的重要知识点,使得我们能够从基本原理层面掌握Android开发基础知识。

Android中最重要的是四大组件,即Activity、Service、ContentProvider和Broadcast。这4个组件分工明确,共同构成了可重用、灵活、低耦合的Android系统。Activity负责UI元素的加载与页面之间的跳转,代表了一个页面单元;Service负责与UI无关的工作,如在后台执行耗时操作等;ContentProvider负责存储、共享数据,使得数据可以在多个应用之间共享;Broadcast则是在各个组件、应用之间进行通信,简化了Android开发中的通信问题。

下面就来简单学习一下这四大开发组件。

1.1 Activity
Activity在应用中的表现就是一个用户界面,它会加载指定的布局文件来显示各种UI元素,例如TextView、Button、ImageView、ListView等,并且为这些UI元素设置事件处理函数,使得用户可以与这些UI进行交互。同时,Activity还可以在不同的Activity之间跳转,将不同的页面串连在一起,共同完成特定的操作流程。每个应用都是由一个或者多个Activity组成,它是Android应用程序中不可缺少的部分。

应用启动时会加载一个默认的Activity,这个Activity在AndroidManifest.xml中会被设置为如下intent-filter:

<intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

每个Activity都有生命周期,在不同的阶段会回调不同的生命周期函数,Activity的生命周期函数有如下几个。

1.onCreate()
相信这是开发者见过次数最多的函数,我们在创建继承自Activity的类时都会默认生成这个函数。它会在Activity第一次被创建时调用,通常会在这个函数中完成Activity的初始化操作,如设置布局、初始化视图、绑定事件等。

2.onStart() 

这个函数在Activity的onCreate函数调用之后被调用,此时的Activity还处在不可见状态,它的下一个状态就是Activity变得可见的时候,也就是这个函数在Activity可见之前被调用。

3.onResume() 

这个函数在Activity变为可见时被调用,执行完onResume之后,Activity就会请求AMS渲染它所管理的视图。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。

4.onPause()
这个函数在系统准备去启动或者恢复另一个Activity时调用,也就是在Activity即将从可见状态变为不可见时。我们通常会在这个函数中将一些消耗CPU的资源释放掉,以及保存一些关键数据。

5.onStop()
这个函数在Activity完全不可见时调用。它和onPause()函数的主要区别在于,如果新启动的Activity是一个对话框式的Activity,那么onPause()函数会得到执行,而onStop() 函数并不会执行。

6.onDestroy()
这个函数在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。

7.onRestart()
这个函数在Activity由停止状态重新变为运行状态之前调用,也就是Activity被重新启动了。

从onCreate()函数到onDestroy()函数运行的时期就是一个Activity的完整生命周期。一般情况下。我们会在一个Activity的onCreate()函数中完成各种初始化操作,而在onDestroy()函数中完成释放内存的操作。然而并不是各个时期Activity都是可见的,只有onResume()函数和onStop()函数之间的Activity是可见的,在Activity可见期内,用户可以与Activity进行交互,完成所需的功能。

为了帮助读者能够更好地理解,Android 官方提供了一个Activity生命周期的示意图,如图1-1所示。


825f31435f463f110db906a36c5cb5d992d3902a

1.1.1 Activity的构成
Activity的构成并不是一个Activity对象再加上一个布局文件那么简单,在Activity和开发人员设置的视图之间还隔着两层。实际上视图会被设置给一个Window类,这个Window中含有一个DecorView,这个DecorView才是整个窗口的顶级视图。开发人员设置的布局会被设置到这个DecorView的mContentParent布局中。也就是说Android中实际上内置了一些系统布局文件xml,我们在xml中定义的视图最终会被设置到这些系统布局的特定节点之下,这样就形成了整个DecorView。结构如图1-2所示。

从图1-2中可以看到,我们的Activity之下有一个PhoneWindow,这个PhoneWindow是Window的实现类,然后Window之下包含一个DecorView,DecorView实际上是页面的顶级视图,它从一些系统布局中加载,并且在运行时将开发人员设置给Activity的布局资源添加到系统布局的mContentParent中。这样一来,用户界面就被添加到系统布局中了,而系统布局会为我们设置好标题栏区域等。


a20cdc347e29ae7079c009839e4e60a2365f055c

下面就是一个名为screen_title的系统布局xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:fitsSystemWindows="true">
     <!-- Popout bar for action modes -->
     <ViewStub android:id="@+id/action_mode_bar_stub"
                   android:inflatedId="@+id/action_mode_bar"
                   android:layout="@layout/action_mode_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:theme="?attr/actionBarTheme" />
     <FrameLayout
           android:layout_width="match_parent" 
           android:layout_height="?android:attr/windowTitleSize"
           style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@android:id/title" 
                style="?android:attr/windowTitleStyle"
                android:background="@null"
                android:fadingEdge="horizontal"
                android:gravity="center_vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
     </FrameLayout>
     <!—这里就是开发人员设置的布局所填充的位置-->
     <FrameLayout android:id="@android:id/content"
           android:layout_width="match_parent" 
           android:layout_height="0dip"
           android:layout_weight="1"
           android:foregroundGravity="fill_horizontal|top"
           android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

上述xml文件中包含了actionbar和标题栏区域,下面就是开发人员设置给Activity的布局区域,这个区域被添加到名为content的布局中,而这整个screen_title.xml又是DecorView的子视图,因此,最终用户界面会显示为标题栏、开发人员设置的界面。例如我们的Activity布局代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:gravity="center"
    android:paddingBottom="@dimen/activity_vertical_margin"
 tools:context=".MainActivity">

    <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
             android:textSize="30sp"
             android:gravity="center"
             android:layout_height="wrap_content" />

</RelativeLayout>

该布局的根视图为RelativeLayout,其中只有一个居中的TextView。运行后的界面如图1-3所示。


6fbdcd13ef9fb8f9b5e35abd8eb0d12b96b2fe1d

jtm_chap01显示的区域就是id为title的TextView,而Hello World就是content布局下的一个子视图。当Activity的onResume函数被调用之后,用户界面就显示在我们面前了。

1.1.2 Activity的4种启动模式
每个应用程序都是由一个或者多个Activity组成,因此,Android内部使用通过回退栈来管理Activity实例。栈是一种后进先出的集合,对于Android来说,当前显示的Activity就在栈顶,当用户点击后退键或者点击应用上的返回按钮,系统就会将栈顶的Activity出栈,此时原来栈顶下的Activity就会变为栈顶显示到设备上。

然而事情可能并不是那么简单,在一些特殊情况下我们可能需要对Activity实例做一些特殊的处理,例如,为了避免重复创建Activity,我们要求一个Activity只有一个实例。好在Android系统为我们提供了这些功能,也就是我们本节要说的Activity的4个启动模式。用户可以在AndroidManifext.xml注册Activity时设置它的启动模式,例如:

<activity
    android:name=".MyActivity"
    android:launchMode=" singleTask"
    android:label="@string/app_name" >
</activity>

Activity的启动模式有4个,分别为standard、singleTop、singleTask、singleInstance,下面我们逐个介绍它们。

1.standard(标准启动模式)
这是Activity的标准启动模式,也是Activity的默认启动模式。在这种模式下启动的Activity可以被多次实例化,即在同一个任务栈中可以存在多个Activity实例,每个实例都会处理一个Intent对象。如果ActivityA的启动模式为standard,并且已经有一个ActivityA被启动,在该ActivityA中调用startActivity时会启动一个新的ActivityA实例。栈的变化如图1-4所示。


a38c7d8decf0e3ef4bd3a1f04690ba593aadd95c

如果ActivityA是一个非常耗资源的类,那么将会使它所依附的应用消耗更多的系统资源。

2.singleTop
如果一个以singleTop模式启动的Activity的实例已经存在于任务栈的栈顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()函数将Intent对象传递到这个实例中。例如,ActivityA的启动模式为singleTop,并且ActivityA的一个实例已经存在于栈顶中。那么再调用startActivity启动另一个ActivityA时,不会再次创建ActivityA的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()函数。此时任务桟中还是这一个ActivityA的实例。栈内变化如图1-5所示。


352d87fe14fd91429d29086299d25ec171e4f30f

如果以singleTop模式启动的Activity的一个实例已经存在于任务桟中,但是不在桟顶,那么它的行为和standard模式相同也会创建一个新的实例。栈内变化如图1-6所示。


941e2ebe48b6254d9fd01e1609d84b7df1839cfe

3.singleTask
singleTask模式是常用的启动模式,如果一个Activity设置了该启动模式,那么在一个任务栈中只能有一个该Activity的实例。如果任务栈中还没有该Activity,会新创建一个实例并放在栈顶。但是,如果已经存在Activity,系统会销毁处在该 Activity上的所有Activity,最终让该 Activity实例处于栈顶。最终让该 Activity实例处于栈顶,同时回调该Activity的onNewIntent()函数。栈内变化如图1-7所示。


1a33dbc387428f5b3c2c828c372448aeb28fae50

4.singleInstance
设置了singleInstance模式的Activity会在一个独立的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他Activity会自动运行于另一个任务中。当再次启动该Activity实例时,会重用已存在的任务和实例。并且会调用该实例的onNewIntent()函数,将Intent实例传递到该实例中。

和singleTask不同的是,同一时刻在系统中只会存在一个这样的Activity实例,而singleTask模式的Activity是可以有多个实例的,只要这些Activity在不同的任务栈中即可,例如,应用A启动了一个启动模式为singleTask的ActivityA,应用B又通过Intent想要启动一个ActivityA,此时由于应用A和应用B都有自己的任务栈,因此,在这两个任务栈中分别都有一个ActivityA示例。而singleInstance能够保证Activity在系统中只有一个实例,不管多少应用要启动该Activity,这个Activity有且只有一个,如图1-8所示。


d7265c49ca725a14102d8c499df3f5fd9f2d896c

1.1.3 FragmentActivity与Fragment
为了更好地运用越来越大的屏幕控件,Android在3.0版本引入了Fragment,它可以像Activity一样包含布局。不同的是Fragment是被嵌套在Activity中使用,它作为一个更大粒度的UI单元。如果需要兼容低于Android 3.0的系统,那么开发人员需要引用android-support-v4的jar包才能使用Fragment功能。

假如有这样的场景:我们的新闻应用含有两个Activity,第一个Activity是显示新闻标题、概要信息的列表,当用户点击这些标题时进入该新闻的详情页面进行阅读。

这是一个再普通不过的场景,但是这样做真的合适吗?我们是否能够简化用户的操作?

答案是:必须的!

Fragment就是为了应对这种情况而出现的,我们可以使用两个Fragment,Fragment1包含了一个新闻标题的列表,每行显示一个新闻的标题;Fragment2则展示这条新闻的详细内容。如果现在程序运行在竖屏模式的平板电脑或手机上,Fragment 1可能嵌入在一个Activity中,而Fragment 2可能嵌入在另一个Activity中,如图1-9所示。


ce5c7dfe91a59f994ca234dbd478e97e18422523

而如果现在程序运行在横屏模式的平板电脑上,两个Fragment就可以嵌入在同一个Activity中,如图1-10所示。


d687da27fe18ce6c27affb285e1bb9b6cd8e44b5

就目前开发来说,使用Fragment已经成为流行的开发方式,尽管在它的support v4中存在各种各样的Bug,以至于Square这样的公司举起了声讨Fragment的大旗,但是也不能阻止Fragment“驰骋”在大屏幕手机盛行的时代。

相关文章
|
24天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
18 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
15天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
18天前
|
监控 算法 Android开发
安卓应用开发:打造高效启动流程
【4月更文挑战第5天】 在移动应用的世界中,用户的第一印象至关重要。特别是对于安卓应用而言,启动时间是用户体验的关键指标之一。本文将深入探讨如何优化安卓应用的启动流程,从而减少启动时间,提升用户满意度。我们将从分析应用启动流程的各个阶段入手,提出一系列实用的技术策略,包括代码层面的优化、资源加载的管理以及异步初始化等,帮助开发者构建快速响应的安卓应用。
|
18天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
19 1
Android开发之使用OpenGL实现翻书动画
|
18天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
15 1
Android开发之OpenGL的画笔工具GL10
|
24天前
|
Android开发
Android开发小技巧:怎样在 textview 前面加上一个小图标。
Android开发小技巧:怎样在 textview 前面加上一个小图标。
12 0
|
24天前
|
Android开发
Android 开发 pickerview 自定义选择器
Android 开发 pickerview 自定义选择器
12 0
|
26天前
|
缓存 Java Android开发
安卓应用开发中的内存优化策略
在移动应用开发领域,性能一直是衡量应用质量的重要指标之一。特别是对于安卓平台,由于设备的硬件配置多样化,内存管理成为开发者面临的重大挑战。本文将深入探讨针对安卓平台的内存优化技巧,包括内存泄漏的预防、合理使用数据结构和算法、以及高效的资源释放机制。通过这些方法,开发者可以显著提升应用的性能和用户体验。
|
1月前
|
Java Android开发
Android开发系列全套课程
本系列课程面向有java基础,想进入企业从事android开发的计算机专业者。学习搭配实战案例,高效掌握岗位知识。
18 1