导图社区 Android开发
这是一篇关于Android開發的思维导图,主要内容包括:Kotlin,开发基础,重要类,SQLite,连接网络,其他类,其他,Log等级,实例,案例,错误。
编辑于2026-01-06 15:04:55Android開發
Kotlin
基础语法
hello word
fun main(args: Array<String>){ println("Hello Word") } //Hello Word
包声明
package com.runoob.main
函数定义
函数定义使用关键字 fun,参数格式为:参数 : 类型
有返回值
fun sum(a: Int, b: Int): Int { // Int 参数,返回值 Int return a + b } 表达式作为函数体,返回类型自动推断: fun sum(a: Int, b: Int) = a + b public fun sum(a: Int, b: Int): Int = a + b // public 方法则必须明确写出返回类型
无返回值
fun printSum(a: Int, b: Int): Unit { print(a + b) } // 如果是返回 Unit类型,则可以省略(对于public方法也是这样): public fun printSum(a: Int, b: Int) { print(a + b) }
可变长参数函数
fun vars(vararg v:Int){ for(vt in v){ print(vt) } } // 测试 fun main(args: Array<String>) { vars(1,2,3,4,5) // 输出12345 }
vararg 关键字
lambda(匿名函数)
// 测试 fun main(args: Array<String>) { val sumLambda: (Int, Int) -> Int = {x,y -> x+y} println(sumLambda(1,2)) // 输出 3 }
as
将一个表达式转换为指定的类型
as?
安全转换,转换失败时不报错输出null
定义常量与变量
可变变量定义:var 关键字
var <标识符> : <类型> = <初始化值>
不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)
val <标识符> : <类型> = <初始化值>
字符串模板
fun main() { var a = 1 // 模板中的简单名称: val s1 = "a is $a" a = 2 // 模板中的任意表达式: val s2 = "${s1.replace("is", "was")}, but now is $a" println(s1) println(s2) } //a is 1 //a was 1, but now is 2
$ 表示一个变量名或者变量值
$varName 表示变量值
${varName.fun()} 表示变量的方法返回值:
NULL检查机制
//类型后面加?表示可为空 var age: String? = "23" //抛出空指针异常 val ages = age!!.toInt() //不做处理返回 null val ages1 = age?.toInt() //age为空返回-1 val ages2 = age?.toInt() ?: -1
对于声明可为空的参数,在使用时要进行空判断处理
// 定义函数 parseInt, 接收一个字符串并尝试将其转换为整数,如果失败返回 null fun parseInt(str: String): Int? { // 使用 toIntOrNull 将字符串转换为整数,失败时返回 null return str.toIntOrNull() } // 定义函数 printProduct, 接收两个字符串参数,尝试将它们转换为整数并输出乘积 fun printProduct(arg1: String, arg2: String) { // 将第一个字符串转换为整数,返回值为 Int?,即可能是 null val x = parseInt(arg1) // 将第二个字符串转换为整数,返回值也可能是 null val y = parseInt(arg2) // 直接使用 `x * y` 会导致错误, 因为它们可能为 null // 如果 x 和 y 都不为 null, 则执行乘法操作 if (x != null && y != null) { // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量 println(x * y) // 输出 x 和 y 的乘积 } else { // 如果 x 或 y 为 null,则输出提示信息,表明其中一个参数不是数字 println("'$arg1' or '$arg2' is not a number") } } // 主函数 fun main() { // 第一次调用 printProduct,两个参数都是有效数字,应该输出乘积 printProduct("6", "7") // 输出: 42 // 第二次调用,第一个参数不是数字,输出错误提示 printProduct("a", "7") // 输出: 'a' or '7' is not a number // 第三次调用,两个参数都不是数字,输出错误提示 printProduct("a", "b") // 输出: 'a' or 'b' is not a number } //42 //'a' or '7' is not a number //'a' or 'b' is not a number
字段后加!!像Java一样抛出空异常
字段后加?可不做处理返回值为 null 或配合 ?: 做空判断处理
类型检测及自动类型转换
fun getStringLength(obj: Any): Int? { if (obj !is String) return null // 在这个分支中, `obj` 的类型会被自动转换为 `String` return obj.length }
区间
for (i in 1..4) print(i) // 输出“1234” for (i in 4..1) print(i) // 什么都不输出 if (i in 1..10) { // 等同于 1 <= i && i <= 10 println(i) } // 使用 step 指定步长 for (i in 1..4 step 2) print(i) // 输出“13” for (i in 4 downTo 1 step 2) print(i) // 输出“42” // 使用 until 函数排除结束元素 for (i in 1 until 10) { // i in [1, 10) 排除了 10 println(i) }
由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
fun main(args: Array<String>) { print("循环输出:") for (i in 1..4) print(i) // 输出“1234” println("\n----------------") print("设置步长:") for (i in 1..4 step 2) print(i) // 输出“13” println("\n----------------") print("使用 downTo:") for (i in 4 downTo 1 step 2) print(i) // 输出“42” println("\n----------------") print("使用 until:") // 使用 until 函数排除结束元素 for (i in 1 until 4) { // i in [1, 4) 排除了 4 print(i) } println("\n----------------") } 输出结果: 循环输出:1234 ---------------- 设置步长:13 ---------------- 使用 downTo:42 ---------------- 使用 until:123 ----------------
中缀函数
to
类似于字典的:用于构建 Map 或元组
menu = mutableMapOf("name" to "焼肉定食", "price" to "950円")
until
创建半开区间(不包含结束值)
val range = 1 until 5 // 生成 [1, 5) 的 IntRange:cite[5]
step
定义区间步长
for (i in 1..10 step 2) { ... } // 步长为 2:cite[5]
union / intersect
集合的并集/交集操作
val set = setOf(1, 2) union setOf(2, 3) // 结果为 [1, 2, 3]:cite[1]
基本数据类型
不同于 Java 的是,字符不属于数值类型,是一个独立的数据类型。
整数类型
Byte
8 位,范围从 -128 到 127。
Short
16 位,范围从 -32,768 到 32,767。
Int
32 位,范围从 -2^31 到 2^31 - 1。
Long
64 位,范围从 -2^63 到 2^63 - 1。
属性
最大最小
.MAX_VALUE
.MIN_VALUE
浮点数类型
Float
32 位,单精度,带有 6-7 位有效数字。
Double
64 位,双精度,带有 15-16 位有效数字。
字符类型
Char
16 位的 Unicode 字符。
布尔类型
Boolean
有两个值:true和false
字符串类型
String
一系列字符的序列。
数组类型
Kotlin 提供了数组类型来存储同种类型的元素,例如:
IntArray
存储Int类型的数组。
DoubleArray
存储Double类型的数组。
Array<T>
泛型数组,可以存储任意类型。
字面常量
十进制:123
长整型以大写的 L 结尾:123L
16 进制以 0x 开头:0x0F
2 进制以 0b 开头:0b00001011
注意:8进制不支持
Doubles 默认写法:123.5,123.5e10
Floats 使用 f 或者 F 后缀:123.5f
类型转换
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
位操作符
shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向
字符
和 Java 不一样,Kotlin 中的 Char 不能直接和数字操作,Char 必需是单引号 ' 包含起来的。比如普通字符 '0','a'。
fun decimalDigitValue(c: Char): Int { if (c !in '0'..'9') throw IllegalArgumentException("Out of range") return c.toInt() - '0'.toInt() // 显式转换为数字 }
布尔
|| – 短路逻辑或
&& – 短路逻辑与
! - 逻辑非
数组
fun main(args: Array<String>) { //[1,2,3] val a = arrayOf(1, 2, 3) //[0,2,4] val b = Array(3, { i -> (i * 2) }) //读取数组内容 println(a[0]) // 输出结果:1 println(b[1]) // 输出结果:2 }
数组用类 Array 实现,并且还有一个 size 属性及 get 和 set 方法
数组的创建两种方式:一种是使用函数arrayOf();另外一种是使用工厂函数。
字符串
for (c in str) { println(c) }
和 Java 一样,String 是不可变的。,也可以通过 for 循环来遍历:
fun main(args: Array<String>) { val text = """ 多行字符串 多行字符串 """ println(text) // 输出有一些前置空格 }
String 可以通过 trimMargin() 方法来删除多余的空白。
fun main(args: Array<String>) { //默认 | 用作边界前缀 val text = """ |多行字符串 |菜鸟教程 |多行字符串 |Runoob """.trimMargin() println(text) // 前置空格删除了 }
字符串模板
模板表达式以美元符($)开头
由一个简单的名字构成: fun main(args: Array<String>) { val i = 10 val s = "i = $i" // 求值结果为 "i = 10" println(s) } 或者用花括号扩起来的任意表达式: fun main(args: Array<String>) { val s = "runoob" val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6" println(str) }
运算符
::类名/函数
引用类名/函数
类名::参数
class Person(val name: String, var age: Int) fun main() { val person = Person("Alice", 25) // 获取属性引用 val nameRef = Person::name // 只读属性(val) val ageRef = Person::age // 可变属性(var) // 通过引用访问属性 println(nameRef.get(person)) // 输出: Alice println(ageRef.get(person)) // 输出: 25 // 修改可变属性 ageRef.set(person, 26) println(person.age) // 输出: 26 }
引用类中的属性
条件控制
IF 表达式
// 传统用法 var max = a if (a < b) max = b // 使用 else var max: Int if (a > b) { max = a } else { max = b } // 作为表达式 val max = if (a > b) a else b
把 IF 表达式的结果赋值给一个变量。
val max = if (a > b) { print("Choose a") a } else { print("Choose b") b }
val c = if (condition) a else b
使用区间
fun main(args: Array<String>) { val x = 5 val y = 9 if (x in 1..8) { println("x 在区间内") } } 输出结果为: x 在区间内
When 表达式
fun main(args: Array<String>) { var x = 0 when (x) { 0, 1 -> println("x == 0 or x == 1") else -> println("otherwise") } when (x) { 1 -> println("x == 1") 2 -> println("x == 2") else -> { // 注意这个块 println("x 不是 1 ,也不是 2") } } when (x) { in 0..10 -> println("x 在该区间范围内") else -> println("x 不在该区间范围内") } } //x == 0 or x == 1 //x 不是 1 ,也不是 2 //x 在该区间范围内
将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。类似其他语言的 switch 操作符
循环控制
For 循环
对集合进行迭代: fun main(args: Array<String>) { val items = listOf("apple", "banana", "kiwi") for (item in items) { println(item) } for (index in items.indices) { println("item at $index is ${items[index]}") } } 输出结果: apple banana kiwi item at 0 is apple item at 1 is banana item at 2 is kiwi
for 循环可以对任何提供迭代器(iterator)的对象进行遍历
while 与 do...while 循环
fun main(args: Array<String>) { println("----while 使用-----") var x = 5 while (x > 0) { println( x--) } println("----do...while 使用-----") var y = 5 do { println(y--) } while(y>0) } 输出结果: ----while 使用----- 5 4 3 2 1 ----do...while 使用----- 5 4 3 2 1
返回和跳转
return
默认从最直接包围它的函数或者匿名函数返回。
break
终止最直接包围它的循环。
continue
继续下一次最直接包围它的循环。
类和对象
类定义
class Runoob { // 类名为 Runoob // 大括号内是类体构成 }
Kotlin 中使用关键字 class 声明类,后面紧跟类名
类的属性
class Runoob { var name: String = …… var url: String = …… var city: String = …… }
可以用关键字 var 声明为可变的,否则使用只读关键字 val 声明为不可变
import java.util.* class Person { var lastName: String = "zhang" get() = field.uppercase(Locale.getDefault()) // 将变量赋值后转换为大写 set var no: Int = 100 get() = field // 后端变量 set(value) { if (value < 10) { // 如果传入的值小于 10 返回该值 field = value } else { field = -1 // 如果传入的值大于等于 10 返回 -1 } } var heiht: Float = 145.4f private set } fun main(args: Array<String>) { var person: Person = Person() person.lastName = "wang" println("lastName:${person.lastName}") person.no = 9 println("no:${person.no}") person.no = 20 println("no:${person.no}") } //lastName:WANG //no:9 //no:-1
主构造器
class Person(val name: String, val age: Int) { init { println("Person created: $name, $age") } }
通常在类定义的同时声明。它的特点是简洁并且适合用于初始化类的成员变量。
init
用于包含需要在构造器中执行的初始化逻辑。
次构造器
class Person { var name: String var age: Int constructor(name: String) { this.name = name this.age = 0 // 默认年龄 } constructor(name: String, age: Int) { this.name = name this.age = age } }
是类的额外构造器,它允许你在类中定义多个构造器来支持不同的初始化方式。
constructor
抽象类
abstract
open class Base { open fun f() {} } abstract class Derived : Base() { override abstract fun f() }
嵌套类
class Outer { // 外部类 private val bar: Int = 1 class Nested { // 嵌套类 fun foo() = 2 } } fun main(args: Array<String>) { val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性 println(demo) // == 2 }
可以把类嵌套在其他类中
内部类
class Outer { private val bar: Int = 1 var v = "成员属性" /**嵌套内部类**/ inner class Inner { fun foo() = bar // 访问外部类成员 fun innerTest() { var o = this@Outer //获取外部类的成员变量 println("内部类可以引用外部类的成员,例如:" + o.v) } } } fun main(args: Array<String>) { val demo = Outer().Inner().foo() println(demo) // 1 val demo2 = Outer().Inner().innerTest() println(demo2) // 内部类可以引用外部类的成员,例如:成员属性 } //1 //内部类可以引用外部类的成员,例如:成员属性 //kotlin.Unit
inner
带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
匿名内部类
class Test { var v = "成员属性" fun setInterFace(test: TestInterFace) { test.test() } } /** * 定义接口 */ interface TestInterFace { fun test() } fun main(args: Array<String>) { var test = Test() /** * 采用对象表达式来创建接口对象,即匿名内部类的实例。 */ test.setInterFace(object : TestInterFace { override fun test() { println("对象表达式创建匿名内部类的实例") } }) } //对象表达式创建匿名内部类的实例
使用对象表达式来创建匿名内部类
类的修饰符
// 文件名:example.kt package foo private fun foo() {} // 在 example.kt 内可见 public var bar: Int = 5 // 该属性随处可见 internal val baz = 6 // 相同模块内可见
classModifier: 类属性修饰符,标示类本身特性
abstract // 抽象类
final // 类不可继承,默认属性
enum // 枚举类
open // 类可继承,类默认是final的
annotation // 注解类
accessModifier: 访问权限修饰符
private // 仅在同一个文件中可见
protected // 同一个文件中或子类可见
public // 所有调用的地方都可见
internal // 同一个模块中可见
继承
Kotlin 继承
open class Base(p: Int) // 定义基类 class Derived(p: Int) : Base(p)
Kotlin 中所有类都继承该 Any 类,它是所有类的超类
Any 默认提供了三个函数
equals()
hashCode()
toString()
构造函数
子类有主构造函数
open class Person(var name : String, var age : Int){// 基类 } class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) { } // 测试 fun main(args: Array<String>) { val s = Student("Runoob", 18, "S12346", 89) println("学生名: ${s.name}") println("年龄: ${s.age}") println("学生号: ${s.no}") println("成绩: ${s.score}") } //学生名: Runoob //年龄: 18 //学生号: S12346 //成绩: 89
则基类必须在主构造函数中立即初始化
子类没有主构造函数
/**用户基类**/ open class Person(name:String){ /**次级构造函数**/ constructor(name:String,age:Int):this(name){ //初始化 println("-------基类次级构造函数---------") } } /**子类继承 Person 类**/ class Student:Person{ /**次级构造函数**/ constructor(name:String,age:Int,no:String,score:Int):super(name,age){ println("-------继承类次级构造函数---------") println("学生名: ${name}") println("年龄: ${age}") println("学生号: ${no}") println("成绩: ${score}") } } fun main(args: Array<String>) { var s = Student("Runoob", 18, "S12345", 89) } //-------基类次级构造函数--------- //-------继承类次级构造函数--------- //学生名: Runoob //年龄: 18 //学生号: S12345 //成绩: 89
必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数
重写
/**用户基类**/ open class Person{ open fun study(){ // 允许子类重写 println("我毕业了") } } /**子类继承 Person 类**/ class Student : Person() { override fun study(){ // 重写方法 println("我在读大学") } } fun main(args: Array<String>) { val s = Student() s.study(); } 输出结果为: 我在读大学
在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。
如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词
如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。
open class A { open fun f () { print("A") } fun a() { print("a") } } interface B { fun f() { print("B") } //接口的成员变量默认是 open 的 fun b() { print("b") } } class C() : A() , B{ override fun f() { super<A>.f()//调用 A.f() super<B>.f()//调用 B.f() } } fun main(args: Array<String>) { val c = C() c.f(); } //AB
属性重写
使用 override 关键字,属性必须具有兼容类型
open class Foo { open val x: Int get { …… } } class Bar1 : Foo() { override val x: Int = …… }
可以用一个var属性重写一个val属性,但是反过来不行。因为val属性本身定义了getter方法
interface Foo { val count: Int } class Bar1(override val count: Int) : Foo class Bar2 : Foo { override var count: Int = 0 }
接口
interface MyInterface { fun bar() // 未实现 fun foo() { //已实现 // 可选的方法体 println("foo") } }
与 Java 8 类似,使用 interface 关键字定义接口,允许方法有默认实现
interface MyInterface { fun bar() fun foo() { // 可选的方法体 println("foo") } } class Child : MyInterface { override fun bar() { // 方法体 println("bar") } } fun main(args: Array<String>) { val c = Child() c.foo(); c.bar(); } //foo //bar
接口中的属性
interface MyInterface { var name:String //name 属性, 抽象的 fun bar() fun foo() { // 可选的方法体 println("foo") } } class Child : MyInterface { override var name: String = "runoob" //重写属性 override fun bar() { // 方法体 println("bar") } } fun main(args: Array<String>) { val c = Child() c.foo(); c.bar(); println(c.name) } 输出结果为: foo bar runoob
接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性
函数重写
interface A { fun foo() { print("A") } // 已实现 fun bar() // 未实现,没有方法体,是抽象的 } interface B { fun foo() { print("B") } // 已实现 fun bar() { print("bar") } // 已实现 } class C : A { override fun bar() { print("bar") } // 重写 } class D : A, B { override fun foo() { super<A>.foo() super<B>.foo() } override fun bar() { super<B>.bar() } } fun main(args: Array<String>) { val d = D() d.foo(); d.bar(); } //ABbar
实现多个接口时,可能会遇到同一方法继承多个实现的问题
扩展
扩展函数
fun receiverType.functionName(params){ body } receiverType:表示函数的接收者,也就是函数扩展的对象 functionName:扩展函数的名称 params:扩展函数的参数,可以为NULL
扩展函数可以在已有类中添加新的方法,不会对原类做修改
class User(var name: String) /**扩展函数**/ fun User.Print() { print("用户名 $name") } fun main(arg: Array<String>) { var user = User("Runoob") user.Print() } //用户名 Runoob
扩展函数是静态解析的
open class C class D : C() fun C.foo() = "c" // 扩展函数 foo fun D.foo() = "d" // 扩展函数 foo fun printFoo(c: C) { println(c.foo()) // 类型是 C 类 } fun main(arg: Array<String>) { printFoo(D()) } //c
若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。
class C { fun foo() { println("成员函数") } } fun C.foo() { println("扩展函数") } fun main(arg:Array<String>){ var c = C() c.foo() } //成员函数
扩展一个空对象
在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数。
fun Any?.toString(): String { if (this == null) return "null" // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString() // 解析为 Any 类的成员函数 return toString() } fun main(arg:Array<String>){ var t = null println(t.toString()) } 实例执行输出结果为: null
伴生对象的扩展
如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数和属性。
class MyClass { companion object { } // 将被称为 "Companion" } fun MyClass.Companion.foo() { println("伴随对象的扩展函数") } val MyClass.Companion.no: Int get() = 10 fun main(args: Array<String>) { println("no:${MyClass.no}") MyClass.foo() } 实例执行输出结果为: no:10 伴随对象的扩展函数
扩展声明为成员
在一个类内部你可以为另一个类声明扩展
class D { fun bar() { println("D bar") } } class C { fun baz() { println("C baz") } fun D.foo() { bar() // 调用 D.bar baz() // 调用 C.baz } fun caller(d: D) { d.foo() // 调用扩展函数 } } fun main(args: Array<String>) { val c: C = C() val d: D = D() c.caller(d) } //D bar //C baz
数据类与密封类
数据类
data class User(val name: String, val age: Int)
Kotlin 可以创建一个只包含数据的类,关键字为 data:
编译器会自动的从主构造函数中根据所有声明的属性提取以下函数
equals()
hashCode()
toString()
格式如
"User(name=John, age=42)"
componentN() functions
对应于属性,按声明顺序排列
copy()
data class User(val name: String, val age: Int) fun main(args: Array<String>) { val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) println(jack) println(olderJack) } 输出结果为: User(name=Jack, age=1) User(name=Jack, age=2)
密封类
用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。
使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中
泛型
即 "参数化类型",将类型参数化,可以用在类,接口,方法上。
class Box<T>(t: T) { var value = t }
以下实例向泛型类传入整型数据和字符串
class Box<T>(t : T) { var value = t } fun main(args: Array<String>) { var boxInt = Box<Int>(10) var boxString = Box<String>("Runoob") println(boxInt.value) println(boxString.value) } 输出结果为: 10 Runoob
在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数
fun main(args: Array<String>) { val age = 23 val name = "runoob" val bool = true doPrintln(age) // 整型 doPrintln(name) // 字符串 doPrintln(bool) // 布尔型 } fun <T> doPrintln(content: T) { when (content) { is Int -> println("整型数字为 $content") is String -> println("字符串转换为大写:${content.toUpperCase()}") else -> println("T 不是整型,也不是字符串") } } 输出结果为: 整型数字为 23 字符串转换为大写:RUNOOB T 不是整型,也不是字符串
泛型约束
可以使用泛型约束来设定一个给定参数允许使用的类型
最常见的约束是上界(upper bound)
型变
Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。
声明处型变
使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型
// 定义一个支持协变的类 class Runoob<out A>(val a: A) { fun foo(): A { return a } } fun main(args: Array<String>) { var strCo: Runoob<String> = Runoob("a") var anyCo: Runoob<Any> = Runoob<Any>("b") anyCo = strCo println(anyCo.foo()) } //a
in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型:
// 定义一个支持逆变的类 class Runoob<in A>(a: A) { fun foo(a: A) { } } fun main(args: Array<String>) { var strDCo = Runoob("a") var anyDCo = Runoob<Any>("b") strDCo = anyDCo }
星号投射
对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。
Function<*, String> , 代表 Function<in Nothing, String> ;
Function<Int, *> , 代表 Function<Int, out Any?> ;
Function<, > , 代表 Function<in Nothing, out Any?> .
枚举类
枚举类最基本的用法是实现一个类型安全的枚举。
枚举常量用逗号分隔,每个枚举常量都是一个对象。
枚举初始化
enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) }
对象表达式/声明
对象表达式
委托
在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。
类委托
即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。
// 创建接口 interface Base { fun print() } // 实现此接口的被委托的类 class BaseImpl(val x: Int) : Base { override fun print() { print(x) } } // 通过关键字 by 建立委托类 class Derived(b: Base) : Base by b fun main(args: Array<String>) { val b = BaseImpl(10) Derived(b).print() // 输出 10 }
属性委托
val/var <属性名>: <类型> by <表达式>
var/val:属性类型(可变/只读)
属性名:属性名称
类型:属性的数据类型
表达式:委托代理类
定义一个被委托的类
import kotlin.reflect.KProperty // 定义包含属性委托的类 class Example { var p: String by Delegate() } // 委托的类 class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, 这里委托了 ${property.name} 属性" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$thisRef 的 ${property.name} 属性赋值为 $value") } } fun main(args: Array<String>) { val e = Example() println(e.p) // 访问该属性,调用 getValue() 函数 e.p = "Runoob" // 调用 setValue() 函数 println(e.p) } //Example@617c74e5, 这里委托了 p 属性 //Example@617c74e5 的 p 属性赋值为 Runoob //Example@617c74e5, 这里委托了 p 属性
该类需要包含 getValue() 方法和 setValue() 方法,且参数 thisRef 为进行委托的类的对象,prop 为进行委托的属性的对象。
标准委托
Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托。
延迟属性 Lazy
val lazyValue: String by lazy { println("computed!") // 第一次调用输出,第二次调用不执行 "Hello" } fun main(args: Array<String>) { println(lazyValue) // 第一次执行,执行两次输出表达式 println(lazyValue) // 第二次执行,只输出返回值 } 执行输出结果: computed! Hello Hello
lazy() 是一个函数, 接受一个 Lambda 表达式作为参数, 返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
可观察属性 Observable
import kotlin.properties.Delegates class User { var name: String by Delegates.observable("初始值") { prop, old, new -> println("旧值:$old -> 新值:$new") } } fun main(args: Array<String>) { val user = User() user.name = "第一次赋值" user.name = "第二次赋值" } 执行输出结果: 旧值:初始值 -> 新值:第一次赋值 旧值:第一次赋值 -> 新值:第二次赋值
observable 可以用于实现观察者模式。
Delegates.observable() 函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。
在属性赋值后会执行事件的响应器(handler),它有三个参数:被赋值的属性、旧值和新值:
把属性储存在映射中
class Site(val map: Map<String, Any?>) { val name: String by map val url: String by map } fun main(args: Array<String>) { // 构造函数接受一个映射参数 val site = Site(mapOf( "name" to "菜鸟教程", "url" to "www.runoob.com" )) // 读取映射值 println(site.name) println(site.url) } 执行输出结果: 菜鸟教程 www.runoob.com
一个常见的用例是在一个映射(map)里存储属性的值。 这经常出现在像解析 JSON 或者做其他"动态"事情的应用中。 在这种情况下,你可以使用映射实例自身作为委托来实现委托属性。
如果使用 var 属性,需要把 Map 换成 MutableMap:
class Site(val map: MutableMap<String, Any?>) { val name: String by map val url: String by map } fun main(args: Array<String>) { var map:MutableMap<String, Any?> = mutableMapOf( "name" to "菜鸟教程", "url" to "www.runoob.com" ) val site = Site(map) println(site.name) println(site.url) println("--------------") map.put("name", "Google") map.put("url", "www.google.com") println(site.name) println(site.url) } 执行输出结果: 菜鸟教程 www.runoob.com -------------- Google www.google.com
Not Null
class Foo { var notNullBar: String by Delegates.notNull<String>() } foo.notNullBar = "bar" println(foo.notNullBar)
notNull 适用于那些无法在初始化阶段就确定属性值的场合。
需要注意,如果属性在赋值前就被访问的话则会抛出异常。
局部委托属性
fun example(computeFoo: () -> Foo) { val memoizedFoo by lazy(computeFoo) if (someCondition && memoizedFoo.isValid()) { memoizedFoo.doSomething() } }
你可以将局部变量声明为委托属性。 例如,你可以使一个局部变量惰性初始化:
memoizedFoo 变量只会在第一次访问时计算。 如果 someCondition 失败,那么该变量根本不会计算。
属性委托要求
对于只读属性(也就是说val属性), 它的委托必须提供一个名为getValue()的函数。该函数接受以下参数:
thisRef —— 必须与属性所有者类型(对于扩展属性——指被扩展的类型)相同或者是它的超类型
property —— 必须是类型 KProperty<*> 或其超类型
这个函数必须返回与属性相同的类型(或其子类型)。
对于一个值可变(mutable)属性(也就是说,var 属性),除 getValue()函数之外,它的委托还必须 另外再提供一个名为setValue()的函数, 这个函数接受以下参数:
property —— 必须是类型 KProperty<*> 或其超类型
new value —— 必须和属性同类型或者是它的超类型。
翻译规则
在每个委托属性的实现的背后,Kotlin 编译器都会生成辅助属性并委托给它。
例如,对于属性 prop,生成隐藏属性 prop$delegate,而访问器的代码只是简单地委托给这个附加属性: class C { var prop: Type by MyDelegate() } // 这段是由编译器生成的相应代码: class C { private val prop$delegate = MyDelegate() var prop: Type get() = prop$delegate.getValue(this, this::prop) set(value: Type) = prop$delegate.setValue(this, this::prop, value) }
提供委托
class ResourceLoader<T>(id: ResourceID<T>) { operator fun provideDelegate( thisRef: MyUI, prop: KProperty<*> ): ReadOnlyProperty<MyUI, T> { checkProperty(thisRef, prop.name) // 创建委托 } private fun checkProperty(thisRef: MyUI, name: String) { …… } } fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { …… } class MyUI { val image by bindResource(ResourceID.image_id) val text by bindResource(ResourceID.text_id) }
通过定义 provideDelegate 操作符,可以扩展创建属性实现所委托对象的逻辑。 如果 by 右侧所使用的对象将 provideDelegate 定义为成员或扩展函数,那么会调用该函数来 创建属性委托实例。
thisRef —— 必须与 属性所有者 类型(对于扩展属性——指被扩展的类型)相同或者是它的超类型
property —— 必须是类型 KProperty<*> 或其超类型。
开发基础
通过wifi连接设备
第一次连接:使用USB线将设备连接到你的电脑
命令获取设备的IP地址 adb shell ip addr show wlan0
找到“inet”后面的IP地址,例如10.5.10.106
输入命令将设备设为无线连接模式 adb tcpip 5555
输入以下命令,连接到指定的IP地址 adb connect 10.5.10.106:5555
创建项目
检查项目包名是否被使用
https://play.google.com/store/apps/details?id=包名
例:包名为 com.test.helloandroid
结构
app 目录
manifests 目录
AndroidManifest.xml: 应用程序的配置文件,定义了应用的包名、组件、权限等基本信息。
kotlin+java 目录
包含应用程序的源代码
com.test.helloandroid: 主要的源代码包(包名)
MainActivity: 应用程序的主入口活动
package 包名 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
在这里可以创建行动kt文件
比如说 MenuListFragment
com.test.helloandroid (androidTest): 包含 Android 测试代码(包名)
ExampleInstrumentedTest: 仪器化测试示例
com.test.helloandroid (test): 包含单元测试代码(包名)
ExampleUnitTest: 单元测试示例
res 目录
包含应用程序的资源文件
drawable: 图形资源
ic_launcher_background.xml: 应用启动图标的背景
ic_launcher_foreground.xml: 应用启动图标的前景
layout: 布局文件
activity_main.xml: 主活动的布局定义
<?xml version="1.0" encoding="utf-8"?> <androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragmentMainContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:name="包名.新kt文件名"/>
mipmap: 应用图标资源,不同分辨率
ic_launcher: 应用启动图标
ic_launcher_round: 圆形应用启动图标
values: 值资源
colors.xml: 定义应用中使用的颜色
strings.xml: 定义应用中使用的字符串
themes: 应用主题定义
xml: 其他 XML 配置文件
backup_rules.xml: 应用数据备份规则
data_extraction_rules.xml: 数据提取规则
Gradle Scripts
项目的构建配置文件
build.gradle.kts (Project: HelloAndroid): 项目级构建脚本
build.gradle.kts (Module: app): 应用模块构建脚本
proguard-rules.pro: ProGuard 混淆规则配置
gradle.properties: 项目属性配置
gradle-wrapper.properties: Gradle 版本配置
libs.versions.toml: 库版本管理目录
local.properties: SDK 位置配置
settings.gradle.kts: 项目设置配置
Activity生命周期

onCreate():Activity首次创建时调用,用于初始化布局和静态数据(如绑定视图、设置监听器)。整个生命周期仅调用一次。
onStart():Activity变为可见但未获取焦点时触发,通常用于注册广播接收器等资源。
onResume():Activity进入前台并与用户交互时调用,恢复动画或CPU密集型任务。
onPause():当Activity失去焦点但仍部分可见时执行,需在此保存临时数据(如表单输入)。
onStop():Activity完全不可见时调用,释放非必要资源以节省内存。
onRestart():Activity从停止状态重新显示前触发,通常与onStart()配合恢复界面。
onDestroy():Activity被销毁前调用,清理onCreate()中分配的资源(如数据库连接)。
Fragment(片段)

Fragment可以将界面划分为离散的区块
模块化

fragment 允许您将界面划分为离散的区块,从而将模块化和可重用性引入 activity 的界面。
创建fragment
class ExampleFragment : Fragment(R.layout.example_fragment)
Fragment 基类
DialogFragment
显示浮动对话框。
PreferenceFragmentCompat
以列表形式显示 Preference 对象的层次结构。
Fragment生命周期

创建阶段
onAttach() Fragment 首次关联到 Activity 时 获取 Activity 引用,初始化与 Activity 的通信
onCreate() Fragment 创建时 初始化非视图相关的数据(如变量、集合)
onCreateView() 创建 Fragment 的 UI 视图时 通过 LayoutInflater 加载布局,返回根视图(无 UI 可返回 null)
onViewCreated() onCreateView() 完成后 初始化视图组件(如 findViewById、设置监听器)
onViewStateRestored() 视图状态恢复后 恢复保存的视图状态(如 Bundle 中的文本框内容)
onStart() Fragment 可见但未交互时 准备用户界面(在 Activity onStart() 后调用)
onResume() Fragment 可交互时 启动动画、传感器监听等(在 Activity onResume() 后调用)
销毁阶段
onPause() Fragment 失去焦点时 暂停耗时操作(在 Activity onPause() 前调用)
onStop() Fragment 不可见时 停止动画、释放资源(在 Activity onStop() 后调用)
onSaveInstanceState() 系统需要保存状态时(如配置变更) 保存临时数据到 Bundle
onDestroyView() 视图被移除时 清理视图相关资源(如取消 RecyclerView 适配器)
onDestroy() Fragment 销毁时 释放非视图资源(如后台线程)
onDetach() Fragment 与 Activity 解绑时 清除 Activity 引用,避免内存泄漏
Fragment 管理器
 
supportFragmentManager
支架片段管理器
getSupportFragmentManager()
parentFragmentManager
父片段管理器
.beginTransaction()
从 FragmentManager 获取 FragmentTransaction 实例
.popBackStack()
子主题
childFragmentManager
子片段管理器
布局
在activity_main.xml设置
常见布局
LinearLayout(线性布局)
:按水平或垂直顺序排列子视图。
android:orientation="vertical"
表示LinearLayout的布局方向为垂直方向
horizontal布局方向为水平方向
android:layout_marginTop="8dp"
设置视图顶部与其父容器或相邻视图的间距为8dp
android:layout_marginBottom="16dp"
设置视图底部与其父容器或相邻视图的间距为16dp
TableLayout(表格布局)
:通过行和列组织子视图,类似表格。
FrameLayout(帧布局)
:堆叠子视图,后添加的视图覆盖前面的。
RelativeLayout(相对布局)
:子视图相对于父视图或其他子视图排列。
ConstraintLayout(约束布局)
:通过设置约束控制视图位置和大小,适用于复杂布局。
布局属性
android:layout_marginStart="8dp"
组件到左侧组件的距离
android:layout_marginEnd="8dp"
组件到右侧组件的距离
android:layout_marginTop="8dp"
组件到上方组件的距离
android:layout_marginBottom="8dp"
组件到下方组件的距离
app:layout_constraintStart_toStartOf="parent"
水平:左侧贴齐
parent为父容器
app:layout_constraintEnd_toEndOf="parent"
水平:右侧贴齐
app:layout_constraintTop_toTopOf="@+id/tvTitle"
垂直:与目标顶侧贴齐
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
垂直:与目标底侧贴齐
app:layout_constraintBaseline_toBaselineOf="@+id/etName"
文本基线与目标视图的文本基线对齐(常用于 TextView 或包含文本的视图)
app:layout_constraintHorizontal_chainStyle="spread"
控制水平链条(chain) 中多个视图的分布方式
spread(默认):视图均匀分布,占用所有可用空间 spread_inside:两端视图贴边,中间视图均匀分布 packed:所有视图打包在一起(可通过bias调整整体位置)
根布局
在Android开发中,焦点(Focus)是指用户界面组件在交互时能够接收到用户输入的能力。
<androidx.constraintlayout.widget.
Barrier(屏障)
:虚拟边界,用于对多个控件进行对齐,不显示在界面中。
ConstraintLayout(约束布局)
:强大的布局类,灵活定义视图的相对位置和大小。
Constraints(约束)
:视图相对于其他视图的布局规则。
Group(组)
:将多个视图组合管理,可同时进行隐藏、显示等操作。
Guideline(指导线)
<androidx.constraintlayout.widget.Guideline android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_begin="115dp" />
:虚拟线条,用于帮助视图对齐,不显示在界面中。
属性
android:orientation="vertical"
参考线方向
垂直:vertical
水平:horizontal(默认)
app:layout_constraintGuide_begin="115dp"
距离起始边的边距(左/上)
app:layout_constraintGuide_end="115dp"
距离结束边的边距(右/下)
app:layout_constraintGuide_percent="0.5"
百分比定位
0.5为50%正中间
Placeholder(占位符)
:运行时替换视图的控件,用于动态布局更新。
ReactiveGuide(响应式指导线)
:动态调整的指导线,能根据条件改变布局。
布局属性
xmlns:android="http://schemas.android.com/apk/res/android"
:声明 Android XML 命名空间。
xmlns:app="http://schemas.android.com/apk/res-auto"
:声明自定义属性命名空间。
xmlns:tools="http://schemas.android.com/tools"
:声明开发工具使用的命名空间。
android:id="@+id/main"
:为视图定义唯一标识符。
android:layout_width="match_parent"
:设置视图宽度为充满父容器。
android:layout_height="match_parent"
:设置视图高度为充满父容器。
tools:context=".MainActivity"
:指定工具预览时的上下文为 MainActivity。
视图
Text - 文本
TextView - 文本视图
文字颜色
android:textColor="#00ff00"
或者在color.xml资源中设置后导入
阴影
android:shadowColor:设置阴影颜色,需要与shadowRadius一起使用
android:shadowRadius:设置阴影的模糊程度,设为0.1就变成字体颜色了,建议使用3.0
android:shadowDx:设置阴影在水平方向的偏移,就是水平方向阴影开始的横坐标位置
android:sh自dowDy:设置阴影在竖直方向的偏移,就是竖直方向阴影开始的纵坐标位置
跑马灯效果
android:singleLine:内容单行显示
android:focusable:是否可以获取焦点
android:focusableInTouchMode:用于控制视图在触摸模式下是否可以聚焦
android:singleLine文本是否单行显示
android:ellipsize:在哪里省略文本
值为marquee时跑马灯
android:margueeRepeatLimit:字幕动画重复的次数
修改注释掉MainActivity文件内容
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) // ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> // val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) // v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) // insets // } } }
修改res/layout/activity_main.xml内容
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="200dp" android:gravity="center_vertical" android:shadowColor="@color/red" android:shadowDx="10.0" android:shadowDy="10.0" android:shadowRadius="3.0" android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit="marquee_forever" android:focusable="true" android:focusableInTouchMode="true" android:clickable="true" android:text="@string/abc" android:textColor="@color/black" android:textSize="30sp" android:textStyle="italic" /> </LinearLayout>
在组件视图内最后添加<requestFocus />可
EditText - 文本输入
<EditText android:id="@+id/etInput" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="24dp" android:background="#ffffff" android:inputType="text" />
属性
inputType
值
基础类型:
none
: 无输入类型。
text
: 普通文本输入。
文本修饰:
textCapCharacters
: 全部字母大写。
textCapWords
: 每个单词首字母大写。
textCapSentences
: 每句首字母大写。
textAutoCorrect
: 自动纠正。
textAutoComplete
: 自动完成。
textMultiLine
: 多行输入。
textNoSuggestions
: 禁用建议。
特定文本类型:
textUri
: URI 输入。
textEmailAddress
: 电子邮件地址。
textPassword
: 密码输入(隐藏)。
textVisiblePassword
: 可见密码。
数字类型:
number
: 数字输入。
numberSigned
: 带符号的数字。
numberDecimal
: 小数输入。
电话和日期时间:
phone
: 电话号码输入。
date
: 日期输入。
time
: 时间输入。
Plain Text - 普通文本
Password - 密码
Password (Numeric) - 数字密码
E-mail - 电子邮件
Phone - 电话
Postal Address - 邮寄地址
Multiline Text - 多行文本
Time - 时间
Date - 日期
Number - 数字
Number (Signed) - 有符号数字
Number (Decimal) - 小数
AutoCompleteTextView - 自动完成文本视图
MultiAutoCompleteTextView - 多自动完成文本视图
CheckedTextView - 带选中的文本视图
TextInputLayout - 文本输入布局
Buttons - 按钮
Button - 按钮
在按钮前添加图标
android:drawableLeft="@android:drawable/ic_menu_send"
添加点击事件
android:onClick="onBackButtonClick"
调用
fun onBackButtonClick(view: View) { finish() }
finish()为关闭当前界面
ImageButton - 图片按钮
ChipGroup - 标签组
Chip - 标签
CheckBox - 复选框
RadioGroup - 单选组
RadioButton - 单选按钮
ToggleButton - 切换按钮
Switch - 开关
FloatingActionButton - 悬浮操作按钮
属性
state_focused 控件是否获得焦点,焦点是指控件可以接收输入的状态。
state_pressed 控件是否被按下,通常用于按钮或可点击的控件。
state_enabled 控件是否可用,当控件不可用时(例如禁用状态),将无法交互。
state_selected 控件是否被选择,通常用于滚轮或列表中的项目。
state_checked 控件是否被勾选,常用于CheckBox、RadioButton等勾选控件。
state_checkable 控件是否可以被勾选,表示控件是否支持勾选状态。
state_window_focused 控件是否获得窗口焦点,表示窗口中控件是否是当前活动窗口的一部分。
state_active 控件是否处于活动状态,例如用于SlidingTab的活动状态指示。
state_single 当控件包含多个子控件时,表示是否只显示一个子控件。
state_first 当控件包含多个子控件时,表示第一个子控件是否处于显示状态。
state_middle 当控件包含多个子控件时,表示中间一个子控件是否处于显示状态。
state_last 当控件包含多个子控件时,表示最后一个子控件是否处于显示状态。
state_focused:文本框获得焦点以供用户输入时。
state_pressed:按钮被按下或点击时的视觉反馈。
state_enabled:控件是否可操作,如启用或禁用的按钮。
state_checked:CheckBox或RadioButton是否被勾选的状态。
state_selected:用于显示选择中的列表项或滚轮上的当前项。
state_window_focused:用于窗口内的控件是否为当前活动窗口的一部分。
Widgets - 小部件
View - 视图
ImageView - 图片视图
WebView - 网页视图
VideoView - 视频视图
CalendarView - 日历视图
Text Clock - 文本时钟
ProgressBar - 进度条
ProgressBar (Horizontal) - 水平进度条
SeekBar - 拖动条
SeekBar (Discrete) - 离散拖动条
RatingBar - 评分条
SearchView - 搜索视图
TextureView - 纹理视图
SurfaceView - 表面视图
Horizontal Divider - 水平分隔线
Vertical Divider - 垂直分隔线
Layouts - 布局
ConstraintLayout - 约束布局
LinearLayout (horizontal) - 线性布局(水平)
LinearLayout (vertical) - 线性布局(垂直)
FrameLayout - 帧布局
TableLayout - 表格布局
TableRow - 表格行
Space - 空白
Containers - 容器
Spinner - 下拉框
可以在strings.xml内追加文字列
<string-array name="命名"> <item>内容1</item> <item>内容2</item> <item>内容3</item> </string-array>
然后在activity_main.xml内调用
android:entries="@array/命名"
RecyclerView - 可回收列表视图
ScrollView - 滚动视图
HorizontalScrollView - 水平滚动视图
NestedScrollView - 嵌套滚动视图
ViewPager2 - 视图分页器2
CardView - 卡片视图
AppBarLayout - 应用栏布局
BottomAppBar - 底部应用栏
NavigationView - 导航视图
BottomNavigationView - 底部导航视图
Toolbar - 工具栏
MaterialToolbar - 材料工具栏
TabLayout - 标签布局
TabItem - 标签项
ViewStub - 视图存根
ViewAnimator - 视图动画器
ViewSwitcher - 视图切换器
<include> - 包含布局
FragmentContainerView - 片段容器视图
NavHostFragment - 导航主机片段
<view> - 自定义视图
<requestFocus> - 请求焦点
Helpers - 辅助
Group - 组
Barrier (Horizontal) - 水平屏障
Barrier (Vertical) - 垂直屏障
Flow - 流布局
Guideline (Horizontal) - 水平指南
Guideline (Vertical) - 垂直指南
Layer - 层
ImageFilterView - 图片过滤视图
ImageFilterButton - 图片过滤按钮
MockView - 模拟视图
Google - 谷歌
AdView - 广告视图
MapView - 地图视图
Legacy - 旧版
GridLayout - 网格布局
ListView - 列表视图
TabHost - 标签主机
RelativeLayout - 相对布局
GridView - 网格视图
通用属性android:
layout_width和layout_height是必须属性
layout_width
:组件的宽度。
值
match_parent
:视图与父容器大小匹配,完全填充父容器。
wrap_content
:视图根据内容大小自动调整。
200dp
单位 类型 参考基准 主要用途 特点
dp 相对单位 屏幕物理密度 Android UI元素尺寸 保证不同密度屏幕上元素物理尺寸一致(160dpi屏上1dp=1px)
sp 相对单位 屏幕密度 + 用户字体设置 Android 文字大小 继承dp特性,同时随用户系统字体缩放设置变化
px 绝对单位 屏幕物理像素点 基础像素单位 直接对应屏幕像素点,不同密度屏幕显示物理尺寸差异大
pt 绝对单位 物理长度(1/72英寸) 印刷/跨平台设计 固定物理尺寸,高密度屏需更多像素渲染,移动端少用
in 绝对单位 物理英寸 物理尺寸参考 固定物理尺寸(400in≈10.16米),屏幕上几乎不可能完整显示
mm 绝对单位 物理毫米 物理尺寸参考 固定物理尺寸(400mm=40厘米),屏幕上显示依赖设备DPI
layout_height
:组件的高度。
id
:为TextView设置一个组件的 ID。
text
:设置显示的文本内容。
textColor
:设置文本的颜色。
textStyle
:设置字体风格,有三个可选值:
normal
(正常)、
bold
(加粗)、
italic
(斜体)。
textSize
:设置字体大小,单位通常是sp
background
:设置控件的背景颜色,可以是纯色或图片。
gravity
:设置控件内容的对齐方式,如TextView中是文字对齐,ImageView中是图片对齐。
值
top :将对象推到容器的顶部,不改变对象的大小。
bottom:将对象推到容器的底部,不改变对象的大小。
left :将对象推到容器的左侧,不改变对象的大小。
right :将对象推到容器的右侧,不改变对象的大小。
center_vertical :将对象在容器的垂直方向居中,不改变对象的大小。
fill_vertical :根据需要增大对象的垂直尺寸,使其完全填充容器。
center_horizontal :将对象在容器的水平方向居中,不改变对象的大小。
fill_horizontal :根据需要增大对象的水平尺寸,使其完全填充容器。
center :将对象在容器的垂直和水平方向同时居中,不改变对象的大小。
fill :根据需要增大对象的水平和垂直尺寸,使其完全填充容器。
可以调用app\src\main\res\values\文件内定义的内容
 
重要类
onCreate
启动程序后最先执行的类,将需要初期化的类写入其中
AppCompatActivity
所有事件的父类
R
用于调用res中的资源
View.OnClickListener
用于监听,包含onClick类
findViewById
findViewById<组件名>(R.id.组件id)
用于根据视图ID查找并返回对应视图对象
setOnClickListener
用于设置视图(如按钮、图片等)点击事件监听的方法
SQLite
创建一个继承自 SQLiteOpenHelper 的类
SQLiteOpenHelper
class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { //其他代码 }
参数
context Context 上下文对象,通常是 Activity 或 Application 的实例。
name String? 数据库名称(例如:"mydatabase.db")。设为 null 表示创建内存数据库(不保存到文件)。
factory SQLiteDatabase.CursorFactory? 可选,通常为 null,表示使用默认的游标工厂。可以自定义查询返回的 Cursor 行为。
version Int 数据库版本号,必须为正整数。用于控制 onUpgrade() 是否执行。
实现 onCreate() 和 onUpgrade() 方法
onCreate()
override fun onCreate(db: SQLiteDatabase) { // SQL语句创建书籍表 val createTableQuery = """ CREATE TABLE $TABLE_BOOKS ( $COLUMN_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COLUMN_TITLE TEXT NOT NULL, $COLUMN_AUTHOR TEXT NOT NULL, $COLUMN_YEAR INTEGER NOT NULL ) """.trimIndent() db.execSQL(createTableQuery) // 执行SQL语句 }
创建数据库时调用
onUpgrade()
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { db.execSQL("DROP TABLE IF EXISTS $TABLE_BOOKS") // 如果表存在则删除 onCreate(db) // 重新创建表 }
数据库升级时调用
实现增删改查(CRUD)方法
在增删改查方法中调用
// 插入书籍数据 fun insertBook(book: Book): Long { val db = writableDatabase // 获取可写数据库实例 val values = ContentValues().apply { // 创建ContentValues对象 put(COLUMN_TITLE, book.title) // 添加书名 put(COLUMN_AUTHOR, book.author) // 添加作者 put(COLUMN_YEAR, book.publicationYear) // 添加出版年份 } return db.insert(TABLE_BOOKS, null, values) // 插入数据并返回行ID }
writableDatabase
获取可写数据库实例
readableDatabase
获取可读数据库实例
使用这个数据库类在 Activity 或 ViewModel 中访问数据
// 活动创建时调用的方法 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 设置界面布局文件 setContentView(R.layout.activity_main) // 初始化数据库帮助类 dbHelper = DatabaseHelper(this) // 获取所有书籍并转换为可变列表 bookList = dbHelper.getAllBooks().toMutableList() ///////////////////////////// }
连接网络

使用现代推荐的 OkHttp 库
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- 添加这一行 --> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Networkdemo" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
<uses-permission android:name="android.permission.INTERNET" />
build.gradle(:app) 中添加以下依赖
dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) implementation(libs.material) implementation(libs.androidx.activity) implementation(libs.androidx.constraintlayout) implementation("com.squareup.okhttp3:okhttp:4.12.0") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) }
implementation("com.squareup.okhttp3:okhttp:4.12.0")
实例
获取一个 Todo 的 JSON 数据 https://jsonplaceholder.typicode.com/todos/1
构建一个 GET 请求对象
Request.Builder() .url("链接地址") .build()
使用 OkHttpClient 方法发起异步请求
// 创建一个 OkHttpClient 实例,用于发起网络请求 private val client = OkHttpClient() client.newCall(GET请求对象).enqueue(object : Callback { //其他代码 }
其他类
Toast
轻量级的消息提示工具,通过短暂地在屏幕上显示一段文本,向用户提供提示信息。
makeText()
在屏幕上显示短暂消息
参数
Toast.makeText(context, text, Toast.LENGTH_LONG).show() 例: Toast.makeText(this@MainActivity, show, Toast.LENGTH_LONG).show()
context
上下文,通常是当前Activity的引用。比如this@MainActivity
text
text:要显示的文本消息。
Toast.
显示时长
LENGTH_SHORT
短时间显示
LENGTH_LONG
长时间显示
mutableListOf
mutableListOf("から揚げ定食", "ハンバーグ定食",....,"焼き魚定食", "焼肉定食")
可变列表
DialogFragment
对话框类
Bundle?
保存状态数据
Dialog
对话类
activity?.let
判断当前上下文中的 activity 是否为 null。
onCreateDialog
创建和管理对话框的关键生命周期方法
AlertDialog
Builder
用于构建对话框的核心类
基础设置
方法名
参数说明
功能描述
setTitle(int titleId)
资源 ID
设置对话框标题(字符串资源)
setTitle(CharSequence title)
字符序列
设置对话框标题(字符串)
setMessage(int messageId)
资源 ID
设置对话框正文内容(字符串资源)
setMessage(CharSequence message)
字符序列
设置对话框正文内容(字符串)
setIcon(int iconId)
图标资源 ID
设置对话框图标
setIcon(Drawable icon)
Drawable 对象
设置对话框图标
列表与单选/多选项
setItems(int itemsId, DialogInterface.OnClickListener listener)
数组资源 ID、点击监听器
设置普通列表项
setItems(CharSequence[] items, DialogInterface.OnClickListener listener)
字符串数组、点击监听器
设置普通列表项
setSingleChoiceItems(int itemsId, int checkedItem, DialogInterface.OnClickListener listener)
数组资源 ID、默认选中项索引、点击监听器
设置单选列表
setSingleChoiceItems(Cursor cursor, int isCheckedIndex, String labelColumn, DialogInterface.OnClickListener listener)
游标、是否选中标记列、显示列名、点击监听器
从数据库设置单选列表
setMultiChoiceItems(int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)
数组资源 ID、默认选中状态数组、多选监听器
设置多选列表
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)
字符串数组、默认选中状态数组、多选监听器
设置多选列表
自定义视图
setView(View view)
自定义 View
设置自定义视图作为对话框内容
setView(int layoutResId)
布局资源 ID
设置自定义布局文件作为对话框内容
按钮设置
setPositiveButton(int textId, DialogInterface.OnClickListener listener)
文本资源 ID、点击监听器
设置积极按钮(如“确定”)
setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener)
文本、点击监听器
设置积极按钮
setNegativeButton(int textId, DialogInterface.OnClickListener listener)
文本资源 ID、点击监听器
设置消极按钮(如“取消”)
setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener)
文本、点击监听器
设置消极按钮
setNeutralButton(int textId, DialogInterface.OnClickListener listener)
文本资源 ID、点击监听器
设置中性按钮(如“稍后”)
setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener)
文本、点击监听器
设置中性按钮
其他设置
setCancelable(boolean cancelable)
是否可取消
设置对话框是否可以通过返回键或点击外部取消
setOnCancelListener(DialogInterface.OnCancelListener listener)
取消监听器
设置对话框被取消时的回调
setOnDismissListener(DialogInterface.OnDismissListener listener)
关闭监听器
设置对话框关闭时的回调
setOnKeyListener(DialogInterface.OnKeyListener onKeyListener)
键盘事件监听器
设置按键监听器,处理键盘事件
create()
无
创建并返回一个 AlertDialog 实例
show()
无
创建并直接显示对话框
其他
Adapter
适配器,是连接后端数据与前端视图的接口,是数据与视图之间交互的中介
BaseAdapter
用于自定义适配器,数据源由用户决定,使用时会被继承并重写方法,最常用也是最灵活的一个adapter
ArrayAdapter
ArrayAdapter(Context,@LayoutRes,Object) ArrayAdapter(this@MainActivity, android.R.layout.simple_list_item_1, menuList)
最简单的适配器,数据源为文本字符,只能显示一行文本;
属性
第一个参数:context上下文对象
第二个参数
每一个item的样式,可以使用系统提供,也可以自定义就是一个TextView
基本列表项布局
simple_list_item_1 - 单行文本列表项
simple_list_item_2 - 双行文本列表项(标题+副标题)
simple_list_item_checked - 带复选框的列表项
simple_selectable_list_item - 可选择的列表项
选择状态列表项
simple_list_item_activated_1 - 单行激活状态列表项
simple_list_item_activated_2 - 双行激活状态列表项
simple_list_item_multiple_choice - 多选列表项
simple_list_item_single_choice - 单选列表项
可展开列表项
simple_expandable_list_item_1 - 单行可展开列表项
simple_expandable_list_item_2 - 双行可展开列表项
expandable_list_content - 可展开列表内容布局
下拉菜单布局
simple_spinner_item - 下拉框主显示项
simple_spinner_dropdown_item - 下拉框下拉列表项
simple_dropdown_item_1line - 单行下拉项
对话框布局
select_dialog_item - 对话框选择项
select_dialog_singlechoice - 对话框单选项
select_dialog_multichoice - 对话框多选项
其他布局
activity_list_item - Activity列表项
preference_category - 设置分类项
simple_gallery_item - 画廊视图项
two_line_list_item - 两行列表项
list_content - 列表内容布局
browser_link_context_header - 浏览器链接上下文头部
test_list_item - 测试用列表项
第三个参数:数据源,要显示的数据
SimpleAdapter
简单适配器,数据源结构比较复杂,一般为List<Map>类型对象;
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, @LayoutRes int resource, String[] from, @IdRes int[] to)
Context context
应用程序上下文
List<? extends Map<String, ?>> data
数据源(核心参数)
@LayoutRes int resource
列表项布局资源 ID
示例:R.layout.list_item
String[] from
数据字段名称数组
示例:val from = arrayOf("name", "price")
@IdRes int[] to
目标视图 ID 数组
示例:val to = intArrayOf(android.R.id.text1, android.R.id.text2)
SimpleCursorAdapter
游标适配器,用于显示简单文本类型的listview,数据源一般为数据库中的数据;
选择适配器
取得画面部品ListVie
val lvMenu = findViewById<ListView>(R.id.lvMenu)
SimpleAdapter生成
val adapter = SimpleAdapter(this@MainActivity, menuList, android.R.layout.simple_list_item_2, from, to)
绑定适配器和监听类
lvMenu.adapter = adapter lvMenu.onItemClickListener = ListItemClickListener()
AdapterView
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // ListViewオブジェクトを取得。 val lvMenu = findViewById<ListView>(R.id.lvMenu) // ListViewにリスナを設定。 lvMenu.onItemClickListener = ListItemClickListener() } /** * リストがタップされたときの処理が記述されたメンバクラス。 */ private inner class ListItemClickListener : AdapterView.OnItemClickListener { override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { // タップされた定食名を取得。 val item = parent.getItemAtPosition(position) as String // トーストで表示する文字列を生成。 val show = "あなたが選んだ定食: $item" // トーストの表示。 Toast.makeText(this@MainActivity, show, Toast.LENGTH_LONG).show() } } }
容器控件,整体由一个个子元素item组成,子元素的内容与数据由Adapter决定。

子视图对象
ListView
以垂直滑动列表形式显示一组数据。
GridView
以网格形式显示一组数据。
Spinner
以下拉列表形式显示一组数据。
监听
OnItemClickListener
用于监听列表视图
onItemClick
onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long)
定义在OnItemClickListener内部,在内部定义事件
参数
parent: AdapterView<*>
触发点击事件的父容器视图,可以获取到完整的列表视图对象
泛型 <*> 或<?>表示可以是任何类型的 Adapter
view: View
被点击的具体视图项即列表中被点击的那一行的 View 对象
通过这个参数访问该项视图中的子控件
position: Int
被点击项在适配器中的位置索引
用来确定用户点击了哪一项
id: Long
被点击项的行 ID
默认情况下等于 position,但可以自定义
getItemAtPosition(position)
ListView 的一个方法,用于获取指定位置的列表项数据。(position),返回该位置上的数据对象
setOnItemClickListener
DialogInterface
OnClickListener
数据传递
两个Activity之前传递数据
Intent传递数据

传递简单数据
Intent it1 = new Intent(A.this, B.class); it1.putExtra("key", value); startActivity(it1);
val intent2MenuThanks = Intent(this@MainActivity, MenuThanksActivity::class.java) // 第2画面に送るデータを格納。 intent2MenuThanks.putExtra("menuName", menuName) intent2MenuThanks.putExtra("menuPrice", menuPrice) startActivity(intent2MenuThanks)
获取简单数据
Intent it2 = getIntent(); getString("key"); // 不同类型数据用对应的String副词~
传递复杂数据
Intent it1 = new Intent(A.this, B.class); Bundle bd = new Bundle(); bd.putInt("num", 1); bd.putString("detail", "问题"); it1.putExtra(bd); startActivity(it1);
获取复杂(Bundle)数据
Intent it2 = getIntent(); Bundle bd = it2.getExtras(); int n = bd.getInt("num"); String d = bd.getString("detail");
Intent传递数组
写入数组
bd.putStringArray("StringArray", new String[]{"呵呵","哈哈"}); //可把StringArray换成其他数据类型,比如int,float等等...
读取数组
String[] str = bd.getStringArray("StringArray")
Intent传递集合
List<基本数据类型或String>
写入集合
intent.putStringArrayListExtra(name, value) intent.putIntegerArrayListExtra(name, value)
读取集合
intent.getStringArrayListExtra(name) intent.getIntegerArrayListExtra(name)
List< Object>
将list强转成Serializable类型,然后传入(可用Bundle做媒介)
写入集合
putExtras(key, (Serializable)list)
读取集合
(List<Object>) getIntent().getSerializable(key)
Map<String, Object>,或更复杂的
解决方法是:外层套个List
//传递复杂些的参数 Map<String, Object> map1 = new HashMap<String, Object>(); map1.put("key1", "value1"); map1.put("key2", "value2"); List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); list.add(map1); Intent intent = new Intent(); intent.setClass(MainActivity.this,ComplexActivity.class); Bundle bundle = new Bundle(); //须定义一个list用于在budnle中传递需要传递的ArrayList<Object>,这个是必须要的 ArrayList bundlelist = new ArrayList(); bundlelist.add(list); bundle.putParcelableArrayList("list",bundlelist); intent.putExtras(bundle); startActivity(intent);
Intent传递对象
将对象转换为Json字符串
Gson解析的例子
Model:
public class Book{ private int id; private String title; //... } public class Author{ private int id; private String name; //... }
写入数据:
Book book=new Book(); book.setTitle("Java编程思想"); Author author=new Author(); author.setId(1); author.setName("Bruce Eckel"); book.setAuthor(author); Intent intent=new Intent(this,SecondActivity.class); intent.putExtra("book",new Gson().toJson(book)); startActivity(intent);
读取数据:
String bookJson=getIntent().getStringExtra("book"); Book book=new Gson().fromJson(bookJson,Book.class); Log.d(TAG,"book title->"+book.getTitle()); Log.d(TAG,"book author name->"+book.getAuthor().getName());
使用Serializable,Parcelable序列化对象
Intent传递Bitmap
bitmap默认实现Parcelable接口,直接传递即可
Bitmap bitmap = null; Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putParcelable("bitmap", bitmap); intent.putExtra("bundle", bundle);
启动另一个Activity在原本的Activity之上
startActivity()
val menuName = item["name"] val menuPrice = item["price"] val intent2MenuThanks = Intent(this@MainActivity, MenuThanksActivity::class.java) intent2MenuThanks.putExtra("menuName", menuName) intent2MenuThanks.putExtra("menuPrice", menuPrice) startActivity(intent2MenuThanks)
生成Intent对象
val 变数名= Intent(当前Activity, 目标Activity::class.java)
存入需要发送给目标Activity的数据
变数名.putExtra("数据名", 数据值)
启动目标画面
startActivity(变数名)
列表
可变列表
MutableList
定义可变列表
有数据
val mutableList = mutableListOf(1, 2, 3)
空
val menuList: MutableList<MutableMap<String, String>> = mutableListOf()
定义数据
var menu = mutableMapOf("name" to "から揚げ定食", "price" to "800円")
将数据添加到可变列表
menuList.add(menu)
可变映射
MutableMap
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
动作栏
菜单
创建menu资源文件夹
 
创建资源文件

新建资源文件内部
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> </menu>
在内部添加菜单内容
 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menuListOptionTeishoku" app:showAsAction="never" android:title="@string/menu_list_options_teishoku"/> <item android:id="@+id/menuListOptionCurry" app:showAsAction="never" android:title="@string/menu_list_options_curry"/> </menu>
属性
android:id
app:showAsAction
never
折叠菜单内
always
显示在动作栏

ifRoom
在动作栏显示,空间不够时显示在折叠列表内
android:title
使用menu
AppCompatActivity类添加
override fun onCreateOptionsMenu(menu: Menu): Boolean { // 加载菜单布局文件 menuInflater.inflate(R.menu.菜单xml文件名, menu) // 表示经功加载了菜单项,系统应该显示这个菜单。 return true }
主题
将res/values/themes.xml改为使用可以添加菜单的主题
<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="Base.Theme.MyTest" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <!-- Customize your light theme here. --> <!-- <item name="colorPrimary">@color/my_light_primary</item> --> </style> <style name="Theme.MyTest" parent="Base.Theme.MyTest" /> </resources>
环境菜单

AppCompatActivity类添加
override fun onCreateContextMenu( menu: ContextMenu, view: View, menuInfo: ContextMenu.ContextMenuInfo ) { super.onCreateContextMenu(menu, view, menuInfo) // 加载上下文菜单布局 menuInflater.inflate(R.menu.菜单xml文件名, menu) // 设置上下文菜单标题 menu.setHeaderTitle(R.string.menu_list_context_header) }
在AppCompatActivity类中onCreate方法中添加
// 获取ListView组件 val lvMenu = findViewById<ListView>(R.id.lvMenu) // 为ListView注册上下文菜单(长按弹出菜单) registerForContextMenu(lvMenu)
返回按钮

在onCreate方法中添加
supportActionBar?.setDisplayHomeAsUpEnabled(true)
Log等级
public override fun onStart() { Log.i("LifeCycleSample", "Sub onStart() called.") super.onStart() } Log.i("标签", "输出信息")
VERBOSE:最低级别,用于详细的调试信息。
v()
Log.v("标签", "输出信息")
DEBUG:用于调试信息,通常在开发过程中使用。
d()
INFO:用于普通信息,例如应用程序的运行状态。
i()
WARNING:用于警告信息,表明潜在的问题。
w()
ERROR:用于错误信息,表示应用程序或系统发生了错误。
e()
Assert/FATAL:用于表示严重的错误,通常伴随应用程序崩溃。
wtf()
使用方法
在Logcat中检索level:error
实例
界面跳转
创建新界面时
在res/layout内创建新xml文件
例activity_main2.xml
准备内容例如
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="欢迎来到第二个页面!" /> </LinearLayout>
在MainActivity同级目录创建新的类
例Main2Activity
准备内容例如
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class Main2Activity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); } }
设定视图界面
setContentView(R.layout.xml文件名);
替换内容
通过findViewById
findViewById<组件名>(R.id.组件id)
用于根据视图ID查找并返回对应视图对象
组件名 变量名 = findViewById(R.id.组件id); 变量名.设定组件内容方法
例
替换视图文字组件的文字内容
TextView tv_hello = findViewById(R.id.tv_hello); // 设置TextView控件的文字内容 tv_hello.setText("你好,世界");
事件和监听

activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 『Androidアプリ開発の教科書Kotlin』 第4章 イベントとリスナサンプル @author Shinzo SAITO ファイル名=activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/tv_name"/> <EditText android:id="@+id/etName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:inputType="textPersonName"/> <Button android:id="@+id/btClick" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/bt_click"/> <Button android:id="@+id/btClear" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/bt_clear"/> <TextView android:id="@+id/tvOutput" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="" android:textSize="25sp"/> </LinearLayout>
strings.xml
<!-- 『Androidアプリ開発の教科書Kotlin』 第4章 イベントとリスナサンプル @author Shinzo SAITO res/values/string.xmlファイル --> <resources> <string name="app_name">イベントとリスナサンプル</string> <string name="tv_name">お名前を入力してください。</string> <string name="bt_click">表示</string> <string name="bt_clear">クリア</string> </resources>
MainActivity.kt
package com.websarva.wings.android.hellosample import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Button import android.widget.EditText import android.widget.TextView /** * 『Androidアプリ開発の教科書Kotlin』 * 第4章 * イベントとリスナサンプル * * メインアクティビティクラス。 * * @author Shinzo SAITO */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 表示ボタンであるButtonオブジェクトを取得。 val btClick = findViewById<Button>(R.id.btClick) // リスナクラスのインスタンスを生成。 val listener = HelloListener() // 表示ボタンにリスナを設定。 btClick.setOnClickListener(listener) // クリアボタンであるButtonオブジェクトを取得。 val btClear = findViewById<Button>(R.id.btClear) // クリアボタンにリスナを設定。 btClear.setOnClickListener(listener) } /** * ボタンをクリックしたときのリスナクラス。 */ private inner class HelloListener : View.OnClickListener { override fun onClick(view: View) { // 名前入力欄であるEditTextオブジェクトを取得。 val input = findViewById<EditText>(R.id.etName) // メッセージを表示するTextViewオブジェクトを取得。 val output = findViewById<TextView>(R.id.tvOutput) // idのR値に応じて処理を分岐。 when(view.id) { // 表示ボタンの場合… R.id.btClick -> { // 入力された名前文字列を取得。 val inputStr = input.text.toString() // メッセージを表示。 output.text = inputStr + "さん、こんにちは!" } // クリアボタンの場合… R.id.btClear -> { // 名前入力欄を空文字に設定。 input.setText("") // メッセージ表示欄を空文字に設定。 output.text = "" } } } } }
对话框

activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/lvMenu" android:layout_width="match_parent" android:layout_height="match_parent"/>
OrderConfirmDialogFragment.kt
package com.websarva.wings.android.listviewsample2 import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment /** * 《Android应用开发教材Kotlin》 * 第5章 * 列表选择示例2 * * 对话框类。 * * @author Shinzo SAITO */ class OrderConfirmDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { // 如果Activity不为null,则创建对话框对象。 val dialog = activity?.let { val builder = AlertDialog.Builder(it) // 设置对话框标题。 builder.setTitle(R.string.dialog_title) // 设置对话框消息内容。 builder.setMessage(R.string.dialog_msg) // 设置“确定”按钮。 builder.setPositiveButton(R.string.dialog_btn_ok, DialogButtonClickListener()) // 设置“取消”按钮。 builder.setNegativeButton(R.string.dialog_btn_ng, DialogButtonClickListener()) // 设置“中立”按钮。 builder.setNeutralButton(R.string.dialog_btn_nu, DialogButtonClickListener()) // 创建对话框对象。 builder.create() } // 返回创建好的对话框对象,如果activity为null则抛出异常。 return dialog ?: throw IllegalStateException("Activity不能为空") } /** * 成员类,用于描述点击对话框按钮时的处理逻辑。 */ private inner class DialogButtonClickListener : DialogInterface.OnClickListener { override fun onClick(dialog: DialogInterface, which: Int) { // 准备用于Toast显示的消息字符串。 var msg = "" // 根据点击的按钮进行判断。 when (which) { // 如果是“确定”按钮... DialogInterface.BUTTON_POSITIVE -> // 设置订单确认的消息。 msg = getString(R.string.dialog_ok_toast) // 如果是“取消”按钮... DialogInterface.BUTTON_NEGATIVE -> // 设置取消订单的消息。 msg = getString(R.string.dialog_ng_toast) // 如果是“中立”按钮... DialogInterface.BUTTON_NEUTRAL -> // 设置需要进一步询问的消息。 msg = getString(R.string.dialog_nu_toast) } // 显示Toast提示信息。 Toast.makeText(activity, msg, Toast.LENGTH_LONG).show() } } }
strings.xml
<!-- 《Android应用开发教材Kotlin》 第5章 列表选择示例2 @author Shinzo SAITO res/values/strings.xml 文件 --> <resources> <string name="app_name">列表选择示例2</string> <string name="dialog_title">订单确认</string> <string name="dialog_msg">您选中的套餐将被下单。确定继续吗?</string> <string name="dialog_btn_ok">下单</string> <string name="dialog_btn_ng">取消</string> <string name="dialog_btn_nu">咨询</string> <string name="dialog_ok_toast">感谢您的订单。</string> <string name="dialog_ng_toast">已取消您的订单。</string> <string name="dialog_nu_toast">请告知我们的客服人员相关问题。</string> </resources>
MainActivity.kt
package com.websarva.wings.android.listviewsample2 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.ListView /** * 《Android应用开发教材Kotlin》 * 第5章 * 列表选择示例2 * * 主活动类。 * * @author Shinzo SAITO */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取ListView对象。 val lvMenu = findViewById<ListView>(R.id.lvMenu) // 创建要在列表视图中显示的列表数据。 var menuList = mutableListOf("炸鸡定食", "汉堡定食", "姜烧定食", "牛排定食", "蔬菜炒定食", "炸猪排定食", "肉饼炸定食", "鸡肉炸定食", "可乐饼定食", "回锅肉定食", "麻婆豆腐定食", "青椒肉丝定食", "八宝菜定食", "醋猪肉定食", "红烧猪肉", "烤串", "烤鱼定食", "烤肉定食") // 创建适配器对象。 val adapter = ArrayAdapter(this@MainActivity, android.R.layout.simple_list_item_1, menuList) // 将适配器对象设置到列表视图中。 lvMenu.adapter = adapter // 设置列表视图的点击监听器。 lvMenu.onItemClickListener = ListItemClickListener() } /** * 成员类,描述当列表被点击时的处理逻辑。 */ private inner class ListItemClickListener : AdapterView.OnItemClickListener { override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { // 创建订单确认对话框片段对象。 val dialogFragment = OrderConfirmDialogFragment() // 显示对话框。 dialogFragment.show(supportFragmentManager, "OrderConfirmDialogFragment") } } }
案例
自适应

MySQLite数据库

错误
无法解析符号
克隆别人项目时会可能出现
使缓存失效并重新构建可以解决

如果还不错可以重启一下编译器