在本文中,我们将为您详细介绍在Android中使用生物识别,kotlin开发思维的相关知识,并且为您解答关于安卓生物识别的疑问,此外,我们还会提供一些关于AndroidKotlinRXKotlinRo
在本文中,我们将为您详细介绍在 Android 中使用生物识别,kotlin开发思维的相关知识,并且为您解答关于安卓生物识别的疑问,此外,我们还会提供一些关于Android Kotlin RXKotlin Room - 错误 Kotlin.unit、Android Kotlin开发实例(Hello World!)及语法详解、Android studio 升级M1版后,kotlin报错 connect to Kotlin Daemon、Android Studio配置Kotlin开发环境详细步骤的有用信息。
本文目录一览:- 在 Android 中使用生物识别,kotlin开发思维(安卓生物识别)
- Android Kotlin RXKotlin Room - 错误 Kotlin.unit
- Android Kotlin开发实例(Hello World!)及语法详解
- Android studio 升级M1版后,kotlin报错 connect to Kotlin Daemon
- Android Studio配置Kotlin开发环境详细步骤
在 Android 中使用生物识别,kotlin开发思维(安卓生物识别)
通过 BiometricPrompt API,您可以在加密和不加密的情况下实现身份验证。如果您的应用需要更强安全性的保障 (例如医疗类或银行类应用),则可能需要 将加密密钥同生物特征绑定在一起 来验证用户的身份。否则您仅需向用户提供生物识别身份验证即可。两种方式的代码实现很类似,除了在需要加密时要用到 CryptoObject
实例。
加密版本:
biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
复制代码
在上述代码中,我们向 CryptoObject 传递了 Cipher
参数,除此之外也支持其余加密对象,比如使用 Mac 或 Signature。
不使用 CryptoObject 的版本:
biometricPrompt.authenticate(promptInfo)
复制代码
若要在 Android 应用中实现生物识别身份验证,请使用 AndroidX Biometric
代码库。虽然 API 可以自动处理不同的认证级别 (指纹、面部识别、虹膜识别等),但您仍然可以通过 setAllowedAuthenticators()
方法设置应用可以接受的生物认证级别,具体如下面的代码所示。Class 3 (以前被称为 Strong) 级别代表您希望使用生物识别来解锁存储在 Keystore 中的凭证;Class 2 (以前被称为 Weak) 级别代表您只需要使用生物识别来解锁应用,而不依赖于加密技术保护的凭证进一步进行身份验证。还有一个 Class 1 级别,但此级别在应用中并不可用。更多详情,请查看 Android 兼容性定义文档。
fun createPromptInfo(activity: AppCompatActivity): BiometricPrompt.PromptInfo =
BiometricPrompt.PromptInfo.Builder().apply {
setAllowedAuthenticators(BIOMETRIC_STRONG)
// 继续设置其他 PromptInfo 属性,如标题、副标题、描述等。
}.build()
复制代码
加密、auth-per-use (每次验证) 密钥 vs time-bound (时间限制) 密钥
auth-per-use 密钥 是一种被用来执行一次性加密操作的密钥。举个例子,如果您想执行 10 次加密操作,那么就必须解锁 10 次密钥。因此,auth-per-use 就意味着每次使用密钥时,都必须进行认证 (即解锁密钥)。
time-bound 密钥 则是一种在一定的时间段内有效的密钥,您通过向 setUserAuthenticationValidityDurationSeconds
方法传递一个以秒为单位的时间参数,过了该时间后该密钥就需要再次进行解锁。如果您传递的时间参数值为 -1,也就是默认值,那么系统会认为您想要使用 auth-per-use 密钥。在这里若您不想设置为 -1,那么我们建议您至少设置为 3 秒,这样系统会遵循您所设置的时间。想要了解更多创建 time-bound 密钥的方法,请参考 Jetpack Security
中关于 MasterKeys
的内容。
通常,即前面提到的 -1 的情况时,您通过向 BiometricPrompt.authenticate() 方法传递一个 CryptoObject 参数来请求 auth-per-use 密钥。然而,您也可以不使用 CryptoObject,而是设置一个很短的时间参数 (比如 5 秒),来将 time-bound 密钥当作 auth-per-use 密钥来使用。这两种方法对于验证用户身份来说实际上是等同的,如何选择取决于您设计应用交互的方式。
让我们看看这两种不同类型的密钥是如何工作的: 当您使用 CryptoObject 时,只有某个特定操作才能够解锁密钥。这是因为 Keymint (或者是 Keymaster) 获取了一个带有特定 operationId 的 HardwareAuthToken (HAT)。当密钥被解锁后,您只能使用密钥去执行那些被定义为 Cipher/Mac/Signature 的操作,并只能执行一次,因为这是一个 auth-per-use 密钥。若不使用 CryptoObject,那么被发送到 Keymint 的 HAT 就没有 operationId,此时,Keymint 会去查找一个带有有效时间戳 (时间戳 + 密钥使用期限 > 当前时间) 的 HAT,在有效时间内,您都能够使用该密钥,因为它是一个 time-bound 密钥。
这样看上去,似乎只要在有效的时间窗口内,任何应用都可以使用 time-bound 密钥。但实际上,只要不是用户空间 (user-space) 受到损害,不用担心某个 X 应用使用了某 Y 应用的密钥或操作。Android 框架不会允许其他应用获取或者初始化另一个应用的操作。
总结
在本篇文章中,我们介绍了:
-
只有用户名 + 密码的认证方式存在问题的原因;
-
在应用中选择使用生物识别身份验证的原因;
-
不同类型应用在
设计认证方式时的注意事项;
原因; -
在应用中选择使用生物识别身份验证的原因;
-
不同类型应用在[外链图片转存中…(img-yNxSCYSH-1642933162675)]
设计认证方式时的注意事项;
Android Kotlin RXKotlin Room - 错误 Kotlin.unit
如何解决Android Kotlin RXKotlin Room - 错误 Kotlin.unit?
我想通过循环数组向房间数据库做一个简单的插入数据。 我使用 RXKotlin 来迭代数组 我有一个这样的数组:
fun defaultDataCategory() : ArrayList<CategoryModel>{
var cat: CategoryModel
var catArrayList: ArrayList<CategoryModel> = ArrayList(0)
val date: Int = Calendar.DATE
val formatedDate = SimpleDateFormat("yyyy-MM-dd").format(Date())
val formatedTime = SimpleDateFormat("HH:mm").format(Date())
val DateTime = "$formatedDate $formatedTime"
catArrayList.add(
CategoryModel(
1,"Personal",true,"Red",Converter.toDate(Calendar.getInstance().timeInMillis),"system","system"
)
)
catArrayList.add(
CategoryModel(
2,"Work","Blue","system"
)
)
catArrayList.add(
CategoryModel(
3,"Home","Purple","system"
)
)
catArrayList.add(
CategoryModel(
4,"Learn","Yellow","system"
)
)
return catArrayList
}
我像这样用 RXKotlin 循环了一个数组
var catArrayList: ArrayList<CategoryModel> = DefaultData.defaultDataCategory()
catArrayList.toObservable()
.subscribeBy( // named arguments for lambda Subscribers
onNext = { homeviewmodel.insertCategory(it) },onError = { Log.e("error insert=",it.printstacktrace().toString()) },onComplete = { Log.e("complete insert=","complete insert") }
)
我得到了一个错误“kotlin.unit”。
Error RXKotlin
如何使用 RXKotlin 迭代数组并插入房间数据库?
解决方法
试试
Observable.fromIterable(catArrayList).subscribeBy {...}
Android Kotlin开发实例(Hello World!)及语法详解
Android Kotlin开发实例及语法详解
前言
Kotlin是一种在 Java虚拟机上执行的静态型别编程语言,它主要是由俄罗斯圣彼得堡的JetBrains开发团队所发展出来的编程语言。该语言有几个优势
1. 简洁
它大大减少你需要写的样板代码的数量。
2. 安全
避免空指针异常等整个类的错误。
3. 通用
构建服务器端程序、Android 应用程序或者在浏览器中运行的前端程序。
4. 互操作性
通过 100% Java 互操作性,利用 JVM 既有框架和库。
配置
在我们的AndroidStudio开发工具中,要想使用Kotlin这个优秀的开发语言,我们需要安装插件,直接在安装插件界面搜索Kotlin然后安装。之后再gradle文件增加如下配置
apply plugin:'kotlin-android' apply plugin:'kotlin-android-extensions' dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" }
项目gradle文件
buildscript { ext.kotlin_version = '1.1.1' repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } }
完成上面的配置后,我们就可以愉快的玩耍了。
Kotlin示例
首先我们还和以前一样,创建一个Android项目,自动创建一个Activity之后我们再创建一个java类
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setonClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view,"Replace with your own action",Snackbar.LENGTH_LONG) .setAction("Action",null).show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main,menu); return true; } @Override public boolean onoptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button,so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onoptionsItemSelected(item); } } public class Test { private static String str = null; public static void main(String[] args) { str = "Code4Android"; System.out.println(str); } }
那上面的代码如果用kotlin实现是什么样子呢。尽管现在我们还不能写出Kotlin代码,但是在安装插件后AS中提供了自动转换Kotlin代码的功能
转换后的Kotlin代码
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById(R.id.toolbar) as Toolbar setSupportActionBar(toolbar) val fab = findViewById(R.id.fab) as FloatingActionButton fab.setonClickListener { view -> Snackbar.make(view,Snackbar.LENGTH_LONG) .setAction("Action",null).show() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_main,menu) return true } override fun onoptionsItemSelected(item: MenuItem): Boolean { val id = item.itemId if (id == R.id.action_settings) { return true } return super.onoptionsItemSelected(item) } } object Test { private var str: String? = null @JvmStatic fun main(args: Array<String>) { str = "Code4Android" println(str) } }
注意:AS提供的java代码自动转换功能,我们不要轻易使用,更不要转化我们成熟的项目,如果需要就需要我们自己去重构实现。否则会有意向不到的事情等着你,毕竟转换不是那么智能。上面的代码只是让你先简单熟悉下Kotlin代码时什么样子的,接下来我们先去学习一下Kotlin的基本语法。相信很容易上手。
Hello World!
我们由一个简单的”Hello World!”输出程序开始。与新建java文件类似,如下图,我们选择Kotlin File/Class.创建一个Kotlin文件。
package com.learnrecord /** *Created by Code4Android on 2017/4/21. */ var str: String = "" fun main(args: Array<String>) { str = "Hello World!" println(str) }
上述代码就是简单的输出一个字符串“Hello World”,package 后面跟的是包名,我们看出了和java文件的区别,在包名后面没有以分号“;”结尾。在Kotlin语法中,语句结尾都不在有分号“;”。
在Kotlin中变量声明有两种类型,val修饰变量是只读变量即只能赋值一次,再次赋值时就会编译错误
,如果我们需要多次修改值就需要使用var。在上面的 var str: String = “”中,str是变量名,:String,表明该变量是String类型变量,后面就是赋值语句。我们也可以这样写var str= “”省略了生命变量类型,它可以根据赋的值而自动推断出类型。如果我们使用下面赋值语句str=null,发现null是不能赋值的,这就是Kotlin的特性,如果我们想赋值null,可以修改为 var str:String?=”“。
fun就是函数生命,而这个main函数就和我们java中的main方法一样,是程序执行的入口。println就是一个打印输出。
Kotlin声明类型
在Kotlin中有如下几种Number类型,他们都是继承自Number抽象类。
Float(32位),Double(64),Int(32),Byte(8),Short(16),Long(64,类型用大写L,如12L),Any(任意类型),数组类型Array 根据传入的泛型数据自动匹配类型,Kotlin还提供了指定类型的Array,如ByteArray,Chararray,ShortArray,IntArray,LongArray,FloatArray,DoubleArray,BooleanArray。在数组类型中都提供了get(index),set(index,value)及iterator()方法供我们使用。
val iArray: IntArray = intArrayOf(1,2,3) val sArray: Array<String> = Array<String>(3,{ i -> i.toString() }) val anyArray: Array<Any> = arrayOf(1,"2",3.0,4.1f) // 可将类型进行混排放入同一个数组中 val lArray: LongArray = longArrayOf(1L,2L,3L)
函数
我们先来实现一个简单的数值求和的函数,通用实现方法如下
fun sum(a: Int,b: Int): Int { return a + b }
传入两个Int型数值,sum是函数名,括号后面的:Int表示该函数返回Int的值,函数体中对两个数字相加并返回。在Kotlin中表达式也可以作为函数体,编译器可以推断出返回类型,可以简化为
fun sum(a: Int,b: Int) = a + b
为了更好理解表达式可以作为函数体,我们可以创建一个函数获取两个数的最大值,如下:
fun max1(a:Int,b:Int)=if (a>b) a else b
需要注意的是若if后有多个表达式,如下
fun max1(a:Int,b:Int)= if (a > b) { println(a) a } else { println(b) //如果我们将println(b)放到b的下面,运行会返回kotlin.Unit为无类型,返回值总是最后一个表达式的返回值或值 b } println(max1(1,3))
括号中的表达式顺序决定了返回的值及其类型。
如果我们的方法体仅仅是打印字符串,并不返回值则
fun printInt(a: Int): Unit { println(a) }
Unit就类似我们java中的void,即没有返回值,此时我们可以省略
fun printInt(a: Int) { println(a) }
对于函数体,方法或者类等和java一样也有一些修饰符,如下
- abstract //抽象类标示
- final //标示类不可继承,默认属性
- enum //标示类为枚举
- open //类可继承,类默认是final的
- annotation //注解类
- private //仅在同一个文件中可见
- protected //同一个文件中或子类可见,不可修饰类
- public //所有调用的地方都可见
- internal //同一个模块中可见,若类不加修饰符,则默认为该修饰符,作用域为同一个应用的所有模块,起保护作用,防止模块外被调用。
操作符
直接上代码如下
//操作符 shl 下面对Int和Long var a: Int = 4 var shl: Int = a shl (1) //Java中的左移运算符 << var shr: Int = a shr (1) //Java中的右移运算符 >> var ushr: Int = a ushr (3) //无符号右移,高位补0 >>> var and: Int = 2 and (4) //按位与操作 & var or: Int = 2 or (4) //按位或操作 | var xor: Int = 2 xor (6) //按位异或操作 ^ print("\nshl:" + shl + "\nshr:" + shr + " \nushr:" + ushr + "\nand:" + and + "\nor:" + or + "\nxor:" + xor)
输出信息为
shl:8 shr:2 ushr:0 and:0 or:6 xor:4
在上面的部分操作符可达到逻辑操作符, 当我们使用Boolean时,or() 相当于 ||,and() 相当于 &&, xor() 当操作符两边相反时为true,否则为false ,not()时取反。
数组遍历及控制语句
遍历数组
fun forLoop(array: Array<String>) { //第一种方式直接输出字符(类似java foreach) for (str in array) { println(str) } //Array提供了forEach函数 array.forEach { println(it) } //array.indices是数组索引 for (i in array.indices) { println(array[i]) } //(类似javafor(int i=0;i<arry.length;i++)) var i = 0 while (i < array.size) { println(array[i++]) } }
使用when判断类型
fun whenFun(obj: Any) { when (obj) { 25 -> println("25") "Kotlin" -> println("Kotlin") !is String -> println("Not String") is Long -> println("Number is Long") else -> println("nothing") } }
is 和java中instanceof是一个作用判断是否为某个类型。!is即判断不是某个类型。
//@定义label,一般用在内层循环中跳到外层循环:i in 0..2等价于java中 for(int i=0;i<=2;i++)效果 loop@ for (i in 0..2) { for (j in 0..3) { println("i:" + i + " j:" + j) if (j == 2) //continue@loop//跳到外层循环,继续往下执行 break@loop //跳到外层循环label处,跳出改层循环 } }
倒序输出是downTo
//倒序输出5 4 3 2 1 0 for (i in 5 downTo 0) { println(i) } //设置输出数据步长 for (i in 1..5 step 3) print(i) // 输出 14 //step和downTo混合使用 for (i in 5 downTo 1 step 3) print(i) //输出52
类与枚举
/*** constructor:构造函数 * constructor无修饰符(如:private)时,constructor可以省略: * 当是无参构造函数时,整个构造函数部分也可以省略,省略的构造函数默认是public的 * 由于primary constructor不能包含任何代码,因此使用 init 代码块对其初始化,* 同时可以在初始化代码块中使用构造函数的参数 */ open class People private constructor(var id: String,var name: String) { //可以类中初始化属性: var customName = name.toupperCase() //初始化属性 //次构造函数,使用constructor前缀声明,且必须调用primary constructor,使用this关键字 constructor( id: String,name: String,age: Int) : this(id,name) { println("constructor") } init { println("初始化操作,可使用constructor参数") } //需要open修饰,子类才可以 open fun study() { print("study") } //People前的冒号":"是继承的意思,实现类接口的时候也是冒号 class Student(id: String,name: String) : People(id,name) { var test: Number = 3 private var name1: String? get() { return name1 } set(value) { name1 = value } //override修饰的方法,默认是可以被继承的。若希望不被继承,可以使用 final 关键词修饰 override fun study() { super.study() } } }
数据类用来保存数据,类似于POJO类,使用data关键词进行定义,编译器默认会为数据类生成以下四个方法
- equals()
- hashCode()
- toString()
- copy()
通过数据类你会看到Kotlin的简洁性,我们创建一个Staff类,有String类型的name,position和泛型T(使用泛型仅仅是为了在Kotlin中接触以下泛型)
java实现代码:
public class StaffJ<T> { private String name; private String position; private T age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public T getAge() { return age; } public void setAge(T age) { this.age = age; } }
Kotlin数据类:
data class Staff<T>(var name: String,val position: String,var age:T)
通过对比我们就看出了优点了,一行代码就实现了,具体使用
var staff = Staff("code4Android","Android工程师","22") //实例化对象
要获取某个属性如获取名字staff.name,赋值就是staff.name=”code4Android2”,既然说了这样可以赋值,但是动手的小伙伴说为什么我敲的报错啊,如下
staff.position="前端"
编译报错了,在前面我们说过val修饰的属性只能赋值一次,那在这里val修饰的属性我们是不能再次赋值的。
fun main(arg:Array<String>){ var staff = Staff("code4Android","22") //实例化对象 staff.name="code4Android2" var staff1=staff.copy() //使用copy的时候可以指定默认值,可以指定任意个用逗号","隔开 var staff2=staff.copy(name="ccc",position = "kotlin") println("name:${staff2.name} position:${staff2.position} age ${staff2.age}") //staff.position="Kotiln" //val不能再次赋值 var anotherStaff= Staff("code4Android",22) //实例化对象 println("staff toString(): ${staff.toString()} anotherStaff toString(): ${anotherStaff.toString()}") println("staff hashCode(): ${staff.hashCode()} anotherStaff hashCode(): ${anotherStaff.hashCode()}") println("staff is equals another staff ? ${staff.equals(anotherStaff)}") }
上面使用了字符模板,在Kotlin中有两种字符模板形式,$<变量>、${<变量>}
var name:String="Code4Android" println("我的名字叫$name") println("我的名字叫${name}")
/** * java允许使用匿名内部类;kotlin也有类似的概念,称为对象表达式-object expressions */ open class KeyBord{ open fun onKeyEvent(code:Int):Unit = Unit } /**匿名内部类**/ var key=object :KeyBord(){ override open fun onKeyEvent(code:Int):Unit = Unit }
枚举
enum class Color{ RED,BLACK,BLUE,GREEN,WHITE } fun display(){ var color:Color=Color.BLACK Color.valueOf("BLACK") // 转换指定name为枚举值,若未匹配成功,会抛出IllegalArgumentException Color.values() //已数组的形式,返回枚举值 println(color.name)////获取枚举名称 println(color.ordinal)//获取枚举值在所有枚举数组中定义的顺序,0开始 }
在Kotlin中枚举还支持方法。
扩展
/** * fun receiverType.functionName(params){ *body *} * receiverType : 待扩展的类名 * . :修饰符为扩展符 * functionName :为自定义的扩展函数名,* params :为自定义的扩展函数参数,可为空 * 扩展函数作用域,受函数的visibility modifiers影响 * 扩展函数并没有对原类做修改,而是为被扩展类的对象添加新的函数。 * 有一条规则,若扩展函数和类原有函数一致,则使用该函数时,会优先使用类本身的函数。 */ class Employee(var name: String) { fun print() { println("Employee") } } //扩展函数 fun Employee.println() { print("println:Employee name is $name") } /** * 可以扩展一个空对象 */ fun Any?.toString1(): String { if (this == null) return "toString1:null" else { return "toString1" + toString() } } /** * 扩展属性 * 由于扩展属性实际上不会向类添加新的成员,* 因此无法让一个扩展属性拥有一个后端域变量. 所以,对于扩展属性不允许存在初始化器. * 扩展属性的行为只能通过明确给定的取值方法与设值方法来定义,也就意味着扩展属性只 * 能被声明为val而不能被声明为var.如果强制声明为var,即使进行了初始化, * 在运行也会报异常错误,提示该属性没有后端域变量。 */ val Employee.lastName: String get() { return "get:"+name }
使用
fun main(arg: Array<String>) { var employee = Employee("Code4Android") employee.print() employee.println() println(employee.toString1()) println(employee.lastName) }
代理
** * 被代理接口 */ interface Base { fun display() } /** * 被代理类 */ open class BaseImpl : Base { override fun display() = print("just display me.") } /** * 代理类,使用:以及关键词by进行声明 * 许代理属性和其他继承属性共用 * class Drived(base: Base) : Base by base,BaseImpl() */ class Drived(base: Base) : Base by base //使用 fun show() { var b = BaseImpl() var drived = Drived(b) drived.display() } ** * 代理类型: * 懒加载:Lazy * 观察者:Delegates.observable() * 非空属性:Delegates.notNull<>() */ class Water { public var weight:Int by Delegates.notNull() /** * 代理属性 */ public val name: String by lazy { println("Lazy.......") "Code4Android" } public var value: String by Delegates.observable("init value") { d,old,new -> println("$d-->$old->$new") } } fun main(arg: Array<String>) { show() var water = Water() println(water.name) println(water.name) water.value = "11111" water.value = "22222" water.value = "33333" println(water.value) println(water.value) //必须先赋值否则IllegalStateException: Property weight should be initialized before get. water.weight=2 print(water.weight) }
操作符::
val String.lastChar: Char get() = this[this.length - 1] class A(val p: Int)
//1,反射得到运行时的类引用: val c = Student::class //2,函数引用 fun isOdd(x: Int) = x % 2 != 0 val numbers = listof(1,3) println(numbers.filter(::isOdd)) //3,属性引用(在此引用main函数主体外声明的变量) println(::x.get()) ::x.set(2) println(x) //4,::x 表达式评估为 KProperty<Int> 类型的属性,它允许我们使用 get() 读它的值或者使用名字取回它的属性 val prop = A::p println(prop.get(A(1))) //5,对于扩展属性 println(String::lastChar.get("abc")) //6,与 java 反射调用 println(A::p.javaClass),var f: Array<Field> = A::p.javaClass.declaredFields
伴生对象
伴生对象(companion object )类似于java中的静态关键字static。在Kotlin没有这个关键字,而是伴生对象,具体用法
open class People constructor(var id: String,var name: String){ //可以类中初始化属性: var customName = name.toupperCase() //初始化属性 //使用constructor前缀声明,且必须调用primary constructor,使用this关键字 constructor( id: String,name) { println("constructor") } init { println("初始化操作,可使用constructor参数") } //,Kotlin的class并不支持static变量,所以需要使用companion object来声明static变量,// 其实这个platformStatic变量也不是真正的static变量,而是一个伴生对象,companion object { val ID = 1 } }
使用的话直接People.ID。
单例模式
在Kotlin中使用object修饰类的时候,。该类是单例对象。
/** * 使用object定义类,该类的实例即为单例,访问单例直接使用类名,不能通过构造函数进行访问,不允许有构造函数 * Place.doSomething() // 访问单例对象 */ object Singleton { fun doSomething() { println("doSomething") } } /** * 实例化的时候,单例是懒加载,当使用的时候才去加载;而对象表达式是在初始化的地方去加载。 * * 当在类内部使用 object 关键词定义对象时,允许直接通过外部类的类名访问内部对象进而访问其相关属性和方法,相当于静态变量 * 可以使用companion修饰单例,则访问其属性或方法时,允许省略单例名 * MyClass.doSomething() // 访问内部单例对象方法 */ class MyClass { companion object Singleton { fun doSomething() { println("doSomething") } } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
源码下载:http://xiazai.jb51.net/201705/yuanma/KotlinForAndroid(jb51.net).rar
Android studio 升级M1版后,kotlin报错 connect to Kotlin Daemon
Android studio 升级M1版后,kotlin报错 Caught an exception trying to connect to Kotlin Daemon。
出现这个问题大约是项目kotlin版本和IDE 插件版本不一致导致的。
Caught an exception trying to connect to Kotlin Daemon:
java.lang.NoClassDefFoundError: org/jetbrains/kotlin/daemon/client/DaemonReportingTargets
at org.jetbrains.kotlin.compilerRunner.KotlinCompilerRunnerUtils.newDaemonConnection(KotlinCompilerRunnerUtils.kt:59)
at org.jetbrains.kotlin.compilerRunner.KotlinCompilerRunnerUtils.newDaemonConnection$default(KotlinCompilerRunnerUtils.kt:49)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner$Companion.getDaemonConnectionImpl$kotlin_gradle_plugin(GradleKotlinCompilerRunner.kt:164)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:134)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:117)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner.runCompilerAsync(GradleKotlinCompilerRunner.kt:146)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner.runCompilerAsync(GradleKotlinCompilerRunner.kt:141)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner.runJvmCompilerAsync(GradleKotlinCompilerRunner.kt:81)
at org.jetbrains.kotlin.gradle.tasks.KotlinCompile.callCompilerAsync$kotlin_gradle_plugin(Tasks.kt:449)
at org.jetbrains.kotlin.gradle.tasks.KotlinCompile.callCompilerAsync$kotlin_gradle_plugin(Tasks.kt:359)
at org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile.executeImpl(Tasks.kt:316)
at org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile.execute(Tasks.kt:288)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:103)
at org.gradle.api.internal.project.taskfactory.IncrementalTaskInputsTaskAction.doExecute(IncrementalTaskInputsTaskAction.java:47)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:42)
at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$5.run(ExecuteActionsTaskExecuter.java:476)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:461)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:444)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$200(ExecuteActionsTaskExecuter.java:93)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:237)
at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$0(ExecuteStep.java:32)
at java.util.Optional.map(Optional.java:215)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:32)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:58)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:35)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:33)
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:39)
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:35)
at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:45)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:31)
at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:208)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:70)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:45)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:43)
at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:32)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:96)
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:89)
at java.util.Optional.map(Optional.java:215)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:90)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:48)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:69)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:47)
at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:140)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:108)
at org.gradle.api.internal.tasks.execution.ResolveBeforeExecutionOutputsTaskExecuter.execute(ResolveBeforeExecutionOutputsTaskExecuter.java:67)
at org.gradle.api.internal.tasks.execution.ResolveAfterPreviousExecutionStateTaskExecuter.execute(ResolveAfterPreviousExecutionStateTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:94)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:95)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:43)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:336)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:322)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:134)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker$1.execute(DefaultPlanExecutor.java:129)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:202)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:193)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:129)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task '':app:compileDebugKotlin''.
> org/jetbrains/kotlin/daemon/client/DaemonReportingTargets
解决方法:
设置>插件,查看kotlin版本 是否和 build.gradle 里的版本一致,
设置同一个版本就好了。
Android Studio配置Kotlin开发环境详细步骤
Android Studio配置Kotlin开发环境详细步骤
第一步:安装Kotlin插件
打开Settings面板,找到Plugins选项,点击browse repositories(浏览仓库),输入“Kotlin”查找,然后安装即可。安装完成之后需要重启Android Studio (切记!)。
安装完成之后如下图所示。
插件当前的最新版本是1.1.2-release-Studio-2.3-3。
第二步:配置Kotlin开发环境
点击菜单栏的“Tools”选项,选择“Kotlin”,然后选择“Configure Kotlin in Project”。如下图所示。
在弹出的窗口中选择需要使用Kotlin的模块和Kotlin编译器和运行时的版本,如下图所示。
点击“OK”之后,Kotlin插件会自动开始配置。配置完成之后,同步一下工程(Sync Project)即可。
[可选]:在菜单栏中点击“Code”菜单项,选择“Convert Java File to Kotlin File”即可根据之前配置将已有的Java文件转换为Kotlin文件。
附:推荐配置
打开模块下的build.gradle文件,在apply plugin: 'kotlin-android'下面加入一行:apply plugin: 'kotlin-android-extensions'。这是一个Kotlin的扩展模块,可以让Activity自动关联xml布局中的View而不需要findViewById。
详情请参考:http://kotlinlang.org/docs/tutorials/android-plugin.html
附:使用Kotlin编写单元测试
在Android开发中免不了要进行各种单元测试,使用Kotlin编写单元测试可以简化代码,提高效率。
将工程切换到Project视图,展开模块下的src目录,这个目录下默认会有三个文件夹。main文件夹通常用来存放模块代码;androidTest文件夹通常用来存放Android相关的单元测试;test文件夹通常用来存放Java(Kotlin)相关的单元测试。
Kotlin的单元测试
在测试包下新建一个Kotlin Class,例如命名为UnitTest1。在这个类中可以编写多个测试方法,不详细叙述。
package cc.duduhuo.kotlintest import org.junit.Test import org.junit.Assert.* class UnitTest1 { @Test fun addition_isCorrect() { assertEquals(4,(2 + 2).toLong()) } }
Android的单元测试
在测试包下新建一个Kotlin Class,例如命名为AndroidTest1。在这个类中可以编写多个测试方法,不详细叙述。
package cc.duduhuo.kotlintest import android.support.test.InstrumentationRegistry import android.support.test.runner.AndroidJUnit4 import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class AndroidTest1 { @Test fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getTargetContext() assertEquals("cc.duduhuo.kotlintest",appContext.packageName) } }
附:有关Kotlin的一些有用资料Kotlin官网:http://kotlinlang.org/
Kotlin用户手册(英文):http://kotlinlang.org/docs/reference/
Kotin开源地址:https://github.com/JetBrains/kotlin
官方介绍如何开始使用Kotlin:http://kotlinlang.org/docs/tutorials/getting-started.html
与Kotlin相关一些库、框架和应用:http://kotlinlang.org/docs/resources.html
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
关于在 Android 中使用生物识别,kotlin开发思维和安卓生物识别的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Android Kotlin RXKotlin Room - 错误 Kotlin.unit、Android Kotlin开发实例(Hello World!)及语法详解、Android studio 升级M1版后,kotlin报错 connect to Kotlin Daemon、Android Studio配置Kotlin开发环境详细步骤的相关知识,请在本站寻找。
本文标签: