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 ...
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
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.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>
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.
Viblo