Search code examples
androidkotlinnullpointerexceptionviewmodeldagger-hilt

I am getting java.lang.NullPointerException which I think should not be the case. Can anyone help me with it?


I have an interface which is passed to a viewmodel from an activity where its implemented. Then in the viewmodel, it calls the implemented interface method. Inside this method, all I want to do is display a Toast but I am getting null error trying to access the activity context. I do not understand why. Just to be clear, inside all otber overridden method such as onCreate, onStop, OnResume, etc. If I display the toast, it works fine. Its only when inside this interface method, activity context seems to be null. I have absolutely no idea.

This is the hilt module

@Module
@InstallIn(SingletonComponent::class)
abstract class ToastListenerModule {
    @Binds
    abstract fun bindToastMessageListener(activity: SplashActivity): ToastMessageListener
}

My SplashActivity.kt

@AndroidEntryPoint
class SplashActivity @Inject constructor() : AppCompatActivity(), ToastMessageListener {
    private lateinit var binding: ActivitySplashBinding

    @Inject
    lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        installSplashScreen()
        binding = ActivitySplashBinding.inflate(layoutInflater)

        setContentView(binding.root)
    }

    override fun showToast(message: String) {
        //THIS IS WHERE THE PROBLEM IS WITH THE CONTEXT
        Toast.makeText(this, "MESSAGE", Toast.LENGTH_SHORT)
    }
}

Below I have my ViewModel:

@HiltViewModel
class AuthenticationViewModel @Inject constructor(
    private val auth: FirebaseAuth,
    private val toastListner: ToastMessageListener,
) : ViewModel() {
    val emailText = ObservableField<String>("")
    val passwordText = ObservableField<String>("")
    val nameText = ObservableField<String>("")

    fun onSubmitClicked(isLogin: Boolean) {
        if (isLogin) {
            val email = emailText.get()
            val password = passwordText.get()

            if (email.isNullOrEmpty() || password.isNullOrEmpty()) {
                println("Email or password is empty")
                return
            }
            auth.signInWithEmailAndPassword(emailText.get() ?: "", passwordText.get() ?: "")
                .addOnCompleteListener() { task ->
                    if (task.isSuccessful) {
                        toastListner.showToast("Login Successful")
                    } else {
                        val exception = task.exception
                        //THIS IS WHERE I CALL showToast
                        //AND YES IT IS GETTING CALLED AND EVERYTHING
                        toastListner.showToast("Login Failed: ${exception?.message}")
                    }
                }
        } else {
            println("SIGN Up BUTTON CLICKED ${emailText.get()} ${passwordText.get()}")
        }
    }

    fun isValidInput(): Boolean {
        val inputEm = emailText.get() ?: return false
        val inputPass = passwordText.get() ?: return false

        return inputEm.isNotEmpty() && inputPass.isNotEmpty()
    }
}

My ERROR

 FATAL EXCEPTION: main                                                                                
                                                                                                            Process: com.example.findroomies, PID: 27661
                                                                                                        java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object referenceat android.content.ContextWrapper.getPackageName(ContextWrapper.java:173)
                                                                                                            at android.widget.Toast.<init>(Toast.java:174)
                                                                                                            at android.widget.Toast.makeText(Toast.java:498)
                                                                                                            at android.widget.Toast.makeText(Toast.java:487)
                                                                                                            at com.example.findroomies.ui.activities.SplashActivity.showToast(SplashActivity.kt:52)
                                                                                                            at com.example.findroomies.ui.viewmodels.AuthenticationViewModel.onSubmitClicked$lambda$0(AuthenticationViewModel.kt:35)
                                                                                                            at com.example.findroomies.ui.viewmodels.AuthenticationViewModel.$r8$lambda$b1GN3_M-m0Ij9SZCrkTUOa2z6PY(Unknown Source:0)
                                                                                                            at com.example.findroomies.ui.viewmodels.AuthenticationViewModel$$ExternalSyntheticLambda0.onComplete(Unknown Source:2)
                                                                                                            at com.google.android.gms.tasks.zzi.run(com.google.android.gms:play-services-tasks@@18.0.2:1)
                                                                                                            at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                            at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                            at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                            at android.os.Looper.loop(Looper.java:288)
                                                                                                            at android.app.ActivityThread.main(ActivityThread.java:7872)
                                                                                                            at java.lang.reflect.Method.invoke(Native Method)
                                                                                                            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

Solution

  • First of all u said that you are having problem in context. So you can solve it by injecting application context in the viewModel class and then pass the context to the function as an argument.

    Here is an example for reference. But still to know the exact reason of nullPointerExeption. I think you should share the error logs.

    @HiltViewModel
    class AuthenticationViewModel @Inject constructor(
        private val auth: FirebaseAuth,
        private val toastListner: ToastMessageListener,
        @ApplicationContext private val context: Context
    ) : ViewModel() {
    

    Then in your activity you can add context as an argument.

     override fun showToast(context : Context, message: String) {
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
        }
    

    Same way u can should pass that context in the viewModel class

     toastListner.showToast(context,"Login Failed: ${exception?.message}")