title: 安卓开发
date: 2024-06-22 14:32:32
tags: [安卓,Kotlin]
categories: 安卓
description: 安卓学习
comment: true
AndroidStudio新建项目
项目目录
1. .gradle和.idea
自动生成的文件
2. app
项目中运行的代码资源都放在此文件夹下类似于src。
3. build
包含编译时自动生成的文件
4. gradle
包含了gradle wrapper配置文件
5. .gitignore
版本控制
6. build.gradle
项目全局的gradle构建脚本
7. gradle.properties
全局配置文件
8. gradlew和gradle.bat
用于在命令行界面执行gradle命令,gradlew在Linux或mac,后者运行于Windows
9. helloworld.iml
所有IDEA项目都会生成用于标识项目
10. local.properties
指定本机sdk路径
11. settings.gradle
用于指定项目中所有引用的模块
app目录
androidTest和test都是用来测试的
主要代码都在main里面,Java包中编写,res下放资源相关。图片一般放在res的mipmap的xxhdpi。
查看res目录下资源意义
res/values/strings.xml
<resources>
<string name="app_name">HelloWorld</string>
</resources>
- 在代码中,通过R.string.app_name可以获取该字符串引用
- 在xml中,通过@string/app_name获取该字符串引用
其中string部分可以替换,如果引用图片资源替换成drawable,应用图标换为mipmap,布局文件替换为layout。
build.gradle文件
外层用于全局配置。
app中的build.gradle中,
- plugin用于选择程序模块,Android.library和Android.application,一般选择后者,后者可以直接运行。
- 如果需要使用kotlin需要导入kotlin-android和kotlin-android-extensions插件
- android闭包中千刀的defaultConfig闭包可以对项目细节进行配置:applicationId是每个应用唯一标识(包名),minSdkVersion:指定项目最低兼容安卓版本。targetSdkVersion:指定在这个目标版本上作了充分测试,可以使用这个版本的所有特性。versionCode:指定版本号。versionName:版本名
- buildTypes闭包:release:指定生成的正式版安装文件的配置。minifyEnabled:true表示混淆
- dependencies:指定依赖关系
日志工具掌握
Log工具类
log.v():打印最为琐碎的意义最小的日志信息,对应verbose
级别
log.d():打印一些调试信息,对应debug
log.i():打印一些比较重要的信息,可以帮助分析用户行为,info
log.w():打印警告信息,warn
log.e():打印错误信息,error
级别依次递增
使用Logcat进行日志调试查看,过滤日志。
为什么不用System.out.println?
这个方法除了使用方便,一无是处。比如:日志开关不可控,不能添加日志标签,日志没有级别区分等。
kotlin开发
kotlin变量声明只有var和val,var表示非final,val为final,可以自动识别准确类型。
kotlin中没有基本类型,他将Java中的基本类型首字母大写,成为对象。
永远优先使用val,当val无法满足时,使用var,来保证程序的健壮性和代码规范
函数
fun关键字来声明,后面跟函数名,括号中填写需要的参数以及类型(可以不填),如果不需要返回值类型就不写。
fun largeNumber(num1: Int, num2: Int): Int{
return max(num1, num2)
}
kotlin语法糖1:当函数中只有一行代码时,允许不必编写函数体,直接将唯一一行代码写在尾部,中间用等号链接。比如上面的函数:
fun largeNumber(num1: Int, num2: Int): Int = max(num1, num2)
//由于kotlin的类型推导机制,可以省略注明返回的Int
fun largeNumber(num1: Int, num2: Int) = max(num1, num2)
程序逻辑控制
if条件语句
if和when
if
fun largeNumber(num1: Int, num2: Int): Int{
var value = 0
if(num1 > num2){
value = num1
}else {
value = num2
}
return value
}
和Java中的不同之处:
if可以有返回值,返回值为每个if语句块中最后一行的返回值
fun largeNumber(num1: Int, num2: Int): Int{
val value = if(num1 > num2){
num1
}else {
num2
}
return value
}
//value冗余,精简
fun largeNumber(num1: Int, num2: Int): Int{
return if(num1 > num2){
num1
}else {
num2
}
}
//根据语法糖,继续精简
fun largeNumber(num1: Int, num2: Int): Int = if(num1 > num2){
num1
}else {
num2
}
}
//继续
fun largeNumber(num1: Int, num2: Int): Int = if(num1 > num2) num1 else num2
}
when条件语句
类似于Java的switch
fun getScore(name: String) = if (name == "Tom"){
86
}else if(name == "Jim"){
77
}else if(name == "Jack"){
99
}else {
0
}
//通过when可以再精简
fun getScore(name: String) = when(name){
"Tom" -> 86
"Jack" -> 99
"Jim" -> 76
else -> 0
}
除了精确匹配,when还允许类型匹配
fun checkNumber(num: Number){
when(num){
is Int -> println("is Int")
is Double -> println("is Double")
else -> println("not support")
}
}
上述的代码,is关键字相当于Java的instanceof关键字。Number是kotlin的抽象类,Int,Long,Double,Float等与数字相关的都是他的子类,这里就使用类型判断是否为需要的参数。
when的不带参数用法
fun getScore(name: String) = when{
name == "Tom" -> 86
name == "Jack" -> 99
name == "Jim" -> 76
else -> 0
}
kotlin中判断对象是否相等可以直接使用“==”来判断。
用法
所有名字开头为Jhon的都为100
fun getScore(name: String) = when{
name.startsWith("Jhon") -> 100
name == "Tom" -> 86
name == "Jack" -> 99
name == "Jim" -> 76
else -> 0
}
循环语句
while和for
while和Java无二
for
for-i直接被省略了。for-each增强为for-in
val range = 0…10,表示[0,10]: ..
是创建两端闭区间的关键字
for (i in 0..10){
println(i)
}
但很多情况下,双端闭区间却不如单端闭区间好用。下标都是从0开始的,长度为10的数组,下标范围为0到9,因此左闭右开在设计中更加常用。kotlin使用until
关键字创建一个左闭右开区间:
val range = 0 until 10
//[0, 10)
默认情况下for-in循环中,每次执行循环都会在区间范围内递增1(i++效果),如果想跳过其中一些元素,可以使用step关键字:
for(i in 0 until 10 step 2){//i+2
println(i)
}
..
和until
都是创建的升序区间,想要创建降序区间需要downTo
关键字。用法:
for(i in 10 downTo 1){//[10, 1]
println(i)
}
面向对象编程
Class创建一个类
class Person {
var name = ""
var age = 0
fun eat(){
println(name + "is eating. He is "+ age + "years old.")
}
}
创建实例对象
val per = Person()
per.name = "Jack"
per.age = 19
per.eat()
继承和构造函数
新建一个类Student:
class Student {
var sno = ""
var grade = 0
}//显然现在和Person类没有关系
需要Person类被继承,需要
1.是Person类可以被继承:kotlin遵守了“如果一个类不是专门为继承而设计的,那么就应该主动加上final声明,禁止它可以被继承”,所有它默认都不能被继承。
开启方法:加上open关键字
open class Person {
var name = ""
var age = 0
fun eat(){
println(name + "is eating. He is "+ age + "years old.")
}
}
2.让Student类继承Person类,在kotlin中继承关键字变成了冒号:
class Student : Person() {
var sno = ""
var grade = 0
}
为什么要加括号?
涉及到了主构造函数和次构造函数。
kotlin将构造函数分为主构造函数
和次构造函数
:
主构造函数将是最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然也可以显式的指名参数。主构造函数的特点是没有函数体,直接定义在类后面即可:
class Student(val sno: String, val grade: Int) {
} //主构造函数
这里表明,在对Student类实例化的时候,必须传入所有参数。
val s = Student("a123", 5)
主函数中没有函数体,如何在主构造函数中编写逻辑?
kotlin提供了init结构体,所有主函数逻辑在这里编写
class Student(val sno: String, val grade: Int): Person() {
init{
println("sno is" + sno)
}
}
Java继承特性:子类的构造函数必须调用父类的构造函数,kotlin也遵守了,那么回头看,Student类中声明了一个主构造函数,是否需要放入init结构体中执行Person的构造方法?可以放入,但是不是个好方法,大部分情况下我们不需要编写init结构体。 因此通过()来指定。
将父类的属性放入主构造函数,如何继承?
class Student(val sno: String, val grade: Int, name: String, age: Int): Person(name, age) {
//不再用val修饰父类构造函数的变量,因为在子类构造函数中声明val或var的参数将自动成为该类的字段,回到是和父类中同名的字段冲突。
}
当一个类中既有主构造函数又有次构造函数,所有的次构造函数都需要调用主构造函数。
class Student(val sno: String, val grade: Int, name: String, age: Int): Person(name, age) {
constructor(name: String, age: Int): this("", 0, name, age){
//通过this关键字调用了主构造函数,并且对sno和grade赋初值
}
constructor(): this("", 0){
//通过this关键字调用了第一个次构造函数,并且将name,age赋初值,间接调用主构造函数也合法。
}
}
//可以通过这几种进行实例化了
val student = Student()
val student = Student("Jack", 19)
val student = Student("a123", 5, "Jack", 19)
特殊情况:只有次构造函数,没有子构造函数
class Student : Person{
constructor(name: String, age: Int) : super(name, age){
//由于Student没有主构造函数,继承类的时候就不需要()了,但是由于没有主构造函数,次构造函数只能直接通过super调用父类的构造函数
}
}
接口
新建一个Study接口
interface Study {
fun readBooks()
fun doHomeWork()
}
让Student类实现Study接口
class Student(name: String, age: Int) : Person(name, age), Study{
override fun readBooks() {
println(name + "is reading.")
}
override fun doHomeWork() {
println(name + "is doing homework.")
}
}
Study接口中定义的两个待实现函数,Student类必须实现。
当接口的函数有了函数体,就不需要强制实现。
interface Study {
fun readBooks()
//默认实现
fun doHomeWork(){
println("do homework")
}
}
函数可见性修饰符
kotlin中:
public:所有类可见,默认
private:当前类可见
protected:当前类、子类可见
default:无
internal:同一模块中的类可见
数据类和单例类
数据类通常需要重写equals,hashcode,toString方法。在kotlin中,在类前面加data,表示这个类是一个数据类
data class Cellphone(val brand: String, val price: Double)
会根据参数生成这些方法。
main函数中测试
fun main(){
val cellphone = Cellphone("iphone", 9988.0)
val cellphone1 = Cellphone("iphone", 9988.0)
println(cellphone)
println(cellphone == cellphone1)
}
实现单例类
创建类型选择Object
object Singleton {
fun singletonTest(){
println("hello singleton")
}
}
kotlin中,在类前面加data,表示这个类是一个数据类
data class Cellphone(val brand: String, val price: Double)
会根据参数生成这些方法。
main函数中测试
fun main(){
val cellphone = Cellphone("iphone", 9988.0)
val cellphone1 = Cellphone("iphone", 9988.0)
println(cellphone)
println(cellphone == cellphone1)
}
[外链图片转存中…(img-5wZsyzsF-1719048740387)]
实现单例类
创建类型选择Object
object Singleton {
fun singletonTest(){
println("hello singleton")
}
}
直接通过函数名调用,kotlin自动帮我们创建了一个实例,并且保证全局只有一个。