3.遥遥领先 Android kotlin 项目中超高频用法
目录:
1. 变量的原理, 变量和属性
2. 基础数据结构, 数组, 集合,字符串相关
3. 函数
4. 异常
5. 循环
6. this语法
7. 类型转换
1. 变量类型: 变量和属性
1.1 在编译之后会变成包装类型, 比如
kolin数组, 为啥不用java的, 而是多弄一套, 因为kotlin里面的更牛逼, 并且它最后生产的是包装类型
1.2 属性原理:get方法私有化
自动生成get和set方法
生成get和set方法,不能自动生成
package kk.yuedong.com.myapplication
class TestBean {
private var height = 0
private var weight = 0
fun getHeight(): Int {
return height
}
fun setHeight(height: Int) {
this.height = height;
}
}
在Kotlin中,getter和setter是可选的,如果你没有在代码中创建它们,它是会默认自动生成,是看不到的:
class Account {
var name: String = ""
var age: Int = 0
var balance: Double = 0.0
}
以上的代码,就算不写getter/setter,默认也会生成getter和setter,例如:
class Account {
var name: String = ""
var age: Int = 0
var balance: Double = 0.0
// 这种set和get方法不推荐在代码中自己手动去写
set(vaule){
field = value
}
get() = field
}
1.3.常量 const
只能修饰基本的数据类型, 不能修饰类!
private const val AI_COACH_VIDEO_INFO = "ai_coach_video_info"
ch.setPivotY(svv_coach.height.toFloat())
Boolean类型,如果不执行,那么就不一定返回boolean
if(result!=null&&result.ok()){
initSdk(isUseYuedongSdk)
}else{
ToastUtil.showShort("模型加载失败,请重试")
finish()
}
从一个方法传到另外一个方法默认是final。和java不一样,就像内部类
var url=modelInfo?.model_file_url
if (url != null&&vesion != null&&name != null) {
download(url,videoId,vesion ,name,true)
download(url,videoId,vesion ,name,false)
};
fun download(url: String, videoId: Int, version: String, name: String,isModelNotPro:Boolean){
var path=AndroidRComp.getPrivateDir("aiModel")
var dirPath=path+File.separator+videoId
val dirFile = File(dirPath);
if(!dirFile.exists()){
dirFile.mkdirs()
}
var urlTemp=""
var fileName= version + "_" + name+version
if(isModelNotPro){
fileName=fileName+".tnnmodel"
urlTemp=url+"model"
2. 基础数据结构, 数组, 集合,字符串相关
在Kotlin中,associate 是一个常用于 Map 创建的函数,它可以将一个集合中的元素转换成键值对的形式,从而构建一个新的映射(Map)。
2.1 数组的扩展函数
- . associate 函数有几种不同的形式,最常见的是 associateWith 和 associateBy。
2). distinctby 去重用的
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(
Person("Alice", 25),
Person("Bob", 30),
Person("Alice", 25), // 与第一个 Alice 重复
Person("Charlie", 35)
)
// 根据名字去重
val distinctPeopleByName = people.distinctBy { it.name }
println(distinctPeopleByName)
// 输出可能是: [Person(name=Alice, age=25), Person(name=Bob, age=30), Person(name=Charlie, age=35)]
// 注意:这里不一定输出第一个 Alice,因为 distinctBy 不保证顺序
}
2.2 集合。可变集合和不可变集合:
集合用法
首先声明如下 IntArray 和 List:
🏝️
val intArray = intArrayOf(1, 2, 3)
val strList = listOf("a", "b", "c")
var reportList: MutableList<CourseReportBean>?=null
val titles = arrayOf(getString(R.string.upload), getString(R.string.download))
2.2.1) list扩展函数:
1).filter:过滤集合中满足条件的元素
2).fold
3).any
4).all
5).find
6).forEach
2.2.2).Map扩展函数:
flatMap
mapValues
filterKeys
sequences: 性能优化, 避免创建中间的集合
在 Kotlin 中,Sequence 是一个表示元素序列的接口,它提供了一种惰性(lazy)的方式来处理集合数据。与 List、Set 和 Map 等集合类型不同,Sequence 不会在创建时立即计算所有元素,而是在每次迭代时按需计算。这使得 Sequence 在处理大量数据或无限序列时特别有用,因为它可以显著减少内存消耗并提高性能
2.3. 字符串String的操作
字符串模板$:
fun main(args: Array<String>) {
val s = "runoob"
val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
println(str)
}
toString生成,$符号
override fun toString(): String {
return "TestBean(height=$height, weight=$weight)"
}
Kotlin 为我们提供了一种更加方便的写法:
🏝️
val name = "world"
// 👇 用 '$' 符号加参数的方式
println("Hi $name")
比如打印:
YDLog.logDebegV2(TAG, "recognizeSuc $reRecognize")
Kotlin的构造函数直接声明在类的后面,并且变量的声明也可以在函数的参数中声明,最后字符串的输出,直接使用${变量名}的形式输出
var testBean=TestBean();
var height=testBean.getHeight();
Log.d("peng","height="+height);
println("$height start paly")
1). 拼接
使用 joinToString 函数
val items = listOf("apple", "banana", "cherry")
val joined = items.joinToString(", ") // 结果为 "apple, banana, cherry"
2). 比较.
使用 == 运算符进行引用比较
val str1 = "hello"
val str2 = "hello"
val str3 = str1 + "" // 虽然是相同的内容,但是通过拼接创建的
println(str1 == str2) // 输出 true,因为 str1 和 str2 引用的是同一个对象
println(str1 == str3) // 输出 false,因为 str3 是通过拼接创建的,与 str1 和 str2 引用不同
属性
val message = "The number is ${number * 2}." // 结果为 "The number is 246."
3. 函数:
3.1 单表达式函数:
当函数返回单个表达式时,可以省略花括号
例如:
fun sum(x: Int, y: Int): Int {
return x + y
}
等价于:
fun sum(x: Int, y: Int): Int = x + y
等价于: (原理: 自己都不知道返回的类型, 可以通过kotlin的类型推导)
//编译器可以推断出该函数的返回类型
fun sum(x: Int, y: Int) = x + y
在Kotlin中,if是表达式,而不是语句。语句和表达式的区别在于,表达式有值,能作为另一个表达式的一部分使用;语句总是包围着它的代码块中的顶层元素,并且没有自己的值。
如果函数体写在花括号中,称这个函数有代码块体。如果它直接返回一个表达式,称有表达式体,如下
fun max(a: Int, b: Int): Int = if (a > b) a else b
3.2 中缀函数
要创建一个中缀函数,您需要按照以下步骤进行:
• 将函数定义为成员函数或扩展函数。
• 在 fun 关键字之前添加 infix 关键字。
下面是定义中缀函数的一般语法:
infix fun <ReceiverType>.functionName(param: ParamType): ReturnType {
// 函数逻辑在这里
// ...
return result
}
中锥函数的具体使用案例:
定义中缀函数: 要定义中缀函数,需要使用 infix 关键字将函数标记为中缀,并将其定义为成员函数或扩展函数
infix fun Int.add(x: Int): Int {
return this + x
}
调用中缀函数: 调用中缀函数时,可以省略点符号,直接使用函数名和参数,如下所示:
//这里的 add 就是一个中缀函数。
// 等同于 5.add(3)
val result = 5 add 3
3.3 本地函数(嵌套函数)
首先来看下这段代码,这是一个简单的登录的函数:
fun login(user: String, password: String, illegalStr: String) {
// 验证 user 是否为空
if (user.isEmpty()) {
throw IllegalArgumentException(illegalStr)
}
// 验证 password 是否为空
if (password.isEmpty()) {
throw IllegalArgumentException(illegalStr)
}
}
该函数中,检查参数这个部分有些冗余,我们又不想将这段逻辑作为一个单独的函数对外暴露。这时可以使用嵌套函数,在 login 函数内部声明一个函数:
🏝️
fun login(user: String, password: String, illegalStr: String) {
👇
fun validate(value: String, illegalStr: String) {
if (value.isEmpty()) {
throw IllegalArgumentException(illegalStr)
}
}
👇
validate(user, illegalStr)
validate(password, illegalStr)
}
4. 异常
Nothing: 用于方法抛出异常
方法永远不返回, 而是抛出一个异常
在 Kotlin 中,Nothing 是一个特殊的类型,它表示一个永远不会有实例的类型。换句话说,Nothing 是所有类型的子类型,但没有类型是其超类型(除了 Nullable<Nothing>)。你可以将 Nothing 看作是一个空的类型,它没有实际的实例。
Nothing 类型主要用于以下几种情况:
表示永远不会返回的函数:如果一个函数声明其返回类型为 Nothing,那么这意味着该函数永远不会正常返回。这样的函数通常用于抛出异常或执行其他形式的程序终止。
fun fail(): Nothing {
throw IllegalStateException("This function always fails")
}
val isSuccess: Boolean
get() = errorCode == 0
5.区间:用于for循环
循环遍历:
linklistTasks.forEachIndexed{ index, item ->
itemList.add(item)
}
for循环的写法
有步长
区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:
var recyclerView=findViewById<RecyclerView>(R.id.recycler_view);
recyclerView.layoutManager = LinearLayoutManager(this)
var adapter=MyAdapter(this,initData()!!);
recyclerView.adapter=adapter;
}
private fun initData(): ArrayList<String>? {
var list=ArrayList<String>()
for (i in 0..50){
list.add(""+i);
}
Log.d("tag","list.size------"+ list.size)
return list
}
6. this语法:
progressDialog = ProgressDialog.show(this@AICoachSingleTrainActivity,
7. 类型转换
7.1) 在Kotlin中如何将String转换为Int?
在Kotlin中可使用toInt()方法将字符串值转换为整数或INT。 以下是示例用法:
数据格式转换
this.sendEmptyMessageDelayed(MSG_TIMER, TIME_INTERVAL.toLong())
7. 2).自动类型转换
//函数返回值类型可以是动态的:自动类型转换
fun add2(num :Int,num2:Int)=num+num2
Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。
public fun sum(a: Int, b: Int): Int = a + b // public 方法则必须明确写出返回类型
7.3 )可变长参数函数:和asyncTask的一样
函数的变长参数可以用 vararg 关键字进行标识:
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
// 测试
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
类型检测及自动类型转换我们可以使用 is 运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。
is 是关键字
‘is’表示你可以这样使用关键字
if (type is ParameterizedType) {
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做过类型判断以后,obj会被系统自动转换为String类型
return obj.length
}
//在这里还有一种方法,与Java中instanceof不同,使用!is
// if (obj !is String){
// // XXX
// }
// 这里的obj仍然是Any类型的引用
return null
}
7.4 ) 比较两个数字
Kotlin 中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所以在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。
在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。
fun main(args: Array<String>) {
val a: Int = 10000
println(a === a) // true,值相等,对象地址相等
//经过了装箱,创建了两个不同的对象
val boxedA: Int? = a
val anotherBoxedA: Int? = a
//虽然经过了装箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,对象地址不一样
println(boxedA == anotherBoxedA) // true,值相等
}
链式调用(类似Glide的模式)
Glide.with(context)
.load(url)
.error(icon)
.into(view);
如果接口只有一个,就可以用lameda。如果有2个的话,就要用object
var completeListener=MediaPlayer.OnCompletionListener {
YDLog.logError(TAG, "OnCompletionListener:", "OnCompletionListener:")
var curCompleteTime=System.currentTimeMillis()
if(curCompleteTime-lastCompleteTime>2000){
mPresenter.stopRecognize()
}
lastCompleteTime=System.currentTimeMillis()
}
var downloadListener=object :ScalableVideoViewAsyn.DownLoadListener{
override fun ProgressChanged(netFile: NetFile?, progress: Int) {
}
override fun DownloadFinished(netFile: NetFile?, result: NetResult?) {
}
}
).设置监听和回调
var lister = object : OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
binding.viewpager.currentItem = tab!!.position
tab?.customView?.findViewById<TextView>(R.id.tv_title)
?.setTextColor(getColor(R.color.color_08C5AC))
tab?.customView?.findViewById<View>(R.id.indicator)
?.setBackgroundColor(getColor(R.color.color_08C5AC))
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
tab?.customView?.findViewById<TextView>(R.id.tv_title)
?.setTextColor(getColor(R.color.color_7A7A7A))
tab!!.customView?.findViewById<View>(R.id.indicator)
?.setBackgroundColor(getColor(R.color.color_transparent))
}
}
有参数的类的写法
binding.viewpager.adapter = object : FragmentStatePagerAdapter(
supportFragmentManager,
FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
) {
override fun getCount(): Int {
return fragments.size
}
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getPageTitle(position: Int): CharSequence? {
return titles[position]
}
}