RxAndroid 3 main thread - android

I am trying to find the main thread for subscribeOn in Rx3
Single.just(getHeavyData())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Data>() {
#Override
public void accept(Data d) throws Throwable {
setAdapters(d);
}
});
AndroidSchedulers.mainThread() - is not compatible with the brand new RX3
Gradle import: implementation "io.reactivex.rxjava3:rxjava:3.0.0-RC3"
How can we find the main thread in order to do changes to the UI?

AndroidSchedulers.mainThread() is not part of Rx Java 1,2 or 3. Its the part of RxAndroid Library. Add RxAndroid dependency to your project and you will get this method.
RxAndroid still uses RxJava2. Until there is an update from the creators of the library this problem remains.
The new package structure has been released with 3.0.0-RC2 and there is a support library so that v2 and v3 can talk to each other without hidden or overt compilation/runtime problems from before.
This also means that module override tricks no longer work so you have to bridge AndroidSchedulers manually or convert from v2 sources used in Retrofit until these (and many other) libraries start supporting v3.
Please refer this and this

This is an issue with imports.
I had a similar problem before realizing that I need to reference RxJava3.
Use these imports for Schedulers and Disposable Single Observers
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.observers.DisposableSingleObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;
Also, if you have a service with a method that returns a Single use
import io.reactivex.rxjava3.core.Single;

Had a similar problem and the compatibility issue was from an import of the Single. Even though I was using RxJava3 library and RxAndroid3, I was still using:
import io.reactivex.Single
But was resolved when pointing the Single to:
import io.reactivex.rxjava3.core.Single

Check your import, maybe you are importing something like:
implementation 'io.reactivex.**rxjava2**:rxandroid:x.y.z'
but you should be importing something like:
implementation 'io.reactivex.**rxjava3**:rxandroid:3.0.0' (check the last version)
that solved my problem

Related

kotlinx.coroutines not found

I'm writing React Native and implemented a custom UI component for Android. One of the props I send to the component is a large array of objects. The deserialization in Android (Kotlin) tooks some time (>200ms) and I'm trying to use async to prevent blocking the UI.
#ReactProp(name = "items")
fun setItems(view: CustomListView, items: ReadableArray) {
async {
val itemsList = deserializItems(items)
view.setItems(itemsList)
}
}
but Android Studio says: Unresolved reference: async
I added these to my app build.gradle:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
and tried to import manually kotlinx.coroutines but Android Studio doesn't find it as well.
How can I get async functionality in Android?
You need a coroutine scope to be able to call async.
I am not familiar with react development, but how i would use it something like this from inside a viewModel.
val asyncFunction = viewModelScope.async {
//do your background work here
}
and then you need to await() it later.
viewModelScope.launch {
asyncFunction.await()
}
For import i have this in the gradle files
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
and these are the imports
import kotlinx.coroutines.*
Also, it might sound silly, but make sure to sync gradle after adding the dependencies.
Or by using the "Sync Now" button displayed on the screen when editing the gradle file.
I solved my problem by adding coroutines dependency.
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4'

ArgumentMatchers.any must not be null

I am trying to test ViewModel to make sure livedata gets updated correctly. However when using ArgumentMatchers.any() it fails with IllegalStateException saying:
ArgumentMatchers.any(mViewModel.CountSubscriber::class.java) must not
be null
#Test
fun emitValueIfCountIs7() {
doAnswer { invocation: InvocationOnMock ->
val subscriber: mViewModel.CountSubscriber = invocation.getArgument(0)
subscriber.onNext(7)
null
}.`when`(countUseCase).execute(
ArgumentMatchers.any(mViewModel.CountSubscriber::class.java),
ArgumentMatchers.any(Parameters::class.java)
)
// When
mViewModel.getCount()
// Verify
assert(mViewModel.countResponse.value != null)
}
I am using Kotlin and have the following dependencies:
testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-inline:2.23.4"
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
Here are my imports:
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.nhaarman.mockitokotlin2.doAnswer
import io.reactivex.Observable
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.invocation.InvocationOnMock
Strange thing is that it used to work before, and I don't know what has happened that could affect this.
Getting matchers to work with Kotlin can be a problem.
If you have a method written in kotlin that does not take a nullable parameter, then we cannot match with it using Mockito.any().
This is because it can return void and this is not assignable to a non-nullable parameter.
If the method being matched is written in Java, then I think that it will work as all Java objects are implicitly nullable.
One possible solution would be to use a library like mockito-kotlin
But you can solve this issue easily with a few lines of code yourself.
If you need typed any(type: Class)
private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
OR
You can use this matcher instead of Matchers.any() :
object MockitoHelper {
fun <T> anyObject(): T {
Mockito.any<T>()
return uninitialized()
}
#Suppress("UNCHECKED_CAST")
fun <T> uninitialized(): T = null as T
}
and use MockitoHelper.anyObject() instead of any() in your kotlin tests.
You can find more information in this post: Using Mockito with Kotlin
There is a discussion about possible solutions in this post :
Is it possible to use Mockito in Kotlin?
The correct solution is mentioned in the comment section of the question by #Ana Koridze. Yes, if you are using Koltin + mockitoKotlin. Make sure you are using the following import:
1 - Using the Mockito-kotlin:
import org.mockito.kotlin.any from Mockito-kotlin
instead of
import org.mockito.Mockito.any
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
2 - Or if you are using older mockito kotlin version original created by nhaarman before the intergation
import com.nhaarman.mockitokotlin2.any from nhaaram's Mockito-kotlin instead of import org.mockito.Mockito.any
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockito_kotlin2_version"
BTW, if you are using Android Studio or IntelliJ IDEA. the any() from mockitokotlin library should be italic by default style/color scheme.
Notice the any() at the end of line. This is from mockitokotlin
And here is the any() from mockito
Thanks #Sattar for the recommended edit.
mockito-kotlin has added support for nullable args with anyOrNull()
`when`(myMock.doesThis(any(), anyOrNull())).thenReturn(someObject)
use Mockito-kotlin
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
this will use any that works for kotlin as this is a wrapper lib for Mockito but for kotlin
This is what worked for me,
either replaced all generic any()s , with a specific anyTYPE(), i.e anyInt(), anyList() etc from core lib org.mockito:mockito-core and it fixes the (nullability)issue, it seems the specific definitions with type can handle null. this option does not require you to import any extra lib
or
if you really need to use the generic type any() , add this official Mckito extension lib https://github.com/mockito/mockito-kotlin and make sure you use the any() from this lib (by making sure your imports has this in it import org.mockito.kotlin.any)
I suggest to start using MockK lib https://github.com/mockk/mockk instead of Mockito as it is a Mock library for Kotlin = MockK)
however, if you feel lazy to switch right now or maybe dealing with legacy tests (as in my case :), this should fix your issue too.
For me all solutions above were not enough - in addition to that I had to mark the called method as an 'open' method.
According to this:
https://github.com/mockito/mockito-kotlin/wiki/Parameter-specified-as-non-null-is-null
The method is final and Mockito couldn't mock it so I had to add 'open'.
I wrote a simple wrapper function around Mockito's any() and got rid of the warning.
private fun <T> any() : T {
return org.mockito.ArgumentMatchers.any()
}
I am still pretty green at Kotlin though, so I am not sure whether there may be some unwanted side effects. I put this answer out there in case it helps anyone or someone gives me feedback.

Package Level Protection in Kotlin [duplicate]

In Java, we have the package protected (default) modifier for classes, which allows us to have many classes in a single package but exposes only a few and keeps the logic encapsulated.
With Kotlin this doesn't seem to be the case. If I want a few classes to be visible to each other but no further, I have to use a private modifier which limits visibility to a single file.
So if you want 10 classes in a package but only one of them to be public, you'd have to have one huge file with all the classes in it (and private all over the place).
Is this normal practice or there is a way to achieve some similar modularity in Kotlin?
I don't understand: if they have the notion of a package, why did they get rid of package protected access?
Update: We might have package protected visibility after all
see the discussion here
Update: If you read through the discussion and still think this is a must-have feature for the language, please vote here
Kotlin, compared to Java, seems to rely on packages model to a lesser degree (e.g. directories structure is not bound to packages). Instead, Kotlin offers internal visibility, which is designed for modular project architecture. Using it, you can encapsulate a part of your code inside a separate module.
So, on top level declarations you can use
private to restrict visibility to the file
internal to restrict visibility to the module
At this point, there is no other option for visibility restriction.
As a workaround for me on android I've created #PackagePrivate annotation and lint checks to control access. Here you can find the project.
Lint checks are obviously not that strict as compiler checks and some setup needed to fail the build on errors. But android studio picks up lint checks automatically and shows error immediately while typing. Unfortunately I don't know a way to exclude annotated members from autocomplete.
Also, as lint is a purely compile-time tool, no checks at runtime performed.
As #hotkeys points out, you can use the internal keyword in a module or you can put all classes that would otherwise belong in a package inside a single file, but sticking several classes in a file may be a questionable design decision.
For me, the package visibility is helpful for its documenting value. I want to know what public interface some package is presenting to the rest of the project, hide factory implementation classes and so on.
So even if it's possible to access package-private classes and methods in Java, I still choose to use the package modifier.
For this I created a project with a single annotation:
package com.mycompany.libraries.kotlinannotations;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Documented
#Retention(SOURCE)
#Target({ TYPE, METHOD, CONSTRUCTOR })
/**
* Use in Kotlin code for documentation purposes.
*
* Whenever a Kotlin class or method is intended to be accesible at package level only.
*
*/
public #interface PackagePrivate {
}
Then I can use this annotation in any Kotlin project.
The second step, which I haven't done yet, is creating a PMD rule to enforce this with maven (or any other build tool for that matter) and also be able to see violations of the rule in my IDE with the pmd plugin.
There no is full Kotlin support in pmd at this moment but it seems to be expected at some point.
A near-replacement for package private visibility is available using the opt-in requirements feature (credit to pdvrieze on Kotlin discussions). This is the annotation syntax typically used to flag experimental features in an API.
To use it, create an annotation denoting package private declarations:
#RequiresOptIn(message = "Only to be used in MyPackage")
#Retention(AnnotationRetention.BINARY)
annotation class MyPackagePrivate
Then annotate any methods you want to be package private with it:
#MyPackagePrivate
fun aPackagePrivateMethod() {
// do something private within a package
}
In this way a warning will be generated on any method that calls the annotated method unless the calling method is itself annotated with the corresponding #OptIn annotation, here shown at class level:
#OptIn(MyPackagePrivate::class)
class AClassInThePackage {
fun userOfPackagePrivateMethod() {
aPackagePrivateMethod()
}
}
This, then, produces a similar effect to Java's package private, except that calling methods need to explicitly opt in to using a package private declaration.
If it is desired to generate an error rather than a warning, the level parameter of #RequiresOptIn can be specified:
#RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "Only to be used in MyPackage")
// annotation declaration as before
Package-based protection is pointless in Kotlin because packages themselves are unprotected
In Java, package was tied to directory structure. So if you put your classes in com\example\yoursecretengine, any attempt (deliberate or accidental) to add a rogue class there would be easily noticeable. This is the kind of security we've depended on.
Kotlin removes the ties between directory and package, so I can put my class in "my" directory (eg.src\java\pl\agent_l\illegalaccess) yet declare its package as com.example.yoursecretengine - and gain access to all the properties you've meant as package private.
In fact, a Kotlin project works perfectly without ANY package declarations. This only highlights that packages are "more what you'd call guidelines than actual rules". They're a convenience feature, useful only to unclutter namespace and nothing more.
Relevant quotes from kotlinlang:
unlike many other languages, Kotlin packages do not require files to have any specific locations w.r.t. itself; the connection between a file and its package is established only via a package header.
And:
an absence of a package header in a file means it belongs to the special root package.

How can I mock and test this class?

The follows was the code which I want to test.
public class Demo {
private static final List<Pair<String, String>> mList;
static {
mList = new ArrayList<>();
mList.add(new Pair<>("F0", "T1"));
mList.add(new Pair<>("F1", "T2"));
mList.add(new Pair<>("F2", "T3"));
}
public String getStr(int pos) {
return mList.get(pos).first;
}
}
I was an android developer. I have get some trouble in test and mock the code.I have use mockito.
I have try some code to test it,but the result was not my expect.
1.First try
#Test
public void test(){
Demo demo=new Demo();
assertEquals(demo.getStr(0),"F0");
/**
* java.lang.AssertionError:
* Expected :null
* Actual :F0
*/
}
2.Second try
#Test
public void test() {
Demo demo = mock(Demo.class);
doCallRealMethod().when(demo).getStr(0);
assertEquals(demo.getStr(0), "F0");
/**
* java.lang.AssertionError:
* Expected :null
* Actual :F0
*/
}
Anyone tell me how can I resolve this problem to make demo.getStr(0) == "F0" by call the real method? Thanks!
===========================
Another question relate to it
I have try an another test to test android.util.Pair class, and the result is that "pair.first" was null,.(There are androidTest and test directory,I put it into test package.Did it impact the result?)
import android.util.Pair;
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
public class DemoTest {
#Test
public void test1(){
Pair<String,String> pair=new Pair("First","Second");
assertEquals("First",pair.first);
//pair.first was null,why?
}
#Test
public void test2(){
Pair<String,String> pair= Mockito.spy(Pair.class);
assertEquals("First",pair.first);
//pair.first was null also,why?
}
}
Why the simple code is correct in real android environment,but failure in test?
I had the same problem too. month ago I have problem with TextUtils class too.
I report this to jUnit but they told me the problem is with android package because in unit test environment you don't have access to platform specific classes
for that pair case you can use this package. this works for me
import android.support.v4.util.Pair;
The problem in your first try is, that the public field "first" is actually null.
Is the Pair class the one from the "javafx.util" package or a custom implementation?
Did you forget "this.first = first" or something similar in the constructor of the "Pair" class?
I would also recommend to change the following line:
assertEquals(demo.getStr(0),"F0");
to
assertEquals("F0", demo.getStr(0));
so that the error is printed correctly.
Your second try does not make any sense. What is the point in mocking the class you want to test?
I think the second example has the same problem as the first one. Pair.first is never set. If you fix that, it should also work (untested).
From Google's Android tools website:
"Method ... not mocked."
The android.jar file that is used to run unit tests does not contain any actual code - that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito).
So how can we solve this?
In other words. If you need a default android class to work properly you either have to include it from a separate repository, or implement it yourself.
In the case of Android's Pair class. You can use android.support.v4.util.Pair instead.
To get access to this class, you can include com.android.support:support-compat:27.0.0 in your build.gradle or dependencies file.
If you are not using Gradle, you can copy the implementation of this file and use it in place of the official one. Or you can try and download the .jar file from this older version https://mvnrepository.com/artifact/com.google.android/support-v4/r7 (I have not tested whether it works)
Another approach (based on this) is to create the class in app/src/test/java/android/util/Pair.java and copy the code from the Android implementation.
This way you don't need extra dependencies. (There may be issues related to the implementation changing after you make the copy, but the dependencies may become stale as well.)

Unit test SparseArray using JUnit (using JVM)

I have an implementation which is using a Integer as key in HashMap. It is already unit tested using JUnit. But I want to change it to SparseArray which is more optimised version from Android. I am not sure how will it be unit tested using JUnit. Does anyone have a better way to do this?
There's an equivalent implementation of SparseArray in Support Library called SparseArrayCompat that can be used in JVM Unit Tests. Also it has more features than the native one, so you're better off using that.
In case anyone is still looking, you don't need any third party libraries. You can simply mock SparseArray.
Create a file SparseArray.java inside app/src/test/java/android/util and paste the following:
package android.util;
import java.util.HashMap;
public class SparseArray<E> {
private HashMap<Integer, E> mHashMap;
public SparseArray() {
mHashMap = new HashMap<>();
}
public void put(int key, E value) {
mHashMap.put(key, value);
}
public E get(int key) {
return mHashMap.get(key);
}
}
Note: In case you are using funcations beside put and get you will need to implement those here as well.
Unmock is a really nice project that gives you this and more. https://github.com/bjoernQ/unmock-plugin
Just add the plugin and it will work.
Configuring tests with roboelectric framework may be simpler.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
#RunWith(RobolectricTestRunner.class)
public class XxxTest {
...
}

Categories

Resources