Android学习笔记(一)
文章目录
1. build.gradle文件
Gradle使用一种基于Groovy的领域特定语言(DSL)进行项目设置
详解Android项目中的build.gradle文件:
// 外层目录build.gradle文件
buildscript {
// 为此项目配置生成脚本类路径(buildscript:配置脚本)
ext.kotlin_version = '1.3.61'
repositories {
// 配置本项目的存储库(repositories:存储库)
google() // Google自家的扩展依赖库
jcenter() // 包含的大多是一些第三方开源库
// 声明后项目可以轻松引用两个仓库中的依赖库
}
dependencies {
// 配置此项目中的依赖关系(dependencies:依赖关系)
// 此处声明了两个插件
classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
// 配置此项目及其每个子项目。
repositories {
google()
jcenter()
}
}
通常不需要修改最外层目录中的配置文件,除非添加一些全局项目构建配置
// app下的build.gradle文件
apply plugin: 'com.android.application' // 应用模块(另一个值为com.android.library库模块)
apply plugin: 'kotlin-android' // 和下面相同,都是声明插件
apply plugin: 'kotlin-android-extensions' // 该插件用于简化findViewById操作
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig { // config:配置
applicationId "com.example.helloworld"
minSdkVersion 21
// targetSdkVersion指定进行了充分测试的sdk版本,新版本sdk的功能就不会引入(target:目标)
targetSdkVersion 29
versionCode l
versionName "1.0"
// testInstrumentationRunner指定当前项目中启用JUnit测试
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
// 指定生成安装文件的相关配置,有debug和release两个子闭包
release {
minifyEnabled false // 是否进行混淆
proguardFiles getDefaultProguardFile('proguard-android-optimize,txt'),
'proguard-rules.pro // 指定混淆规则文件(proguard:混淆器)
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['* jar']) // 本地依赖
// implementation声明远程依赖
// 远程依赖格式:域名部分:工程名部分:版本号
implementation "org jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.8'
// 可以来格式:implementation project 依赖的库的名称
}
应用模块可以直接运行,库模块只能作为代码库依附于别的应用模块来运行
- 本地依赖:对本地jar包或目录添加依赖关系
- 库依赖:对项目中的库模块添加依赖关系
- 远程依赖:对jcenter仓库上的开源项目添加依赖
注:随着Android Studio版本的更新,Gradle文件内具体内容会更改,但了解基本结构,也会快速理解新版本中Gradle文件内容
相关知识:
Gradle教程 - 简书
2. Activity
2.1 基本用法
Activity用于和用户进行交互
略
2.2 Menu
使用步骤:
- 创建menu的xml文件res/menu/main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:titLe="Add"/>
<item
android:id="@+id/remove_item"
android:titLe="Remove"/>
</menu>
- 重写Activity方法onCreateOptionMenu()(option:选项)
override fun onCreateOptionMenu(menu: Menu?): Boolean {
// inflate() 根据布局id动态加载返回一个View
menuInflater.inflate(R.menu.main, menu)
// 本质是getmenuInflater().inflate(R.menu.main, menu)
return true
}
- 重写Activity方法onOptionsItemSelected()
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.add_item -> Toast.makeText(this."You click Add",
Toast.LENGTH_SHORT).show()
R.id.remove_item -> Toast.makeText(this."You click Remove",
Toast.LENGTH_SHORT).show()
}
return true
}
相关知识:
Android inflate方法总结 - 简书
3. Intent与数据传递
3.1 显式Intent
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
3.2 隐式Intent
指定一系列action和category等信息,由系统分析intent判断启动哪个Activity
<activity android:name=".SecondActivity" :
<intent-filter>
<!-- filter:过滤器 -->
<action android:name="com.example,activitytest,ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.activitytest.MY_CATEGORY"/>
</intent-filter>
</acttivity>
val intent = Intent("com.example.activitytest.ACTIONSTART")
intent.addCategory("com.example.activitytest.MY_CATEGORY")
更多用法:
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com") // parse:解析
// 会打开系统浏览器,打开网页https://www.baidu.com
val intent1 = Intent(Intent.ACTION_DIAL)
intent1.data = Uri.parse("tel:10086") // tel 表示拨打电话协议
data标签:
- 可以配置以下内容
android:scheme
指定数据协议部分android:host
android:port
android:path
指定主机名和端口号之后的部分,如一段网址中在域名之后的内容
总结:根据activity等标签内部的intent-filter标签中的action、category和data数据来判断是否是与指定intent匹配
3.3 传递数据
向下一个Activity传递
intent的putExtra()方法根据键值存放数据(第一个Activity),intent的一系列getXxx()方法根据键来获取传递的值(第二个Activity,先通过getIntent()获取到intent实例对象,在进行操作)
返回数据给上一个Activity
使用除startActivity()方法的另一个启动Activity的方法startActivityForResult(),在Activity销毁后返回一个结果给上一个Activity
- 第一个参数:Intent
- 第二个参数:请求码,用于判断数据来源
// 第一个Activity中
override fun onCreate(savedInstanceState: Bundle?) {
...
button1.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivityForResult(intent, 1)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// 使用startActivityForResult()启动Activity返回后自动回调该方法
// request:请求
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
1 -> if (resultCode == RESULT_OK) {
val returnData = data?.getStringExtra("returnData")
Log.d("FirstActivity", "return data is $returnData")
}
}
}
// 第二个Activity中
override fun onCreate(savedInstanceState: Bundle?) {
...
button2.setOnClickListener {
val intent = Intent()
intent.putExtra("returnData", "Hello")
setResult(RESULT_OK, intent) // 参数:处理结果,带有数据的Intent
finish()
}
}
override fun onBackPressed() {
// 按下Back键,执行此方法
val intent = Intent()
intent.putExtra("returnData", "Hello")
setResult(RESULT_OK, intent)
finish()
}
相关知识:
intent-filter - Android 开发者
onBackPressed()使用 - CSDN博客
4. Activity生命周期和启动模式
4.1 生命周期
返回栈:Android使用task(任务)管理Activity,一个任务就是一组存放在返回栈里的Activity
Activity状态:
- 运行状态:返回栈栈顶
- 暂停状态:不在栈顶,但可见
- 停止状态:不在栈顶且完全不可见
- 销毁状态:从返回栈中移除
系统一般不会回收运行状态和暂停状态的Activity,停止状态会保存相应状态和成员变量,但内存不足或其他地方需要内存时会被回收,一般会回收销毁状态的
方法和生存期:
- onCreate():第一次创建调用
- onStart():不可见变可见时调用
- onResume():准备与用户进行交互时调用(处于运行状态)
- onPause():启动或恢复另一个Activity时调用(处理一些资源释放和保存关键数据)
- onStop():完全不可见时调用
- onDestory():被销毁之前调用
- onRestart():停止状态变为运行状态时调用
- 完整生存期:onCreate()~onDestory()
- 可见生存期:onStart()~onStop(),处于暂停状态或运行状态,使用两个方法合理地管理用户可见资源
- 前台生存期:onResume()~onPause(),处于运行状态
4.2 Activity被回收怎么办
Activity提供了onSaveInstanceState()回调方法,保证在Activity被回收之前一定调(Instance:实例)
override fun onSaveInstanceState(outState: Bundle) {
// Bundle提供一系列putXxx方法保存数据,一系列getXxx方法提取数据
super.onSaveInstanceState(outState)
val tempData = "Something you just typed"
outState.putString("data_key", tempData)
}
暂存数据的提取可以通过onCreate()方法Bundle类型参数savedInstanceState来提取
4.3 启动模式
在AndroidManifest.xml中通过<activity>
标签属性android:lauchMode
来指定启动模式(lauch:开展)
- standard(标准):默认模式,每当启动一个新Activity就会入栈,并处于栈顶
- singleTop(顶部单一):启动Activity时如果栈顶已经是该Activity,则直接使用,不再创建新实例
- singleTask(任务单一):启动Activity时如果返回栈中存在该Activity实例,则该实例之上的所有Activity全部出栈
- singleInstance:指定该模式的Activity会启动一个新的返回栈来管理这个Activity,当多个程序想要共享这个Activity实例的时候可以使用这个模式
相关知识:
了解 Activity 生命周期 - Android 开发者
Activity的4种启动模式 - 简书
5. Activity实践
5.1 知道当前是哪一个Activity
编写BaseActivity
open class BaseActivity : AppCompatActivity() { // compat:兼容
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("BaseActivity", javaClass.simpleName)
}
}
之后再让其他Activity继承BaseActivity,因为BaseActivity也继承了AppCompatActivity,所以功能不会受影响,可以在BaseActivity中编写一些所有Activity都会用到的功能,从而使开发更方便
5.2 随时随地退出程序
编写单例类ActivityCollector
object ActivityCollector {
private val activities = ArrayList<Activity>()
fun addActivity(activity: Activity) {
activities.add(activity)
}
fun removeActivity(activity: Activity) {
activities.remove(activity)
}
fun finishAll() {
for (activity in activities) {
if (!activity.isFinishing) {
activity.finish()
}
}
activities.clear()
}
}
在BaseActivity内编写
open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("BaseActivity", javaClass.simpleName)
ActivityCollector.addActivity(this)
}
override fun onDestory() {
super.onDestory()
ActivityCollector.removeActivity(this)
}
}
在Activity中调用ActivityCollector的finishAll()方法就可以随时退出程序了
5.3 启动Activity的最佳方法
使用场景:实际应用中不同Activity不同程序员编写,不知道下一个Activity需要什么数据
class SecondActivity : BaseActivity() {
...
companion object {
fun actionStart(context: Context, data1: String, data2: String) {
val intent = Intent(context, SecondActivity::class.java)
intent.putExtra("param1", data1)
intent.putExtra("param2", data2)
context.startActivity(intent)
}
}
}
这里使用的方法的是:由编写这个Activity的程序员来定义一个方法来声明自己需要什么数据,而其他程序员只需要通过类似调用静态方法的方式就可以调用该方法,通过参数来确定数据类型和个数
Context(语境、上下文)是一个抽象类,Activity、Service、Application都是其子类
(查看继承关系Ctrl
+ H
)
相关知识:
Context都没弄明白,还怎么做Android开发? - 简书