Module with Main dispatcher is missing - android

I'm trying to make a background call to my local database and update the UI with the results using coroutines.
Here is my relevant code:
import kotlinx.coroutines.experimental.*
import kotlinx.coroutines.experimental.Dispatchers.IO
import kotlinx.coroutines.experimental.Dispatchers.Main
import kotlin.coroutines.experimental.CoroutineContext
import kotlin.coroutines.experimental.suspendCoroutine
class WarehousesViewModel(private val simRepository: SimRepository)
: BaseReactViewModel<WarehousesViewData>(), CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Main
override val initialViewData = WarehousesViewData(emptyList())
override fun onActiveView() {
launch {
val warehouses = async(IO) { loadWarehouses() }.await()
updateViewData(viewData.value.copy(items = warehouses))
}
}
private suspend fun loadWarehouses(): List<Warehouse> =
suspendCoroutine {continuation ->
simRepository.getWarehouses(object : SimDataSource.LoadWarehousesCallback {
override fun onWarehousesLoaded(warehouses: List<Warehouse>) {
Timber.d("Loaded warehouses")
continuation.resume(warehouses)
}
override fun onDataNotAvailable() {
Timber.d("No available data")
continuation.resume(emptyList())
}
})
}
}
My problem is that I get a runtime exception:
java.lang.IllegalStateException: Module with Main dispatcher is missing. Add dependency with required Main dispatcher, e.g. 'kotlinx-coroutines-android'
I already added these to my gradle:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.26.0'
I'm a bit new to this, can someone help me?

Using just the kotlinx-coroutines-android version solves the problem.
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.1'

You may be missing some Proguard rules.
I had the same problem in release build and solved it by adding the following rules:
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
from https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro

Use both Core and Android dependency
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6'

If you're facing this problem with coroutines version 1.3.8, add this rule in your proguard-rules.pro:
-keep class kotlinx.coroutines.android.AndroidDispatcherFactory {*;}

./gradlew assembleDebug --rerun-tasks
fixes it if the above answers don't work for you (because you already had the required dependencies and you are using R8 which does not need the proguard rules).

"core" is transitive dependency of "android" version in current version of "kotlinx-coroutines" so only use "android"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'

Just an additional hint if anyone tries the solutions from above and they didn't work.
For me, --no-build-cache didn't help. Instead, a rule in proguard-rules.txt did the job:
-keep class kotlinx.coroutines.android.** {*;}
My setup is kotlinx-coroutines-android:1.3.9, no kotlinx-coroutines-core (I removed it as it turned out to be unnecessary), Kotlin 1.3.72, and Gradle 3.2.1.

I have fixed by doing both version same
'kotlinx-coroutines-android' and ensure it has the same version as 'kotlinx-coroutines-core'
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'//same as coroutines-android
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5"//same as coroutines-core

Well, in my case keeping minifyEnabled true was causing the issue. but to achieve the obfuscation it was mandatory for me to keep the minifyEnabled true on the release build. So I did the following changes.
//keep only
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
in your proguard-rules.pro add
-keep class kotlinx.coroutines.android.AndroidDispatcherFactory {*;}
I also required to add the model classes used for API call via retrofit in the proguard-rules.pro
-keep class com.example.test.login.data.model.** { *; }
-keepclassmembers class com.example.test.login.data.model.** { *; }

Related

Kotlin 1.6.0 (There are no problems in 1.5.21) + Proguard + Gson (Registering an InstanceCreator with Gson...)

I have enabled Proguard and configured the rules
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
For GSON I used these rules
added my models to exceptions (-keep class my.package.model.** { *; })
Also used other rules for various libraries
I have this error -> Registering an InstanceCreator with Gson for this type may fix this problem.
the error occurred when switching to kotlin 1.6.0 and 1.6.10.
There is no error on version Kotlin 1.5.21!
Error (I have a bug only on Kotlin 1.6.0/1.6.10. There is no error on kotlin 1.5.21) --->
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.project.main, PID: 2943
java.lang.RuntimeException: Unable to invoke no-args constructor for class com.project.main.domain.entity.MyEntityClass. Registering an InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.c$e.a(SourceFile:228)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(SourceFile:212)
at com.google.gson.Gson.h(SourceFile:963)
at com.google.gson.Gson.j(SourceFile:928)
at com.google.gson.Gson.l(SourceFile:877)
at com.project.main.data.cache.converter.MyEntityClassConverter.toMyEntityClass(SourceFile:14)
at com.project.main.data.cache.dao.MyProjectDao_Impl$21.call(SourceFile:947)
at com.project.main.data.cache.dao.MyProjectDao_Impl$21.call(SourceFile:889)
at k1.c$a$a$a$a.invokeSuspend(SourceFile:128)
at uh.a.resumeWith(SourceFile:33)
at uk.z0.run(SourceFile:106)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.UnsupportedOperationException: Abstract class can't be instantiated! Class name: com.project.main.domain.entity.MyEntityClass
at com.google.gson.internal.l.a(SourceFile:120)
at com.google.gson.internal.l$a.c(SourceFile:49)
at com.google.gson.internal.c$e.a(SourceFile:225)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(SourceFile:212) 
at com.google.gson.Gson.h(SourceFile:963) 
at com.google.gson.Gson.j(SourceFile:928) 
at com.google.gson.Gson.l(SourceFile:877) 
at com.project.main.data.cache.converter.MyEntityClassConverter.toMyEntityClass(SourceFile:14) 
at com.project.main.data.cache.dao.MyProjectDao_Impl$21.call(SourceFile:947) 
at com.project.main.data.cache.dao.MyProjectDao_Impl$21.call(SourceFile:889) 
at k1.c$a$a$a$a.invokeSuspend(SourceFile:128) 
at uh.a.resumeWith(SourceFile:33) 
at uk.z0.run(SourceFile:106) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:923) 
I have rules for this error.
-keep class com.project.main.domain.entity.MyEntityClass { ; }
but I'm adding the whole package
-keep class com.project.main.domain.entity.* { *; }
I also have all the other rules for GSON -> rules
#TypeConverter
fun toMyEntityClass(value: String): MyEntityClass =
gson.fromJson(value, object : TypeToken<MyEntityClass>() {}.type) //Error
I also tried to prescribe just one rule. The rule helps to run the project on 1.5.21 and works. But it doesn't work on 1.6.0 - 1.6.10. I don't want to create an Instance Creator. I have too many models and I will waste a lot of time.
-keep class ** { *; }
For any classes that interact with GSON you have to keep as follow :
-keep class "MODEL CLASSES"
for your issue you can do like :
-keep class com.project.main.domain.entity.** { *; }
It will keep all classes under the entity package.
The problem was solved by itself, after updating the libraries
gson 2.9.0
and kotlin 2.6.21
I didn't do anything, just updated to these versions
I haven't checked 1.6.0 and 1.6.10 works in tandem with gson 2.9.0 but gson didn't work with the previous release version
As a result, I upgraded Kotlin from 1.5.21 -> 1.6.21

#Keep annotation and keep rules are not working for interfaces nested inside classes or other interfaces by enabling Android R8 obfuscation

I am using Android R8 obfuscation in my Android library.
After including the AAR file in the application module of the library's client project, I am getting compile time errors for interfaces that are declared inside the class or another interface.
e.g. one of the public interfaces is MyPublicInterface:
interface InterfaceA {
fun a()
}
interface InterfaceB {
fun b()
}
class ClassA {
interface NestedInterfaceOfA {
fun nia()
}
}
interface MyPublicInterface : InterfaceA, InterfaceB, ClassA.NestedInterfaceOfA
The interface MyPublicInterface is used by the application module.
I am getting the below errors while compiling the application module:
"Cannot access ClassA$NestedInterfaceOfA which is a supertype of MyPublicInterface. Please make sure you have the required dependencies in the classpath."
"unresolved supertypes ClassA$NestedInterfaceOfA"
I tried all the below rules:
-keepclasseswithmembers public interface * {
*;
}
-keepclasseswithmembernames public interface * {
*;
}
-keep public interface *$* {
*;
}
-keepclasseswithmembers public interface *$* {
*;
}
-keepclasseswithmembernames public interface *$* {
*;
}
-keepattributes InnerClasses, Signature
I tried by explicitly adding #Keep annotation in code and by explicitly adding the keep rule for a particular interface as well. But it didn't work.
Note: The entire code of the library is in Kotlin.
The above specified issue is resolved now.
I used below solution for it:
Android studio version: 4.1.x
Android tools version:
classpath 'com.android.tools.build:gradle:4.1.1' (Issue was occurring with version 4.0.2)
Gradle version: 6.5.1 (Issue was occurring with version 6.3)

Cannot serialize Kotlin type with Moshi AND R8

i have this strange problem. When using minify/obfuscation with R8 i have the following error
java.lang.IllegalArgumentException: Cannot serialize Kotlin type <omitted>auth.model.ErrorResponse. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact.
With no minify/obfuscation everything it's ok. I'm using
val moshi = Moshi.Builder()
.add(BigDecimalAdapter)
.add(KotlinJsonAdapterFactory())
.build()
as readme from moshi, stated. Also in gradle i'm using
implementation("com.squareup.moshi:moshi-kotlin:1.9.3")
and added rules
-keep class com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
-keep class <omitted>auth.model.ErrorResponse
but still have the same exception. what am i missing ?
Thanks
updated
here's my BigDecimalAdapter
object BigDecimalAdapter {
#FromJson
fun fromJson(string: String) = BigDecimal(string)
#ToJson
fun toJson(value: BigDecimal) = value.toString()
}
try adding to your proguard:
-keepclassmembers class * {
#com.squareup.moshi.FromJson <methods>;
#com.squareup.moshi.ToJson <methods>;
}

Using Kotlin reflection sealedSubClasses property in Android release build

When I am trying to use the sealedSubClasses attribute of a reified class in Kotlin, it only works in my debug and not in my release build. I guess this is a problem with ProGuard, but I don't know how to fix this. I already tried keeping all classes in the module where the sealed class is, but I am having no luck with this. The sealedSubClasses property always returns an empty list.
Found two ways to fix this issue:
Add rule to your proguard-rules.pro file:
-keep class com.example.ClassName { *; }
-keep class com.example.ClassName$* { *; }
Use #Keep annotation:
#Keep
sealed class ClassName{
#Keep
object A : ClassName()
#Keep
object B : ClassName()
}
This one didn't work for me:
-keep class kotlin.Metadata { *; }
Also there is a bug https://issuetracker.google.com/issues/169264693 that could be the part of your problem.
You can try
-keep class kotlin.Metadata { *; }
to get missing attributes from your class
Add an additional rule to your proguard file:
-keepnames class com.fully.qualified.ClassName* {
*;
}
Notice the asterisk character.

Realm Kotlin not in schema

I try to use Realm.io to store data in android i have RealmClass
#RealmClass
public open class Alarm : RealmObject() {
#Required
public open var hourOfDay: Int? = null
#Required
public open var minute: Int? = null
#Required
public open var days: BooleanArray? = null
public open var name: String? = null
}
and in onCreate i try to add some test data
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mRealm = Realm.getInstance(activity);
mRealm.beginTransaction()
var a = mRealm.createObject(Alarm::class.java)
a.hourOfDay = 12
a.minute = 1;
a.days = booleanArrayOf(true, true, true, true, true, false, false);
a.name = "Test${System.currentTimeMillis()}"
mRealm.commitTransaction()
}
but i get exception.
> java.lang.IllegalArgumentException: Alarm is not part of the schema for this Realm
at var a = mRealm.createObject(Alarm::class.java)
i have set realm rules
-keep class io.realm.annotations.RealmModule
-keep #io.realm.annotations.RealmModule class *
-keep class io.realm.internal.Keep
-keep #io.realm.internal.Keep class *
-dontwarn javax.**
-dontwarn io.realm.**
in > proguard-rules.pro
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
realmFlavor {
proguardFile 'proguard-rules.pro'
}
}
but this did not bring solution
CONCLUSION
so far its looks like we have to write models in Java, Realm and any ORM libraries Kotlin examples posted on GitHub have models written in pure Java
"java.lang.NoClassDefFoundError: io/realm/annotations/RealmClass"
If you run into the error above, You'll most likely have to add something like this to your build.gradle. The bottom two lines for kapt are key.
//Realm
compile 'io.realm:realm-android:0.87.1'
kapt "io.realm:realm-annotations:0.87.1"
kapt "io.realm:realm-annotations-processor:0.87.1"
Per the comment at the bottom of this issue: https://github.com/realm/realm-java/issues/509
For Kotlin to work with Realm's annotation processor you need the following setup in your build.gradle
compile "io.realm:realm-android-library:0.86.0#aar"
compile "io.realm:realm-annotations:0.86.0"
kapt "io.realm:realm-annotations-processor:0.86.0"
For me, I added #RealmClass to all models and fixed despite that it is not required.
I think it forces to run Realm processor correctly by using annotator.
To check RealmObject models are processed or not, your Gradle console output (you can open it in Android Studio at the right bottom toggle panel) has to show Red-colored model processing log as below.
:app:compileDebugJavaWithJavac
Full recompilation is required because at least one of the classes of removed jar 'kotlin-stdlib-1.0.0.jar' requires it. Analysis took 1.572 secs.
Note: Processing class ModelSomething
Note: Processing class ModelAnotherThing
Note: Creating DefaultRealmModule
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:app:transformClassesWithRealmTransformerForDebug
:app:transformClassesWithInstantRunVerifierForDebug
:app:transformClassesWithJavaResourcesVerifierForDebug
The Note: lines are red colors and you can see Processing class ModelSomething message.
All of your model should be listed as this message.
This issue is filed as a suspicious bug: https://github.com/realm/realm-java/issues/2822

Categories

Resources