# learn-android
**Repository Path**: hrews/learn-android
## Basic Information
- **Project Name**: learn-android
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-07-18
- **Last Updated**: 2025-07-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# AndRoid
## 初体验
gradle 配置阿里云仓库
- gradle-wrapper.properties
```
#Thu Jul 17 16:09:48 CST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.aliyun.com/gradle/distributions/v8.11.1/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
```
从阿里云下载项目依赖
- settings.gradle.kts
```kotlin
pluginManagement {
repositories {
// 先加阿里云仓库,提高插件下载速度
maven {
url = uri("https://maven.aliyun.com/repository/gradle-plugin")
}
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// 阿里云中央仓库代理
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
// 阿里云 Google 仓库代理
maven {
url = uri("https://maven.aliyun.com/repository/google")
}
google()
mavenCentral()
}
}
rootProject.name = "GeoQuiz"
include(":app")
```
过去,Google一直维护着庞大的支持库,用来协助开发和解决兼容性问题。作为改进,AndroidX将这个巨型库拆分为一个个独立的开发和版本库,统称为Jetpack。
按照约定,布局文件的命名基于其关联的activity:activity_作为前缀,activity子类名的其余部分全部转小写并紧随其后,单词之间以下划线隔开。例如,当前新建项目的布局文件名为activity_main.xml,或者说你有个activity名为SplashScreenActivity,那么对应的布局就命名为activity_splash_screen。
默认的activity布局(res/layout/activity_main.xml)
```xml
```
视图是用户界面的构造模块。显示在屏幕上的一切都是视图。用户能看到并与之交互的视图称为部件 (widget)。有些部件可以用来显示文字或图像,有些部件(比如按钮)可以点击以触发事件任务。
Android SDK内置了多种部件,通过配置各种部件可获得应用所需的外观及行为。每一个部件都是View类或 其子类(比如TextView或Button)的一个具体实例。
我们得想办法告诉部件它们在屏幕上该位于哪里。ViewGroup就是这样一种特殊的View,它包含并布置其 他视图。ViewGroup视图本身不显示内容,它规划其他视图内容应该显示在哪里。ViewGroup通常又称为 布局。
在当前默认布局里,ConstraintLayout这个ViewGroup布置了一个TextView部件,这是它唯一的子部件。
```xml
```
作为根元素,LinearLayout部件必须指定Android XML资源文件的命名空间属性。
LinearLayout部件继承自ViewGroup部件(也是一个View子类)。ViewGroup部件是包含并布置其他视图的特殊视图。想要以一列或一排的样式布置部件,就可以使用LinearLayout部件。其他ViewGroup子类还有ConstraintLayout和FrameLayout。
如果某个视图包含在一个ViewGroup中,该视图与ViewGroup即构成父子关系。根LinearLayout有两个子部件:TextView和另一个LinearLayout。作为子部件的LinearLayout自己还有两个Button子部件。
### 部件属性
#### android:layout_width和android:layout_height属性
几乎每类部件都需要android:layout_width和android:layout_height属性。以下是它们的两个常见属性值(二选一)。
- match_parent:视图与其父视图大小相同。
- wrap_content:视图将根据其显示内容自动调整大小
根LinearLayout部件的高度与宽度属性值均为match_parent。LinearLayout虽然是根元素,但它也有父视图——Android提供该父视图来容纳应用的整个视图层级结构。
#### android:orientation属性
它决定两者的子部件是水平放置还是垂直放置。
#### android:text属性
TextView与Button部件具有android:text属性。该属性指定部件要显示的文字内容。
请注意,android:text属性值不是字符串值,而是以@string/语法形式对字符串资源(string resource)的引用。
字符串资源包含在一个独立的名叫strings的XML文件中(strings.xml),虽然可以硬编码设置部件的文本属性值,比如android:text="True",但这通常不是个好办法。比较好的做法是将文字内容放置在独立的字符串资源XML文件中,然后引用它们。这样会方便应用的本地化
需要在activity_main.xml文件中引用的字符串资源还没添加,现在就来处理。
### 创建字符串资源
每个项目都包含一个默认字符串资源文件res/values/strings.xml。
打开res/values/strings.xml文件,可以看到,项目模板已经添加了一个字符串资源。如代码清单1-3所示,添加应用布局需要的三个新字符串。
- res/values/strings.xml
```xml
GeoQuiz
Canberra is the capital of Australia.
True
False
Correct!
Incorrect!
```
(Android Studio某些版本的strings.xml默认带有其他字符串,这些字符串可能与其他文件有关联,请勿随意 删除。)
现在,在GeoQuiz项目的任何XML文件中,只要引用到@string/false_button,应用运行时,就会得到“False”文本。
默认的字符串文件虽然已命名为strings.xml,但你仍可以按个人喜好重新命名。一个项目也可以有多个字符串文件。只要这些文件都放在res/values/目录下,含有一个resources根元素,以及多个string子元素,应用就能找到并正确使用它们。
### 预览布局
在工具栏左上角,有个钻石按钮,我们可以通过它的下拉菜单切换显示不同的布局预览模式——设计(Design)预览或蓝图(Blueprint)预览,或者并排显示设计预览和蓝图预览。
左边是设计预览模式,用来展示布局在设备上的效果,也包括主题样式;右边是蓝图预览模式,用来展示部件的尺寸以及它们之间的位置关系。
在设计预览模式下,你还可以查看布局在不同的设备配置下的样子。通过预览窗口上方的面板,可以指定设备类型、Android模拟器版本、设备主题以及设备使用区域,查看布局的不同渲染结果。你甚至可以模拟某个语言区域的自右到左的文字显示模式。
除了预览,你也可以直接使用布局编辑器摆放部件,布置布局。项目窗口左边有个面板,包括了Android所有的内置部件。你可以将它们从面板拖曳到视图上,或者拖到左下方的部件树上,更精准地控制如何摆放部件
## 从布局XML到视图对象
知道activity_main.xml中的XML元素是如何转换为视图对象的吗?答案就在于MainActivity类。
在创建GeoQuiz项目的同时,向导也创建了一个名为MainActivity的Activity子类。MainActivity类文件存放在项目的app/java目录下。
- MainActivity.kt
```kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
}
}
```
是不是不明白AppCompatActivity的作用?它实际就是一个Activity子类,能为Android旧版本系统提供兼容支持。
该类文件有一个Activity函数:onCreate(Bundle?)。
activity子类的实例创建后,onCreate(Bundle?)函数会被调用。activity创建后,它需要获取并管理用户界面。要获取activity的用户界面,可以调用以下Activity函数:
```kotlin
Activity.setContentView(layoutResID: Int)
```
根据传入的布局资源ID参数,该函数生成指定布局的视图并将其放置在屏幕上。布局视图生成后,布局文件包含的部件也随之以各自的属性定义完成实例化。
资源与资源ID
布局是一种资源。资源是应用非代码形式的内容,比如图像文件、音频文件以及XML文件等。
项目的所有资源文件都存放在目录app/res的子目录下。在项目工具窗口中可以看到,activity_main.xml布局资源文件存放在res/layout/目录下。strings.xml字符串资源文件存放在res/values/目录下。
可以使用资源ID在代码中获取相应的资源。activity_main.xml布局的资源ID为R.layout.activity_main。
> APG 8.0 以后的版本已经看不到 R.java 文件了
GeoQuiz应用需要的字符串同样具有资源ID。目前为止,我们还未在代码中引用过字符串,如果需要,可以使用以下函数:
```kotlin
setTitle(R.string.app_name)
```
Android为整个布局文件以及各个字符串生成资源ID,但activity_main.xml布局文件中的部件除外,因为不是所有部件都需要资源ID。
要为部件生成资源ID,请在定义部件时为其添加android:id属性。
```xml
```
注意,android:id属性值前面有一个+标志,android:text属性值则没有。这是因为我们在创建资源ID,而对字符串资源只是做引用。
## 部件的实际应用
接下来,我们来编码使用按钮部件,这需要以下两个步骤:
- 引用生成的视图对象;
- 为对象设置监听器,以响应用户操作。
### 引用部件
既然按钮有了资源ID,我们就可以在MainActivity中引用它们了。
# 第 7 章 Android SDK版本与兼容
## 7.1 Android SDK版本
[Android SDK Levels](https://apilevels.com/#footnotes)
```xml
android {
namespace = "com.learn.geoquiz"
compileSdk = 35
defaultConfig {
applicationId = "com.learn.geoquiz"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}
```
- minSdk: 以最低版本设置值为标准,操作系统会拒绝将应用安装在低于此标准的设备上。例如:24,即Android 7.0 Nougat。低于 Android 7.0 Nougat 的设备将无法运行该应用。
- targetSdk:目标版本的设定值会告诉Android应用是为哪个API级别设计的。大多数情况下,目标版本即最新发布的Android版本。
- compileSdk:编译版本设置值会告诉Android应用使用哪个API级别进行编译。
SDK最低版本和目标版本会通知给操作系统,而SDK编译版本只是你和编译器之间的私有信息
Android的特色功能是通过SDK中的类和函数展现的。在编译代码时,SDK编译版本(编译目标)指定具体 要使用的系统版本。Android Studio在寻找类包导入语句中的类和函数时,编译目标确定具体的基准系统版 本。
编译目标的最佳选择为最新的API级别。当然,如有需要,也可以改变应用的编译目标。例如,Android新 版本发布时,可能就需要更新编译目标,以便使用新版本引入的函数和类。
可以修改build.gradle文件中的SDK最低版本、目标版本以及编译版本。不过要注意,修改完毕,项目和 Gradle更改重新同步后才能生效。
## 7.3 使用Android开发者文档
从Android Lint错误信息中可看到不兼容代码所属的API级别。也可在Android开发者文档里查看各API级别特 有的类和函数。
越早熟悉使用开发者文档越有利于开发。没人能记住Android SDK中的海量信息,更不要说定期发布的新版 本系统了。因此,学会查阅SDK文档,不断学习新的知识尤显重要。
Android开发者文档是优秀而丰富的信息来源。文档分为六大部分:平台、Android Studio、Google Play、 Android Jetpack、参考文档和新闻。如果有机会,一定要仔细研读这些资料。从开发起步到在Google Play商 店里发布应用,每一部分都包含了Android开发方方面面的内容。
- 平台:基本平台信息、重点关注平台基础支持和Android不同的系统版本。
- Android Studio:开发工具相关的文档,介绍不同的开发工具和流程以方便开发。
- Google Play:帮助部署应用以及使你的应用更受用户欢迎的一些指导和小技巧。
- Android Jetpack:介绍Jetpack库以及Android团队是如何致力提高开发体验的。本书只用了部分Jetpack 库,建议你查看全部库内容,熟悉它们。
- 参考文档:开发者文档主页。在这里,可以找到开发框架中各种类的使用信息,以及各种开发学习教 程和实验代码。用好它们,可以帮你提高开发水平。
- 新闻:最新文章和新闻消息,方便你了解Android开发的最新动态。
### TODO
- Navigation架构组件库
### 第 14 章 应用栏
- 14.1 AppCompat默认应用栏
- 14.2 应用栏菜单
- 14.3 使用Android Asset Studio
- 14.4 深入学习:应用栏、操作栏与工具栏
- 14.5 深入学习:AppCompat版应用栏
- 14.6 挑战练习:RecyclerView空视图
### 第 15 章 隐式intent
- 15.1 添加按钮部件
- 15.2 添加嫌疑人信息至模型层
- 15.3 使用格式化字符串
- 15.4 使用隐式intent
- 15.5 挑战练习:又一个隐式intent
### 第 16 章 使用intent拍照
- 16.1 布置照片
- 16.2 文件存储
- 16.3 使用相机intent触发拍照
- 16.4 缩放和显示位图
- 16.5 功能声明
- 16.6 挑战练习:优化照片显示
- 16.7 挑战练习:优化缩略图加载
### 第 17 章 应用本地化
- 17.1 资源本地化
- 17.2 配置修饰符
- 17.3 测试备选资源
- 17.4 深入学习:确定设备屏幕尺寸
- 17.5 挑战练习:日期显示本地化
### 第 18 章 Android辅助功能
- 18.1 TalkBack
- 18.2 实现非文字型元素可读
- 18.3 提升辅助体验
- 18.4 深入学习:使用辅助功能扫描器
- 18.5 挑战练习:优化列表项
- 18.6 挑战练习:补全上下文信息
- 18.7 挑战练习:事件主动通知
### 第 19 章 数据绑定与MVVM
- 19.1 为何要用MVVM架构
- 19.2 MVVM View Model与Jetpack ViewModel
- 19.3 创建BeatBox应用
- 19.4 实现简单的数据绑定
- 19.5 导入assets
- 19.6 处理assets
- 19.7 使用assets
- 19.8 绑定数据
- 19.9 深入学习:数据绑定再探
- 19.10 深入学习:LiveData和数据绑定
### 第 20 章 音频播放与单元测试
- 20.1 创建SoundPool
- 20.2 访问Assets
- 20.3 加载音频文件
- 20.4 播放音频
- 20.5 测试依赖
- 20.6 创建测试类
- 20.7 配置测试类配置测试对象
- 20.8 编写测试函数测试对象交互
- 20.9 数据绑定回调
- 20.10 释放音频
- 20.11 深入学习:整合测试
- 20.12 深入学习:模拟对象与测试
- 20.13 挑战练习:播放进度控制
- 20.14 挑战练习:设备旋转问题
### 第 21 章 样式与主题
- 21.1 颜色资源
- 21.2 样式样式继承
- 21.3 主题修改默认主题
- 21.4 添加主题颜色
- 21.5 覆盖主题属性主题探秘
- 21.6 修改按钮属性
- 21.7 深入学习:样式继承拾遗
- 21.8 深入学习:引用主题属性
### 第 22 章 XML drawable
- 22.1 统一按钮样式
- 22.2 shape drawable
- 22.3 state list drawable
- 22.4 layer list drawable
- 22.5 深入学习:为什么要用XML drawable
- 22.6 深入学习:使用mipmap图像
- 22.7 深入学习:使用9-patch图像
- 22.8 挑战练习:按钮主题
### 第 23 章 深入学习intent和任务
- 23.1 创建NerdLauncher项目
- 23.2 解析隐式intent
- 23.3 在运行时创建显式intent
- 23.4 任务与回退栈
- 23.5 用NerdLauncher当主屏幕
- 23.6 深入学习:进程与任务
- 23.7 深入学习:并发文档
- 23.8 挑战练习:应用图标
### 第 24 章 HTTP与后台任务
- 24.1 创建PhotoGallery应用
- 24.2 Retrofit网络连接基本
- 24.3 从Flickr获取JSON数据
- 24.4 应对设备配置改变
- 24.5 在RecyclerView里显示结果
- 24.6 深入学习:其他JSON数据解析器和数据格式
- 24.7 深入学习:撤销网络请求
- 24.8 深入学习:管理依赖
- 24.9 挑战练习:自定义Gson反序列化器
- 24.10 挑战练习:分页
- 24.11 挑战练习:动态调整网格列
### 第 25 章 Looper、Handler和HandlerThread
- 25.1 配置RecyclerView以显示图片
- 25.2 准备下载数据
- 25.3 批量下载缩略图
- 25.4 创建后台线程
- 25.5 Message与message handler
- 25.6 观察视图的生命周期
- 25.7 保留fragment
- 25.8 深入学习:解决图片下载问题
- 25.9 深入学习:StrictMode
- 25.10 挑战练习:观察视图LifecycleOwner的LiveData
- 25.11 挑战练习:优化ThumbnailDownloader
- 25.12 挑战练习:预加载以及缓存
### 第 26 章 搜索
- 26.1 搜索Flickr网站
- 26.2 使用SearchView
- 26.3 使用sharedpreferences实现轻量级数据存储
- 26.4 优化应用
- 26.5 用Android KTX编辑SharedPreferences
- 26.6 挑战练习:优化PhotoGallery应用
### 第 27 章 WorkManager
- 27.1 创建Worker类
- 27.2 调度工作
- 27.3 检查新图片
- 27.4 通知用户
- 27.5 服务的用户控制
### 第 28 章 broadcast intent
- 28.1 普通intent与broadcast intent
- 28.2 过滤前台通知
- 28.3 receiver与长时运行任务
- 28.4 深入学习:本地事件
- 28.5 深入学习:受限的Broadcast Receiver
- 28.6 深入学习:探测fragment的状态
### 第 29 章 网页浏览
- 29.1 最后一段Flickr数据
- 29.2 简单方式:使用隐式intent
- 29.3 较难的方式:使用WebView
- 29.4 处理WebView的设备旋转问题
- 29.5 WebView与定制UI
- 29.6 深入学习:注入JavaScript对象
- 29.7 深入学习:WebView升级
- 29.8 深入学习:Chrome Custom Tabs
- 29.9 挑战练习:使用回退键浏览历史网页
### 第 30 章 定制视图与触摸事件
- 30.1 创建DragAndDraw项目
- 30.2 创建定制视图
- 30.3 处理触摸事件
- 30.4 onDraw(Canvas)函数内的图形绘制
- 30.5 深入学习:GestureDetector
- 30.6 挑战练习:设备旋转问题
- 30.7 挑战练习:旋转矩形框
- 30.8 挑战练习:辅助功能支持
### 第 31 章 属性动画
- 31.1 建立场景
- 31.2 简单属性动画
- 31.3 播放多个动画
- 31.4 深入学习:其他动画API
- 31.5 挑战练习
### 第 32 章 编后语
- 32.1 终极挑战
- 32.2 插个广告
- 32.3 致谢