Kotlin在实际项目中的使用小结

一.Kotlin属性
1.默认方法
    var uuid:String
        get() = CacheTool.localCache.getString(UUID)?:""
        set(value) {
            CacheTool.localCache.put(UUID,value)
        }
2.get 和set属性

我们可以为属性定义自定义的访问器。如果我们定义了一个自定义的 getter,那么每次访问该属性时都会调用它 (这让我们可以实现计算出的属性)。以下是一个自定义 getter 的示例:

val isEmpty: Boolean
    get() = this.size == 0

如果我们定义了一个自定义的 setter,那么每次给属性赋值时都会调用它。一个自定义的 setter 如下所示:

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value) // 解析字符串并赋值给其他属性
    }

按照惯例,setter 参数的名称是 value,但是如果你喜欢你可以选择一个不同的名称。

自 Kotlin 1.1 起,如果可以从 getter 推断出属性类型,则可以省略它:

val isEmpty get() = this.size == 0  // 具有类型 Boolean

如果你需要改变一个访问器的可见性或者对其注解,但是不需要改变默认的实现, 你可以定义访问器而不定义其实现:

var setterVisibility: String = "abc"
    private set // 此 setter 是私有的并且有默认实现

var setterWithAnnotation: Any? = null
    @Inject set // 用 Inject 注解此 setter

如不想对外公开某个方法时,可以使用修饰符private实现,如:

// 是否加载失败
var isLoadFail = false
	private set  // 此 setter 是私有的并且有默认实现

设置 set 属性为private 后, 那么它将只在同一个源代码文件内可以访问,在其他作用域下 如其他包名下不能访问。

注意:这种方式只适用于 set 方法, get的访问权限默认和属性是一致的,如下面的使用会编译错误

var isLoadFail = false
	private get  // 编译错误,get的访问权限和属性一致
3.get /set 方法使用注意事项
var isSelected: Boolean = false
        set(value) {
            isSelected = value
            invalidate()
        }

这段代码会使得循环调用,最终ANR,正确的写法应该是:

var isSelected: Boolean = false
        set(value) {
            field = value
            invalidate()
        }
二.基本类型

Double类型值 如:123.5, 123.5e10

Float值需要用f或F标识:123.5f

Long类型需要大写的L来标识:123L

在数字字面值中添加下划线,提高可读性。(kotlin1.1开始支持)

val oneMillion = 1_000_000
val creditCardNumber = 1234_5678L

三.when表达式

如果对多种条件需要进行相同的处理,那么可以对一个分支指定多个条件,有逗号分隔:

when (x){
    0,1 -> print("x==0 or x==1")
    else -> print("otherwise")
}
四.var、val、lateinit、by lazy的使用

var 是一个变量,初始化的值可以修改,val 是一个常量,只读。

lateinit 和lazy是两种不同的延迟初始化

lateinit 只用于变量var ,lazy只用于常量val

lateinit 不能用于可空的属性上和java的基本类型

private val money: Int by lazy {1} //正确
private lateinit val test:String  //正确

lateinit val test:String //error
lateinit val test:Float //error

lazy 应用于单例模式 (if-null-then-init-else-return),而且当且仅当常量被第一次调用的时候,委托方法才会被执行。

实际项目中运用举例:

1.比如这样的常见操作,只获取,不赋值(val类型),并且多次使用的对象

private val mUserManager : UserManager by lazy {
    UserManager.getInstance()
} 

2.再比如 Activity中控件的初始化,一般传统的进入界面就初始化所有的控件,而使用懒加载,只有用到时才会对控件初始化

//kotlin 封装:
fun <V : View> Activity.bindView(id: Int): Lazy<V> = lazy {
    viewFinder(id) as V
}
 
//acitivity中扩展调用
private val Activity.viewFinder: Activity.(Int) -> View?
    get() = { findViewById(it) }
 
//在activity中的使用姿势
val mTextView by bindView<TextView>(R.id.text_view)
mTextView.text="执行到我时,才会进行控件初始化"

lateinit则用于只能在生命周期流程中进行获取或初始化的变量。有一些在 Android 中某些属性需要在 onCreate() 方法中初始化。

private lateinit var mAdapter: RecyclerAdapter<Transaction>

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mAdapter = RecyclerAdapter(R.layout.item_transaction)
}

//或者类似这样的
private lateinit var vehicleListDialog: VehicleListDialog

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
     
     initVehicleListDialog()
    }   
private fun initVehicleListDialog() {
        var dialog = childFragmentManager.findFragmentByTag(VehicleListDialog.TAG) as 						VehicleListDialog?
        if (dialog == null) {
            dialog = VehicleListDialog()
        }
    	//进行初始化
        vehicleListDialog = dialog
    }

再比如:

class App:Application(){
    init {
        instance = this
    }
    
    @Inject lateinit var apiComponent: ApiComponent
    override fun onCreate() {
        super.onCreate()
        					DaggerApiComponent.builder().apiModule(ApiModule()).appModule(AppModule(this)).build().inject(this)

    companion objectf{
        lateinit var instance:App
    }
}

注意:要慎用,使用延迟初始化时 要注意,变量的使用前需要初始化,否则会报错。

如:使用对象判断是否初始化

private lateinit var avatarFile: File
//是否初始化
private fun isAvaFileInitialzed():Boolean = ::avatarFile.isInitialized
五. !!.和?.的区别

!!.和?.都是Kotlin提供的检测空指针的方法。

“?”用来明确指定一个对象,或者一个属性变量是否可以为空。

private var mContext:Context? = null

"?"加在变量名后,系统在任何情况不会报它的空指针异常。
"!!"加在变量名后,如果对象为null,那么系统一定会报异常!

?.
//kotlin
foo?.run()

//与java相同
if(foo != null){
    foo.run()
}//不会空指针

!!.
//kotlin
foo!!.run()

//与java相同
if(foo != null){
    foo.run();
}else{//为空,则出现空指针
    throw new KotlinNullPointException();
}

六.Anko用于执行后台任务

搭配 Anko lib 使用。后台和主线程的切换特别直观和简单。uiThread 在主线程上运行,并且我们不需要关心 Activity 的生命周期(pause 与 stop), 所以也不会出错了。

如果一个Activity调用doAsync,那么如果该Activity消亡(isFinishing返回true)uiThread代码是不会执行的。这样,我们就避免了AsyncTask经常出现的错误或其他没有注意activity生命周期的任何回调函数。


doAsync{
    //后台执行
    var result = getResult()
    //回到主线程
    uiThread{
        toast(result)
    }
}

项目中运用实例:

如在微信支付中,接收支付成功或失败的回调事件。

doAsync {
            WeChatPay.wxApi.handleIntent(intent, object : IWXAPIEventHandler {
                override fun onReq(req: BaseReq) {}

                override fun onResp(resp: BaseResp) {
                    uiThread {
                        if (resp.type == ConstantsAPI.COMMAND_PAY_BY_WX) {
                            handlePayResponse(resp)
                        }
                        finish()
                    }
                }
            })
        }
七.with 、apply、let、run、takeif等函数的使用场景总结
1.with

定义:

fun<T,R>with(receiver:T,block:T.() ->R):R

功能:将对象作为函数的参数,在函数内可以通过this指代该对象。返回值为函数的最后一行或return 表达式。

实例1:

    /**
     * 画笔对象的引用
     */
    private var paint = Paint()
  		paint.strokeCap = Paint.Cap.ROUND
        paint.isAntiAlias = true // 消除锯齿
        paint.isDither = true //防止抖动
        paint.color = roundColor // 设置圆环的颜色
        paint.style = Paint.Style.FILL // 设置空心
        paint.strokeWidth = roundWidth // 设置圆环的宽度

    //用with后更自然
 	private var paint = Paint()
       with(paint) {
           //this指代Paint对象,此处可以省略
            strokeCap = Paint.Cap.ROUND
            isAntiAlias = true // 消除锯齿
            isDither = true //防止抖动
            color = roundColor // 设置圆环的颜色
            style = Paint.Style.FILL // 设置空心
            strokeWidth = roundWidth // 设置圆环的宽度
        }

实例2:

var list = mutableListOf<Int>()
list.add(1)
list.add(2)

//用with后 
var list = with(mutableListOf<Int>()){
    add(1)
    add(2)
    this
}

2.apply

定义:

fun T.apply(block:T.() ->Uint):T

功能:调用对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。

实例:

var list = mutableListOf<Int>().apply{
    add(1)
    add(2)
}


val paint = Paint().apply {
         strokeCap = Paint.Cap.ROUND
         isAntiAlias = true // 消除锯齿
         isDither = true //防止抖动
         color = roundColor // 设置圆环的颜色
         style = Paint.Style.FILL // 设置空心
         strokeWidth = roundWidth // 设置圆环的宽度
     }

此外由于apply函数返回的是其对象本身,那么可以配合?.完成多级的非空判断操作,或者用于建造者模式的Builder中。

3.let

定义:

fun <T,R> T.let(block:(T) -> R):R

功能:调用对象(T)的let函数,则该对象为函数的参数。在函数内可以通过 it 指代该对象。返回值为函数的最后一行或指定return表达式。

实例:有点类似于run(),let在使用中可用于空安全验证,变量?.let{}例如

val bean = listParkingVehicleEntity.find { it.plateNo == plateNo }
        bean?.let {
            parkingVehicleEntity = bean
            showUserVehicle(it)
        }
4.run

定义:有两种

fun <R> run(block: () -> R): R 
fun <T, R> T.run(block: T.() -> R): R

功能:执行传入的函数式,并返回函数的执行结果。run的主要目的是强调需要执行的函数。函数内可通过this引用当前对象; 返回值为最后一行, 可以与当前对象类型不同

实例:

intentEXTRA_URL的值,不为非空且内容不为空,赋值给url。否则弹出提示并关闭页面。

url = intent.getStringExtra(EXTRA_URL)?.takeIf{it.isNotEmpty()}?:run{
    toast("不能浏览一个空链接哦")
    activity.finish()
}

"kotlin".run{"Hello $this"}
>>> Hello kotlin

小结:run()、with(T)、T.run()、 T.let()、 T.apply() 、T.also()选择时的流程图参考如下:

20190127222038222

5.takeIf和takeUnless

定义:

/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 */
fun <T> T.takeIf(predicate: (T) -> Boolean): T?

功能:传递一个函数参数,如果函数结果为true,返回T对象,否则返回null。

实例1:

"123".takeIf {it.length > 10}

//返回值为null

//takeUnless与takeIf相反,参数函数返回false时返回T对象,否则返回null
"123".takeUnless{it.length > 10}
//返回值为123

实例2:

var file = File("filePath")
if(file.exists()){
    //do something
}else{
    return false
}

//引入takeIf 后
var file  = File("filePath").takeIf{it.exists()}?:return false
//do something
八 、类型别名(Type alias)的使用

自kotlin 1.1起,类型别名(Type alias)为现有类型提供替代名称,
如果类型名称太长,可引入较短别名替代原类型名。

1.为集合类型(collection type)提供别名
//缩短较长泛型类型(generic type)是很有吸引力的
typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>
2.为函数类型(function type)提供别名(alias)
typealias MyHandler = (Int, String, Any) -> Unit
typealias Predicate<T> = (T) -> Boolean
3.为内部类(inner)和嵌套类(nested)创建别名
class A{
    inner class Inner
}
class B{
    inner class Inner
}
typealias AInner = A.Inner
typealias BInner = B.Inner

提示:
类型别名不会引入新类型,等效于相应底层类型,编译器会把别名翻译为原有类型:

//添加别名声明typealias Predicate<T>后,Kotlin编译器总是把它扩展为(Int) -> Boolean     
typealias Predicate<T> = (T) -> Boolean
    fun foo(p: Predicate<Int>) = p(42) 
    
    fun main(args: Array<String>) {
        //类型别名和原有类型,可以相互替代,因为编译器会把别名翻译为原有类型
        val f: (Int) -> Boolean = { it > 0 }
        println(foo(f)) // 输出 "true"

        val p: Predicate<Int> = { it > 0 }
        println(listOf(1, -2).filter(p)) // 输出 "[1]"
    }

实例运用:如在网络请求中,有时为了命名的规范性,可以适当引入别名来实现。

typealias CZGetRequest = GetRequest

typealias CZPostRequest = PostRequest

九、数组循环

   run outside@{
        (0..10).forEachIndexed { index, it ->
            println("-- forEach -- $index --")
            if (it > 5) return@outside
            println(it)
        }
    }
```

注意,不要 return ,否则会退出整个方法,而不是返回退出方法。
参考:

[1.慎用延迟初始化(lazy initialization)](https://blog.csdn.net/en_joker/article/details/81429085)

[2.Kotlin with 、apply等函数的使用场景总结](https://blog.csdn.net/coder_e/article/details/80659115)

[3.Kotlin官方文档介绍Type aliases](https://kotlinlang.org/docs/reference/type-aliases.html)


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 在 Kotlin 连接数据库需要使用 JDBC (Java Database Connectivity)。 首先,你需要在项目导入 JDBC 驱动,比如可以在 build.gradle 文件添加以下依赖: ``` dependencies { implementation 'com.mysql:mysql-connector-java:8.0.21' } ``` 然后就可以在代码使用 JDBC 连接数据库了。下面是一个示例,假设我们要连接一个 MySQL 数据库: ```kotlin import java.sql.DriverManager fun main() { // 加载 JDBC 驱动 Class.forName("com.mysql.cj.jdbc.Driver") // 连接数据库 val connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/database_name", "username", "password" ) // 使用数据库 // ... // 关闭数据库连接 connection.close() } ``` 在这个示例,我们首先加载了 JDBC 驱动,然后使用 `DriverManager.getConnection` 方法来连接数据库。这个方法需要传入三个参数:数据库的 URL、用户名和密码。在这个例子,我们连接的是本地的 MySQL 数据库,数据库名称为 `database_name`,用户名为 `username`,密码为 `password`。 使用数据库的代码取决于你想要实现什么功能,可以使用 SQL 语句执行查询、插入、更新等操作。 最后,使用完数据库后一定要记得关闭数据库连接 ### 回答2: Kotlin是一种非常适合开发Android应用程序的语言,它也可以用于连接数据库。连接数据库是许多应用程序的基本功能之一,这允许我们存储和检索数据。在Kotlin,我们可以使用JDBC(Java Database Connectivity)来连接数据库。 要连接数据库,我们首先需要在项目包含适当的数据库驱动程序库。根据我们使用的数据库,我们可以选择不同的驱动程序库。例如,如果我们使用的是MySQL数据库,我们可以在gradle文件添加以下依赖项: `implementation 'mysql:mysql-connector-java:8.0.27'` 一旦我们包含了适当的驱动程序库,我们就可以在Kotlin代码连接到数据库。 首先,我们需要导入所需的库: ```kotlin import java.sql.DriverManager import java.sql.Connection import java.sql.SQLException ``` 然后,我们可以编写连接数据库的功能: ```kotlin fun connectToDatabase() { val url = "jdbc:mysql://localhost:3306/mydatabase" val username = "root" val password = "password" try { Class.forName("com.mysql.cj.jdbc.Driver") val connection: Connection = DriverManager.getConnection(url, username, password) println("成功连接到数据库!") // 在这里执行数据库操作 connection.close() } catch (e: SQLException) { println("连接数据库时出错:${e.message}") } catch (e: ClassNotFoundException) { println("找不到数据库驱动程序:${e.message}") } } ``` 在上述示例,我们首先指定了数据库的URL,以及用于连接的用户名和密码。然后,我们使用`DriverManager.getConnection()`方法来建立与数据库的连接。如果连接成功,则显示成功消息,并可以在连接上执行数据库操作。最后,我们使用`connection.close()`方法关闭数据库连接。 通过调用`connectToDatabase()`函数,我们可以在Kotlin连接到数据库。这是一个简单的示例,但在实际开发,我们可以根据需求进行更复杂的数据库查询和操作。 ### 回答3: Kotlin是一种面向对象的程序设计语言,它可以与多种数据库连接并交互。在Kotlin,我们可以使用不同的库或框架来连接数据库,如JDBC和Exposed。 使用JDBC连接数据库: 1. 导入Java的JDBC库:在Kotlin,我们可以直接使用Java的JDBC库,无需特殊的配置。 2. 加载数据库驱动程序:使用Class.forName()方法加载数据库驱动程序,如com.mysql.jdbc.Driver。 3. 建立数据库连接:使用DriverManager.getConnection()方法建立与数据库的连接,并传入数据库的URL、用户名和密码。 4. 执行SQL查询或更新:使用Connection对象创建Statement或PreparedStatement,执行SQL查询或更新操作。 5. 处理查询结果:使用ResultSet对象处理查询结果,如获取查询结果集的数据。 使用Exposed连接数据库: 1. 导入Exposed库:Exposed是一个轻量级的Kotlin库,用于简化数据库访问和操作。 2. 配置数据库连接:在Kotlin,我们可以使用exposed的Database对象来配置数据库连接,如指定数据库驱动程序、URL、用户名和密码。 3. 编写数据模型:使用exposed的Table对象定义数据模型,包括表名、列名、列类型等。 4. 执行SQL查询或更新:使用exposed的DSL(领域专用语言)执行SQL查询或更新操作,如插入、更新、删除等。 5. 处理查询结果:使用exposed的DSL处理查询结果,如获取查询结果集的数据。 总结来说,Kotlin连接数据库可以使用JDBC和Exposed两种方式。无论是使用JDBC还是Exposed,我们都需要导入相应的库,配置数据库连接,执行SQL操作,并处理查询结果。根据具体需求和项目的特点,选择适合的数据库连接方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羊子说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值