Android原生开发学习笔记

1. 环境搭建

Java开发环境 + Android Studio + Android SDK

JDK可以直接从官方下载:JDK官方下载
Android Studio官方下载:AS官方下载

Android SDK直接在AS中添加即可,不必所有的版本都下载,只要下载我们所需要的版本即可,可以参考项目的CompileSDKVersion。
SDK添加
之后添加环境变量,新增系统变量ANDROID_HOME为Android SDK路径,随后在系统变量下的Path中
添加环境变量
path环境变量

2. 项目创建

其实可以参考Android官网教程:创建Android项目,我们也按照官网教程来实际操作一下,创建一个可以运行并具有一些简单功能的Android项目。

安装完AS之后,第一次打开会进入Welcome页面,这里我们点击Create New Project来创建项目。
Create New Project
如果之前打开过项目,我们可以点击左上角File->New->New Project
File New New Project
接下来,会弹出Select a Project Template 窗口,选择 Empty Activity,然后点击 Next
Empty Activity
进入Configure your project 窗口,进行如下配置,点击Finish
配置项目信息
(补充:可以看到我们勾选了旧版本库,其实官方是不推荐的,并且如果Minimum SDK选择了29或者以上,强制不可勾选。如无需使用旧版本库中的组件,不必勾选。)

等待一段时间,就可以看到如下窗口,可以看到左上角AS已经贴心的将目录结构切换为Android模式方便我们开发,并打开了我们的主Activity以及对应的布局文件。

我们可以看到 MainActivity.java 中有一条语句 setContentView(R.layout.activity_main); 这条语句就将我们的java文件和布局xml文件绑定。
打开项目
还有一个manifests文件夹,里面的 AndroidManifest.xml 是清单文件,用来描述应用的基本特性并定义其每个组件,可以看到MainActivity已经自动在这里定义了。
除此之外,build.gradle 也非常重要,我们可以看到项目中有两个build.gradle,一个是项目级别的,一个是Module模块级别的,每个项目都有一个app模块,以后我们也可以根据需要创建其他的模块。
build.gradle中我们可以配置gradle编译版本、引入依赖、设置应用目标SDK版本、代码混淆等。

注意:TargetSDKVersion一般设置28,这是由于在29即Android10及以上,存储策略变更,当然,我们也可以选择将TargetSDKVersion设置为29甚至30,然后在代码层面进行适配。 MinSDKVersion我们选择的目的是可以适配尽可能多的系统版本并且代码层面不需要做太多的适配,要注意第三方库支持的最小SDK版本,我们选择的是23也就是Android6,当然也可以选择更低的,比如uni-app就需要MinSDKVersion在21及以下。

AndroidManifest

3. 页面布局

其实上面生成的项目已经可以直接运行,不过没有任何功能。

关于页面布局的xml文件以及图片是放在res文件夹下的,例如下面是Android结构下展示的内容,如果打开project结构,可以看到更细致的划分。

我们看到mipmap有很多文件夹,我们应该怎么选择呢?其实蓝湖/摹客上对应大小的切图都有,可以直接全部复制到对应文件夹中,由应用自动选择合适的切图即可,或者我们自己来选择合适的切图放到对应mipmap文件夹中。

可以看到有两个特别的文件夹:
drawable-v24:仅仅在API 24+设备上才会使用。
mipmap-***-v26:仅仅在API 26+设备上才会使用。

这两个文件夹我们不常用,一般只用drawable、mipmap-xhdpi即可。
res
蓝湖

下面我们添加一个简单的按钮以及文本框,点击按钮切换文字,并在下面弹出一个可以自动消失的弹窗。

由于默认有一个TextView,我们只加一个Button即可。

从可用组件中找到Button,拖拽到蓝图中,可以看到,现在是有报错的,原因是我们的布局默认是约束布局(ConstraintLayout),需要给每个组件添加约束。我们可以通过代码形式或者蓝图形式修改组件约束,下面我们看一下完善后的代码以及蓝图。
代码
按钮背景
按钮文本
这样,我们的页面布局就开发完成了,下面就需要进行功能实现的部分,比如按钮的点击事件。

4. 功能实现

上面我们已经提到了,Java是通过 setContentView(R.layout.activity_main); 让布局与功能联系起来的。

我们可以看到我们通过R.layout.activity_main就找到了activity_main.xml这个布局,那么R是什么呢?

R.java文件由编译器生成,一般无需维护。R.java会自动收录当前应用中所有的资源,并根据这些资源建立对应的ID,包括:布局资源、控件资源、String资源、Drawable资源等。我们可以简单的把R.java理解成是当前Android应用的资源字典。

接下来我们把我们需要的功能实现出来,下图红框内是我们添加的内容,根据id获取到对应的组件,然后进行相应的修改。
点击事件

(注意:如果是用来开发原生插件,最好不用R.*,它的包名与Cordova工程包名一致,使用插件时还需要手动修改插件代码import的R.java文件的包名,很麻烦。直接使用Activity下的getResources().getIdentifier即可)

R.java
代码已经写完,接下来就是运行,我们可以使用真机或者模拟器进行测试,AS自带模拟器,但是非常的卡,下面我还是简单介绍一下怎么去创建模拟器。实际测试中,最好使用真机或者使用其他模拟器,比如市面上流行的雷电、夜神等。

点击下图图标(AVD Manager),AVD:Android Virtual Device,打开模拟器管理页面。
AVD Manager
随后,在弹窗中选择设备类型为phone(默认),选择合适的屏幕尺寸,点击Next。
屏幕尺寸
随后,选择Android系统,点击Next。
Next
修改模拟器名称,直接Finish即可。
Finish
至此,模拟器创建完成,我们就利用这个模拟器进行测试,选择模拟器,debug模式运行。
debug
AS自带模拟器比较卡顿,需要等待一段时间,等待应用运行成功,我们点击按钮,可以看到在屏幕下方有弹窗,并且TextView文本框中的文字也成功修改。
效果演示

5. 基础知识

5.1 四大组件

Android四大组件:Activity(活动)、Service(服务)、Content Provider(内容提供者)、Broadcast Receiver(广播接收者)。

活动(Activity)

Activity是Android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。当我们创建完毕Activity之后,需要调用setContentView()方法来完成界面的显示;以此来为用户提供交互的入口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。

服务(Service)

服务是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖于任何用户界面,即使当程序被切换到后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。
服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。

内容提供者(Content Provider)

内容提供者为应用程序之间共享数据提供了可能,比如你想要读取系统电话簿中的联系人,就需要通过内容提供者来实现。

这个在我们开发的插件中暂时没有用到,不过在ImagePicker插件中用到了,有兴趣的可以看一下。

广播接收器(Broadcast Receiver)

广播接收器可以允许你的应用接收来自各处的广播消息,比如电话、短信等,当然你的应用同样也可以向外发出广播消息。

5.2 Activity的生命周期

掌握活动的生命周期对任何Android开发者来说都非常重要,当你深入理解活动的生命周期之后,就可以写出更加连贯流畅的程序,并在如何合理管理应用资源方面,你会发挥得游刃有余,而且你的应用程序将会拥有更好的用户体验。

返回栈

Android中使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动集合,这个栈也称为返回栈。在默认情况下,每当我们启动了一个新的活动,它会在返回栈中入栈,并处于栈顶的位置。而每当我们按下 Back 键或调用 finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。

模拟单个任务内活动切换:
单个任务内活动切换
多任务,当用户开始一个新任务(或通过主屏幕按钮进入主屏幕)时,任务可移至“后台”:
多任务
活动状态

每个活动在生命周期中最多有4种状态。

运行状态
一个活动处于返回栈的栈顶时,这个活动就处于运行状态。系统不会回收该状态的活动。

暂停状态
当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。
如对话框形式的活动,该活动只占用屏幕中间的部分区域,在对话框下面的活动就处于暂停状态。
系统只有在内存空间不足的情况下,才考虑回收处于该状态的活动。

停止状态
当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但当其他地方需要内存时系统便有可能回收该活动。

销毁状态
当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。

生命周期方法
生命周期方法
onCreate()
必须实现此回调,它会在系统首次创建 Activity 时触发,在 onCreate() 方法中,需执行基本应用启动逻辑,该逻辑在 Activity 的整个生命周期中只应发生一次。
例如声明界面(在 XML 布局文件中定义)、定义成员变量,以及配置某些界面。

onStart()
在活动由不可见变为可见的时候调用,应用会为 Activity 进入前台并支持互动做准备。
例如,应用通过此方法来初始化维护界面的代码。

onResume()
在活动准备好和用户进行交互的时候调用。活动处于栈顶,且处于运行态。

onPause()
系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗 CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
不应使用 onPause() 来保存应用或用户数据、进行网络调用或执行数据库事务。因为在该方法完成之前,此类工作可能无法完成。相反,您应在 onStop() 期间执行高负载的关闭操作。

onStop()
这个方法在活动完全不可见的时候调用。它和 onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么 onPause()方法会得到执行,而 onStop()方法并不会执行。
在 onStop() 方法中,应用应释放或调整在应用对用户不可见时的无用资源。例如,应用可以暂停动画效果,或从精确位置更新切换到粗略位置更新。
还应使用 onStop() 执行 CPU 相对密集的关闭操作。

onDestroy()
该方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。

onRestart()
该方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动时。

下面,我们模拟从MainActivity跳转到GoToActivity,看生命周期的顺序是怎么样的:
模拟跳转

5.3 启动模式

启动Activity的四种模式:standard(标准)、singleTop(栈顶复用)、singleTask(栈内复用)、singleInstance(单例)。

用例 启动模式 多个实例? 注释
大多数Activity的正常启动 standard 默认。系统始终会在目标任务中创建新的 Activity 实例,并向其传送 Intent。
大多数Activity的正常启动 singleTop 视情况而定 如果目标任务的顶部已存在 Activity 实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而非创建新的 Activity 实例。
专用启动(不建议在一般情况下使用) singleTask 系统会在新任务的根位置创建 Activity 并向其传送 Intent。不过,如果已存在 Activity 实例,则系统会调用该实例的 onNewIntent() 方法向其传送 Intent,而非创建新的 Activity 实例。
专用启动(不建议在一般情况下使用) singleInstance 与“singleTask"”相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务中的唯一 Activity。

任务是用户在执行某项工作时与之互动的一系列 Activity 的集合。这些 Activity 按照每个 Activity 打开的顺序排列在一个返回栈中。

我们有两种方式设置Activity的启动模式:

1 AndroidManifest.xml清单文件中activity标签的launchMode属性,默认是standard.
launchMode
2 启动Activity时使用Intent标记,参考下面的例子
Intent
标记位属性 含义:

FLAG_ACTIVITY_SINGLE_TOP 指定启动模式为栈顶复用模式(SingleTop)

FLAG_ACTIVITY_NEW_TASK 指定启动模式为栈内复用模式(SingleTask)

FLAG_ACTIVITY_CLEAR_TOP 所有位于其上层的Activity都要移除,SingleTask模式默认具有此标记效果

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有该标记的Activity不会出现在历史Activity的列表中,即无法通过历史列表回到该Activity上

二者设置的区别:

1.优先级不同
Intent设置方式的优先级 > Manifest设置方式,即 以前者为准

2.限定范围不同
Manifest设置方式无法设定 FLAG_ACTIVITY_CLEAR_TOP;Intent设置方式 无法设置单例模式(SingleInstance)

5.4 常用布局

布局定义了应用中的界面结构(例如 Activity 的界面结构)。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常用于绘制用户可看到并与之交互的内容,是所有UI组件的基类。ViewGroup 则是不可见的容器,用于定义 View 和其他 ViewGroup 对象的布局结构。
View
常见的布局有LinearLayout(线性布局)、ConstraintLayout(约束布局)、RelativeLayout(相对布局)、GridLayout(网格布局)、FrameLayout(帧布局)等。

这些布局都是可以嵌套使用的,在BIM+GIS插件中常用的就是ConstraintLayout与LinearLayout嵌套使用。

LinearLayout(线性布局)
LinearLayout容器中的组件一个挨一个排列,通过控制android:orientation属性,可控制各组件是横向排列还是纵向排列。
比如BIM+GIS插件中的菜单,一个个按钮横向排列,就是使用的此布局。

RelativeLayout(相对布局)
和 LinearLayout 的排列规则不同,RelativeLayout 显得更加随意一些,它可以通过相对定位的方式让控件出现在布局的任何位置。也正因为如此,RelativeLayout 中的属性非常多,不过这些属性都是有规律可循的,其实并不难理解和记忆。

ConstraintLayout(约束布局)
与RelativeLayout类似,要在 ConstraintLayout 中定义某个视图的位置,为该视图添加至少一个水平约束条件和一个垂直约束条件。每个约束条件均表示与其他视图、父布局或隐形引导线(中线等)之间连接或对齐方式。
约束
DrawerLayout(抽屉布局)
顾名思义,抽屉式布局,可以定义侧滑内容,根据layout_gravity属性标识从左还是从右滑出。例如BIM+GIS插件的侧边树功能就是利用DrawerLayout实现的。
抽屉

5.5 常用UI组件

介绍完布局,再说一下常用的UI组件。

组件的尺寸以及字体、切图等设置不是开发者要关注的问题,直接参考UI设计稿即可,我们要关注的是如何更好的实现UI设计稿展示的效果。

Button:普通按钮,用户交互中使用最多的组件,当用户单击按钮的时候,会有相对应的响应动作。BIM+GIS插件中菜单里的按钮都是使用的这个组件。
效果
Button
ImageButton:图像按钮,显示一个可以被用户点击的图片按钮,默认情况下,ImageButton看起来像一个普通的按钮。按钮的图片可用通过 XML元素的android:src属性或setImageResource(int)方法指定。要删除按钮的背景,可以定义自己的背景图片或设置背景为透明。
效果代码
ImageView: 显示任意图像(包括图标),可以加载各种来源的图片(如资源或图片库),实际应用中需要计算图像的尺寸以达到最佳效果,并提供例如缩放和着色(渲染)等各种显示选项。
效果
代码
android.support.design.widget.FloatingActionButton: 悬浮按钮,FAB代表一个App或一个页面中最主要的操作,如果一个App的每个页面都有FAB,则通常表示该App最主要的功能是通过该FAB操作的。
为了突出FAB的重要性,一个页面最好只有一个FAB。
添加,收藏,编辑,分享,导航等推荐使用FloatingActionButton
效果
代码
TextView: 文本展示。
ListView: 列表展示。
EditText: 可编辑文本框。
com.warkiz.widget.IndicatorSeekBar: 进度条。能改变尺寸、颜色、滑块(thumb)图片、刻度(tick)图片、刻度文字(text)和气泡指示器(indicator),当滑动时显示带有进度的气泡指示器。
效果
代码

5.6 权限申请

在Android 6也就是SDK23之前,我们只需要在AndroidManifest.xml中声明我们需要的权限即可,但是在Android 6之后,引入运行时权限的概念,需要用户同意才能拥有这些权限,我们需要在代码中动态申请权限,可以查看Android 动态权限申请及回调

我们需要在代码中向用户申请权限,并根据用户是否授予权限进行不同的处理。

需要注意的是,如果我们设置的TargetSDKVersion在29及以上,由于存储访问权限变更,我们可以暂时在AndroidManifest.xml的application标签中添加以下内容:
android:requestLegacyExternalStorage=“true”
也可以在代码中适配Android10+的存储访问权限。
具体变更可以参考Android开发者官网Android 10 中的隐私权变更

6.参考资料

安卓中文网–开发指南
Android四大启动模式和使用场景
Android之四大组件、六大布局、五大存储
Android-Activity的四状态、七生命周期、和四启动模式
Android Service详解
Android连接服务器的五种方式

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐