《Android第一行代码》第3版学习笔记——自个儿记录学习过程用,持续更新中

目录

第一章

第二章

1.如何在Android Studio中运行Kotlin代码

2.Kotlin中如何定义变量,与JAVA语言有何区别

3.Kotlin中的函数与JAVA相比有什么特点?

4.Kotlin的逻辑控制语句与JAVA相比有什么不同?

5.Kotlin中类、接口与Java有何异同

6.Kotlin与Java在可见性修饰符上的异同

7.数据类

8.单例类

9.Kotlin中集合的使用

11.Kotlin代码中调用Java方法,当被调用的方法接收了一个Java单抽象接口参数时,Kotlin是怎么简化的

12.Kotlin中在避免空指针异常上,与Java有什么不一样。

第三章



第一章

        这一章作者带着我创建了我的第一个安卓程序——HelloWorld。简要地描述了Android系统的四层架构,Android Studio中安卓项目的项目目录结构以及日志工具的使用。

        在阅读的过程中,通过自己翻阅xml语言的相关资料,加深了对这一章中出现的各种xml文件的理解。

        这一章中我认为需要记忆的点有以下几个:

        1.注册Activity

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name = "android.intent.action.MAIN"/>
            <category android:name = "android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

        2.Android程序的设计讲究逻辑和视图分离

                具体体现在:布局文件中编写界面,而后通过Activity引入

                setContentView(R.layout.activity_main)

        3.res文件夹中的资源引用

                代码中:R.xx.xxxx

                XML中:@xx/xxxx

        xx为res下属目录文件夹名,xxxx为具体资源名

        4.日志工具类andriod.util.Log

    Log.v()        verbose级别  最低级、最琐碎的日志信息
    Log.d()        debug级别    调试程序用
    Log.i()        info级别     分析用户行为用
    Log.w()        warn级别
    Log.e()        error级别

第二章

        本章主要通过Java和Kotlin两种语言之间的联系,对比地学习了Kotlin语言的基本语法。

        Java语言是一种解释型语言。解释型语言是一行行代码一边编译成机器语言,一边运行代码的语言。因此,解释型语言的效率通常会差一些,不过因为解释器的存在,它的跨平台性会好一些。但是为什么编译型语言也有编译器存在,而其跨平台性却要差一些呢?编译器跟解释器的工作原理有什么不同吗,是哪些关键步骤导致了二者在跨平台性上的差别?此处留下这些问题,待以后解答,目前的主要任务是尽快学会这本书并作出一个我想做的APP。

        前面说到JAVA是一种解释型语言,它首先通过javac命令预编译成.class文件,而后通过JVM处理.class文件。JVM在此处充当了解释器的作用。而Kotlin语言是在Java的基础上修改的,它可以很好的简化代码,减少开发代码量。为什么说Kotlin是在JAVA语言上修改的呢?因为Kotlin语言源代码.kt文件同样需要预编译成.class文件,而后利用JVM进行解释。因此其与JAVA的联系是十分紧密的。

        那么接下来就总结一下第二章讲得一些知识点吧。

1.如何在Android Studio中运行Kotlin代码

       在项目源文件目录中创建一个file文件(生成后可以注意到这是一个.kt文件),而后编写一个main函数,会发现main函数头左边会出现一个运行标志的小箭头,单击该标志选择第一个选项即可运行。

2.Kotlin中如何定义变量,与JAVA语言有何区别

        Kotlin中声明变量的关键字仅有两个,分别是valvar,举例使用如下:

    fun main(){
        val value = 10 //val声明的是常量,其值不可变化,对应JAVA的final变量
        var variable = ‘a’ //var声明的是变量,其值可变
    }//注意,Kotlin是不采用分号分隔语句的

        学过Java语言的同学都知道,Java中声明不同的数据类型需要使用不同的关键字,其数量远远不止2个。而Kotlin中仅有两个关键字,那编译器如何知道你声明的是什么数据类型呢?

        编译器可以通过两种方式知道你所声明的值是什么类型。第一种是通过Kotlin的类型自动推导机制,这适用于变量在声明时就被初始化的情况,如上面的代码段所示。还有一个问题就是,当将变量初始化为一个数字的时候,这个数字类型会是Int、Long、还是Double呢?具体各种数据类型表示,留到之后的when关键字进行学习实验。第二种则需要显式地声明变量类型,适用于变量声明时未被初始化的情况,如下面的代码所示

    fun main(){
        val value:Int = 10
        var variable:Char
    }
    /******************************************************************
   ·可以做几个实验加深对变量声明的语法理解:
    1.是否由val声明的变量一定要初始化
    答:不一定要初始化,但是不初始化一定要显式声明类型。
    2.如果变量声明后一直没被赋值,代码能否编译成功,程序能否正常运行结束?
    答:可以正常运行,但是会提示变量未被使用。
    3.在声明时不初始化变量,同时不显式声明类型,之后下一行代码处赋值,是否能编译通过且正常运行。
    答:无法编译通过,这种情况是延时赋值的情况。
    ******************************************************************/

        可以看到显式声明数据类型的语法结构,与之后讲的接口实现的结构十分的相似。因此是否可以大胆的猜测一下,Kotlin中的数据类型都被写出了接口的形式?不过作者说是对象数据类型,具体的验证还需要以后去查阅Kotlin的源代码才能知道。

        为什么Kotlin要把具体数据类型的声明分为两种方式呢?我认为首先是平时的开发工作中变量延迟赋值的情况比较少,利用类型自动推导机制可以大大简化编码量,提高开发效率。同时还能引导程序员养成在声明变量的同时初始化的习惯,我记得在学习C语言时有提到,如果一个变量在声明时未进行初始化,那么其值并非不存在,它会是一个无法预知的值,取决于上一个使用过该变量分配的内存地址上的内存空间的程序,因此可能会导致一些莫名其妙的bug出来。

        另外此处提到了一个编码习惯,如果不是变量明确应该被修改,则使用val来声明变量。

3.Kotlin中的函数与JAVA相比有什么特点?

        1.Kotlin中的函数,将函数返回值类型声明放到了函数名后面,中间用冒号连接。同时需要使用关键字fun声明,而JAVA语言则不需要。

        Kotlin函数返回值的声明,有点类似于变量声明的形式,变量有自动类型推导机制,函数返回值也有自动类型推导机制,同样这种自动类型推导也不是所有情况都可以起作用的。当且仅当函数只有一行代码,并且采用了简化形式(将改行代码写在函数名后面,中间用 等号连接)才可以起作用。

        2.Kotlin函数参数不用val、var关键字声明,如果使用了编译无法通过。

        此处可以跟类的定义中的主构造函数做对比,类的主构造函数参数,如果使用了val、var关键字进行声明,则声明的变量会成为类的字段。

        对此我的理解是,函数参数中不使用var、val声明,则表明这个变量仅作为局部变量之用。

        笔记整理到此处,我突然想到了JAVA中的静态变量,Kotlin中又是如何解决的呢?看来在看完这本书之后,有必要再系统地学习一下Kotlin语言。

        3.Kotlin中的函数当只有一行代码的时候,有简化的写法。写到这里,突然想到了JAVA中的inline函数 - - 查询资料发现是inline内联函数是C++中的关键字,跟这个简化没啥关系哈哈哈哈

        言归正传,当函数只有一行代码时,Kotlin可以进行如下简化:

fun largeNum(num1:Int,num2:Int):Int{
    return max(num1,num2)
}

fun largeNum(num1:Int, num2:Int):Int = max(num1,num2)//函数只有一行代码,可以使用Kotlin中的代码糖

fun largeNum(num1:Int, num2:Int) = max (num1, num2)//这种形式可以触发自动类型推导机制,因此返回值声明可以省略

4.Kotlin的逻辑控制语句与JAVA相比有什么不同?

        1.Kotlin中的逻辑运算是有返回值的,其返回值是所执行条件的最后一行代码。

        2.Kotlin中多了一个关键词when

    /*带参when*/
    fun  getScore(name:String) = when(name){
        "Tom" -> {86}//基本格式为“匹配值 -> {执行逻辑}”
        "Jim" -> 77 //只有一行代码,括号可省略
        "Jack"-> 95
        else  -> 0
    }

    /*when结构语句允许进行类型匹配*/
    fun checkNum(num:Number){
        when(num){
            is Int -> println("num is Int")//is关键字相当于JAVA中的instanceof
            is Double -> println("num is Double")
            else -> println("other")
        }
    }

    /*不带参的when结构语句,方便进行更多样的匹配*/
    fun getScore(name:String) = when{
        name == "Tom" -> 86    //Kotlin中判断对象是否相等可以直接用等号
        name.startWith("Tom") -> 77
        name == "Jack" -> 94
        else -> 0
    }

        3.循环语句中有两种类型 for 、while,其中while循环与JAVA相差不多。for循环则进行了大改,采用了区间的形式。区间的表示用到了1个符号‘..’,2个关键字until、downTo 

for(i in 0..10){
    println(i)
}//[0,10]递增1

for(i in 0 until 10 step 2){
    println(i)
}//[0,10)递增2


for(i in 10 downTo 0){
    println(i)
}//[0,10]区间从10开始递减1

5.Kotlin中类、接口与Java有何异同

        在类的定义上,主要的不同在于构造函数。Kotlin的构造函数分为主构造函数和次构造函数。主构造函数不显式地写出函数体,其默认逻辑为将函数参数中的值赋给类中字段,要为构造函数编写其他逻辑则需要用到关键字init。次构造函数用constructor作为函数名,同时要求其必须调用主构造函数,形如constructor():this(){}。另外,Kotlin允许只定义次构造函数,不定义主构造函数,这种情况更类似于Java的构造函数写法,形如constructor():super(){},同时在类的头部继承父类时,父类没有括号(这是十分合理的,括号表示冒号前的主体调用了父类的构造函数,而只有函数才能调用函数)。

        Kotlin中的一般函数是不可以使用val或者var声明变量的,而主构造函数却可以,在主构造函数中声明var或者val,会将其作为类的字段。

        在类的继承以及接口的上,Kotlin使用符号‘:’表示继承与实现关系,然后通过是否带括号来区分是接口的实现还是类的继承(类的继承中,子类需要调用父类的构造函数。带括号的实质就是调用父类的构造函数,因此括号中是可以带参数的。这是一种杂糅的方法,虽然看起来有点奇怪,但是又不影响其表达其主要意思,而代码量却大大减少)。

        还有就是Kotlin中的类都是默认不可继承的,要用关键字open声明,才能使类可以被继承。

        另外Kotlin类的实例化去掉了new关键字。

        以下这段代码有用到类、接口、主次构造函数、字符串内嵌表达式以及为函数参数提供默认值。

    open class Person(val name:String, val age:Int, val sex:String){
        init{
            println("此人名$name,年方$age,是一个${sex}人")
        }
    }

    interface Study{
        fun readBooks()
        fun doHomework(){
            println("The person is doing homework")
        }//这是接口中的默认实现,可以不被强制要求实现
    }

    class Student(val sno:String, name:String, age:Int, sex:String):Person(name, age, sex), Study{
        init{
            println("Student类的主构造函数被调用")
        }

        constructor(name:String, age:Int, sex:String):this("123456",name, age, sex){
            println("构造参数被调用")
        }//主次构造函数一起使用的目的主要是为了给主构造函数提供默认值,但其实有更好地方式去提供
       
        override fun readBooks(){
            println("$name is reading books.")
        }
    }

    /*只有次构造函数的情形*/
    class Teacher:Person{
        constructor(name:String = "佚名", age:Int, sex:String):super(name, age, sex){
            println("${name}是一个教师")
        }
    }

    fun main(){
        val defaultSno = Student("张三",18,"男")
        val diySno = Student("789542","李四",17,"女")
        val defaultName = Teacher(age = 45, sex = "男")
        val diyName = Teacher("王五",55, sex = "女")
        doStudy(diySno)
    }

    fun doStudy(study:Study){
        study.readBooks()
        study.doHomework()
    }

6.Kotlin与Java在可见性修饰符上的异同

修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected同一包路径下的类可见、当前类、子类可见当前类、子类可见
default同一包路径下的类可见/
internal/同一模块中可见

7.数据类

        当用data声明一个类时,Kotlin会自动根据主构造函数的参数生成equals()、hashCode()、toString()等固定且无实际逻辑意义的函数,从而减少开发工作量。

8.单例类

        单例类只能有一个实例,声明单例类,用object代替class声明。

        其调用类似于Java 中静态方法的调用。

9.Kotlin中集合的使用

        listOf()用来创建不可变的List集合;mutableListOf()用来创建一个可变的List集合。

        setOf()用来创建不可变的Set集合;mutableSetOf()用来创建一个可变的Set集合。

        Set集合底层用hash映射机制,因此其中元素无法保证有序。

        Set集合与List集合的遍历都采用for-in机制:

    for(element in list){
    
    }

        Map集合的使用:

    fun main(){
        val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4)//Kotlin同样提供了mutableMapOf()用于创建可修改的Map集合
        for ((fruit,number) in map){
            println("fruit is $fruit, number is $number")
        }
    }

        Kotlin的集合有一些使用Lambda表达式作为参数的API,如maxBy()、toUpperCase()等。Kotlin的Lambda表达式结构为:{ 参数列表 -> 函数体}

        Lambda表达式作为函数参数的时候,代码有很多可以简化的地方:

    //未经简化
    val maxLengthFruit = list.maxBy({fruit:String -> fruit.length}

    //Lambda表达式是函数的最后一个参数,大括号可以写在括号外面
    val maxLengthFruit = list.maxBy(){fruit:String -> fruit.length}

    //Lambda表达式是函数的唯一参数,括号可以省略
    val maxLengthFruit = list.maxBy{fruit:String -> fruit.length}

    //Lambda表达式只有一个参数,不必声明参数名,用it关键字来代替
    val maxLengthFruit = list.maxBy{ it.length }

        文中提到的函数式API这个概念,我的理解是,API提供的参数中有一个或以上的参数是函数。而Lambda表达式本质上是一个函数。查看maxBy的源代码没看懂,插个眼,以后再看。

11.Kotlin代码中调用Java方法,当被调用的方法接收了一个Java单抽象接口参数时,Kotlin是怎么简化的

        Java单抽象接口,是指接口中有且仅有一个待实现方法。Java中最常见的单抽象接口莫过于Runnable接口,只有一个待实现的run()方法。简化前后对比如下

    //简化前
    Thread(object:Runnable{
        override fun run(){
            //run方法实现逻辑
        }
    }).start()

    //简化后
    Thread{
        //run方法实现逻辑
    }.start()

        简化前的代码的一个猜测理解:前面提到单例类的时候,使用的关键字也是object,会自动实现一个实例。因此在此处使用object,跟单例类也是有异曲同工之妙,同样是声明类而后自动实现一个类实例。因为这里是匿名类,也就不需要类名,所以直接在object关键字后实现接口。       

12.Kotlin中在避免空指针异常上,与Java有什么不一样。

        首先,Kotlin默认所有的参数和变量都不可以为空。也就是将空指针异常的检查提前到了编译时期。

        当我们需要变量为空时,则需要使用到Kotlin提供的可空类型系统,在使用时需要将所有潜在的空指针异常都处理掉。

        Int? ,类似这样的结构,在数据类型后面加一个问号,就表示该数据类型是可以为空的。

        至于如何处理潜在异常,Kotlin提供了一些方便的判空辅助工具。

        ?.操作符:当且仅当调用主体不为空时,才执行方法调用

                a?.doSomething()

                相当于

                if( a != null){

                        a.doSomething()

                }

        ?:操作符:a?:b 如果左边为空,返回右边;否则返回左边。

                val c = a?:b

                相当于

                val c = if( a != null) a else b

        !!变量后缀,表示该变量一定非空,一般用于强行通过编译,用于解决函数之间判空逻辑一般不沟通导致的编译无法通过。

        let(Lambda)函数,用于解决同一个对象多次调用其方法,每次调用都要判空的情况。let()的作用是将对象本身作为参数传递给Lambda表达式,其参数有且仅有一个Lambda表达式,因此可以进行简化。使用示例如下:

    fun doStudy(study: Study?){
        study?.doHomework()
        study?.readBooks()
    }

    //使用let函数,避免多次判空
    fun doStudy(study: Study?){
        study?.let{
            it.doHomework()
            it.readBooks()
        }
    }

        需要注意的是,处理全局变量时,if语句无法代替let函数。因为采用let函数,需要将一整个代码块执行完毕才能执行其他代码。也就是说在let函数的代码块执行完毕前,全局变量不会被其他函数修改。

第三章

        本章学习Android四大组件之一的Activity。

        最好的学习过程莫过于自己动手做一遍。本章作者带着创建了一个不带Activity的项目,用于与Activity相关的知识点的实验。

        本章主要的知识点如下:

1.什么是Activity

        一种可以包含用户界面的组件,主要用于和用户进行交互。Activity中可以引用页面布局、菜单等资源文件,并编写相关的交互代码。

2.以Button控件为例,大概展示了layout中控件的用法

        layout控件有两种用法,一种是可视化界面中进行拖动,一种是编写xml代码。而后在Activity中使用setContentView()引用布局,布局中的控件id因为Kotlin中的JavaBean语法糖的存在可以直接使用。

3.创建了菜单文件,并在Activity 中引用。P93-P95

        在res文件夹下创建menu文件,之后创建Menu Resource File文件。在xml中使用item标签添加菜单项。在Activity中重写方法onCreateOptionsMenu(),并返回true以显示出来。采用when结构给菜单项添加响应事件。

4.如何销毁一个Activity

        在控件响应代码中添加语句finish()

5.Toast是什么

        按钮响应消息,在屏幕上显示一小段时间即消失。

6.什么是Intent

        Intent用于不同的组件之间进行交互。其使用方式分为显式调用和隐式调用两种。

        显式调用:通过构造方法,制定需要打开的具体组件,而后通过组件自带的函数,如startActivtiy(intent)执行交互。

        隐式调用:在AndroidManifest.xml中注册组件时,制定相应的<intent-filter>过滤规则。intent-filter可以制定三种不同的响应规则:action、category、data。隐式调用可以进行不同程序之间的交互。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值