观察通过改造更改的实时数据不会在更改时触发

时间:2019-10-03 12:20:00

标签: java android mvvm retrofit

首先,我检查了两个问题thisthis,但都没有解决我的问题。

其次,我将详细解释所有内容,请原谅我的冗长帖子。

因此,我第一次尝试在android中实现MVVM,并遵循了tuto1tuto2中的一些指导和步骤,正如我在问题中所明确指出的那样,观察者没有触发,我不明白为什么。 这是我的代码架构:

Authentication.java:

@FormUrlEncoded
@POST("service/api/login/")
Call<LoginResponse> login(@Field("username") String username,
                          @Field("password") String password);

为处理错误,我在tuto1之后实现了通用请求处理程序:

GenericRequestHandler.java:

public abstract class GenericRequestHandler<T extends Response> {

private static final String TAG = GenericRequestHandler.class.getName();

abstract protected Call<T> makeRequest();

public final MutableLiveData<DataWrapper<T>> doRequest() {
    final MutableLiveData<DataWrapper<T>> liveData = new MutableLiveData<>();
    final DataWrapper<T> dataWrapper = new DataWrapper<>();
    makeRequest().enqueue(new ApiCallback<T>() {
        @Override
        protected void handleResponseData(T data) {
            Log.e(TAG, "handleResponseData: being handled");
            dataWrapper.setData(data);
            liveData.postValue(dataWrapper);
        }

        @Override
        protected void handleError(String message) {
            Log.e(TAG, "handleError: error handled");
            dataWrapper.setErrorMessage(message);
            liveData.postValue(dataWrapper);
        }

        @Override
        protected void handleException(Exception t) {
            Log.e(TAG, "handleException: exception handled");
            dataWrapper.setApiException(t);
            liveData.postValue(dataWrapper);
        }

        @Override
        protected void handleHttpCodes(int code) {
            Log.e(TAG, "handleHttpCodes: code handled");
            dataWrapper.setCode(code);
            liveData.postValue(dataWrapper);
        }
    });
    return liveData;
}

}

然后我根据它制定了一个规范,以处理登录:

SignInRequestHandler.java:

public class SignInRequestHandler extends GenericRequestHandler {

private Authentication service = RestClient.getInstance().create(Authentication.class);
private String username, password;

public SignInRequestHandler(String username, String password) {
    this.username = username;
    this.password = password;
}

@Override
protected Call<LoginResponse> makeRequest() {
    return service.login(username, password);
}

public MutableLiveData<DataWrapper<LoginResponse>> onAuthRequest() {
    return doRequest();
}
}

出于验证目的,我在模型中调用登录请求处理程序,如下所示:

public MutableLiveData<DataWrapper<LoginResponse>> login() {
    SignInRequestHandler handler = new SignInRequestHandler(this.userName, this.pass);
    return handler.onAuthRequest();
}

这是viewModel:

LoginVModel.java:

public class LoginVModel extends ViewModel {

private static final String TAG = LoginVModel.class.getName();

private Driver driver; //this is my model
public MutableLiveData<String> username;
public MutableLiveData<String> password;
public MutableLiveData<DataWrapper<LoginResponse>> loginLiveData;

public LoginVModel() {
    driver = new Driver();
    username = new MutableLiveData<>();
    loginLiveData = new MutableLiveData<>();
    password = new MutableLiveData<>();
}

public void onLogin(View view) {
    Log.e(TAG, "onLogin: " + username.getValue() + " " + password.getValue() );
    driver.setUserName(username.getValue()); 
    driver.setPass(password.getValue());
    loginLiveData = driver.login();
}
}

为了更好地处理错误,我从tuto1实现了api观察器:

ApiObserver.java:

public class ApiObserver<T> implements Observer<DataWrapper<T>> {
private ChangeListener<T> changeListener;

public ApiObserver(ChangeListener<T> changeListener) {
    this.changeListener = changeListener;
}

@Override
public void onChanged(@Nullable DataWrapper<T> tDataWrapper) {
    if (tDataWrapper != null)
        if (tDataWrapper.getApiException() != null)
            changeListener.onFail(tDataWrapper.getApiException());
        else if (tDataWrapper.getCode() != 0)
            changeListener.handleCodes(tDataWrapper.getCode());
        else if (!tDataWrapper.getErrorMessage().equals(""))
            changeListener.onErrorMessage(tDataWrapper.getErrorMessage());
        else
            changeListener.onSuccess(tDataWrapper.getData());
}


public interface ChangeListener<T> {
    void onSuccess(T dataWrapper);

    void onFail(Exception exception);

    void handleCodes(int code);

    void onErrorMessage(String message);
}
}

在活动中,我对电子邮件和密码使用双向绑定,并且登录按钮从viewModel触发onLogin:

SignInActivity.java:

public class SignInActivity extends AppCompatActivity {

private static final String TAG = SignInActivity.class.getName();
private ActivitySignInBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_sign_in);
    Utilities.setHtmlText(R.string.forget_password, binding.forgetPassword);

    LoginVModel login = ViewModelProviders.of(this).get(LoginVModel.class);
    binding.setLoginModel(login);
    binding.setLifecycleOwner(this);

    login.loginLiveData.observe(this, new ApiObserver<>(listener));
}

private ApiObserver.ChangeListener<LoginResponse> listener = new ApiObserver.ChangeListener<LoginResponse>() {
    @Override
    public void onSuccess(LoginResponse dataWrapper) {
        startActivity(new Intent(getApplicationContext(), MainActivity.class));
        finish();
    }

    @Override
    public void onFail(Exception exception) {
        exception.printStackTrace();
        CheckInternetConnection.requestFail();
    }

    @Override
    public void handleCodes(int code) {
        // TODO: 10/2/2019 implement code handling here
        Log.e(TAG, "handleCodes: " + code);
    }

    @Override
    public void onErrorMessage(String message) {
        Log.e(TAG, "onErrorMessage: i'm here");
        ToastMaker.getInstance().showErrorToast(message);
    }
};

}

所以我正尝试使用错误的数据登录,因此会触发错误消息,这是控制台日志:

E/driver.itgds.khadametdz.viewmodel.viewmodel.LoginVModel: onLogin: test test
E/driver.itgds.khadametdz.api.requesthandler.GenericRequestHandler: handleError: error handled

所以不显示吐司,上面的日志也没有,所以请问我做错了什么?

PS:对于通用处理程序中的实时数据,我同时尝试了.setValue()和.PostValue(),但它们均未获得理想的结果。

编辑: 我用这种方法尝试了viewmodel,但是它什么也没改变。

 public void onLogin(View view) {
    Log.e(TAG, "onLogin: " + username.getValue() + " " + password.getValue() );
    driver.setUserName(username.getValue());
    driver.setPass(password.getValue());
//        loginLiveData = driver.login();
    loginLiveData.postValue(driver.login().getValue());
}

1 个答案:

答案 0 :(得分:0)

创建ViewModel时,您将像这样创建LiveData

loginLiveData = new MutableLiveData<>();

因此,在活动中

login.loginLiveData.observe(this, new ApiObserver<>(listener));

您收听此新的MutableLiveData <>();。但是在用此替换LiveData的引用之后

loginLiveData = driver.login();

因此,您没有观察到相同的MutableLiveData。我认为问题出在这里。