Please if you want to devote question write reason to improve.
The problem is I dont know how to implement the eventbus in presenter with Kotlin. It works fine if I implement and subscribe in activity class but when I am trying the same code in the presenter I got an exception. Might be something in Kotlin way of implementation. There must be nothing wrong with eventbus setting up because implementation in view works fine
My activity => constructor of presenter
private val mMainPresenter = MainPresenter(this, MainInteractor(), this)
My presenter
class MainPresenter(var mMainView: MainInterface?, val mMainInteractor: MainInteractor, val mContext : Context){
/**
* Checking if user have language otherwise show list of games
*/
fun checkingLanguage() {
if(mMainInteractor.getUserLanguage() == "") mMainView?.callLanguageDialog()
else EventBus.getDefault().post(LanguageEvent (mMainInteractor.getUserLanguage()))
}
fun registerSubscribers() {
if (!EventBus.getDefault().isRegistered(mContext)) {
EventBus.getDefault().register(mContext)
}
}
#Subscribe
fun inflateGamesList(event: LanguageEvent){
mMainView?.showGamesList(event.language)
} }
Exception code
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.a3802256.zzzz, PID: 13508
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.a3802256.zzzz/com.example.a3802256.zzzz.view.main.MainActivity}: org.greenrobot.eventbus.EventBusException: Subscriber class com.example.a3802256.zzzz.view.main.MainActivity and its super classes have no public methods with the #Subscribe annotation
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: org.greenrobot.eventbus.EventBusException: Subscriber class com.example.a3802256.zzzz.view.main.MainActivity and its super classes have no public methods with the #Subscribe annotation
at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:67)
at org.greenrobot.eventbus.EventBus.register(EventBus.java:140)
at com.example.a3802256.zzzz.view.main.MainPresenter.registerSubscribers(MainPresenter.kt:20)
at com.example.a3802256.zzzz.view.main.MainActivity.onCreate(MainActivity.kt:32)
at android.app.Activity.performCreate(Activity.java:6679)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
If you want to listen to events in presenter, you should register presenter, and not activity (context). So,
fun registerSubscribers() {
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this)
}
}
Related
I have this interface:
interface MyListener : Serializable {
fun onClick()
}
In my Fragment I have a lazy instance of it which I attach it to the fragment's arguments. Something like:
class MyFragment: Fragment() {
private val listener: MyListener by lazy {
object : MyListener {
override fun onClick() {
// Do something
}
}
}
fun testFun1() {
arguments = bundleOf(
"listener" to listener
)
}
fun onAcceptClick() {
val listener = arguments?.getSerializable("listener")
}
}
Everything works fine, until the moment when I press home button, or recents button and the app throughs this exception:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.me, PID: 8501
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.test.me.MyFragment$listener$2$1)
at android.os.Parcel.writeSerializable(Parcel.java:1833)
at android.os.Parcel.writeValue(Parcel.java:1780)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.os.Parcel.writeBundle(Parcel.java:997)
at androidx.fragment.app.FragmentState.writeToParcel(FragmentState.java:159)
at android.os.Parcel.writeTypedObject(Parcel.java:1634)
at android.os.Parcel.writeTypedList(Parcel.java:1513)
at android.os.Parcel.writeTypedList(Parcel.java:1470)
at androidx.fragment.app.FragmentManagerState.writeToParcel(FragmentManagerState.java:64)
at android.os.Parcel.writeParcelable(Parcel.java:1801)
at android.os.Parcel.writeValue(Parcel.java:1707)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.os.Parcel.writeBundle(Parcel.java:997)
at androidx.fragment.app.FragmentState.writeToParcel(FragmentState.java:161)
at android.os.Parcel.writeTypedObject(Parcel.java:1634)
at android.os.Parcel.writeTypedList(Parcel.java:1513)
at android.os.Parcel.writeTypedList(Parcel.java:1470)
at androidx.fragment.app.FragmentManagerState.writeToParcel(FragmentManagerState.java:64)
at android.os.Parcel.writeParcelable(Parcel.java:1801)
at android.os.Parcel.writeValue(Parcel.java:1707)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.os.Parcel.writeBundle(Parcel.java:997)
at android.os.Parcel.writeValue(Parcel.java:1698)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.os.Parcel.writeBundle(Parcel.java:997)
at android.os.Parcel.writeValue(Parcel.java:1698)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.app.IActivityTaskManager$Stub$Proxy.activityStopped(IActivityTaskManager.java:4505)
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:145)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
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.io.NotSerializableException: com.test.me.MyFragment
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
at android.os.Parcel.writeSerializable(Parcel.java:1828)
E/AndroidRuntime: ... 45 more
I know that I can solve the problem by using Parcelable instead of Serializable but I would like to understand why this is happening. Also, if I want to use Parcelable in combination with #Parcelize annotation then I will have to convert MyListener from an interface to a class.
So, what would be the solution or workaround here while keep using an interface?
I have an instrumented test that starts an application with a content provider.
The test is straightforward:
#HiltAndroidTest
#UninstallModules({...})
public class MyTest {
#Rule
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
#Test
...
}
However, the application under test includes a ContentProvider, and this provider is using Hilt to inject data:
public class MyProvider extends ContentProvider {
#EntryPoint
#InstallIn(ApplicationComponent.class)
interface MyProviderEntryPoint {
#SqliteDatabaseName String databaseName();
}
#Override
synchronized public boolean onCreate() {
Context appContext = getContext().getApplicationContext();
MyProviderEntryPoint entryPoint =
EntryPointAccessors.fromApplication(appContext, MyProviderEntryPoint.class);
mOpenHelper = new SqliteStoreOpener(getContext(), entryPoint.databaseName());
return true;
}
This causes the test to crash on startup:
java.lang.RuntimeException: Unable to get provider com.test.MyProvider: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
at android.app.ActivityThread.installProvider(ActivityThread.java:6242)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:5805)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5722)
at android.app.ActivityThread.-wrap1(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
at dagger.hilt.internal.Preconditions.checkState(Preconditions.java:83)
at dagger.hilt.android.internal.testing.TestApplicationComponentManager.generatedComponent(TestApplicationComponentManager.java:79)
at dagger.hilt.android.testing.HiltTestApplication.generatedComponent(HiltTestApplication.java:49)
at dagger.hilt.EntryPoints.get(EntryPoints.java:46)
at dagger.hilt.android.EntryPointAccessors.fromApplication(EntryPointAccessors.java:36)
at com.test.MyProvider.onCreate(EboBirthdayProvider.java:114)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1917)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1892)
at android.app.ActivityThread.installProvider(ActivityThread.java:6239)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:5805)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5722)
at android.app.ActivityThread.-wrap1(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
I suppose the problem is that the framework is trying to install the provider before Hilt even had a chance to start up and create the components. What's the proper setup to allow Hilt to run first and then construct the providers? For reference, I have a simple test runner:
public class MyRunner extends AndroidJUnitRunner {
#Override
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return super.newApplication(cl, HiltTestApplication.class.getName(), context);
}
This is very anti-climactic, but it ended up being a problem in the build.gradle file.
The annotation processor was added as
annotationProcessor 'com.google.dagger:hilt-android-compiler:2.30.1-alpha'
instead of
androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.30.1-alpha'
I know this has been asked before but my problem is strange and I couldn't find an answer.
I have a parent class where a member is declared protected
class BaseContoller<G: BaseContract.BasePresenter, F: BaseModel> {
protected var presenter: G? = null
// ...
}
In each of BaseController's descendants, I refer to presenter with no problem as it is accessible in the same package and subclasses.
One BaseController's descendant has to be extended by other classes too but I have to do one check before of performing certain actions in where presenter is referenced again
class BackupPrinterController<G: BackupPrinterContract.Presenter, F: BaseModel>: BackupController<G, F>
private fun startScan() {
if(this is PrinterAssociationController) {
PrinterConnection.onConnection = { presenter?.onDeviceConnected(it) }
// ...
}
}
}
The strange behaviour comes here, presenter is perfectly accessible only without the filter if(this is PrinterAssociationController), with that if statement, when the onConnection callback is invoked, an IllegalAccessError exception is thrown by presenter
Here is the declaration of PrinterAssociationController
class PrinterAssociationController: BackupPrinterController<PrinterAssociationContract.Presenter, PrinterAssociationModel>(),
PrinterAssociationContract.View
and here is the exception
java.lang.IllegalAccessError: Method 'package.common.base.BaseContract$BasePresenter package.common.base.BaseController.getPresenter()' is inaccessible to class 'package.project.features.shared.controllers.BackupPrinterController$startScan$1' (declaration of 'package.project.features.shared.controllers.BackupPrinterController$startScan$1' appears in /data/app/package.project-1/base.apk:classes2.dex)
at package.project.features.shared.controllers.BackupPrinterController$startScan$1.invoke(BackupPrinterController.kt:53)
at package.project.features.shared.controllers.BackupPrinterController$startScan$1.invoke(BackupPrinterController.kt:35)
at package.project.utils.print.PrinterConnection$scan$1$4.accept(PrinterConnection.kt:84)
at package.project.utils.print.PrinterConnection$scan$1$4.accept(PrinterConnection.kt:24)
at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:63)
at io.reactivex.internal.operators.observable.ObservableFilter$FilterObserver.onNext(ObservableFilter.java:52)
at io.reactivex.internal.operators.observable.ObservableDistinct$DistinctObserver.onNext(ObservableDistinct.java:85)
at io.reactivex.internal.operators.mixed.CompletableAndThenObservable$AndThenObservableObserver.onNext(CompletableAndThenObservable.java:65)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.tryEmit(ObservableFlatMap.java:265)
at io.reactivex.internal.operators.observable.ObservableFlatMap$InnerObserver.onNext(ObservableFlatMap.java:562)
at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:101)
at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:62)
at io.reactivex.internal.operators.observable.ObservableUnsubscribeOn$UnsubscribeObserver.onNext(ObservableUnsubscribeOn.java:60)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onNext(ObservableCreate.java:66)
at com.polidea.rxandroidble2.internal.serialization.FIFORunnableEntry$1.onNext(FIFORunnableEntry.java:66)
at io.reactivex.internal.operators.observable.ObservableUnsubscribeOn$UnsubscribeObserver.onNext(ObservableUnsubscribeOn.java:60)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onNext(ObservableCreate.java:66)
at com.polidea.rxandroidble2.internal.operations.ScanOperationApi21$1.onScanResult(ScanOperationApi21.java:77)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:471)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at com.osama.firecrasher.FireLooper.run(FireLooper.kt:39)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6780)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1500)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1390)
I don't understand why this is happening when I put that if statement
SO I am trying to observe some LiveData in my repository, so I can work with this data and update it's items according to my operations. But I can't figure out how to access the data. When I try to observe it, the ~Observeris asking for a LifecycleOwner. Reading about similar problems I've seen a suggestion to extendLifecycleService, but when I do I get the error sayingOnly one class may appear in a supertype list`.
How do I go around this?
This is my service:
class DetectJobIntentService : JobIntentService() {
private val TAG = "DetectJobIntentServi22"
fun enqueueWork(context: Context, work: Intent) {
enqueueWork(context, DetectJobIntentService::class.java, 12, work)
}
override fun onHandleWork(intent: Intent) {
Log.d(TAG, "onHandleWork")
val options = FirebaseVisionFaceDetectorOptions.Builder()
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ACCURATE)
.setClassificationMode(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
.setMinFaceSize(0.15f)
.build()
val detector = FirebaseVision.getInstance()
.getVisionFaceDetector(options)
val repo = PhotoRepository(application)
val allPhotos = repo.getAllPhotos()
allPhotos.observe(SomeLifeCycleOwner, Observer {
for (file in it) {
val image = FirebaseVisionImage.fromFilePath(application, Uri.parse(file.uri))
detector.detectInImage(image).addOnSuccessListener { list ->
if (list.isNotEmpty()) {
file.hasFaces = 1
repo.update(file)
} else {
file.hasFaces = 2
repo.update(file)
}
}
}
})
}
}
EDIT: Following Sina's suggestion which sounds right, I've tried implementing a query that fetches the data into a non-LiveData object my app crashes.
This is the quesry I've added in my Dow:
#Query("SELECT * FROM photos_table")
fun getAllPhotosStatic(): MutableList<Photo>
If I run at at this point it's all good.
Then in my repository I've added this:
val allPhotosStatic = photoDao.getAllPhotosStatic()
And as soon as I've done that and try to run the app it crashes, and I get this stack:
2019-11-13 23:49:37.079 20720-20720/tech.levanter.anyvision E/AndroidRuntime: FATAL EXCEPTION: main
Process: tech.levanter.anyvision, PID: 20720
java.lang.RuntimeException: Unable to start activity ComponentInfo{tech.levanter.anyvision/tech.levanter.anyvision.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class tech.levanter.anyvision.viewModels.AllPhotosViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3126)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1846)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6882)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.RuntimeException: Cannot create an instance of class tech.levanter.anyvision.viewModels.AllPhotosViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:238)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
at tech.levanter.anyvision.MainActivity.onCreate(MainActivity.kt:66)
at android.app.Activity.performCreate(Activity.java:7232)
at android.app.Activity.performCreate(Activity.java:7221)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2971)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3126)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1846)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6882)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:230)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
at tech.levanter.anyvision.MainActivity.onCreate(MainActivity.kt:66)
at android.app.Activity.performCreate(Activity.java:7232)
at android.app.Activity.performCreate(Activity.java:7221)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2971)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3126)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1846)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6882)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:267)
at androidx.room.RoomDatabase.query(RoomDatabase.java:323)
at androidx.room.util.DBUtil.query(DBUtil.java:83)
at tech.levanter.anyvision.room.PhotoDao_Impl.getAllPhotosStatic(PhotoDao_Impl.java:154)
at tech.levanter.anyvision.room.PhotoRepository.<init>(PhotoRepository.kt:37)
at tech.levanter.anyvision.viewModels.AllPhotosViewModel.<init>(AllPhotosViewModel.kt:12)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:230)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
at tech.levanter.anyvision.MainActivity.onCreate(MainActivity.kt:66)
at android.app.Activity.performCreate(Activity.java:7232)
at android.app.Activity.performCreate(Activity.java:7221)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2971)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3126)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1846)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6882)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
I thought maybe I can just get a copy of the data into a static list in my repository, but for that I'd need to observe it in the repository and I'm stuck at the same place again because I don't have a lifecycleOwner.
The idea in MVVM is to observe from view if you are doing an action that you want to be sure is finished do not wrap it in a livedata. Basically you don't need any life cycle aware component. Your query should return list of photos without any need to observe it. I mean in your dao if you don't wrap data in a livedata you don't need to observe anything and getAllPhotos return photos. You can do this kind of thing anywhrere just do everything from background, in a thread or something. For both kind of designs you can have 1 livedata wraped method in dao and 1 method without livedata for jobs that need to be done serially.
Update: put your code in a background thread:
new Thread(new Runnable() {
#Override
public void run() {
val allPhotosStatic = photoDao.getAllPhotosStatic()
for (file in it) {
val image = FirebaseVisionImage.fromFilePath(application, Uri.parse(file.uri))
detector.detectInImage(image).addOnSuccessListener { list ->
if (list.isNotEmpty()) {
file.hasFaces = 1
repo.update(file)
} else {
file.hasFaces = 2
repo.update(file)
}
}
}
}
}).start();
or:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
val allPhotosStatic = photoDao.getAllPhotosStatic()
for (file in it) {
val image = FirebaseVisionImage.fromFilePath(application, Uri.parse(file.uri))
detector.detectInImage(image).addOnSuccessListener { list ->
if (list.isNotEmpty()) {
file.hasFaces = 1
repo.update(file)
} else {
file.hasFaces = 2
repo.update(file)
}
}
}
}
});
I moved Firebase Cloud Messaging to a library, so that I can import this into any of my apps and provide push messages. So therefore I created a library and moved everything from this example to my library.
Then I compile this library in my build.gradle and use it as desired.
This works so far when I instantiate Firebase from app level:
FirebaseMessaging.getInstance().subscribeToTopic(topic)
Now, I thought of moving this down into my library:
fun initFirebaseMessaging(topic : String) : String
{
FirebaseMessaging.getInstance().subscribeToTopic(topic)
Timber.d("Push subscribeToTopic $topic")
val token = FirebaseInstanceId.getInstance().token!!
Timber.d("Push FirebaseinstanceId token $token")
sendRegistrationToServer(token)
return token
}
Since I do not hand over the app level context, I get:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.demo, PID: 8047
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.demo/com.example.MainActivity}: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.example.demo. Make sure to call FirebaseApp.initializeApp(Context) first.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.example.demo. Make sure to call FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(Unknown Source:58)
at com.google.firebase.iid.FirebaseInstanceId.getInstance(Unknown Source:0)
at com.google.firebase.messaging.FirebaseMessaging.getInstance(Unknown Source:9)
at com.example.network.fcm.exampleFirebaseInstanceIdService$Companion.initFirebaseMessaging(exampleFirebaseInstanceIdService.kt:14)
at com.example.MainActivity.onCreate(MainActivity.kt:168)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
ADDENDUM: I added that line to my init
fun initFirebaseMessaging(topic : String, context : context) : String
{
FirebaseApp.initializeApp(context)
FirebaseMessaging.getInstance().subscribeToTopic(topic)
Timber.d("Push subscribeToTopic $topic")
val token = FirebaseInstanceId.getInstance().token!!
Timber.d("Push FirebaseinstanceId token $token")
sendRegistrationToServer(token)
return token
}
leads to very same error message.
Your error
Make sure to call FirebaseApp.initializeApp(Context) first.
In your library u need create function like
public static void Init(Context context) {
FirebaseApp.initializeApp(context);
}
and call it before using firebase. Best way its add to your application
example :
... extends Application /*** code **/
onCreate () {
YourLibrary.Init(this);
}