Android中Kotlin的应用

    本文以创建一个Activity为总结下Android中如何使用Kotlin,并罗列出常用的功能,包含以下内容:


  • 静态变量
  • findviewbyid
  • 设置点击事件
  • 扩展方法——吐司
  • 线程切换
  • 数据类
  • 网络请求
  • RecycleView的Kotlin编程
  • 集合的创建和分类
  • 操作重载符invoke
  • 单例模式、reified关键字、泛型
  • 枚举、when表达式

静态变量

    在Android常常创建很多静态类,例如:sp的标志,日志TAG,接口url等等,在Java中常用public static final来修饰,而在kotlin中则使用companion object,其中object可以省略,但是一般不建议省略,如下例子:

    companion object{
        val TAG = "MainActivity"
        val url = "http://www.sojson.com/open/api/weather/json.shtml?city=北京"
                ………………………………
    }

findViewById

    之前代码中要写很多findViewById,这重复的东西很浪费时间,因此出现了ButterKnife,Xutils3等注解框架,而在kotlin中这些框架可以解放了,只要我们在xml中加上id,则在Activity或者Fragment上面直接引用,例如xml中设置了Button,则在Activity中可以直接使用:

    btn.setText("点我试试")

    需要注意的是需要导入:import kotlinx.android.synthetic.main.activity_main.*包。

设置点击事件

    在kotlin中点击事件的设置很简化了,如下:

    btn.setOnClickListener {
        …………………………
    }

扩展方法——吐司

    在开发中通常使用吐司,每次写吐司都是一行重复的代码,kotlin中可以使使用扩展方法来扩展Context的方法,这样每次使用的时候直接调用方法,连类名都不需要。

     fun Context.toast(message: CharSequence,  duration: Int = Toast.LENGTH_SHORT){
         Toast.makeText(this,message,duration).show()
     }

线程切换

    之前创建一个子线程一般都是使用Thread、线程池或者AsyncTask,需要写很多的代码非常繁琐,而kotlin的anko框架可以帮助我们非常快速而简洁的实现线程切换,而且还能避免一些崩溃问题。在使用之前需要引入依赖:

    implementation "org.jetbrains.anko:anko-commons:$anko_version"
    在切换线程的时候可以:

    doAsync {

        ……………………………………子线程………………………………

        //如果Acivity被销毁了,则此方法不会再执行,避免了崩溃
        uiThread {

          ……………………………………主线程………………………………

        }
     }
    除此之外anko还提供了其他功能:布局功能,数据库功能,常用类的扩展方法等等。

数据类

    在请求网络后一般返回的数据都是json格式的数据,通常需要建立JavaBean进行数据的解析,Kotlin里面不用像Java一样,编写大量setter/getter方法,在Java编码中Android Studio中提供了GsonFormat插件可以很方便的生成JavaBean。在Kotlin编码中在另外提供了JsonToKotlin插件,能够自动生Kotlin编码的JavaBean。另外Kotlin提供了一个数据类,只需要加在JavaBean的class之前就可以实现setter/getter方法,toString方法,hashCode方法,copy方法。这样我们在使用的时候可以直接获取到,而不同在中JavaBean重写。

    data class WeatherBean(
            val date: String
            val message: String
            val status: Int
            val city: String
            val count: Int
            val data: Data
    )

网络请求

    kotlin提供了一个readText()方法,可以进行网络的请求,这是kotlin标准库的扩展方法,但是这个方法响应延迟很大,请求一次数据很耗时,不推荐使用:

     val url = URL(url)
     val text = url.readText()
    可以在doAsync里面进行网络请求,然后在uiThread里面更新UI。

    另外,在Java中常用的第三方网络请求框架:Volley,Okhttp,Retrofit等在Kotlin中国中可以正常使用,需要注意的是SAM 转换。

    1、字节码的获取

    Java中:
    (1)Class<?> clazz = Hello.class;
    (2)Hello hello = new Hello();
        Class<?> clazz2 = hello.getClass

    Kotlin中:
    (1)val clazz = Hello::class.java
    (2)val hello = Hello()
        val clazz2 = hello.javaClass

     在使用第三方框架的时候调用Kotlin调用Java代码应该替换为以上任意一个。

     2、SAM 转换

    在Java中经常new XxxCallback<T>接口类型的参数,而在Kotlin中需要使用object:Callback<T>{}进行替代,例如:

     call.enqueue(object:Callback<T>{
         override fun onResponse(call: Call<T>?, response: Response<T>?) {
             TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
         }

         override fun onFailure(call: Call<T>?, t: Throwable?) {
             TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
         }
     })
     接口中包含单个方法的,可以被简化为一个函数。

RecycleView的Kotlin编程

一、RecycleView使用

    1、MyViewHolder的创建
    创建一个MyViewHolder继承自RecyclerView.ViewHolder,看一下ViewHolder的构造方法:

    public ViewHolder(View itemView) {
        if (itemView == null) {
            throw new IllegalArgumentException("itemView may not be null");
        }
        this.itemView = itemView;
    }
    她需要一个参数View itemView,因此我们需要在MyViewHolder中构造参数,传递给RecyclerView.ViewHolder,因此MyViewHolder中需要一个构造方法:

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    }
    在Java中常用findViewById,在kotlin中如何使用?anko框架提供了一个find的方法供我们使用,因此可以这样:

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var tv_text1  = itemView.find<TextView>(R.id.tv_text1)
        var tv_text2  = itemView.find<TextView>(R.id.tv_text2)
        var tv_text3  = itemView.find<TextView>(R.id.tv_text3)
        var tv_text4  = itemView.find<TextView>(R.id.tv_text4)
   }

    2、MyAdapter的创建
    同样也是继承自RecyclerView.Adapter,在创建Adapter的时候需要传递集合参数作为数据源,也需要一个柱构造方法实现三个抽象方法:

    class MyAdapter(val list: List<Forecast>) : RecyclerView.Adapter<MyAdapter.MyViewholder>() {
        override fun getItemCount(): Int {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }

        override fun onBindViewHolder(holder: MyViewHolder?, position: Int) {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }

        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyViewHolder {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }
    }
    然后在getItemCount返回集合大小,onBindViewHolder中绑定数据,onCreateViewHolder绑定布局,大功告成。但是代码比较长,和kotlin不太符合kotlin的风格,接下来进行优化。

二、RecycleView的简化

    1、MyViewHolder的简化
    在onBindViewHolder主要进行了数据的绑定,我们可以把这一部分内容转移到MyViewHolder里面进行处理,这是时候MyViewHolder需要提供一个绑定数据的方法,供onBindViewHolder来调用并且传递参数,这样可以省略= itemView.find<TextView>(R.id.tv_text1)这一步:

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(forecast: Forecast) {
            itemView.tv_text1.text = forecast.date
            itemView.tv_text2.text = forecast.high
            itemView.tv_text3.text = forecast.low
            itemView.tv_text4.text = forecast.notice
        }
    }

     2、MyAdapter的简化
    在Kotlin语法中,如何返回值的数据类型和要求的数据类型一致,并且只有一条表达式,可以简化为一句代码,按照这个规则,可以对上述三个方法进行优化,三行代码就实现了:

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_list, null, false))

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) = holder.bind(list[position])

    override fun getItemCount() = list.size

    3、操作重载符invoke
    以上的RcycleView不能点击item,如果想定义一个setOnItemClickListener方法监听点击事件,该怎么办呢?这里用到操作重载符invoke函数,他是Kotlin能够重载一些操作符,在我们的类中实现其相应的函数,这些函数前必须加上保留字operator。如下定义一个接口监听点击事件:

    interface OnItemClickListener {
        operator fun invoke(forecast: Forecast)
    }
    定义好之后和Java一样需要在MyAdapter主构造方法中初始化,在onCreateViewHolder中使用参数,传参到MyAdapter中,然后给itemView设置点击事件,再调用invoke时候这个方法名称可以省略掉。完整代码如下:

class MyAdapter(val list: List<Forecast>, val itemClick: OnItemClickListener) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_weather, null, false), itemClick)

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) = holder.bind(list[position])

    override fun getItemCount() = list.size

    class MyViewHolder(itemView: View, private val itemClick: OnItemClickListener) : RecyclerView.ViewHolder(itemView) {

        fun bind(forecast: Forecast){
            itemView.tv_text1.text = forecast.date
            itemView.tv_text2.text = forecast.high
            itemView.tv_text3.text = forecast.low
            itemView.tv_text4.text = forecast.notice
            itemView.setOnClickListener { itemClick(forecast) }
        }
    }

    interface OnItemClickListener {
        operator fun invoke(forecast: Forecast)
    }
}

单例模式、reified关键字、泛型

    在网络请求框架中Retrofit是比较常用的,他的创建配置信息一般都比较固定,因此我们可以让他变为一个单例模式,Kotlin中单例模式比Java简洁的多,只需要把class换位object关键字就可以了,先来看看那Retrofit初始化原始代码:

    val retrofit = Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create())
                    .baseUrl("http://www.json.com")
                    .build()
    val create = retrofit.create<API>(API::class.java)
    val call = create.call("北京")
    Retrofit单例模式:

    1、Kotlin中创建RetrofitInstance

    object RetrofitInstance{

    }
    2、设置静态成员变量
    const val url = "http://www.json.com"
    3、提供初始化方法
    inline fun <reified T> getRetrofit(): T {
        return Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(url)
                .build()
                .create<T>(T::class.java)
    }

    inline:内联函数关键字,内联函数是以目标代码的增加为代价来换取时间的节省。
    reified:它代表你可以在方法体内访问泛型指定的Java类对象。必须以 inline 内联方式声明这个方法才有效。
    T:泛型参数,和Java中使用方法基本一致。

枚举、when表达式

enum class Lang(val day: String) {
    SUN("一"), MON("二"), TUE("三"), WED("四");

    fun day() {
        val bay = when (this) {
            Lang.SUN -> "星期一"
            Lang.MON -> "星期二"
            Lang.TUE -> "星期三"
            Lang.WED -> "星期四"
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值