2023-4-25更新
这篇文章给出了算是经典的解决方式,推荐使用这个方法(之前没浏览到这个大佬的文章,浪费了好多时间)
场景
在平常项目开发中,经常会遇到一个布局在整个项目中会出现很多次的情况。这时候,我们就需要将这个布局拖出来,作为一个子布局,在需要使用的地方通过标签复用。
问题
在数据双向绑定中,如果一个子布局要想通用,又必须保持数据双向绑定的功能,使用ViewModel的时候,在子布局和界面中使用的时候,就会遇到,无法保持子布局数据的唯一性(也就是同一个子布局,在同一个界面中使用的时候,如果这个这个界面多次这个子布局)
问题中的代码
主界面xml
解决过程
本来在这里是要写解决过程的历程,这样可以给大家一些解决问题的启发。不过这次解决的过程比较久,也比较复杂。鉴于本人是个小菜鸟的缘故,所以这次就不写具体的过程了。
简单的描述一下解决的过程
开始的时候,我拿着 ViewModel include关键词,在百度、必应、谷歌、stackoverflow等网站都搜了一下,看了很多的文章【在这里吐槽一下,stackoverflow网站,我真的不会搜东西,用关键词查的时候,我总是没找到需要的,可能stackoverflow上的答案和我无缘吧,不过我还是喜欢在无助的时候,来找找,也许就给我找到答案了呢】
在这里我找到了有用的东西,感谢大佬的分享,但是这里并没有解答我的问题。
后来我又多次的在网上找答案,依然没有找到
然后我只能去找大佬们了
大佬们拿着ChatGPT,给我搜索,哈哈哈,启发了我,我也用YouChat搜索着,结果奈何表达不到位,结果不理想啊,真的很想把整个项目丢给ChatGPT,告诉我这个怎么做吧(哈哈哈)
后面跟着另一个大佬一起,一边测试,一遍思考,才最终得到了自己想要的答案
在解决问题的前期
遇到的一个问题【以下图片的报错】
问题原因是我在主xml内给子布局赋值ViewModel的数据的时候,没有根据子布局设定的ViewModel的变量名来命名,两个名字要改成一样的就可以了。
改后
继续解决问题
早期的时候在想,子布局也使用ViewModel,所以,我给子布局添加了ViewModel,并在主布局的ViewModel中尝试新建子布局的ViewModel,如下:
这个方法会遇到一个问题,使用了同一个MvvmModel作为子布局的ViewModel;这时候要追究到ViewModel的创建时候了。
这个是两个不同的ViewModel,是没有问题的
但是
查看创建ViewModel的过程,可以发现是根据类名作为key的,所以这时候两个子布局都是使用MvvmModel,就会出现数据一样的情况。
我们在平常开发中,肯定是使用不同的数据显示,这时候,你如果改成两个不同的ViewModel,那么也就意味着,你必须写两个不同的子布局,那就起不到子布局复用的情况。
欢迎来到最后的解决方案,在此之前,先插个另一个没有报错的错误
界面无法显示ViewModel的数据
日志打印了修改后的数据,但是界面上一直是初始化的数据,真的很爪机
后来查看了笔记(我在有道的笔记,这个已经很久没打开了,我一直记得有做过这个,但是在飞书上没有搜到,只好打开有道了,然后真的找到了),才找到原因的
这个笔记,注释是在fragment的时候使用的,但是我记得这句话,用上了,数据成功显示了,这口气终于通了真爽(哈哈哈哈)
展示一下数据变化后的界面
这个按钮是之前判断会不会因为是handler来触发引起的界面不能显示的问题,将handler的触发改成了按钮的事件,还有线程,后面成功了之后发现这3个都能实现界面数据的变化的。
真的来到最后了
解决办法
直接上图了
子布局的ViewModel修改成了使用基本数据类型
别只看到界面里的String,是基本数据类型,这样你可以在主界面的ViewModel内使用一个变量来控制子布局
这样,在任何时候,子布局都能通用,也不会产生在同一个界面的多次include的时候,同个inclde的子布局数据一起变化
那么大佬又问了,那我在子布局里有多个的TextView(大佬在举栗子哈,别笑),这个就简单了
看吧这个例子很简单,一下秒懂,有没有;就是在data标签里搞动作,记得在主界面调用的时候也要动一下,别偷懒,具体主界面的xml怎么动,前面已经有说过了,认真看的朋友已经有了答案了
好了,这次的问题解决已经有了答案,终于可以开心的使用MVVM了,没有双向绑定的MVVM,我觉得失去灵魂,在解决问题过程中还看了一个说是MVVM框架的项目,以为会有数据双向绑定的,结果根本就没有,挺郁闷的
最后感谢各位大佬的帮忙,鲜花献花~~~
哇哈哈哈哈,结束
追续【2023.3.2】
使用实体对象来替代基础类型,在字不居中使用
不使用基础类在子布局中使用
改用实体对象【这里的实体对象是没有继承ViewModel,如果继承了,就是前面说的情况】
在子布局中使用实体对象
在父布局中使用
变化实体对象的内容
结果:修改成功
但是,如果使用以下方式修改视图对象的数据,就无法生效【这里的setValue是因为内部属性是value,才会有这个set方法】
只能每次都是重新设置一个新的对象
追续【2023.6.29】
单个使用LiveData修饰需要双向绑定的数据,然后统一绑定到一个ViewModel之下,就可以实现单个LiveData变量的复用