9.kotlin安卓实践课程-用kotlin写第一个fragment的recyclerView的adapter具体实现

简介: 简介主要会通过安卓实战来讲解kotlin语法和实际应用,本教程设及知识点包括框架模式mvp+mvvm, Databinding(数据绑定框架),Dagger2(依赖注入框架),DeepLink(页面路由框架),Rxjava,RxAndroid(异步操作框架),Retrofit,Okhtttp等,不过本教程重点在kotlin所以这些框架需要了解可自行百度。

简介

主要会通过安卓实战来讲解kotlin语法和实际应用,本教程设及知识点包括框架模式mvp+mvvm, Databinding(数据绑定框架),Dagger2(依赖注入框架),DeepLink(页面路由框架),Rxjava,RxAndroid(异步操作框架),Retrofit,Okhtttp等,不过本教程重点在kotlin所以这些框架需要了解可自行百度。

针对人群:Android中级以上,kotlin入门


本系列最后一篇我们看看recyclerView的adapter怎么实现的


首先先看一下代码

/**
 * Created by bigman on 18-05-18.
 */
class AndroidAdapter(private val mList: List<AndroidBean>) 
:BaseBindingAdapter<ItemAndroidBinding>() {
  override fun getItemCount(): Int {
    return mList.size
  }

  override fun onBindViewHolder(holder: DataBoundViewHolder<ItemAndroidBinding>, position: Int) {
    super.onBindViewHolder(holder, position)
    //数据绑定
    holder.binding.androidbean = mList[position]
    //数据立即绑定而不是在下一帧的时候才绑定,避免闪烁和数据错乱
    holder.binding.executePendingBindings()
  }

  override fun onCreateViewHolder(parent: ViewGroup,
      viewType: Int): DataBoundViewHolder<ItemAndroidBinding> {
    return DataBoundViewHolder(
            ItemAndroidBinding.inflate(LayoutInflater.from(parent.context), parent, false))
  }
}

首先看主构造函数和继承

class AndroidAdapter(private val mList: List<AndroidBean>) 
:BaseBindingAdapter<ItemAndroidBinding>() 
  1. 主构造函数传入一个List<AndroidBean>类型的mList只读变量
  2. 继承至BaseBindingAdapter<ItemAndroidBinding>()

下一步我们看一下基类BaseBindingAdapter的具体实现

/**
 * Created by bigman on 18-05-18.
 */
abstract class BaseBindingAdapter<B : ViewDataBinding>
 : RecyclerView.Adapter<DataBoundViewHolder<B>>() {
    var mListener: ((pos: Int) -> Unit)? = null

    override fun onBindViewHolder(holder: DataBoundViewHolder<B>, position: Int) {
        holder.binding.root.setOnClickListener {
            mListener?.invoke(holder.adapterPosition)
        }
    }

    fun setOnItemClickListener(listener: ((pos: Int) -> Unit)) {
        mListener = listener
    }

}
  • 大家可以看到BaseBindingAdapter需要传入ViewDataBinding类型,这个ViewDataBinding是databinding里面所有视图bingding类的基类,
  • 然后毫无疑问它必须继承于RecyclerView.Adapter<DataBoundViewHolder<B>>,这个我们平时写java的RecyclerView.Adapter的时候都需要继承的
    这里还有一个DataBoundViewHolder<B>,看一下代码实现
/**
 * Created by bigman on 18-05-18.
 */
 class DataBoundViewHolder<T : ViewDataBinding>(val binding:T) 
: RecyclerView.ViewHolder(binding.root) {
}

其实它就是一个RecyclerView.ViewHolder,只是这里我们传入了通用的ViewDataBinding使它变成可以绑定任意视图

回到BaseBindingAdapter,这个基类主要功能就是实现一个通用的databinding用的适配器,只要传入databinding视图类型即可,类内部提供了一个点击事件的回调方法

然后再回到AndroidAdapter
这里主要由三个方法,

  • getItemCount ()返回绑定列表长度,
  • onBindViewHolder ()实现视图数据绑定,这里用的databingding的数据绑定,holder.binding.executePendingBindings(),这句代码比较重要不加可能导致数据错乱或者页面闪烁
  • onCreateViewHolder()主要是完成databinding的holder构建
 override fun onCreateViewHolder(parent: ViewGroup,
      viewType: Int): DataBoundViewHolder<ItemAndroidBinding> {
    return DataBoundViewHolder(
            ItemAndroidBinding.inflate(LayoutInflater.from(parent.context), parent, false))
  }

这里的 ItemAndroidBinding是databinding根据我们的布局文件自动生成的,我们看一下我们这个列表条目布局代码,名称item_android.xml注意对比databinding生成的binding类名称

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="android.view.View" />

        <variable
            name="androidbean"
            type="com.bigman.kotlin.bean.AndroidBean" />
    </data>

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_marginLeft="2dp"
        android:layout_marginRight="2dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:background="#fff"
        android:orientation="vertical"
        app:cardCornerRadius="5dp"
        android:paddingTop="10dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="vertical"
            android:paddingLeft="16dp"
            android:paddingBottom="10dp"

            android:paddingRight="16dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{androidbean.desc}"
                android:textColor="#000"
                android:textSize="16sp" />

            <ImageView

                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="10dp"
                android:scaleType="center"
                android:visibility="@{androidbean.hasImg()?View.VISIBLE:View.GONE}"
                app:load_image="@{androidbean.images[0]}" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView
                    android:layout_marginTop="10dp"
                    android:text="@{androidbean.who}"
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    />

                <TextView
                    android:layout_marginTop="10dp"
                    android:text = "@{androidbean.create()}"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    />

            </LinearLayout>
        </LinearLayout>

    </android.support.v7.widget.CardView>
</layout>

具体代码和前面说过的布局没啥太大区别,主要就是data数据的传入和数据绑定

眼神比较犀利的同学可能会看到几个比较不一样的地方而存在疑惑,我们看看是哪里

 <ImageView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="10dp"
                android:scaleType="center"
                android:visibility="@{androidbean.hasImg()?View.VISIBLE:View.GONE}"
                app:load_image="@{androidbean.images[0]}" />

这里的app:load_image这是''databinding允许的一个函数绑定形式
我们看一下具体实现:

/**
 * Created by bigman on 18-05-18.
 */

@BindingAdapter("load_image")
fun loadImage(imageView: ImageView, url: String?) =
        Glide.with(imageView.context).load(url)
                .crossFade()
                .into(imageView)

@BindingAdapter("set_text")
fun setText(textView: TextView, string: String) {
    textView.setText("bigman" + string)
}


@BindingAdapter("load_asset")
fun loadAsset(imageView: ImageView, id: Int) =
        Glide.with(imageView.context).load(id).into(imageView)

这几个函数被我卸载随意的一个kt文件里面,然后通过 @BindingAdapter注解,我们的databinding框架就能很容易的找到它

那么我们这一系列kotlin 安卓实战内容到这里结束了,虽然kotlin知识点讲的不错,但是基本的运用知道这些也差不多够了,大家可以自己动手写一下,本系列主要目的已经达到,就是kotlin在这种mvp+mvvm目前最合理框架上的具体应用


欢迎一起交流,有问题加群交流

kotlin实战交流群群二维码.png
相关文章
|
3天前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
14 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
3天前
|
Android开发 Kotlin
kotlin开发安卓app,如何让布局自适应系统传统导航和全面屏导航
使用`navigationBarsPadding()`修饰符实现界面自适应,自动处理底部导航栏的内边距,再加上`.padding(bottom = 10.dp)`设定内容与屏幕底部的距离,以完成全面的布局适配。示例代码采用Kotlin。
38 15
|
4天前
|
存储 API Android开发
kotlin开发安卓app,使用webivew 触发 onShowFileChooser, 但只能触发一次,第二次无法触发,是怎么回事。 如何解决
在Android WebView开发中,`onShowFileChooser`方法用于开启文件选择。当用户只能选择一次文件可能是因为未正确处理选择回调。解决此问题需确保:1) 实现`WebChromeClient`并覆写`onShowFileChooser`;2) 用户选择文件后调用`ValueCallback.onReceiveValue`传递URI;3) 传递结果后将`ValueCallback`设为`null`以允许再次选择。下面是一个Kotlin示例,展示如何处理文件选择和结果回调。别忘了在Android 6.0+动态请求存储权限,以及在Android 10+处理分区存储。
|
5天前
|
存储 移动开发 Android开发
使用kotlin Jetpack Compose框架开发安卓app, webview中h5如何访问手机存储上传文件
在Kotlin和Jetpack Compose中,集成WebView以支持HTML5页面访问手机存储及上传音频文件涉及关键步骤:1) 添加`READ_EXTERNAL_STORAGE`和`WRITE_EXTERNAL_STORAGE`权限,考虑Android 11的分区存储;2) 配置WebView允许JavaScript和文件访问,启用`javaScriptEnabled`、`allowFileAccess`等设置;3) HTML5页面使用`<input type="file">`让用户选择文件,利用File API;
|
6天前
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
21 6
|
1天前
|
Android开发 Kotlin
Android经典面试题之Kotlin中Lambda表达式有哪些用法
Kotlin的Lambda表达式是匿名函数的简洁形式,常用于集合操作和高阶函数。基本语法是`{参数 -&gt; 表达式}`。例如,`{a, b -&gt; a + b}`是一个加法lambda。它们可在`map`、`filter`等函数中使用,也可作为参数传递。单参数时可使用`it`关键字,如`list.map { it * 2 }`。类型推断简化了类型声明。
6 0
|
1天前
|
Android开发 Kotlin
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
**Kotlin中的匿名函数与Lambda表达式概述:** 匿名函数(`fun`关键字,明确返回类型,支持非局部返回)适合复杂逻辑,而Lambda(简洁语法,类型推断)常用于内联操作和高阶函数参数。两者在语法、返回类型和使用场景上有所区别,但都提供无名函数的能力。
7 0