KunMinX 专注 “业务架构”,致力消除敏捷开发过程中 “不可预期问题”。
kunminx / jetpack-mvvm-best-practice Goto Github PK
View Code? Open in Web Editor NEW难得一见 Jetpack MVVM 最佳实践!在 "以简驭繁" 代码中,对 "视图控制器" 乃至 "标准化开发模式" 形成正确、深入理解!
难得一见 Jetpack MVVM 最佳实践!在 "以简驭繁" 代码中,对 "视图控制器" 乃至 "标准化开发模式" 形成正确、深入理解!
KunMinX 专注 “业务架构”,致力消除敏捷开发过程中 “不可预期问题”。
不管来自网络还是apk内部。既然写的是最佳实践,应该需要异常处理
有没有在此框架基础上实现的稍微复杂一点的示例。可以更好的学习该架构
public static final UnPeekLiveData<Boolean> ENABLE_SWIPE_DRAWER =
new UnPeekLiveData.Builder<Boolean>().setEventLiveTime(500).create();
public Builder<T> setEventSurvivalTime(int eventSurvivalTime) {
this.eventSurvivalTime = eventSurvivalTime;
return this;
}
任何缺乏实证依据和因果逻辑的泛泛而谈,都可能对其他使用者造成困扰。
在发表个人见解前,请先确保自己认真阅读过源码。这是对自己、对作者、对其他读者最起码的尊重。
在 readme 中看到有一项说绝不使用 Dagger,但对于 jetpack 中的 hilt,请问怎么看。。。后续会加到这个项目中吗?看了官方文档,感觉 hilt 的使用相比 Dagger 方便很多,又减少了一部分样板代码,还是挺不错的,1.0.0 正式版也已经发布了
PlaylistAdapter 类继承了SimpleDataBindingAdapter ,想问下AdapterPlayItemBinding 这个类是怎么来的?
ViewDataBinding 不暴露给实现Activity问题
比如xml中定义的TabItem,它的onClick事件无法通过databinding实现,如果用了会报空指针异常。。 这时就要在自己实现的Acitivity中 取到TabItem , 对它进行点击事件处理
比如先登录后使用的应用! 登录页面 LoginFragment 里面的登录按钮,登录成功以后 打开 MainFragment 并关闭 LoginFragment。这情况如何实现呢?
看了一下 issue ,貌似没人提这个问题 ……
如果按照打开抽屉栏相同的思路(MainActivity 与 MainFragment 使用 SharedViewModel 进行信息传递),那 PlayerFragment 滑动时控件的移动应该是 (MainActivity 与 PlayerFragment 使用 SharedViewModel 进行信息传递)。
可以做一个 EventHandler 实现 SlidingUpPanelLayout.PanelSlideListener ,在 MainActivity 中将观察到的滑动百分比记录给 SharedViewModel ,在 PlayerFragment 中对 SharedViewModel 该百分比进行观察,对应调整 PlayerFragment 中控件的位置或透明。
如果不在 PlayerFragment 中使用 getBinding() 方法获取 viewBinding ,那应该如何初始化工程中 PlayerSlideListener 这个类呢 ?
感觉也可以将每个需要改变的控件做一个 BindAdapter 方法,将单个控件与观察到的百分比在 layout/fragment_player 中进行绑定,但有些时候要考虑父View 的大小;PlayerSlideListener 中还有个 mStatus (当然这个可以放在 PlayerFragmentViewModel 中),总体来说这样肯定不如写成一个类 PlayerSlideListener 整体控制好一点。
所以想知道下规范的写法,这里应该是怎样的 ?
复现方法:MainActivity 在前台,点击播放音乐,下拉通知栏,点击通知进入 MainActivity
出现概率: 100%
Stacktrace:
com.kunminx.puremusic E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.kunminx.puremusic, PID: 2055
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.kunminx.puremusic/com.kunminx.puremusic.MainActivity}: java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
at androidx.lifecycle.LiveData.observe(LiveData.java:197)
at com.kunminx.architecture.bridge.callback.UnPeekLiveData.observe(UnPeekLiveData.java:39)
at com.kunminx.puremusic.ui.base.BaseActivity.onCreate(BaseActivity.java:52)
at com.kunminx.puremusic.MainActivity.onCreate(MainActivity.java:43)
at android.app.Activity.performCreate(Activity.java:7801)
at android.app.Activity.performCreate(Activity.java:7790)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
我认为这里是因为 MainActivity 没有设置启动模式,导致重复初始化了,加上了 SingleTask, SingleTop, SingleInstance 都可以解决此问题,但我隐约觉得这个不是 root cause。
LifeCycle 库用得不多,请大佬给解释一下这个问题。
看到注释 子类警惕使用getBinding获取view实例,如果需要对view做一些动画操作,那需要如何处理比较好一些呢?
目前项目只有少量的页面,所以登录相关的问题不大。但页面多了,登录就复杂了。
1.navigation不支持拦截,所以没法设置统一登录
2.navigation跳转需要写action,如果导航xml每个fragment下都写一个登录的action,那需要写很多。
基于上面2个条件,请教一下作者,在稍微大一点的项目里面,登录拦截这块应该如何规划比较好。
作者你好,将项目加载到手机上后,布局 fragment_player 左上角出现不可消除的警告提示:”PlayerFragment 未遵循 Databinding 严格模式,存在 null 安全风险“。拆解后,应该是 PlayerFragment.java 中调用 (FragmentPlayerBinding) getBinding(),所致。请问使用系统生成的 databindingimpl 操作控件就会出现此警告吗,并且这种水印应该怎么消除呢,多谢。
有kotlin版本么?
我在OKHttp build中使用到持久化Cookie,所以在build过程中需要用传入Context ,那么我在ViewModel请求网络过程中也要传入Context, 这样好像违背了MVVM..不知道该如何解决
返回的数据Flowable有改变没有考虑到只会刷新一次 以及UI与数据层双向无感知 databing 有部分问题 切入性大
一个request里如果有多个请求,每个请求都设置里netStateEvent。但是每个请求对netStateEvent的结果处理不一样,这样就会有问题。比例一个需要根据state显示dialog,一个需要根据state显示loading。
首先,先为作者的详细注释点个赞,毕竟能详细到每一步怎么设计怎么考虑的入门项目确实少;
不过因此,我在看 ViewModel的时候产生了一个疑问:
谷歌关于Jetpack的移动架构指南(https://developer.android.google.cn/jetpack/guide 中构造界面那部分) 中是这么规定ViewModel的作用的:
ViewModel 对象为特定的界面组件(如 Fragment 或 Activity)提供数据,并包含数据处理业务逻辑,以与模型进行通信。例如,ViewModel 可以调用其他组件来加载数据,还可以转发用户请求来修改数据。ViewModel 不了解界面组件,因此不受配置更改(如在旋转设备时重新创建 Activity)的影响。
也就是说,ViewModel 应该也负责业务逻辑;
但是我看项目中任何一个继承ViewModel的类都不负责任何业务上的逻辑,比如说state的下面的只进行状态存储,那个SharedViewModel也只是为了实现 唯一可信源
比如说state下的注释中明确规定了不会有业务方面的逻辑
此外,state-ViewModel 的职责仅限于 状态托管,不建议在此处理 UI 逻辑, UI 逻辑只适合在 Activity/Fragment 等视图控制器中完成,是 “数据驱动” 的一部分, 将来升级到 Jetpack Compose 更是如此。
所以问题来了
为什么违背谷歌设计的建议而设计目前这样的架构呢?是有什么特殊使用场景需求还是?这么设计的原因和目的是?如果没有什么特殊需求的话,应该怎么设计架构?
我使用了您的BaseActivity,有多个Activity都继承了BaseActivity,我在使用的时候报错
java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
找到原因代码
NetworkStateManager.getInstance().mNetworkStateCallback.observe(this, netState -> {
//TODO 这里可以执行统一的网络状态通知和处理
});
如果有多个Activity,如何正确的使用BaseActivity呢
使用了room配合livedata处理数据变动,一有数据变更就反馈到ui层,这没错,有时候一条数据某些值要变动,或者收到服务器传递过来的数据,需要修改相同的数据,会传递2次以上到ui导致adapter重复添加数据到界面上这种是要通过减少相同数据操作,还是ui上数据处理,还是把livedata换成一个子类M开头的。感觉表达起来有点问题,其实我就是想问相同数据操作数据库引起的重复通知更新,大神你是怎么处理的。
大佬有没有room结合livedata 和ViewModel的案例推荐的?
这个在activity跳转的时候有问题。
@KunMinX
理解了,我看了下配置发生变化时保存的具体对象是viewModelStore,这个对象具体activity的属性,它有个属性mMap,存储了所有的viewModel,通过ViewModelProvider.get()方法时,先获取最后配置变化的viewModelStore,然后从mMap中获取viewModel.理解了这个原理,也有一个小想法,就是viewModelStore是activity的对象,配置发生变化时,因为viewModelStore被保存下来了,所以旧的activity回收不了,感觉也是一个内存泄漏.
Originally posted by @hanshengjian in #41 (comment)
为什么不转成kotlin
大佬可以咨询2个关于PureMusic项目的问题吗:
1) com.kunminx.binding_recyclerview.adapter.BaseDataBindingAdapter 的 viewholder中 ViewDataBinding 没有调用setLifecycleOwner(),item随着滑动被销毁不需要移除掉观察者吗
2)BaseDataBindingAdapter 中只有一个 submitList(list),只能全量替换列表,databinding中如何 只更新某个position 的item呢,以及 insert ,remove等单个操作,都是整个list替换吗?
应该是appcompat版本问题,看错题提示是webview报错了
clone下来无法正常运行,关了翻墙也还是这样,是我的环境的问题吗?
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':architecture:compileDebugLibraryResources'.
> Could not resolve all dependencies for configuration ':architecture:_internal_aapt2_binary'.
> org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@23c916c2 for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category) (Caused by org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@23c916c2 for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category))
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 6s
看您的项目,从MainFragment->LoginFragment,的确MainFragment没有走onDestoyView
但是小的copy了architecture模块下navigation.fragment整个包到新项目,从
AFragment->BFragment,A就发生了onDestoryView。我看了下路由没啥异,是要有什么额外的设置才能让A不销毁视图吗?很疑惑,望解答
PlayerManager.getInstance().getChangeMusicLiveData().observe()
期待解答传道 :),感谢!
java.lang.IllegalStateException: no current navigation node
at androidx.navigation.NavController.navigate(NavController.java:824)
at androidx.navigation.NavController.navigate(NavController.java:804)
at androidx.navigation.NavController.navigate(NavController.java:790)
at androidx.navigation.NavController.navigate(NavController.java:778)
at com.kunminx.puremusic.ui.page.MainFragment$ClickProxy.search(MainFragment.java:156)
at com.kunminx.puremusic.databinding.FragmentMainBindingImpl._internalCallbackOnClick(FragmentMainBindingImpl.java:289)
at com.kunminx.puremusic.generated.callback.OnClickListener.onClick(OnClickListener.java:11)
at com.kunminx.architecture.utils.ClickUtils$1.onDebouncingClick(ClickUtils.java:357)
at com.kunminx.architecture.utils.ClickUtils$OnDebouncingClickListener.onClick(ClickUtils.java:420)
你好,请问下如果想在基类抽取公共的ui及对应的逻辑该怎么做呢?(像返回,title这种)
The link for the playstore is the same as the link for coolapk in the Readme File on line 83
[![google-play1.png](https://upload-images.jianshu.io/upload_images/57036-f9dbd7810d38ae95.png)](https://www.coolapk.com/apk/247826)
請問是否有針對 Kotlin 版本的 Jetpack-MVVM-Best-Practice?
謝謝
请问这句话“MVP 的 Presenter 和 MVVM - Clean 的 ViewModel 都不具备状态管理分治的能力”怎么理解
作者你好,这套框架非常好,有很多值得思考的地方。
不过有个疑问,假设有一模块既不是Activity也不是Fragment的域使用到ShareViewModel的数据时,应该如何获取会是比较好的方案呢?
目前adapter中关于ViewDataBinding的泛型其实是对应着holder的布局(因为holder在进行绑定的ui的时候会使用到此ViewDataBinding),假如一个列表中存在多种holder那该怎么处理ViewDataBinding的问题呢
我这边在模拟器里测试这个返回仍然在下载的界面
SearchFragment
点开“测试下载,返回页面仍有效”按钮,进度条开始动,然后我重复退出进入SearchFragment,就会发现离开页面终止的那个进度条也有数据了
Debug断点打在getDownloadFileCanBeStoppedLiveData里,复现这个问题,但是并没有断点,很奇怪。
换成真机到是没有出现过这个问题
您这个架构的一个目的是保持Activity或Fragment中不出现DataBinding中的内容,但是如果要配置一些组件的程序,比如viewPager2要使用TabLayoutMediator,需要进行acctch() 和detach()的调用,也就是要绑定周明周期,这种情况需要怎么处理呢
项目看到ViewModel类只单纯持有liveData,且直接暴露liveData。
比较好的一种写法是添加Model层,例如XXXRepository或XXXModel。
所有对liveData的写操作都通过ViewModel调用Repository来写。
暴露的liveData只调用observe方法。
不然写操作多的话,遍地的liveData的set会导致很难维护。
可能项目里liveData数据结构简单所以感知不是特别大。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.