首先,我检查了两个问题this和this,但都没有解决我的问题。
其次,我将详细解释所有内容,请原谅我的冗长帖子。
因此,我第一次尝试在android中实现MVVM,并遵循了tuto1和tuto2中的一些指导和步骤,正如我在问题中所明确指出的那样,观察者没有触发,我不明白为什么。 这是我的代码架构:
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());
}
答案 0 :(得分:0)
创建ViewModel时,您将像这样创建LiveData
loginLiveData = new MutableLiveData<>();
因此,在活动中
login.loginLiveData.observe(this, new ApiObserver<>(listener));
您收听此新的MutableLiveData <>();。但是在用此替换LiveData的引用之后
loginLiveData = driver.login();
因此,您没有观察到相同的MutableLiveData。我认为问题出在这里。