Android: Exception using MVVM pattern architecture observe - android

I'm trying to run an app adopting MVVM pattern architecture, but I'm getting an exception that I can't solve.
I have my MainActivity.java which has an observe to the firstTime() method in the MainViewModel.java.
MainActivity.java
(...)
ViewModelProvider.Factory mViewModelFactory;
ActivityMainBinding mActivityStartBinding;
private MainViewModel mainViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivityStartBinding = getViewDataBinding();
mainViewModel.firstTime().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean aBoolean) {
if(aBoolean !=null && aBoolean){
mainViewModel.setisFirstRun();
}
}
});
MainViewModel.java
(...)
private final DataManager mDataManager; <--- repository
public LiveData<Boolean> firstTime(){
if(mDataManager.isFirstRun())
{
Timber.d("-------------- Is first read from database ");
return mDataManager.saveValues();
}
else
{
Timber.d("-------------- Is not first read from database ");
return null;
}
}
And every time I run I get the following Exception that I can't resolve.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rd.ch/com.rd.ch.ui.main.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.arch.lifecycle.LiveData.observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.arch.lifecycle.LiveData.observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer)' on a null object reference
at com.rd.ch.ui.main.MainActivity.onCreate(MainActivity.java:55)
at android.app.Activity.performCreate(Activity.java:6251)
How can I solve this?

The reason of getting NPE is that you have missed to initialize your viewModel object in activity onCreate.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
// Rest of the code
}

Related

AndroidViewModel onChanged is called after activity onCreate function?

I have a ViewModel that access a List of object of LiveData and i want to assign my variable to that list. Here is the code.
chatViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(ChatViewModel.class);
chatViewModel.getAllContactsForChat().observe(this, new Observer<List<UserContacts>>() {
#Override
public void onChanged(List<UserContacts> userContacts) {
Toast.makeText(ChatActivity.this, "inside", Toast.LENGTH_SHORT).show();
for(int i = 0; i<userContacts.size(); i++)
{
UserContacts user = userContacts.get(i);
if(user.getId() == id)
{
firstName = user.getFirstName();
lastName = user.getLastName();
friendPublicKeyString = user.getFriendPublicKey();
profile = user.getPicture();
}
}
}
});
This function is being called in onCreate of the ChatActivity. Now I noticed that the variable firstName, lastName, etc were being given null and my app kept on crashing. Upon debugging further I noticed that when ChatActivity onCreate is called this function is ignored and the main thread goes to next line and after some time it returns to this function and assign values. Now I want it to assign values on the very first run so my app can run normally. Here is the AndroidViewModel code.
public class ChatViewModel extends AndroidViewModel {
private ChatRepository chatRepository;
private LiveData<List<UserContacts>> allContactsForChat;
public ChatViewModel(#NonNull Application application)
{
super(application);
allContactsForChat = chatRepository.getAllContactsForChat();
}
public LiveData<List<UserContacts>> getAllContactsForChat()
{
return allContactsForChat;
}
}
Here is ChatRepository code
public class ChatRepository {
private ChatDao chatDao;
private LiveData<List<UserContacts>> allContactsForChat;
public ChatRepository(Application application)
{
ChatDatabase db = ChatDatabase.getInstance(application);
chatDao = db.chatDao();
allContactsForChat = chatDao.getAllContactsForChat();
}
public LiveData<List<UserContacts>> getAllContactsForChat()
{
return allContactsForChat;
}
}
Here is ChatDao code
#Dao
public interface ChatDao
{
#Query("SELECT * FROM UserContacts")
LiveData<List<UserContacts>> getAllContactsForChat();
}
Here is the crash log. I am converting the profile string to image and profile should be initialized inside onChanged. Since profile is not initialized the function is given null and this error occured.
2021-04-12 11:59:11.440 10151-10151/com.example.privatechatcopy E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.privatechatcopy, PID: 10151
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.privatechatcopy/com.example.privatechatcopy.ChatActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'byte[] java.lang.String.getBytes()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'byte[] java.lang.String.getBytes()' on a null object reference
at android.util.Base64.decode(Base64.java:120)
at com.example.privatechatcopy.NameAndImage.stringToImage(NameAndImage.java:162)
at com.example.privatechatcopy.ChatActivity.onCreate(ChatActivity.java:168)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:223) 
at android.app.ActivityThread.main(ActivityThread.java:7656) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

Protected method not accessible from subclass

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

How to put logic with eventbus in presenter for Kotlin

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)
}
}

Fail when check is start another activity:

When click button on TradersActivity start JsonViewActivity
I need to check is success started JsonViewActivity. Here Espresso test:
#RunWith(AndroidJUnit4::class)
class TradersActivityTest {
val context = InstrumentationRegistry.getInstrumentation().getContext()
val targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext()
#Rule
#JvmField
var tradersActivitytRule = ActivityTestRule(TradersActivity::class.java)
#Test
fun itemList_viewJsonButton_click_check() {
//scroll
onView(withId(R.id.tradersRecyclerView))
.perform(scrollToPosition<RecyclerView.ViewHolder>(checkItemCount));
// click
onView(withRecyclerView(R.id.tradersRecyclerView).atPositionOnView(checkItemCount, R.id.viewJsonButton))
.perform(click())
// check is start JsonViewActivity activity
intended(hasComponent(JsonViewActivity::class.java.getName()))
}
But test is fail:
Started running tests
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.test.espresso.intent.Intents.internalIntended(org.hamcrest.Matcher, androidx.test.espresso.intent.VerificationMode, java.util.List)' on a null object reference
at androidx.test.espresso.intent.Intents$2.check(Intents.java:194)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:419)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:282)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:268)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
You should use IntentsTestRule instead of ActivityTestRule.

Error Null pointer. (io.reactivex.Scheduler)' on a null object reference

This is my log cat. When i click on specific tab, my app crashes.
java.lang.NullPointerException: Attempt to invoke virtual method 'io.reactivex.Flowable io.reactivex.Flowable.observeOn(io.reactivex.Scheduler)' on a null object reference
at com.example.haji.Fragment.RecentFragment.loadRecents(RecentFragment.java:93)
at com.example.haji.Fragment.RecentFragment.onCreateView(RecentFragment.java:86)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2346)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1428)
When i call loadRecents, it give me error. Please help.
private void loadRecents() {
Disposable disposable = recentsRepository.getAllRecents().observeOn(AndroidSchedulers
.mainThread()).subscribeOn(Schedulers.io()).subscribe(new Consumer <List <Recents>>() {
#Override
public void accept(List <Recents> recents) throws Exception {
onGetAllRecentsSuccess(recents);
}
}, new Consumer <Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
Log.d("Error",throwable.getMessage());
}
});
compositeDisposable.add(disposable);
}
Your method recentsRepository.getAllRecents() return null instead of Flowable<List <Recents>>
Add this line to Biuld.gradle dependencies
dependencies {
//other code...
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
}
error - null object reference
maybe because you have not initialized
compositeDisposable = new CompositeDisposable();
Databasename databasename= Databasename.getInstance(this);
recentsRepository=RecentsRepository.getInstance(RecentsDataSource.getInstance(mainDatabase.recentsDAO()));

Categories

Resources