对比普通方式开发列表
先上效果图。2种方式的效果一致的,只是开发的代码不同。
- 普通方式
- Activity
class JpBlogActivity : BaseActivity<ActivityJpBlogBinding, JpBlogViewModel>() {
private val mLoopAdapter by lazy { LoopAdapter() }
override fun getLayoutId() = R.layout.activity_jp_blog
override fun initView() {
vb.btnOpenDb.singleClick {
navActivity<LoopDatabindingActivity>()
}
//初始化rv
vb.rvLoop.layoutManager = LinearLayoutManager(this)
vb.rvLoop.adapter = mLoopAdapter
}
override fun getVariableId(): Int {
return BR.mainVm
}
override fun startObserve() {
//等待结果
viewModel.apply {
liveDataLoops.observe(this@JpBlogActivity, {
//得到结果
mLoopAdapter.setList(it)
})
}
}
override fun initData(savedInstanceState: Bundle?) {
//请求数据
viewModel.httpGetLoop()
}
}
- ViewModel
/**
* @author: dr
* @date: 2021/1/29
* @description 博客轮播图vm
*/
class JpBlogViewModel : BaseViewModel() {
//轮播图数据
val liveDataLoops = MutableLiveData<List<SobLoop>>()
fun httpGetLoop() {
viewModelScope.launch {
request { getLoop() }
.onSucceed {
//成功处理.有些接口,data是没有的。
this?.let { liveDataLoops.value = this }
}.onFailure {
//错误处理
AppToast.toast(it)
}
}
}
}
- 普通Adapter
/**
* @author: dr
* @date: 2020/12/31
* @description 轮播图适配器
*/
class LoopAdapter : BaseQuickAdapter<SobLoop, BaseViewHolder>(R.layout.item_loop_layout) {
override fun convert(holder: BaseViewHolder, item: SobLoop) {
holder.setText(R.id.tv_loop_title, item.title)
holder.setText(R.id.tv_loop_url, item.targetUrl)
ImageHelper.load(
holder.getView(R.id.iv_loop_cover),
item.imageUrl,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher
)
}
}
其实,目前官方的组件支持下,已经解决了以前存在的很普遍的问题 - 比如网络请求之后,activity或者fragment被回收,然后继续更新ui导致的NPE(空指针) - 或者是页面在请求中,使用新的线程请求数据,但是页面主动back,退出,取消请求的统一处理,或者资源回收 - 这些经常发生的,但是又不得不处理的现在已经被官方组件‘fix’了 - 所以,大家开发还是使用官方组件吧
把适配器和item,换data binding
- Activity
class LoopDatabindingActivity : BaseActivity<ActivityLoopDatabindingBinding, JpBlogViewModel>() {
private val loopAdapter: DbLoopAdapter by lazy {
DbLoopAdapter().apply {
vb.rvLoop.layoutManager = LinearLayoutManager(this@LoopDatabindingActivity)
vb.rvLoop.adapter = this
}
}
override fun getLayoutId() = R.layout.activity_loop_databinding
override fun getVariableId() = BR.loopVm
override fun startObserve() {
viewModel.apply {
liveDataLoops.observe(this@LoopDatabindingActivity, {
loopAdapter.setList(it)
})
}
}
override fun initView() {
}
override fun initData(savedInstanceState: Bundle?) {
viewModel.httpGetLoop()
}
}
- Adapter
/**
* @author: dr
* @date: 2021/2/1
* @description data binding 方式做列表
*/
class DbLoopAdapter : BaseQuickAdapter<SobLoop, BaseDataBindingHolder<ItemDbLoopBinding>>(R.layout.item_db_loop) {
override fun convert(holder: BaseDataBindingHolder<ItemDbLoopBinding>, item: SobLoop) {
holder.dataBinding?.apply {
loop = item
executePendingBindings()
}
}
}
- item
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import
alias="appR"
type="com.android.debug.R" />
<variable
name="loop"
type="com.android.debug.model.bean.SobLoop" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/sw_60dp"
android:background="?android:attr/selectableItemBackground">
<com.debug.widget.RadiusImageView
android:id="@+id/iv_loop_cover"
imagePlaceholder="@{appR.mipmap.ic_launcher}"
imageUrl="@{loop.imageUrl}"
android:layout_width="@dimen/sw_40dp"
android:layout_height="@dimen/sw_40dp"
android:layout_marginLeft="@dimen/sw_10dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:riv_border_color="#ff0000"
app:riv_border_width="@dimen/sw_1dp"
app:riv_corner_radius="@dimen/sw_4dp"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_loop_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/sw_10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@{loop.title}"
android:textColor="#000810"
android:textSize="@dimen/sw_15sp"
app:layout_constraintLeft_toRightOf="@id/iv_loop_cover"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_loop_cover"
tools:text="我是轮播图的标题啊我是轮播图的标题我是轮播图的标题啊" />
<TextView
android:id="@+id/tv_loop_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/sw_10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@{loop.targetUrl}"
android:textColor="#454646"
android:textSize="@dimen/sw_12sp"
app:layout_constraintBottom_toBottomOf="@id/iv_loop_cover"
app:layout_constraintLeft_toRightOf="@id/iv_loop_cover"
app:layout_constraintRight_toRightOf="parent"
tools:text="这是url" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
简单的列表就是这样了。如果元素非常多,而且布局或者业务复杂,会导致xml嵌入很多代码,或者说有些实现在xml不好做的,可能写起来不太顺手,个人还是喜欢之前的模式。
这里面,使用到的activity是封装过的。 adapter也是使用cym的。还有一些其他隐藏的封装。 目前这个架子还在完善中,差不多完成的时候,就用这个架子来开发博客系统的移动端。 这个估计是年后的事情了。
- 图片加载Glide
- 网络Retrofit-协程
- 其他待完善
- 由于公司目前在开发项目使用的是MVP,新开发项目目前切换到这个架子中,还需要不断完善
- 使用kotlin开发,看起来代码量减少了,其实是隐藏了大量细节实现,导致可读性降低,如果新队友不熟悉kotlin可能上手需要点门槛