2

i am working on a project in which i am trying to implement Android architecture components with data binding. I have an activity, viewmodel and repository and i am crating a login page right now. I have to make two repository functions to make the user login, the first function will return the uid and by passing this uid, the second function will return the details. once everything is done then only i want to redirect the user to inside page. I have tried with Transformations.switchMap, which is not working. Please help...

public class LoginViewModel extends ViewModel {
private final VendorRepository vendorRepository;
private final ResourceProvider resourceProvider;
public MutableLiveData<String> error = new MutableLiveData<>();
public MutableLiveData<Boolean> loading = new MutableLiveData<>();
private MutableLiveData<Resource<String>> vendorId = new MutableLiveData<>();
public LiveData<Resource<Vendor>> vendor;

public LoginViewModel() {
    this.vendorRepository = VendorRepository.getInstance();
    this.resourceProvider = ResourceProvider.getInstance();
    /*vendor = Transformations.switchMap(vendorId, new Function<Resource<String>, LiveData<Resource<Vendor>>>() {
        @Override
        public LiveData<Resource<Vendor>> apply(Resource<String> input) {
            if (input!=null&&input.status.equals(Status.SUCCESS))
            return vendorRepository.getVendor(vendorId.getValue().data);
            else return null;
        }
    });*/
}

/**
 * called when a user clicks on the login button
 * if the inputs are valid, will call the login function
 *
 * @param email    entered email
 * @param password entered password
 */
public void onClickLogin(String email, String password) {
    //loading.setValue(true);
    if (validInputs(email, password)) {
        vendorId = vendorRepository.login(
                email, password
        );
    } else loading.setValue(false);
}}

This is my viewmodel

public class VendorRepository {
private static VendorRepository INSTANCE;
private FirebaseAuth firebaseAuth;
private FirebaseFirestore firebaseFirestore;

public static VendorRepository getInstance() {
    if (INSTANCE == null)
        INSTANCE = new VendorRepository();
    return INSTANCE;
}

private VendorRepository() {
    this.firebaseAuth = FirebaseAuth.getInstance();
    this.firebaseFirestore = FirebaseFirestore.getInstance();
}

public MutableLiveData<Resource<String>> login(String email, String password) {
    final MutableLiveData<Resource<String>> data = new MutableLiveData<>();
    data.setValue(Resource.<String>loading(null));
    firebaseAuth
            .signInWithEmailAndPassword(email, password)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        data.postValue(Resource.success(task.getResult().getUser().getUid()));
                    } else {
                        data.postValue(Resource.<String>error(task.getException().getMessage(), null));
                    }
                }
            });
    return data;
}

public LiveData<Resource<Vendor>> getVendor(String id) {
    final MutableLiveData<Resource<Vendor>> data = new MutableLiveData<>();
    data.postValue(Resource.<Vendor>loading(null));
    firebaseFirestore
            .collection(DB_VENDOR)
            .document(id)
            .get()
            .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                @Override
                public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                    if (task.isSuccessful()) {
                        Vendor vendor = task.getResult().toObject(Vendor.class);
                        data.postValue(Resource.success(vendor));
                    } else {
                        data.postValue(Resource.<Vendor>error(task.getException().getMessage(), null));
                    }
                }
            });
    return data;
} }

This is my repo

Vipin KT
  • 31
  • 2
  • What is the error that you get? Is there a problem in the execution of `getVendor` or `login` ? Can you paste the stacktrace in the question? – Rajan Prasad Jul 11 '18 at 07:34
  • all my repository functions are working fine, but my vendor id live data is not triggering even if i observe that in my activity. I want to observe the vendorId in viewmodel and based on that i want to call getVendor(id) – Vipin KT Jul 11 '18 at 07:39
  • Check for nullability of vendorId after the `vendorId = vendorRepository.login` call. Also, check the `OnCompleteListener` interface to see if you are missing any of the other callback methods. Finally, put a log (something like `Log.d("myclass", "inside method...");` in all the callback methods that you implement in `OnCompleteListener` inside the `login` method. You can also, in another thread, keep sleeping for a few ms and after every wake, check whether `vendorId.getValue` is `null` or not. – Rajan Prasad Jul 11 '18 at 07:52
  • vendorId is not null and iam getting the id in oncomplete call back.. but my vendorId live data in viewmodel is not triggering – Vipin KT Jul 11 '18 at 07:58
  • What observer have you attached to the Livedata vendorId? I cannot see any observer attached here. Have you attached it in some other class, (probably your activity class) which you obviously have not pasted here? Or you have not attached it at all? – Rajan Prasad Jul 11 '18 at 08:04
  • can i user switchMap for observing vendorId and call getVendor() based on the changes in vendorId – Vipin KT Jul 11 '18 at 08:09
  • You can, but you don't need to. You can call the `VendorRepository.getInstance().getVendor( vendorId)` in the observer of the `vendorId` live data itself. – Rajan Prasad Jul 11 '18 at 08:13
  • I don't see that you need a live data which is a transformed output of the vendorId livedata. You can probably shoehorn the code calling the `getVendor` repo call in an instance of `Function`, but I don't see the need. – Rajan Prasad Jul 11 '18 at 08:15
  • where i will write code for that observer, i dont want to write it in activity, how to observe vendor Id in viewmodel – Vipin KT Jul 11 '18 at 08:16
  • You will sort of have to write it in the `activity`. Otherwise you will have to pass the `this` reference of the activity wherever you construct the observer. Trust me, you do not have to worry about memory leak by creating an anonymous class for the observer in the activity. The way ViewModels are designed, the observer will get detached and subsequently destroyed as soon as the activity is destroyed. You can read up about it on the Android dev guide on ViewModels and LiveData. – Rajan Prasad Jul 11 '18 at 08:18
  • can i observe a MutableLiveData in activity – Vipin KT Jul 11 '18 at 08:23
  • Yes, it is sort of built for that purpose itself. Let me write an answer to this question. – Rajan Prasad Jul 11 '18 at 08:24
  • thanks for your patience, anyway its not working for me – Vipin KT Jul 11 '18 at 08:28
  • Check the answer. – Rajan Prasad Jul 11 '18 at 08:36

1 Answers1

0

You need to add an observer of the vendorId livedata somewhere in your activity, possibly in onCreate(Bundle) after you have initialized the viewModel.

Your code will look something like this.

public final class MyActivity extends AppCompatActivity {
    ...
    LoginViewModel mViewModel;

    @Override protected final void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);
        mViewModel = ViewModelProviders.of(this)
            .get(LoginViewModel.class);

        //make vendorId public in the viewModel

        mViewModel.vendorId.observe ( this, new Observer<String> (){

            @Override public void onChanged(@Nullable final String vendorId) {
                VendorRepository.getInstance().getVendor(vendorId);
            }
        });

        //Similarly, add observer for the vendor live data
    }

}
Rajan Prasad
  • 1,582
  • 1
  • 16
  • 33