android mvvm实例解析

这篇具有很好参考价值的文章主要介绍了android mvvm实例解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

android mvvm实例解析
MVVM架构,将整个应用分为三层,View层,VM层,Model层。其中View层单向引用VM层,VM层单向引用Model层。如上图。
单向引用,而非双向引用,这是MVVM与MVP最大的区别。View层,只是单向引用VM层,VM层不需要引用View层,但是却可以
更新View层。这是通过VM层的观察者模式实现的,在这里使用架构组件LiveData,观察者注册LiveData,当LiveData数据发生变更
的时候,就会通知注册的观察者。
VM层,执行业务逻辑,获取Model层的数据,Model层的数据由repository来提供。
 
举例子:
ChooseAreaFragment是View层,它持有ViewModel,它可以监听相关数据,相关数据发生变化的时候,对应的UI就会被更新。
比如:dataChanged数据发生变化,就会执行定义的观察者操作。
  viewModel.dataChanged.observe(this, Observer {
            adapter.notifyDataSetChanged()
            listView.setSelection(0)
            closeProgressDialog()
        })
class ChooseAreaFragment : Fragment() {


    private val viewModel by lazy { ViewModelProviders.of(this, InjectorUtil.getChooseAreaModelFactory()).get(ChooseAreaViewModel::class.java) }
    private var progressDialog: ProgressDialog? = null
    private lateinit var adapter: ArrayAdapter<String>


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.choose_area, container, false)
        val binding = DataBindingUtil.bind<ChooseAreaBindingImpl>(view)
        binding?.viewModel = viewModel
        return view
    }


    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        adapter = ChooseAreaAdapter(context!!, R.layout.simple_item, viewModel.dataList)
        listView.adapter = adapter
        observe()
    }


    private fun observe() {
        viewModel.currentLevel.observe(this, Observer { level ->
            when (level) {
                LEVEL_PROVINCE -> {
                    titleText.text = "中国"
                    backButton.visibility = View.GONE
                }
                LEVEL_CITY -> {
                    titleText.text = viewModel.selectedProvince?.provinceName
                    backButton.visibility = View.VISIBLE
                }
                LEVEL_COUNTY -> {
                    titleText.text = viewModel.selectedCity?.cityName
                    backButton.visibility = View.VISIBLE
                }
            }
        })


        viewModel.dataChanged.observe(this, Observer {
            adapter.notifyDataSetChanged()
            listView.setSelection(0)
            closeProgressDialog()
        })
        viewModel.isLoading.observe(this, Observer { isLoading ->
            if (isLoading) showProgressDialog()
            else closeProgressDialog()
        })
        viewModel.areaSelected.observe(this, Observer { selected ->
            if (selected && viewModel.selectedCounty != null) {
                if (activity is MainActivity) {
                    val intent = Intent(activity, WeatherActivity::class.java)
                    intent.putExtra("weather_id", viewModel.selectedCounty!!.weatherId)
                    startActivity(intent)
                    activity?.finish()
                } else if (activity is WeatherActivity) {
                    val weatherActivity = activity as WeatherActivity
                    weatherActivity.drawerLayout.closeDrawers()
                    weatherActivity.viewModel.weatherId = viewModel.selectedCounty!!.weatherId
                    weatherActivity.viewModel.refreshWeather()
                }
                viewModel.areaSelected.value = false
            }
        })
        if (viewModel.dataList.isEmpty()) {
            viewModel.getProvinces()
        }
    }


    /**
     * 显示进度对话框
     */
    private fun showProgressDialog() {
        if (progressDialog == null) {
            progressDialog = ProgressDialog(activity)
            progressDialog?.setMessage("正在加载...")
            progressDialog?.setCanceledOnTouchOutside(false)
        }
        progressDialog?.show()
    }


    /**
     * 关闭进度对话框
     */
    private fun closeProgressDialog() {
        progressDialog?.dismiss()
    }


    companion object {
        const val LEVEL_PROVINCE = 0
        const val LEVEL_CITY = 1
        const val LEVEL_COUNTY = 2
    }


}
VM层,ViewModel:
使用LiveData包装被View层监听的数据,在VM层数据发生的变化,会通知到View层,但却无需要View层的引用。
因为LiveData应用了观察者模式,注册的观察者,在数据发生变化的时候,会自动通知观察者。
如下,currentLevel,dataChanged,isLoading等都是使用LiveData包装的,意味着,它们发生变化的时候View层会监听得到,从而进行相应的更新操作。
在VM层,持有Model层的引用,Model层的数据获取,网络请求,都依赖repository实现。
class ChooseAreaViewModel(private val repository: PlaceRepository) : ViewModel() {


    var currentLevel = MutableLiveData<Int>()


    var dataChanged = MutableLiveData<Int>()


    var isLoading = MutableLiveData<Boolean>()


    var areaSelected = MutableLiveData<Boolean>()


    var selectedProvince: Province? = null


    var selectedCity: City? = null


    var selectedCounty: County? = null


    lateinit var provinces: MutableList<Province>


    lateinit var cities: MutableList<City>


    lateinit var counties: MutableList<County>


    val dataList = ArrayList<String>()


    fun getProvinces() {
        currentLevel.value = LEVEL_PROVINCE
        launch {
            provinces = repository.getProvinceList()
            dataList.addAll(provinces.map { it.provinceName })
        }
    }


    private fun getCities() = selectedProvince?.let {
        currentLevel.value = LEVEL_CITY
        launch {
            cities = repository.getCityList(it.provinceCode)
            dataList.addAll(cities.map { it.cityName })
        }
    }


    private fun getCounties() = selectedCity?.let {
        currentLevel.value = LEVEL_COUNTY
        launch {
            counties = repository.getCountyList(it.provinceId, it.cityCode)
            dataList.addAll(counties.map { it.countyName })
        }
    }


    fun onListViewItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
        when {
            currentLevel.value == LEVEL_PROVINCE -> {
                selectedProvince = provinces[position]
                getCities()
            }
            currentLevel.value == LEVEL_CITY -> {
                selectedCity = cities[position]
                getCounties()
            }
            currentLevel.value == LEVEL_COUNTY -> {
                selectedCounty = counties[position]
                areaSelected.value = true
            }
        }
    }


    fun onBack() {
        if (currentLevel.value == LEVEL_COUNTY) {
            getCities()
        } else if (currentLevel.value == LEVEL_CITY) {
            getProvinces()
        }
    }


    private fun launch(block: suspend () -> Unit) = viewModelScope.launch {
        try {
            isLoading.value = true
            dataList.clear()
            block()
            dataChanged.value = dataChanged.value?.plus(1)
            isLoading.value = false
        } catch (t: Throwable) {
            t.printStackTrace()
            Toast.makeText(CoolWeatherApplication.context, t.message, Toast.LENGTH_SHORT).show()
            dataChanged.value = dataChanged.value?.plus(1)
            isLoading.value = false
        }
    }


}
Model层:
在这个例子中,Model层对外提供的方法是
getProvinceList,getCityList,getCountyList。
它的数据来源,可能是数据库Dao,或者是网络,各自的实现,再委托到具体的方法去实现。
class PlaceRepository private constructor(private val placeDao: PlaceDao, private val network: CoolWeatherNetwork) {


    suspend fun getProvinceList() = withContext(Dispatchers.IO) {
        var list = placeDao.getProvinceList()
        if (list.isEmpty()) {
            list = network.fetchProvinceList()
            placeDao.saveProvinceList(list)
        }
        list
    }


    suspend fun getCityList(provinceId: Int) = withContext(Dispatchers.IO) {
        var list = placeDao.getCityList(provinceId)
        if (list.isEmpty()) {
            list = network.fetchCityList(provinceId)
            list.forEach { it.provinceId = provinceId }
            placeDao.saveCityList(list)
        }
        list
    }


    suspend fun getCountyList(provinceId: Int, cityId: Int) = withContext(Dispatchers.IO) {
        var list = placeDao.getCountyList(cityId)
        if (list.isEmpty()) {
            list = network.fetchCountyList(provinceId, cityId)
            list.forEach { it.cityId = cityId }
            placeDao.saveCountyList(list)
        }
        list
    }


    companion object {


        private var instance: PlaceRepository? = null


        fun getInstance(placeDao: PlaceDao, network: CoolWeatherNetwork): PlaceRepository {
            if (instance == null) {
                synchronized(PlaceRepository::class.java) {
                    if (instance == null) {
                        instance = PlaceRepository(placeDao, network)
                    }
                }
            }
            return instance!!
        }


    }


}
以上就是MVVM的实例解析。应用MVVM的时候,关键是划分功能属于哪一个层次,然后,再确定引用关系。划分功能属于哪个层次,可以依据单一职责原则,让功能代码原子化,再在这一基础上去区分层次。
 
 

文章来源地址https://www.toymoban.com/news/detail-624438.html

到了这里,关于android mvvm实例解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Android】MVC,MVP,MVVM三种架构模式的区别

    MVC 传统的代码架构模式,仅仅是对代码进行了分层,其中的C代表Controller,控制的意思 将代码划分为数据层,视图层,控制层,三层之间可以任意交互 MVP MVP是在MVC基础上改进而来的一种架构,其中的P代表Presenter,主持的意思 它主要在以下两方面进行了改进:解耦,接口化

    2024年02月13日
    浏览(42)
  • Android安卓架构MVC、MVP、MVVM模式的概念与区别

    目录 MVC框架 MVP框架 MVVM框架 MVVM与MVP区别 MVVM与MVC区别 MVC、MVP、MVVM模式哪个要好一些 MVC(Model-View-Controller)、MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)是三种常见的软件架构模式,它们的目的都是将应用程序的不同部分分离开来,以提高代码的可维护性、可扩展性和可

    2024年02月21日
    浏览(38)
  • Android模板设计模式之 - 构建整个应用的BaseActivity

    模式的定义 定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 模式的使用场景 1.多个子类有公有的方法,并且逻辑基本相同时。 2.重要、复杂的算法,可以把核心算法设计为模板方法,周边

    2024年02月13日
    浏览(28)
  • 大型Android项目架构:基于组件化+模块化+Kotlin+协程+Flow+Retrofit+Jetpack+MVVM架构实现WanAndroid客户端

    前言:苟有恒,何必三更眠五更起;最无益,莫过一日曝十日寒。 之前一直想写个 WanAndroid 项目来巩固自己对 Kotlin+Jetpack+协程 等知识的学习,但是一直没有时间。这里重新行动起来,从项目搭建到完成前前后后用了两个月时间,平常时间比较少,基本上都是只能利用零碎的

    2024年02月09日
    浏览(42)
  • Unity解析json文件(分为json与jsonArray)

    什么是json? JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度, 那么,JSON到底是什么? JSON就是一串字符串 只不过元素会使用特定的符号标注。 {} 双括号表示对象 [] 中括号表示数组 “” 双引号内是

    2024年02月08日
    浏览(33)
  • Node.js在Python中的应用实例解析

    随着互联网的发展,数据爬取成为了获取信息的重要手段。本文将以豆瓣网为案例,通过技术问答的方式,介绍如何使用Node.js在Python中实现数据爬取,并提供详细的实现代码过程。 Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它提供了一种在服务器端运行JavaScript代码

    2024年02月07日
    浏览(44)
  • 超简单演示Android地图开发应用实例

    手机地图开发应用广泛,本实例演示了在手机上显示各种地图的方法。比如3D矢量地图、卫星地图、交通地图、夜景地图等在手机上的显示。可以根据手势自由做地图缩放,地图旋转等操作。代码简洁、实用,可以帮助你快速上手地图开发。 一、实现效果图: 二、实现过程

    2024年02月11日
    浏览(29)
  • Android MVI架构的深入解析与对比

    M:model,此处的model并不是传统的数据模块,它是指用来存储视图状态UI State的一个模块 。比如请求数据时的loading、请求失败的提示页面等UI层面的变化状态。 V:view,视图模块 I:intent,此处的intent并非是我们页面跳转的intent,而是取起实际意思:意图、目的。用来响应用户

    2024年02月05日
    浏览(30)
  • 为Android构建现代应用——应用架构

    选择风格( Choosing a style ) 我们将依照Google在《应用架构指南》中推荐的最佳实践和架构指南来构建OrderNow的架构。 这些定义包括通过各层定义组件的一些Clean Architecture原则。 层次的定义( Definition of the layers ) 在应用程序中,我们将定义以下主要层次: • 用户界面(UI)层 •

    2024年02月15日
    浏览(34)
  • Android架构进阶之高级UI系列(精编解析,值得收藏)

    public FrameHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_FRAME: // 执行doFrame // 如果启用VSYNC机制,当VSYNC信号到来时触发 doFrame(System.nanoTime(), 0); break; case MSG_DO_SCHEDULE_VSYNC: // 申请VSYNC信号,例如当前需要绘制任务时 doScheduleVsync()

    2024年04月14日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包