2

I am using MVVM. I want to implement Firebase Auth in app. But to implement it I need an activity context in my repo class. How can I get it from ViewModel or is there any simple method available?

Here is the firebase code I need to implement:

 PhoneAuthProvider.getInstance().verifyPhoneNumber("+91"+phone,        // Phone number to verify
            60,                 // Timeout duration
            TimeUnit.SECONDS,   // Unit of timeout
            (Activity) context,               // Activity (for callback binding)
            new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                @Override
                public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) 
               {
                    signInWithPhoneAuthCredential((Activity)context,phoneAuthCredential);
                }

                @Override
                public void onVerificationFailed(@NonNull FirebaseException e) {
                    setLoginFailed(e);

                }

                @Override
                public void onCodeSent(@NonNull String s, @NonNull 
                PhoneAuthProvider.ForceResendingToken forceResendingToken) {
                    super.onCodeSent(s, forceResendingToken);
                    loginResponse.setOnProgress(false);
                    loginResponse.setStatus(true);
                    loginResponse.setCodeVerified(false);
                    loginResponseLiveData.setValue(loginResponse);
                    verificationId =s;

                }
            });
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
sum20156
  • 646
  • 1
  • 7
  • 19

3 Answers3

1

In general, ViewModel objects are not supposed to reference anything that has to do with the Android platform APIs, especially Activity objects. You would not want a ViewModel to retain (and leak) an Activity across orientation changes. Retaining Activity objects in a ViewModel is a huge anti-pattern that should be avoided.

Instead, you should use a different version of that Firebase API. Choose one of the alternatives that do not take an Activity, according to the API documentation. Once the API is complete, you can bubble a callback up to the hosting activity to start any other activities.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • yes, I was also thinking that I am violating the law of MVVM...i didn't find an alternative inAPI doc.. so I should handle it in activity!!? – sum20156 Sep 06 '20 at 07:44
  • In my answer, I linked to API documentation that gives you multiple alternatives of `verifyPhoneNumber` that do not use an Activity. I'm recommending that you use one of those altenratives. – Doug Stevenson Sep 06 '20 at 15:52
1
  • If you work not related to any UI then you can use AndroidViewModel instead of ViewModel

  • In AndroidViewModel there in one important default parameter ApplicationContext

  • Or if you want any specific activity References then use LiveData<YourActivity> and set class reference when you initialize ViewModel in class

Peter Haddad
  • 78,874
  • 25
  • 140
  • 134
Vikas
  • 432
  • 4
  • 17
  • i can't use android view model as I need activity context for firebase.. can you briefly explain LiveData thing – sum20156 Sep 06 '20 at 07:41
  • OK in you View Model Class Add This first var activityReference: MutableLiveData? = MutableLiveData() and in your Activity Class add This line viewModel.activityReference?.value = this@SignUpActivity //(your class reference) then in your view model you have reference of your current activity – Vikas Sep 06 '20 at 07:46
  • What is `AndroidViewModel`? How to use that. – IgorGanapolsky Apr 22 '21 at 01:39
1

First of all, according to official view model guidelines:

Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity content

So in accordance with your MVVM architecture, don't pass your activity context to a ViewModel.

I guess in that method you want to implement you do not specifically need an activity context. You could also use the context of your application.

Follow these 3 steps of this answer to get access your Application context statically:

  1. create Application class which references the context on create
    public class MyApplication extends Application {
    
        private static Context context;
    
        public void onCreate() {
            super.onCreate();
            MyApplication.context = getApplicationContext();
        }
    
        public static Context getAppContext() {
            return MyApplication.context;
        }
    }
    
  2. Declare your application class in your Manifest
    <application android:name="com.xyz.MyApplication">
    
    </application>
    
  3. Access this context statically inside your repository class
    MyApplication.getAppContext()
    

There is also the possibility to access the application context via AndroidViewModel class. But I guess you usually do not want to initialize your repository from your ViewModel.

cewaphi
  • 410
  • 2
  • 7
  • storing context like this may result in memory leak..also I have already tried using AndroidViewModel but as you know it provides application context, not activity context... so firebase giving exception..and ask to cast the context from application to activity – sum20156 Sep 06 '20 at 07:39
  • Then what about Doug Stevenson's suggestion, does the API also provide such a method without requiring the activity context? It would probably be the best solution if you do not need to worry about messing with the context at all – cewaphi Sep 06 '20 at 07:44