Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning LiveData from domain layer #14

Open
pablobaldez opened this issue May 10, 2018 · 21 comments
Open

Returning LiveData from domain layer #14

pablobaldez opened this issue May 10, 2018 · 21 comments

Comments

@pablobaldez
Copy link

What do you think about returning LiveData instances directly from domain Layer?
I'm asking it because the one of the best features of Room framework is the hability to observe changes in DB directly.

So the LiveData instances should be returned directly from domain (usecase and repositories)?

@St4B
Copy link

St4B commented May 11, 2018

LiveData is part of the framework so i would not use it in the domain layer.

@Zhuinden
Copy link

AFAIK livedata can work even in unit tests?

@pablobaldez
Copy link
Author

@St4B I don't think is a good aproach lose Room features of update LiveData just because its part of framework.
This rule is very important to make the unit tests easier, but we can test livedata using Junit without any problem, just like another project class.

@St4B
Copy link

St4B commented May 14, 2018

hmmm ... I was affected by the old project (with rxJava) which had different models per layers and mappers. Now that we use the same model in every layer it does not seem wrong to me. Basically I started to like it! : p

@pablobaldez
Copy link
Author

@Zhuinden yes. You have to add dependencies of livedata to unit test
android.arch.core:core-testing:$arch_version
and than add the rule InstantTaskExecutorRule into unit test file

@android10
Copy link
Owner

Totally agree here with the above comments.

LiveData belongs to the Android Framework which is something you wanna avoid as much as you can, at least at domain level.

In my opinion, it clearly belong to the UI layer, being a key part of MVVM.

@nikolajakshic
Copy link

If you use RxJava in your project, the solution might be to return the Observable from the domain layer and use the reactive streams to convert it to the LiveData in the UI layer.

@crjacinro
Copy link

If you use RxJava in your project, the solution might be to return the Observable from the domain layer and use the reactive streams to convert it to the LiveData in the UI layer.

Is this available already in the source code? This would be a big help since I want to take advantage of Room -> LIve Data interaction by using this clean arch repository.

@nikolajakshic
Copy link

If you use RxJava in your project, the solution might be to return the Observable from the domain layer and use the reactive streams to convert it to the LiveData in the UI layer.

Is this available already in the source code? This would be a big help since I want to take advantage of Room -> LIve Data interaction by using this clean arch repository.

No, this sample app is not using RxJava.

@SaeedMasoumi
Copy link

I agree that the domain layer must not have a dependency on the platform-specific frameworks/libraries, but based on YAGNI principle we're just adding an extra level of abstraction without gain.
So I think passing LiveData in domain layer give us some advantages like less boilerplate for some features like Room.

@mitevyav
Copy link

I am kind a new to the Clean Approach, but there was always something that made my crazy in the begging when I tried to understand it. Everywhere, like in here, everybody are saying - just plain Java! No Android, not this, no that, but every time RxJava is the solution of everything. But RxJava is not pure Java!! I swear, I have never seen an article saying - "Here we are using RxJava, and we are breaking the principle, but there are more pros than cons, so it is OK!". So saying this I don't see why RxJava is ok, but LiveData not.

@nikolajakshic
Copy link

@mitevyav Well, RxJava is not something that is Android specific, it can be used everywhere (web, mobile, desktop, etc..), on the other side, LiveData is Android specfic, that's why it's "acceptable" to return something like Observable from the domain layer, and for LiveData it is not. It's just that RxJava is so popular, widely accepted and some will say it feels almost like a part of the language.

IMO, you don't need to strictly follow clean "rules", just pick what suits your use-case the best and as long as your app is testable and maintainable you are good.

@lawloretienne
Copy link

lawloretienne commented Oct 28, 2018

@Zhuinden yes. You have to add dependencies of livedata to unit test
android.arch.core:core-testing:$arch_version
and than add the rule InstantTaskExecutorRule into unit test file

After adding the core-testing dependency

testImplementation "androidx.arch.core:core-testing:2.0.0"

it throws an error that has do with with Powermockito.

java.lang.AbstractMethodError: org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.isTypeMockable(Ljava/lang/Class;)Lorg/mockito/plugins/MockMaker$TypeMockability;

at org.mockito.internal.util.MockUtil.typeMockabilityOf(MockUtil.java:29)
at org.mockito.internal.util.MockCreationValidator.validateType(MockCreationValidator.java:22)
at org.mockito.internal.creation.MockSettingsImpl.validatedSettings(MockSettingsImpl.java:232)
at org.mockito.internal.creation.MockSettingsImpl.build(MockSettingsImpl.java:226)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:64)
at org.mockito.Mockito.mock(Mockito.java:1871)
at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:36)
at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16)
at org.mockito.internal.configuration.IndependentAnnotationEngine.createMockFor(IndependentAnnotationEngine.java:38)
at org.mockito.internal.configuration.IndependentAnnotationEngine.process(IndependentAnnotationEngine.java:62)
at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:57)
at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:41)
at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:69)
at com.etiennelawlor.pitted.TopSpotsViewModelTest.setUp(TopSpotsViewModelTest.kt:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

This error gets thrown after you call the following function in the setUp function

MockitoAnnotations.initMocks(this)

@lawloretienne
Copy link

So i commented out these dependencies

// testImplementation “org.mockito:mockito-all:$mockitoVersion”
// testImplementation “org.hamcrest:hamcrest-all:$hamcrestVersion”
// testImplementation “org.powermock:powermock-module-junit4:2.0.0-RC.1”
// testImplementation “org.powermock:powermock-api-mockito:1.7.4"

and now i just have these depenedencies

testImplementation “junit:junit:$junitVersion”
testImplementation “org.mockito:mockito-core:2.21.0"

and there is no longer a conflict.

@IMDroidude
Copy link

Why don't you go for Flow instead of LiveData. as Flow is a pure data driven item.

@Zhuinden
Copy link

LiveData is part of the framework so i would not use it in the domain layer.

Objectively, if you don't want to use LiveData, then you shouldn't use Room.

Room is also Android-specific.

Honestly, we should just all use Flutter, you can port that to any platform now. 😂

@vasilyev04
Copy link

Definitely, at the moment there is only one solution for this problem and it's using Coroutine Flow instead of LiveData.

That's it!

@Zhuinden
Copy link

Zhuinden commented Nov 6, 2023

RxJava / Reaktive are technically both valid options

@vasilyev04
Copy link

RxJava / Reaktive are technically both valid options

I suppose that it's not necessary to bring huge framework in your project just for gaining data from Room :)

@Zhuinden
Copy link

Zhuinden commented Nov 6, 2023

In that case, just use LiveData 😉

@vasilyev04
Copy link

In that case, just use LiveData 😉

The question is "how to avoid liveData in domain layer?", so..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests