Code Monkey home page Code Monkey logo

jetpack-mvvm-best-practice's Introduction

jetpack-mvvm-best-practice's People

Contributors

dependabot[bot] avatar geertjanw avatar goooler avatar kunminx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jetpack-mvvm-best-practice's Issues

SharedViewModel类中使用UnPeekLiveData的构造器方法报错的问题

您提交的646a58de记录中修改UnPeekLiveData构造器的方式后,调用的地方未进行变更,请知悉

  • SharedViewModel类
public static final UnPeekLiveData<Boolean> ENABLE_SWIPE_DRAWER =
           new UnPeekLiveData.Builder<Boolean>().setEventLiveTime(500).create();
  • UnPeekLiveData.Builder类中原有方法已经变更为下列方法
public Builder<T> setEventSurvivalTime(int eventSurvivalTime) {
        this.eventSurvivalTime = eventSurvivalTime;
        return this;
}

【 提问须知 】

如有 bug,请另外 new 一个 issue ⚠️⚠️⚠️

本项目开 issue 规范:

  1. 有任何 bug 都欢迎及时开 issue,我看到后予以处理。
  2. 如有使用上的疑问,请先认真阅读 Readme 和源码 sample,在没有找到答案后,另外开 issue。
  3. 如开 issue 是为了发表个人见解,请务必 客观、具体、严谨;严禁草率、乱入、带节奏:

务必注明观点所对应的场景,并附上完整可复现的代码,

不然缺乏一致的前提依据来有效交流!

任何缺乏实证依据和因果逻辑的泛泛而谈,都可能对其他使用者造成困扰。

在发表个人见解前,请先确保自己认真阅读过源码。这是对自己、对作者、对其他读者最起码的尊重。

【探讨】关于依赖注入的使用

在 readme 中看到有一项说绝不使用 Dagger,但对于 jetpack 中的 hilt,请问怎么看。。。后续会加到这个项目中吗?看了官方文档,感觉 hilt 的使用相比 Dagger 方便很多,又减少了一部分样板代码,还是挺不错的,1.0.0 正式版也已经发布了

ViewDataBinding 不暴露给实现Activity问题

ViewDataBinding 不暴露给实现Activity问题

比如xml中定义的TabItem,它的onClick事件无法通过databinding实现,如果用了会报空指针异常。。 这时就要在自己实现的Acitivity中 取到TabItem , 对它进行点击事件处理

想请教一下 PlayerFragment 的正确写法应该是怎样的呢 ?

看了一下 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 整体控制好一点。

所以想知道下规范的写法,这里应该是怎样的 ?

【Bug】从通知点击进入 MainActivity 发生 Crash

复现方法: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 库用得不多,请大佬给解释一下这个问题。

多页面下如何该编写登录逻辑?

目前项目只有少量的页面,所以登录相关的问题不大。但页面多了,登录就复杂了。
1.navigation不支持拦截,所以没法设置统一登录
2.navigation跳转需要写action,如果导航xml每个fragment下都写一个登录的action,那需要写很多。

基于上面2个条件,请教一下作者,在稍微大一点的项目里面,登录拦截这块应该如何规划比较好。

底部播放器提示风险警告水印:”PlayerFragment 未遵循 Databinding 严格模式,存在 null 安全风险“

作者你好,将项目加载到手机上后,布局 fragment_player 左上角出现不可消除的警告提示:”PlayerFragment 未遵循 Databinding 严格模式,存在 null 安全风险“。拆解后,应该是 PlayerFragment.java 中调用 (FragmentPlayerBinding) getBinding(),所致。请问使用系统生成的 databindingimpl 操作控件就会出现此警告吗,并且这种水印应该怎么消除呢,多谢。

关于网络请求

我在OKHttp build中使用到持久化Cookie,所以在build过程中需要用传入Context ,那么我在ViewModel请求网络过程中也要传入Context, 这样好像违背了MVVM..不知道该如何解决

获取结果没有双向无感知

返回的数据Flowable有改变没有考虑到只会刷新一次 以及UI与数据层双向无感知 databing 有部分问题 切入性大

netStateEvent的问题

一个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 更是如此。

所以问题来了

为什么违背谷歌设计的建议而设计目前这样的架构呢?是有什么特殊使用场景需求还是?这么设计的原因和目的是?如果没有什么特殊需求的话,应该怎么设计架构?

Cannot add the same observer with different lifecycles

我使用了您的BaseActivity,有多个Activity都继承了BaseActivity,我在使用的时候报错
java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
找到原因代码
NetworkStateManager.getInstance().mNetworkStateCallback.observe(this, netState -> {
//TODO 这里可以执行统一的网络状态通知和处理

    });

如果有多个Activity,如何正确的使用BaseActivity呢

请教个livedata机制问题

使用了room配合livedata处理数据变动,一有数据变更就反馈到ui层,这没错,有时候一条数据某些值要变动,或者收到服务器传递过来的数据,需要修改相同的数据,会传递2次以上到ui导致adapter重复添加数据到界面上这种是要通过减少相同数据操作,还是ui上数据处理,还是把livedata换成一个子类M开头的。感觉表达起来有点问题,其实我就是想问相同数据操作数据库引起的重复通知更新,大神你是怎么处理的。

探讨页面成员变量的保存和恢复

@KunMinX
理解了,我看了下配置发生变化时保存的具体对象是viewModelStore,这个对象具体activity的属性,它有个属性mMap,存储了所有的viewModel,通过ViewModelProvider.get()方法时,先获取最后配置变化的viewModelStore,然后从mMap中获取viewModel.理解了这个原理,也有一个小想法,就是viewModelStore是activity的对象,配置发生变化时,因为viewModelStore被保存下来了,所以旧的activity回收不了,感觉也是一个内存泄漏.

Originally posted by @hanshengjian in #41 (comment)

框架设计咨询

大佬可以咨询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报错了

Could not resolve all dependencies for configuration ':architecture:_internal_aapt2_binary'

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

关于Navigation

看您的项目,从MainFragment->LoginFragment,的确MainFragment没有走onDestoyView
但是小的copy了architecture模块下navigation.fragment整个包到新项目,从
AFragment->BFragment,A就发生了onDestoryView。我看了下路由没啥异,是要有什么额外的设置才能让A不销毁视图吗?很疑惑,望解答

对ViewModel的一些疑惑

  • ClickProxy能不能写在VM,我直接设置liveData值,然后试图控制器里去观察是不是也可以呢?
  • Model应该只能VM去引用吧?那这样的话,视图控制器直接去观察ModelliveData,这样有没有违背这个原则。比如在 MainFragment onViewCreated
    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)

wrong link for playstore

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)

怎么理解状态管理分治

请问这句话“MVP 的 Presenter 和 MVVM - Clean 的 ViewModel 都不具备状态管理分治的能力”怎么理解

ShareViewModel的一些疑问

作者你好,这套框架非常好,有很多值得思考的地方。
不过有个疑问,假设有一模块既不是Activity也不是Fragment的域使用到ShareViewModel的数据时,应该如何获取会是比较好的方案呢?

想知道怎么在列表中增加多种样式的item

目前adapter中关于ViewDataBinding的泛型其实是对应着holder的布局(因为holder在进行绑定的ui的时候会使用到此ViewDataBinding),假如一个列表中存在多种holder那该怎么处理ViewDataBinding的问题呢

下载模拟显示问题

     我这边在模拟器里测试这个返回仍然在下载的界面
     SearchFragment
    点开“测试下载,返回页面仍有效”按钮,进度条开始动,然后我重复退出进入SearchFragment,就会发现离开页面终止的那个进度条也有数据了
    Debug断点打在getDownloadFileCanBeStoppedLiveData里,复现这个问题,但是并没有断点,很奇怪。
    换成真机到是没有出现过这个问题

您这个架构的一个目的是保持Activity或Fragment中不出现DataBinding中的内容,但是如果要配置一些组件的程序,比如viewPager2要使用TabLayoutMediator,需要进行acctch() 和detach()的调用,也就是要绑定周明周期,这种情况需要怎么处理呢

您这个架构的一个目的是保持Activity或Fragment中不出现DataBinding中的内容,但是如果要配置一些组件的程序,比如viewPager2要使用TabLayoutMediator,需要进行acctch() 和detach()的调用,也就是要绑定周明周期,这种情况需要怎么处理呢

不建议直接暴露liveData的写操作

mPlayerViewModel.maxSeekDuration.set(playingMusic.getDuration());

项目看到ViewModel类只单纯持有liveData,且直接暴露liveData。
比较好的一种写法是添加Model层,例如XXXRepository或XXXModel。
所有对liveData的写操作都通过ViewModel调用Repository来写。
暴露的liveData只调用observe方法。
不然写操作多的话,遍地的liveData的set会导致很难维护。

可能项目里liveData数据结构简单所以感知不是特别大。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.