JYGod / JYGank

借用了Gank.io的现成API,顺便练习一下最近新学的Google官方推荐的新框架Architecture component,再用Kotlin磨磨刀~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

中文说明

关键技术

  • 语言:Kotlin
  • Google官方推荐框架: Architecture Component( Room + Lifecycle + ViewModel + LiveData )
  • 本地数据持久化 : Room
  • 依赖注入:Dagger2
  • 网络请求:Retrofit2 + OkHttp3
  • rxKotlin + rxAndroid

架构原则

首先是模块分离的原则,Activity 和 Fragment 中只做界面组件初始化操作而不做其他业务逻辑的操作。

其次是利用 Model 驱动 UI , 其中 Model 最好是持久化的 Model,保证应用销毁、网络中断后不会丢失数据。Model只负责针对数据,而不关注UI的问题。

ViewModel 作为 Model 和 UI 的桥梁,当 Model 中的数据发生改变时, ViewModel控制相应的 UI 来将数据的变换反映到页面上。

用法

下面,我将结合自己写的 Demo 来介绍一下框架的具体使用。

Demo 暂时写得比较简单,以后会不定期增加功能或美化UI... 项目中使用到的API来源于 干货集中营

程序效果图如下:

screenshot

screenshot

整体思路

AC

Activity

这个就不多说了...

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        supportFragmentManager.beginTransaction()
                .add(R.id.main_container, AndroidFragment(), AndroidFragment.TAG)
                .commit()
    }

Fragment

在 Fragment 中只进行界面组件的初始化和相应的界面改变操作

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        toolbar.setTitleTextColor(context.resources.getColor(R.color.pureWhite))
        initRecycler()
        viewModel = ViewModelProviders.of(this).get(AndroidViewModel::class.java)
        viewModel.getList(PAGE.toString())?.observeForever { list ->
            list?.let {
                mAdapter.addData(it)
                mAdapter.loadMoreComplete()
            }
        }
        mAdapter.setOnLoadMoreListener {
            viewModel.getList((PAGE++).toString())
        }
    }

这里的 viewModel.getList() 返回的是一个 LiveData 类型的 list,LiveDate 是一个可观察的数据持有者,在 ViewModel 中持有一个 list 的实例,当这个 list 的值改变时,viewModel 都会将改变信息返回给 Fragment,通知Fragment更新UI。

因此,只需要在 Fragment 初始化时 使用 LiveData 的 observe方法来监听数据的改变即可。

但是,这里有个问题, 如果只是在 ViewModel 中持有这个 list,在退出应用或其他异常时都可能丢失数据... 这样是不科学的🤔。因此需要一个能够持久化数据的方案,所以就引入了 Room 作为数据持久化的策略。

然而,viewModel 中的数据都来自 Repository,它是提供数据的地方,数据来源分两种,一种是通过远程的 Web API 获取数据;另一种是通过本地 Room 获取本地数据库中的数据。

为了保证单一数据来源的原则,这里我的策略是:向 viewModel 提供的数据都是来自本地 RoomDatabase,从Web API 获取的数据都会存入 Room 中,这样,我们需要观察的 LiveData 就可以直接来源于 Room了。

ViewModel

    fun getList(page: String): LiveData<List<AndroidModel>>? {
        return androidRepo.loadList(page)
    }

Repository

从远程 API 获取的数据都先存入RoomDatabase中,提供给viewModel的数据唯一来源是roomDatabase,返回LiveData类型可供Fragment观察。

 fun loadList(page: String): LiveData<List<AndroidModel>>? {
        remoteDataSource.loadAndroidList(page)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ entity ->
                    entity.results?.let { resList ->
                        roomDataSource.androidDao().insertList(resList)
                    }
                }, { t: Throwable -> t.printStackTrace() })
        return roomDataSource.androidDao().selectList()
    }

学生狗…🐶,平时比较忙... 前段时间研究了下google推荐框架,一直没时间去实践…之后会一直更新学习该框架的状态~

About

借用了Gank.io的现成API,顺便练习一下最近新学的Google官方推荐的新框架Architecture component,再用Kotlin磨磨刀~


Languages

Language:Kotlin 90.7%Language:Java 9.3%