Xây dựng ứng dụng Viblo trên android bằng kotlin sử dụng lib jsoup (Phần 2) - Áp dụng data binding cho kotlin

Như ở phần 1 mình giới thiệu thì khi chưa dùng data binding với mỗi 1 recycler view mình lại phải tạo 1 adapter cho nó như thế rất tốn code , mất thời gian và khá chán -> Chính vì thế ở phần này mình sẽ hướng dẫn các bạn áp dụng data binding vào kotlin và tạo 1 single adapter chung để tiết kiệm thời gian và công sức sau này khi sử dụng recycler view

1. Cấu hình

Code : build.gradle Chúng ta cần cấu hình như sau trong file build.gradle Bên kotlin cấu hình phức tạp hơn java khá nhiều (khá buồn)

apply plugin: 'kotlin-kapt'

và kapt trong android

android {
    ...
         kapt {
                generateStubs = true
         }
    ...
}                

cuối cùng là com.android.databinding:compiler trong dependencies

dependencies {
    ...
    kapt 'com.android.databinding:compiler:3.0.1'
    ...
}

2. SingleAdapter

2.1. SingleAdapter

Code : SingleAdapter.kt

Chúng ta set giá trị cho 3 biến có thể lấy trong layout là : - position : Vị trí của item - data : giá trị của item - listener : bắt sự kiện cho item và 3 variable được lấy từ simple_place_holder.xml đây có thể là 1 layout tiêu chuẩn của 1 item recycler view

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val data = mDataList[position]
        holder.getBinding().setVariable(BR.position, position)
        holder.getBinding().setVariable(BR.data, data)
        holder.getBinding().setVariable(BR.listener, mPresenter)
        if (mDecorator != null) {
            mDecorator!!.decorator(holder, position, getItemViewType(position))
        }
        holder.getBinding().executePendingBindings()
    }

Có 2 interface : Presenter dùng cho các listener ko cần viewholder , Decorator dùng cho các listener cần tương tác , chỉnh sửa phức tạp hơn với viewholder

interface Presenter

interface Decorator {
        fun decorator(holder: ViewHolder, position: Int, viewType: Int)
}

2.2. simple_place_holder.xml

Tạo file simple_place_holder.xml có chứa các variable là data, listener, position

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

    <data>

        <variable
            name="data"
            type="com.asia.viblo.model.BaseModel"/>

        <variable
            name="listener"
            type="com.asia.viblo.model.BaseModel"/>

        <variable
            name="position"
            type="int"/>
    </data>

    <View android:tag="placeholder"/>
</layout>

3. Ứng dụng với PostFragment.kt

Code : PostFragment.kt

3.1. Khởi tạo recycler view

 override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initRecyclerPost()
    }

    private fun initRecyclerPost() {
        mPostAdapter = SingleAdapter(context, R.layout.item_post)
        mPostAdapter.setPresenter(BaseListener(activity))  // set listener for item recycler view
        recyclerPost.adapter = mPostAdapter
        recyclerPost.layoutManager = LinearLayoutManager(context)
    }

3.2. Update data vào adapter

 override fun onUpdateData(data: Post?) {
        // nothing
    }

    override fun onUpdateDataList(dataList: MutableList<Post>?) {
        mPostAdapter.setData(dataList)   // update data vào adapter
        mProgressDialog.dismiss()
        updateViewNextBackBottom()
    }

3.3. BaseListener.kt

Code : BaseListener.kt

Chứa tất cả các listener của adapter

Code

class BaseListener(activity: Activity) : OnClickTag, OnClickDetail, OnClickComment {
    private val mActivity: Activity = activity
    override fun onOpenTag(tagUrl: String) {
        val intent = Intent(mActivity, TagsActivity::class.java)
        intent.putExtra(extraUrl, tagUrl)
        mActivity.startActivity(intent)
    }

    override fun onOpenAuthorComment(authorUrl: String) {
    }

    override fun onOpenAllAuthorComment(authorUrlList: MutableList<String>?) {
    }

    override fun onOpenDetail(url: String, isVideo: Boolean) {
        val intent = when {
            url.contains("/s/") -> Intent(mActivity, SeriesActivity::class.java)
            url.contains("/q/") -> Intent(mActivity, QuestionsActivity::class.java)
            isVideo -> Intent(mActivity, WebViewActivity::class.java)
            else -> Intent(mActivity, PostDetailActivity::class.java)
        }
        intent.putExtra(extraUrl, url)
        mActivity.startActivity(intent)
    }

    override fun onOpenAuthor(baseModel: BaseModel) {
        val intent = Intent(mActivity, AuthorActivity::class.java)
        intent.putExtra(extraData, baseModel)
        mActivity.startActivity(intent)
    }
}

3.4. item_recycler_post.xml

Code : item_recycler_post.xml

<data>

        <import type="android.text.TextUtils"/>

        <variable
            name="data"
            type="com.asia.viblo.model.post.Post"/>

        <variable
            name="listener"
            type="com.asia.viblo.listener.BaseListener"/>
    </data>
    
  • Cách set các listener cho view
...
android:onClick="@{() -> listener.onOpenDetail(data.postUrl, data.isVideo)}"
...
android:onClick="@{() -> listener.onOpenAuthor(data)}"
...
android:onClick="@{() -> listener.onOpenAuthor(data)}"

3.5. Các tạo các include layout

    <include
                    android:id="@+id/layoutStatus"
                    layout="@layout/include_layout_status"
                    app:clips="@{data.clips}"
                    app:comments="@{data.comments}"
                    app:posts="@{data.posts}"
                    app:score="@{data.score}"
                    app:views="@{data.views}"/>

    <include
                    android:id="@+id/layoutStats"
                    layout="@layout/include_layout_stats"
                    app:followers="@{data.followers}"
                    app:post="@{data.post}"
                    app:reputation="@{data.reputation}"/>

3.5.1. include_layout_status.xml

Code : include_layout_status.xml Các lấy dự liệu từ các biến trên :

    <include
                    android:id="@+id/layoutStatus"
                    layout="@layout/include_layout_status"
                    app:clips="@{data.clips}"
                    app:comments="@{data.comments}"
                    app:posts="@{data.posts}"
                    app:score="@{data.score}"
                    app:views="@{data.views}"/>

Khi gọi

 app:clips="@{data.clips}"

nó sẽ truyền dữ liệu vào

 <variable
            name="clips"
            type="String"/>

Tương tự với các biến khác

3.5.2. include_layout_stats.xml

Tương tự như 3.5.1 thôi Code : include_layout_stats.xml

3.6.

Source Code

Viblo


All Rights Reserved