Giter Site home page Giter Site logo

qingmei2 / mvvm-architecture Goto Github PK

View Code? Open in Web Editor NEW
1.8K 45.0 284.0 2.75 MB

The practice of MVVM + Jetpack architecture in Android.

Kotlin 100.00%
android mvvm rxjava android-jetpack kotlin rxjava-bindings navigation lifecycle android-paging hilt

mvvm-architecture's Introduction

MVVM-Architecture

Android端 MVVM + Jetpack 架构组件的Github客户端。

通知

这个项目采用了数种 MVVM 的实现方式,你可以参考任意感兴趣的进行了解:

屏幕截图

三方组件

Android Jetpack 组件

网络请求

依赖注入

其它

开始使用

如果编译遇到如下图的错误:

出现这个问题的原因,最新版本的代码,需要开发者注册一个自己的OAuth Application,注册后,Github的API访问次数就能达到5000次/小时(之前的版本只有60次/小时),之前很多朋友反应在Debug过程中不够用,断点打了几次就被限制请求了,因此最新版本添加了这个配置的步骤,虽然麻烦了一小步,但是对于学习效率的提升,这点配置时间可以忽略不计。

  • 1.直接通过git命令行进行clone:
$ git clone https://github.com/qingmei2/MVVM-Architecture.git
  • 2.注册你的GitHub App

首先参考这个链接, 注册获取属于你的Access Token

获取到AccessToken后,并配置到你的项目根目录的local.properties文件中:

USER_ACCESS_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxx"

大功告成,接下来点击编译并运行即可。:tada: :tada: :tada:

如何入手学习这个项目?

如何使用Android Jetpack

一些有趣的项目推荐

  • Net: 基于kt协程的网络请求库,简单易上手;
  • BRV: 基于kt的列表库,快速构建MVVM下的UI列表

感谢

🎨 项目中的UI设计部分参考了 gitme.

⭐ 项目参考了 rx-mvvm-android 并对其部分代码进行了引用.

Contributor

License

The MVVM-Rhine: Apache License

Copyright (c) 2018 qingmei2

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

mvvm-architecture's People

Contributors

daqinshgy avatar georgcantor avatar qingmei2 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

mvvm-architecture's Issues

android4.4 Me页面无法显示头像

Could not find class 'de.hdodenhof.circleimageview.CircleImageView$OutlineProvider', referenced from method de.hdodenhof.circleimageview.CircleImageView.init
circleimageview这个库出的问题,我看了下这个库的issue hdodenhof/CircleImageView#260
叽里呱啦说了一大堆看的不是很明白,不过看到了把版本改成2.1,现在这个项目是用的2.2的,我尝试修改了下,就显示了。

登录返回401,Unauthorized

1、已参考README,注册OAuth Application,并在根目录的local.properties文件中填写CLIENT_ID 、CLIENT_SECRET
2、输入有效的github账号密码,登录失败,提示:network failure
3、断点返回错误信息如下:
Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://api.github.com/authorizations}

请教一个问题

我在使用官方demo发现paging3+room添加下拉刷新触发adapter.fresh()方法时页面会闪一下。运行你的项目并没有此现象。就算把paging3版本修改为3.0.0也不会闪。

这个框架太棒了,都是很新的技术

但是对还没学过kotlin的我,看到一脸懵逼,甚至不知道如何在application里面使用项目中的PrefsHelper,
请问这个框架可以用到正式项目中吗?后续是否在维护。
如果用java写的估计star 至少x10了现在。

关于gradle的插件 versionPlugin

我把 你的versionPlugin移植到新的项目中 但是 我无法引用 内部的变量
而且我每次导入 import com.github.qingmei2.plugin.* 到 build.gradle 文件里面,每次都会被gradle自动删除 ,我已经被搞得遍体鳞伤了 ,求大佬救救

关于状态管理的疑问

感谢大佬提供这么美妙的设计思路,想请问下大佬,关于状态管理这块,大佬最终采用了什么解决方案么?该MVVM项目,有协程和rxjava,我看到rxjava好像是类似于mvi文章讲到的,类似:
data class MainViewState(
val isLoading: Boolean,
val error: Throwable?
)

然后协程好像还是使用了传统的mvvm方式,每个view对于一个livedata,这么监听着改变状态。

使用mvi那种概念的话,有个疑问,就是每一次小小的变动,比如把viewA设为不可见,都把整个viewstate下发下去,这样相当于所有的view都重复无意义的更新了一遍,要是不想更新的话,就得让view层变得聪明起来,能够判断是哪里发生了变化,但这又增加了很大的累赘,请问大佬是怎么理解这状态管理的啊

关于Navigation库的疑问

用Navigation库的时候,FragmentA中会执行动画,跳转到FragmentB后回退到FragmentA,这时候动画又会重新执行,就觉得很怪,请教一下,这该怎么处理.
十分感谢~

E/AndroidRuntime: FATAL EXCEPTION: main

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.qingmei2.sample, PID: 18875
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.qingmei2.sample/com.qingmei2.sample.ui.login.LoginActivity}: android.view.InflateException: Binary XML file line #2: Binary XML file line #2: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3253)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
at android.app.ActivityThread.access$1100(ActivityThread.java:221)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7225)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: android.view.InflateException: Binary XML file line #2: Binary XML file line #2: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
at android.view.LayoutInflater.inflate(LayoutInflater.java:551)
at android.view.LayoutInflater.inflate(LayoutInflater.java:429)
at com.qingmei2.rhine.base.view.fragment.BaseFragment.onCreateView(BaseFragment.kt:17)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2544)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:884)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1235)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1301)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:710)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2071)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1861)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1816)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1723)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2624)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1265)
at android.app.Activity.performStart(Activity.java:6915)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3216)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349) 
at android.app.ActivityThread.access$1100(ActivityThread.java:221) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7225) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
Caused by: android.view.InflateException: Binary XML file line #2: Error inflating class androidx.constraintlayout.widget.ConstraintLayout
at android.view.LayoutInflater.createView(LayoutInflater.java:657)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)
at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
at com.qingmei2.rhine.base.view.fragment.BaseFragment.onCreateView(BaseFragment.kt:17) 
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2544) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:884) 
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1235) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1301) 
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:710) 
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2071) 
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1861) 
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1816) 
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1723) 
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2624) 
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580) 
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246) 
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541) 
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178) 
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1265) 
at android.app.Activity.performStart(Activity.java:6915) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3216) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349) 
at android.app.ActivityThread.access$1100(ActivityThread.java:221) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7225) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance(Native Method)
at android.view.LayoutInflater.createView(LayoutInflater.java:631)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:498) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
at com.qingmei2.rhine.base.view.fragment.BaseFragment.onCreateView(BaseFragment.kt:17) 
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2544) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:884) 
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1235) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1301) 
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:710) 
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2071) 
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1861) 
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1816) 
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1723) 
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2624) 
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580) 
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246) 
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541) 
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178) 
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1265) 
at android.app.Activity.performStart(Activity.java:6915) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3216) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349) 
at android.app.ActivityThread.access$1100(ActivityThread.java:221) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7225) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/constraintlayout/widget/R$styleable;
at androidx.constraintlayout.widget.ConstraintLayout.init(ConstraintLayout.java:590)
at androidx.constraintlayout.widget.ConstraintLayout.(ConstraintLayout.java:567)
at java.lang.reflect.Constructor.newInstance(Native Method) 
at android.view.LayoutInflater.createView(LayoutInflater.java:631) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:498) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:429) 
at com.qingmei2.rhine.base.view.fragment.BaseFragment.onCreateView(BaseFragment.kt:17) 
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2544) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:884) 
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1235) 
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1301) 
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:710) 
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2071) 
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1861) 
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1816) 
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1723) 
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2624) 
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2580) 
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246) 
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541) 
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:178) 
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1265) 
at android.app.Activity.performStart(Activity.java:6915) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3216) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349) 
at android.app.ActivityThread.access$1100(ActivityThread.java:221) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7225) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.constraintlayout.widget.R$styleable" on path: DexPathList[[zip file "/data/app/com.qingmei2.sample-1/base.apk"],nativeLibraryDirectories=[/data/app/com.
I/Process: Sending signal. PID: 18875 SIG: 9
Process 18875 terminated.

登录时有问题

在登录界面,不填任何数据 ,第一次 Sing in 后就会出现提示,但是在次点击 就会没有任何反应,随后再输入任意账号密码后 sign in 就会显示network failure 然后progress一直存在
image 框架中使用了很多新框架,学习价值很高 希望作者多加些注释,有助于理解和使用。 谢谢作者的贡献

登陆

请问怎么登陆进去啊~~·账号和密码

com.google.protobuf plugin找不到的问题

sync 结果提示:

FAILURE: Build failed with an exception.

  • Where:
    Build file 'D:\StudioProjects\MVVM-Architecture\app\build.gradle' line: 8

  • What went wrong:
    Plugin [id: 'com.google.protobuf', version: '0.8.12'] was not found in any of the following sources:

  • Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
  • Included Builds (None of the included builds contain this plugin)
  • Plugin Repositories (could not resolve plugin artifact 'com.google.protobuf:com.google.protobuf.gradle.plugin:0.8.12')
    Searched in the following repositories:
    Gradle Central Plugin Repository

了解版本更新日志及下阶段目标,请看这里

更新日志

Update :2020/ 8/ 27

  • 重构,分页库迁移到Paging3
  • 增加首页搜索功能页面;

感谢DaQinShgy对本次更新相关功能的贡献 🎉。

Update: 2020/ 7/ 3

  • 重构,移除了 Kodein, 使用 Dagger-Hilt;
  • 添加 ActivityFragment 库。

Update: 2020/ 1/ 15

  • 重构,添加了 Coroutine + Jetpack 对 MVVM 的实现方式;

现在项目采用了2种 MVVM 的实现方式,你可以参考任意感兴趣的进行了解:Jetpack + 协程 或者 Jetpack + RxJava


...
...
更多早期的更新日志都已经随风飘逝......

可以加入开发行列一起丰富这个框架吗

使用了一段时间之后,觉得这个框架还可以更丰富点,在实际使用过程中情况更复杂,比如不用room的情况,常见的场景就是搜索列表;还有点赞等更新item的功能;上拉加载更多效果、list为空的情况。

个人觉得一些好的和不好的

居然git主还有一面之缘,4月我去心田花开面试的时。下载了项目下来看了login和home 2块,开始看着一脸懵逼,跟着文章补了点kodein,然后明朗了许多,很多地方都值得学习。
好的:
1 对kotlin和r'x'java运用确实比较熟练
2 对jetpack组件使用也很好
不好的:
1 一登陆就崩溃了,还有几个地方
2 项目分得太细了特别是配合上databinding kodein arrow 然后再加上 rxjava kotlin一搅和,在实际生产环境难以调试和维护,当人员流动比较大的时候更为突出

关于takeUntil(mAutoDisposeObserver)导致请求无法下发的问题

大神,我在你的demo的基础上将HomeFragment单独提出到另一个JumpActivity时,发现一个问题:
第一次启动JumpActivity时,HomeFragment中的刷新操作是可以正常下发的,此时关闭JumpActivity,然后再次进入,会出现HomeFragment刷新事件无法下发的情况,被takeUntil(mAutoDisposeObserver)拦截了。
按照我的思路,正常关闭的时候,HomeViewModel和HomeRepository会跟随Fragment和Activity的生命周期被销毁,但是这里貌似并没有。

fun refreshPagedList() {
    fetchEventByPage(1)
                .takeUntil(mAutoDisposeObserver)
                .subscribe { mRemoteRequestStateProcessor.onNext(it) }
}

mAutoDisposeObserver在ViewModel中调用了下面代码后:

    override fun onCleared() {
        super.onCleared()

        repo.mAutoDisposeObserver.onNext(Unit)
        repo.mAutoDisposeObserver.onComplete()
    }

mAutoDisposeObserver貌似并没有重新创建,导致请求被截断。

JumpActivity代码:

class JumpActivity : BaseActivity() {
    val fragment: BaseFragment = HomeFragment()

    override val layoutId = R.layout.activity_common_fg

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager.apply {
            findFragmentByTag(fragment::class.simpleName) ?: beginTransaction()
                    .add(R.id.flContainer, fragment, fragment::class.simpleName)
                    .commitAllowingStateLoss()
        }
    }
}

activity_common_fg.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/flContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

求教?新手上路

一点小问题

1 列表加载,首页/第二(..N)页 失败重试这个好像不容易实现
2 首页其实可以不用viewpager,navigation导航虽然会replace fragment,使用viewmdel完全可以保留数据状态,MainActivity里面BottomNavigationView 搭配NavHostFragment,然后4个子页面viewmodel使用ViewModelProviders.of(requireActivity(), viewModelFactory)创建,在fragment stop的时候记录列表状态
Parcelable listState = binding.recycleview.getLayoutManager().onSaveInstanceState(); viewModel.mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, listState);
然后
viewModel.pagedList.observe(this, new Observer<PagedList<ItemBean>>() { @Override public void onChanged(@Nullable PagedList<ItemBean> pagedList) { adapter.submitList(pagedList); Parcelable listState = viewModel.mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE); if (listState != null) { binding.listFeed.getLayoutManager().onRestoreInstanceState(listState); } } });
切换效果很好,另外可以在MainActivity里面监听onDestinationChanged,判断是否是首页4个tab,是显示BottomNavigationView ,不是就隐藏
navController.addOnDestinationChangedListener

【关于】作者本人对这个MVVM项目的定位是什么?

MVVM-Architecture 这个项目维护了近2年了,从一开始独自的实践探索,到越来越多的同行对这个项目的肯定和建议,在这个过程中我也同样成长了很多。

在这个过程中,有部分小伙伴好奇 为什么这个项目这么简单 ,这似乎不太符合对 框架类 项目的认知,实际上我对这个项目的定义就是 个人对MVVM的一种诠释

看过我 MVVM 系列文章的人应该会有印象,架构 应该是依托于项目的业务本身的,只有真正细分到业务,才称得上 架构 二字,不同项目其架构千差万别是非常正常的——如果说想要通过一个 大而全面的框架 适用于各种应用的研发,让业务服务于架构,那么这一定是本末倒置了。

既然架构是服务于业务的,那么MVVM的推广又是什么呢?我更倾向于将其描述为一种**,即 数据驱动视图 的响应式**,真正融入理解了这种**之后,开发者自身会在日常开发过程中对不同的编程方式进行对比,从而提升自己对编程的理解。

因此,如果这个项目让你感受到了和常规 命令式编程 模式的不同,从而深入思考并慢慢喜欢上这种开发模式的话,那么就已经达到作者本人的初衷了 👍 。

希望你能够通过这个项目喜欢上 MVVM,并根据个人的理解,找到并开发出适合你和你的团队的开发框架🎉。

编译器警告

API 'variant.getPackageLibrary()' is obsolete and has been replaced with 'variant.getPackageLibraryProvider()' 这个是哪个库API过时了吗

网络请求

大佬,可以出一个只有网络请求的paging模板吗?因为的有点业务对数据的及时性或者数据变动比较频繁,所以希望出一个直接从服务端获取数据而不走数据库的模板。多谢大佬

android4.4闪退

Process: com.qingmei2.sample, PID: 3337 java.lang.RuntimeException: Unable to get provider androidx.lifecycle.ProcessLifecycleOwnerInitializer: java.lang.ClassNotFoundException: Didn't find class "androidx.lifecycle.ProcessLifecycleOwnerInitializer" on path: DexPathList[[zip file "/data/app/com.qingmei2.sample-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.qingmei2.sample-1, /vendor/lib, /system/lib]] at android.app.ActivityThread.installProvider(ActivityThread.java:4793) at android.app.ActivityThread.installContentProviders(ActivityThread.java:4385) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4325) at android.app.ActivityThread.access$1500(ActivityThread.java:135) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5017) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.lifecycle.ProcessLifecycleOwnerInitializer" on path: DexPathList[[zip file "/data/app/com.qingmei2.sample-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.qingmei2.sample-1, /vendor/lib, /system/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:497) at java.lang.ClassLoader.loadClass(ClassLoader.java:457) at android.app.ActivityThread.installProvider(ActivityThread.java:4778) at android.app.ActivityThread.installContentProviders(ActivityThread.java:4385)  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4325)  at android.app.ActivityThread.access$1500(ActivityThread.java:135)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:136)  at android.app.ActivityThread.main(ActivityThread.java:5017)  at java.lang.reflect.Method.invokeNative(Native Method)  at java.lang.reflect.Method.invoke(Method.java:515)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)  at dalvik.system.NativeStart.main(Native Method) 

dex问题,需要启用multidex。好久没有遇到这个报错了。

BaseFragment貌似有点问题

MVVMRhine/mvvm_rhine/src/main/java/com/qingmei2/rhine/base/view/fragment/BaseFragment.kt

abstract class BaseFragment : InjectionFragment() {

private var mRootView: View? = null

abstract val layoutId: Int

override fun onCreateView(inflater: LayoutInflater,
                          container: ViewGroup?,
                          savedInstanceState: Bundle?): View {

//这里有点问题,改成mRootView = inflater.inflate(layoutId, container, false)就好了,具体原因未知
mRootView = LayoutInflater.from(context).inflate(layoutId, container, false)
return mRootView!!
}

override fun onDestroyView() {
    super.onDestroyView()
    mRootView = null
}

}

登陆退出

/com.qingmei2.sample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.qingmei2.sample, PID: 12087
java.net.ConnectException: Failed to connect to api.github.com/13.250.168.23:443
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:268)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:180)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:238)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:111)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:79)
at okhttp3.internal.connection.Transmitter.newExchange$okhttp(Transmitter.kt:163)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:35)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:71)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at com.qingmei2.sample.http.interceptor.BasicAuthInterceptor.intercept(BasicAuthInterceptor.kt:24)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:219)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:194)
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:784)
Caused by: java.net.ConnectException: failed to connect to api.github.com/13.250.168.23 (port 443) from /192.168.124.107 (port 50196) after 10000ms: isConnected failed: ECONNREFUSED (Connection refused)
at libcore.io.IoBridge.isConnected(IoBridge.java:278)
at libcore.io.IoBridge.connectErrno(IoBridge.java:187)
at libcore.io.IoBridge.connect(IoBridge.java:129)
at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:137)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:391)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:231)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:213)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
at java.net.Socket.connect(Socket.java:621)
at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.kt:57)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:266)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:180) 
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:238) 
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:111) 
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:79) 
at okhttp3.internal.connection.Transmitter.newExchange$okhttp(Transmitter.kt:163) 
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:35) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:71) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at com.qingmei2.sample.http.interceptor.BasicAuthInterceptor.intercept(BasicAuthInterceptor.kt:24) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:219) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:194) 
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138) 
at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:784) 
Caused by: android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
at libcore.io.IoBridge.isConnected(IoBridge.java:267)
at libcore.io.IoBridge.connectErrno(IoBridge.java:187) 
at libcore.io.IoBridge.connect(IoBridge.java:129) 
at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:137) 
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:391) 
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:231) 
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:213) 
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436) 
at java.net.Socket.connect(Socket.java:621) 
at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.kt:57) 
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:266) 
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:180) 
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:238) 
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:111) 
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:79) 
at okhttp3.internal.connection.Transmitter.newExchange$okhttp(Transmitter.kt:163) 
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:35) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:71) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at com.qingmei2.sample.http.interceptor.BasicAuthInterceptor.intercept(BasicAuthInterceptor.kt:24) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:219) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:112) 
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:87) 
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.kt:194) 
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138) 
at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:784) 

关于导航事件的一些问题

  • 对于View层和ViewModel层,UI事件比如Snackbar、页面导航,之前我们公司项目一直参考Google使用SingleLiveEvent(现在切换为Event包装),最近在学习您项目发现这一块您使用的是ViewDelagate来处理的,想请问一下您对Mvvm中这块的想法,关于这几种方式的优缺点。

  • 另外想问一下,DataBinding做数据绑定,为什么现在一些新的Mvvm项目都使用MutableLiveData而不使用Observeable(ObservableBoolean这些)来绑定数据了呢?

非常感谢~

升级viewmodel到2.3.0 升级lifecycle到2.2.0 ,在LoginViewModel中如果构造函数有参数时,就会提示这个错误,不知道怎么改,是代码要修改还是google版本的bug呢

Caused by: java.lang.RuntimeException: Cannot create an instance of class com.hisense.smartlab.link.tv.ui.LoginViewModel
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
02-25 14:56:53.059 15106 15106 E AndroidRuntime: at com.hisense.smartlab.link.tv.ui.LoginActivity.getMViewModel(LoginActivity.kt:25)

关于项目中的一些疑惑

你好,最近追了你的几篇博客之后,也决定了学习这个项目。为了简单(本人愚钝),我是从"添加异常处理“的版本开始看的,即2018/9/10那天提交的。期间遇到了几个疑惑,劳烦您指点下。

  1. 关于ViewDataBing调试的。在布局文件中data节点中的元素,其创建一般有多个依赖,若其中的依赖有错,编译只告知ViewDataBinding创建失败,没法追溯到错误源,具体是哪个依赖错误导致。 于这点,有什么好的解决办法吗?
  2. 关于本项目中具体的一些细节的。在登录模块中,登录成功View层如何处理结果。

你的实现:

//LoginViewDelegate file
init {
        viewModel.userInfo
                .toFlowable()
                .subscribe { it ->
                    Log.d("tag", it.toString())
                    navigator.toMain()
                }
    }
//

fun <T> LiveData<T>.toFlowable(): Flowable<T> = Flowable.create({ emitter ->
    val observer = Observer<T> { data ->
        data?.let { emitter.onNext(it) }
    }
    observeForever(observer)
   //允许下游叫停流(cancel the flow),或当流中出现错误/完成信号时停止。不知道这里要怎么理解?
    emitter.setCancellable {
        object : MainThreadDisposable() {
            override fun onDispose() = removeObserver(observer)
        }
    }
}, BackpressureStrategy.LATEST)

我想要的实现

//plan A
    init {
        viewModel.userInfo
            .observe(viewModel.lifecycleOwner!!, Observer { //报错,该类初始化时,Activity并没有onCreate()
                navigator.toMain()
            })
    } 
//plan B
    init {
        viewModel.userInfo.observeForever{ //参照你的实现,LIveData无视生命周期,直接添加观察者。问题在于,异步请求返回后的结果,若acitivity不在合适的生命周期内,无法处理结果。
            navigator.toMain()
        }
    }
//plan C
//在LoginViewModel中
    override fun onCreate(lifecycleOwner: LifecycleOwner) {
        super.onCreate(lifecycleOwner)
        userInfo.observe(lifecycleOwner, Observer { 
            //operate the UI
//看到别的Demo中是这么弄的,这样子表达得很清晰。但在ViewModel中操作操作UI,viewModel就要持有context了,突然又觉得你的方案分离出一个ViewDelagate会更清晰了😅
我的想法是,能不能在viewDelegate中监听到onCreate()事件再做相应事件?或是说,我是哪里理解错了?
        })
    }

请教范例中 main 的 repository lifecycle 架构问题

Hi Qingmei2 大您好,

从您这个例子学到很多东西,想请教有关于 main 的数据生命周期问题。

这个专案里,进入 main 后,各个子页面各自有自己的 repository,生命周期跟著该 Fragment走。然而,是不是其实有些数据会是需要以 mainFragment 的生命周期为主,这样如果 Fragment 被回收掉才不会数据丢失需要从remote或是local storage 重载。
在这个专案比较少看到透过一个viewmodel/repository在多个Fragment共享数据的例子,有机会的话会想知道 qingmei2 会怎么样写这种场景需求。
期待有空回复指教,感谢。

FATAL EXCEPTION: main

崩了
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property viewModel has not been initialized
at com.qingmei2.rhine.base.acitivty.BaseActivity.instanceViewModel(BaseActivity.kt:73)

sharedpref读取问题

想问一下,你把所有的sharedpref都放在了本地的userRepository中,如果其他类想读写这个sharepref的属性,但是这个类又没传入context对象,在不直接调用sharedpref的方法和实现kodein提供的接口情况下,有什么优雅的方法调用你userRepository中的属性?

关于实现点赞功能的问题(Paging)

Hello,关于实现点赞功能的细节想要请教一下,根据 Android官方架构组件Paging-Ex:列表状态的响应式管理 一文中关于更新item的思路,我尝试了类似于点赞功能的实现。
通过更新room的数据去通知pagelist的方式可行,但是却遇到了一个问题:当点击点赞按钮后,再重复点击点赞按钮取消点赞,此时按钮状态不会改变。
重复试验发现,点击同一个item时不会更新,但是点击其他item之后再去点击原先的item,此时item的点赞状态会更新。
同时尝试了打印了submitList提交的数据,其中的数据点赞状态是有被更新的,但是因为DiffUtil.ItemCallback中的areContentsTheSame(oldItem: Repo, newItem: Repo)方法返回的oldItem和newItem是相同的,导致点赞状态不会被更新。

不知道您这边是怎么实现这个功能的呢?是否也遇到过类似的问题?
代码如下:

@Dao
interface UserReposDao {
    @Update
    fun insertItem(repo: Repo)
}
class ReposRepository(
        remote: RemoteReposDataSource,
        local: LocalReposDataSource,
        val mAutoDisposeObserver: AsyncProcessor<Unit> = AsyncProcessor.create()
) : BaseRepositoryBoth<RemoteReposDataSource, LocalReposDataSource>(remote, local) {

    .......

    fun setSelectMode(item: Repo, state: Int) {
        item.forksCount = state
        localDataSource.insertNewItemData(item)
                .observeOn(RxSchedulers.ui)
                .doOnError { toast { "${it.message}" } }
                .subscribe()
    }
    .......
}

class RemoteReposDataSource(private val serviceManager: ServiceManager) : IRemoteDataSource {
    .......
}

class LocalReposDataSource(
        private val db: UserDatabase
) : ILocalDataSource {
    fun insertNewItemData(newItem: Repo): Completable {
        return Completable.fromAction {
            db.runInTransaction { db.userReposDao().insertItem(newItem) }
        }.subscribeOn(RxSchedulers.io)
    }
}
@SuppressWarnings("checkResult")
class ReposViewModel(
        private val repo: ReposRepository
) : BaseViewModel() {

    .......
    fun setItemSelectMode(item: Repo, state: Int) {
        repo.setSelectMode(item, state)
    }

    .......
}
class ReposFragment : BaseFragment() {

    .......
    private fun binds() {
    
        .......
        // list item clicked event.
        mAdapter.getItemClickEvent()
                .autoDisposable(scopeProvider)
                .subscribe(::itemSubViewClickAction)

        .......
    }

    private fun itemSubViewClickAction(item: Repo) {
        mViewModel.setItemSelectMode(item, if (item.forksCount != 1000) 1000 else 1)
    }
}

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.