栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android—Jetpack教程(二)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android—Jetpack教程(二)

前言

在上一篇中,对Jetpack有了初步的认知,也详细讲解了LifeCycle的实际使用。在本篇中,将会对Jetpack对应的ViewModel进行详解!

1、ViewModel

ViewModel诞生之前出现的问题:

  • 瞬态数据丢失
  • 异步调用的内存泄露
  • 类膨胀提高维护难度和测试难度

ViewModel的作用


如图所示

  • 它是介于View(视图)和Model(数据模型)之间的桥梁
  • 使视图和数据能够分离,也能保持通信

ViewModel的生命周期特性


如图所示

我们看到:

  • ViewModel的生命周期长与Activity的生命周期,因此在使用ViewModel时,不要向ViewModel传入Activity的Context,因为这样会导致内存泄露!
  • 如果硬要使用Context,那就使用AndroidViewModel中的Application

概念说了,接下来实战:

1.1 实战一(未使用ViewModel)

布局文件就一个TextView,所以这里就不贴布局代码了!

class Step1Activity : AppCompatActivity() {
    private var textView: TextView? = null
    private var count = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView = findViewById(R.id.textView)
    }
    fun plusNumber(view: View) {
        count++
        textView!!.text = "$count"
    }
}

这里我们看到,当我们点击按钮时,全局变量count自加一,随后给textView赋值!

来看看运行效果(屏幕旋转前)

保持这个值,旋转屏幕,看看效果:


当屏幕旋转时,我们发现用这种方式,自加的数据丢失了!

当然这个肯定有解决方案,这里也并不是解决这个方案出现的问题的。只是为了和ViewModel作个对比!

那现在看看使用ViewModel将会是怎样的?

1.2 实战二(使用ViewModel)

MyViewModel.kt

class MyViewModel(application: Application) : AndroidViewModel(application) {
    var number = 0 //
}

这里代码很简单,就继承了AndroidViewModel,里面定义了number变量。

来看看使用

class Step2Activity : AppCompatActivity() {

    private var textView: TextView? = null
    private var viewModel: MyViewModel? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView = findViewById(R.id.textView)
        
        //实例化viewModel 的方式
        viewModel =
            ViewModelProvider(this, AndroidViewModelFactory(application))[MyViewModel::class.java]
        
        textView!!.text = String.valueOf(viewModel!!.number)
    }

    fun plusNumber(view: View) {
        textView!!.text = String.valueOf(++viewModel!!.number)
    }
}

这里我们看到,实例化对应的viewModel后,通过访问viewModel里的属性实现的逻辑。

这时我们运行发现,不管怎么切换横竖屏,对应的屏幕上的数字都不会被清空,也就是说,并没有出现之前的数据丢失的情况! 在这就不放运行效果图了哈。

接下来下一个组件!

2、LiveData

LiveData和ViewModel的关系


如图所示

它们对应关系是:在ViewModel中数据发生变化时通知页面

既然如此,那就开始实战校验一番!

2.1 实战一(简单应用)

上面说了,LiveDta需要有ViewModel才会发挥其作用,因此:

MyViewModel.kt

class MyViewModel : ViewModel() {

	//定义对应的LiveData集合
    private var linkNumber: MutableLiveData? = null

	//得到对应的LiveData集合
    fun getlinkNumber(): MutableLiveData? {
        //保证linkNumber不为null
        if (linkNumber == null) {
        	//初始化
            linkNumber = MutableLiveData()
            linkNumber!!.value = 0
        }
        return linkNumber
    }

	//给外部提供修改集合内部属性的方法
    fun addlinkedNumber(n: Int) {
        linkNumber!!.value = linkNumber!!.value!! + n
    }

}

我们可以看到,在这对应的ViewModel里,定义了MutableLiveData对应的LiveData集合,然后就是一顿初始化,修改等方法。

来看看怎么使用的?

class MainActivity : AppCompatActivity() {
    private var viewModel: MyViewModel? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView: TextView = findViewById(R.id.textView)
        
        viewModel =
            ViewModelProvider(this, AndroidViewModelFactory(application))[MyViewModel::class.java]
        
        
        viewModel!!.getlinkNumber()!!.observe(this, Observer {
            textView.text = String.valueOf(it)
        })
    }

    fun reduce(view: View) {
        viewModel!!.addlinkedNumber(-1)
    }

    fun add(view: View) {
        viewModel!!.addlinkedNumber(1)
    }

}

这个页面的布局很简单,就两个按钮和一个文本,因此就没有贴对应的布局代码。

这里我们看到:

  • 初始化ViewModel和上面如出一辙,当点击对应按钮时,将通过addlinkedNumber对ViewModel对应LiveData属性做了修改操作!
  • 随后activity通过viewModel!!.getlinkNumber()!!.observe(this, Observer {xx},来接受ViewModel发过来的修改通知,并及时更新至textView上

来看看运行效果:


哈哈哈,有点简陋哈!不过只要效果达到了就行!

接下来进入下一个实战!

2.2 实战二(Fragment通信) 2.2.1 对应的布局文件

fragment.xml (两个相同的布局)





    

activity布局

如图所示

首页布局,就两个Fragment,上下各一个,平均分配,每个Fragment布局相同,都含有相同的SeekBar

想要实现的效果:不管拖动哪个Fragment里面的SeekBar,另一个SeekBar跟着移动

2.2.2 对应实现逻辑

先看MyViewModel.kt

class MyViewModel : ViewModel() {

    private var progress: MutableLiveData? = null

    fun getProgress(): MutableLiveData? {
        if (progress == null) {
            progress = MutableLiveData()
            progress!!.value = 0
        }
        return progress
    }
}

狠简单,直接看怎么使用!

FirstFragment.kt

class FirstFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        
        var rootView = inflater.inflate(R.layout.fragment_first, container, false)
        var seekBar = rootView.findViewById(R.id.seekBar)
        
        //实例化对应ViewModel
        val viewModel = ViewModelProvider(
            requireActivity(), AndroidViewModelFactory(
                requireActivity().application
            )
        )[MyViewModel::class.java]

        //接受ViewModel对应的通知
        viewModel.getProgress()!!.observe(requireActivity(), Observer {
            seekBar.progress = it
        })

        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
            	//这里修改对应ViewModel里面LiveData的属性值
                viewModel.getProgress()!!.setValue(progress)
            }

            override fun onStartTrackingTouch(seekBar: SeekBar) {}
            override fun onStopTrackingTouch(seekBar: SeekBar) {}
        })

        return rootView
    }

}

我们看到,这里使用方式如出一辙,当seekBar属性值发生改变时,将修改LiveData的值,随后通知对应Fragment达到刷新UI的作用!

第二个Fragment实现逻辑和这个一模一样,直接复制粘贴重命名一份。

来看看运行效果


完美,当然使用了ViewModel,任凭旋转屏幕哈,数据都不会丢失!

2.3 总结

从上面的实战中可以看出LiveData的优势

  • 确保界面符合数据状态
  • 不会发生内存泄露
  • 不会因Activity停止而导致崩溃
  • 不再需要手动处理生命周期
  • 数据始终保持最新状态
  • 适当的配置更改
  • 共享资源
结束语

好了,本篇到这里差不多结束了,相信读者对ViewModel+LiveData有所了解了!在下一篇中将会详解DataBinding以及将前面所讲解的集合成一个:LifeCycle+ViewModel+LiveData+DataBinding实战!

Demo下载:点我下载(包含下一篇部分源码)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591897.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号