Why does my activity doesn't see an observed o

2020-05-07 07:21发布

问题:

I'm new to Android development and i am trying to understand Live Data with MVVM architecture. I am trying to make the main activity recognize when there is a change in an object that belong to the view-model of the activity.

I have created a simple login activity that takes the text from the username and password fields and passes them to the view-model's login function, then the function sends the data to the users repository and then it makes a POST request toa spring-server that is running on my PC. The repository login function returns a MutableLiveData object with the logged-in username if the username and password are right, and null as it's value otherwise. The repository works fine( the data coming back from the server is correct). The view-model has a field of type MutableLiveData and it is need to be updated after the login function is called. In the activity there is an observer that supposed to be notified when a changed accrued in the loggedInUser field (of type MutableLiveData) field and even though there is a change, the function onChange of the observer is never activated.

There is some code that i hope will help me explain better.

Main activity:

public class MainActivity extends AppCompatActivity {
        public EditText usernameTxt;
        public EditText passwordTxt;
        public Button loginBtn;
        public String loggedInuUser;
        LoginViewModel loginViewModel;


    @Override
    protected void onCreate(Bundle savedInstanceState) {



        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        usernameTxt = findViewById(R.id.usernameTxt);
        passwordTxt   = findViewById(R.id.passwordTxt);
        loginBtn   = findViewById(R.id.loginBtn);

        loginViewModel = ViewModelProviders.of(this ).get(LoginViewModel.class);
        loginViewModel.init();
        try {
            loginViewModel.getLoggedInUser().observe(this, new Observer<String>() {
                        @Override
                        public void onChanged(@Nullable String s) {
                            Toast toast=  Toast.makeText(MainActivity.this,"changed" , Toast.LENGTH_LONG );
                            toast.show();
                        }
                    }
            );
        }catch (Exception e){
            System.out.println("==========================================================");
            System.out.println( e.getMessage());
            System.out.println("==========================================================");
        }

    }


    protected void onLogInCliked(View v ){

//        Toast toast=  Toast.makeText(getApplicationContext(),loggedInuUser, Toast.LENGTH_LONG );
//        toast.show();
        loginViewModel.login(usernameTxt.getText().toString(),passwordTxt.getText().toString());
//        Toast toast2=  Toast.makeText(getApplicationContext(),loggedInuUser, Toast.LENGTH_LONG );
//        toast2.show();


    }
}

view-model:

public class LoginViewModel extends ViewModel {


    private UsersRepository usersRepository;
    private MutableLiveData<String> loggedInUser;

    public void init(){
        if(loggedInUser!= null){
            return;
        }

        usersRepository = UsersRepository.getInstance();
        loggedInUser=new MutableLiveData<>();
    }


    public MutableLiveData<String> getLoggedInUser(){
        return loggedInUser;
    }

    public void login(String userName , String hashedPassword) {

        loggedInUser = usersRepository.login(userName, hashedPassword);
    }
}

repository:

public class UsersRepository {

private static UsersRepository usersRepository;

public static UsersRepository getInstance(){
    if (usersRepository == null){
        usersRepository = new UsersRepository();
    }
    return usersRepository;
}

private UsersRepositoryApi usersRepositoryApi;

public UsersRepository(){
    usersRepositoryApi = RetrofitService.cteateService(UsersRepositoryApi.class);
}


public MutableLiveData<String> login(String username , String hashedPassword){
   final MutableLiveData<String> loggedInUser = new MutableLiveData<>();
    User user = new User(username,hashedPassword);

    usersRepositoryApi.login(user).enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            if (response.isSuccessful()) {
                loggedInUser.setValue(response.body());
            }
        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            loggedInUser.setValue(null);
        }
    });

    return loggedInUser;
}

}

In the mainActivity i set the observer and i expect the app to show my the Toast message but nothing happens.

i have tried to see what happens in the view-model and it is a little strange, so i printed stuff like this:

    public void login(String userName , String hashedPassword) {

    System.out.println("222======================================");
    System.out.println("==========================================");
    System.out.println("==========================================");
    System.out.println(loggedInUser.getValue());
    System.out.println("==========================================");
    System.out.println("==========================================");
    System.out.println("==========================================");
    loggedInUser = usersRepository.login(userName, hashedPassword);

    System.out.println("333======================================");
    System.out.println("==========================================");
    System.out.println("==========================================");
    System.out.println(loggedInUser.getValue());
    System.out.println("==========================================");
    System.out.println("==========================================");
    System.out.println("==========================================");

}

in first time that i run the login function the output of both 222 and 333 was null, but in the second time i run the login function the output of 222 was the loggedInUser and the output of 333 was null

in both cases the on change function of the observer was unvisited

does anyone have any idea of what i am doing wrong??

thank you ronen!

回答1:

here your problem is with repository code inside repository you are creating new object of mutable live data and observing different one.

Interface Callback{
    onSuccess(String response)
    onError(String error)
}

public void login(String username , String hashedPassword,Callback callback){
    final MutableLiveData<String> loggedInUser = new MutableLiveData<>();
    User user = new User(username,hashedPassword);

    usersRepositoryApi.login(user).enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            if (response.isSuccessful()) {
                callback.onSuccess(response.body());
            }
        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            callback.onError(null);
        }
    });
}
//login method of your viewmodel 
public void login(String userName , String hashedPassword) {
     usersRepository.login(userName, hashedPassword,new Callback(){
          void onSuccess(String responsebody){
               loggedInUser.setValue(responsebody);
          }

          void onError(String error){
               loggedInUser.setValue(responsebody);
          }
     });
}


回答2:

In your repository, try changing this part:

loggedInUser.setValue(response.body());

to postValue function. like that:

loggedInUser.postValue(response.body());


回答3:

Solution by OP.

As Neha Rathore suggested this is the solution that works for me:

in the view Model:

public void login(String userName , String hashedPassword) {
    usersRepository.login(userName, hashedPassword, new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            loggedInUser.setValue(response.body());
        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            loggedInUser.setValue(null);
        }
    });
}

and in the Repository:

public void login(String username, String hashedPassword,@Nullable final Callback<String> callback){
    final MutableLiveData<String> loggedInUser = new MutableLiveData<>();
    User user = new User(username,hashedPassword);

    usersRepositoryApi.login(user).enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {
            if (response.isSuccessful()) {
                callback.onResponse(call,response);
            }
        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            callback.onFailure(call,t);
        }
    });
}