MVVM理念实践:Android图像识别为文字

如果要弄懂一个框架,学习或动手做一个示例工程,会是很好的办法,参照实践的时间就会明悟很多。

分享一个自己写的项目,实现了Android图像转文字的功能。也因为功能单一,所以工程结构非常清晰简单,适合初学者弄懂MVVM的面貌。

源码下载:Github

一、涉及的技术内容

  1. MVVM的简明实践,只有一个model,一个视图层/View、一个ViewModel层,连起来也是MVVM名字的由来
  2. 基于百度Ai平台的文字识别能力
  3. 最高适配到Android 10的相机和相册选择工具类

二、MVVM使用理念

我们为什么要用MVVM,解耦?恐怕不止这么简单吧

解耦方面,可以用一张图,来说明数据的传输结构:
MVVM结构
清晰可见,但并不能说明MVVM的优势,顶多只能表示设计上View和Model是不能直接交互的。要体会MVVM的理念,需要去理解它所涉及的主要技术,也就是ViewModel、LiveData和Databinding。


1.ViewModel :桥梁或者说是容器

其他文章都讲烂了,ViewModel是和Activity/Fragment的生命周期绑定的,在ViewModel里,一般放有LiveData数据。类似于这样:

class MainViewModel : ViewModel() {
    //识别文字的LiveData
    var idText = MutableLiveData<String>()
    ...
}

我们要来说好处了:

①作为容器,ViewModel可以在界面回收或重建时保存其中的数据

如果不理解的话,想想我们为了界面恢复数据时所作的努力,界面回收时在OnSaveInstanceState(Bundle outState)存储,然后去OnCreate()窘迫地恢复。

而利用ViewModel的持久存储特性 + LiveData 就完全可以摒弃这些存储的操作了,很美好不是吗?

②界限分明,ViewModel是依据调用者LifecycleOwner创建的,可以追溯到调用者界面。

数据存储的话,一个单例也足够(静态对象),但ViewModel只有被初始化时传入的界面所持有,另一界面采用不同的LifecycleOwner初始化同一个ViewModel时,其实是新建了另外一个ViewModel。

也就是说,ViewModel中数据不会因界面回收而消失,却又不是简单的单例,不会被其他来源的调用所污染,清晰可见!

于是,ViewModel有着作为桥梁连接数据Model和界面View时,清晰明确可追溯数据源的特性,也有作为容器持久保存数据状态的功能


2.LiveData:唯一信源的分发者

LiveData只有两种方法:(1)存储数据setValue/postValue;(2)observe添加观察者 根据数据改变进行UI更新。

//初始化ViewModel
val viewModel by lazy {
	ViewModelProvider(this, Injector.getMainFactory()).get(MainViewModel::class.java)
}

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
      	
      	//ViewModel中的LiveData监听数据改变进行UI更新
        viewModel.idText.observe(this, Observer { 
            textView.text = it
        })
}

那么我们怎么定义LiveData的作用呢? 从它仅有两三个方法就可以看出,LiveData是一种职责极其克制的数据对象。

在MVVM中,当数据源改变时,LiveData通过setValue/postValue来通知绑定的UI更新,也就是说他是UI取材的唯一信源

使用方式一般有两种:
》UI单向绑定:如上代码的例子,通过observe添加观察者更新UI
》UI双向绑定:配合Databinding,xml中绑定LiveData的值,当LiveData改变时,UI会自动更新。

另外有一个特殊技巧:LiveData + 单例模式 可以作为唯一数据信源,同步更新多个界面
ViewModel仅能被一个界面持有,但单例没有这样的限制。若使用单例取代ViewModel作为model和View的桥梁,即可为多个界面统一数据源。


3.Databinding:xml与数据的绑定

DataBinding在MVVM架构中属于非必选项,在使用中可以避免重复的findViewById代码。

若运用双向绑定,可以使视图和数据的界限更加分明,即xml中根据绑定数据进行显示,代码(kotlin/java)无需理会视图的状态

或者这样说:

我们编写的代码(kotlin/java)作用到LiveData改变后,就可以了。其余如何进行数据显示是xml的事情。我不用理会横屏竖屏切换导致的控件不一致,因为是xml绑定的数据,不用管理繁琐的界面数据刷新,因为xml已经绑定了

此外,有一个令人吐槽的点是,xml中处理逻辑,即使是简单的if…else…也是极不易维护的,所以应该避免在xml处理逻辑。

比如判断控件是否可视,不应该在xml中写

android:visibility="@{ User.age > 18 ? View.VISIBLE : View.GONE }"

而应该写

android:visibility="@{ User.isAdult ? View.VISIBLE : View.GONE }"

以上,就是我对MVVM的一些理解了。没有具体的代码使用,只是一些想法,希望有所帮助

发布了12 篇原创文章 · 获赞 36 · 访问量 4771

猜你喜欢

转载自blog.csdn.net/weixin_42229694/article/details/103859070