UI 线程改造 2 回调问题
Retrofit 2 callback issues with UI thread
我正在制作一个简单的 material 设计登录屏幕,该屏幕显示一个进度对话框,同时改造正在获取数据。ui环。
我最近升级到改造 2,所以我是 qui新手。
我的 LoginActivity 代码:
private void login(){
Log.d(TAG, "Attempting login");
if(!validate()){
onLoginFailure();
return;
}
login_button.setEnabled(false);
progressDialog = new ProgressDialog(LoginActivity.this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Authenticating...");
progressDialog.show();
String username = _usernameText.getText().toString().toLowerCase(); //all usernames are lowercase only
String password = _passwordText.getText().toString();
//here we handle the NWL section.
startTime = System.currentTimeMillis();
NWL.login(username, password, this); //This runs async to UI anyway.
}
以及LoginActivity中的其他功能:
@BindView(R.id.login_button)
Button login_button;
public void loginOK() {
progressDialog.dismiss();
login_button.setEnabled(true);
toastCreator.showToastLong("Login OK");
Log.d(TAG, "Total time: " + (System.currentTimeMillis()-startTime));
}
我的 NetworkLogic (NWL) 代码class:
public void login(String username, String password, final LoginActivity loginActivity){
LoginUser loginUser = new LoginUser(username, password);
Call<Username> call = apiService.login(loginUser);
Log.d(TAG, call.toString());
call.enqueue(new Callback<Username>() {
@Override
public void onResponse(Call<Username> call, Response<Username> response) {
Log.d(TAG, "Responsecode : " + response.code());
try {
Thread.sleep(2000); //To test if the progressdialog actually shows up
} catch (InterruptedException e) {
e.printStackTrace();
}
if(response.code()==200){
loginActivity.loginOK();
} else {
loginActivity.loginFail();
}
}
@Override
public void onFailure(Call<Username> call, Throwable t) {
Log.d(TAG, "Failed: " + t.getMessage());
loginActivity.loginFail();
}
});
}
现在我不断收到如下错误:
- android.util.AndroidRuntimeException:动画师只能在 Looper 线程上 运行(关于登录按钮)
- java.lang.RuntimeException:无法在未调用 Looper.prepare() 的线程内创建处理程序(关于 toastCreator)
我明白是什么导致了这个问题(改造 2 的异步线程正在执行调用),它应该将调用传递给 ui 线程。
我的问题是,处理这个问题的最佳解决方案是什么?当然,我可以破解一些代码以及 CountdownLatch 和 运行 整个异步调用作为强制同步,但这并不是我真正想要的。
我应该使用处理程序吗?如果是这样,实现它的最佳方法是什么?
所有代码可用:https://github.com/mathieudevos/pinkiponki-app
期待答案!
Retrofit onResponse 在 UI 线程上工作,所以你的 thread.sleep() 会给你带来问题。
Thread.sleep(2000); //This line must not be on UI thread.
如果您需要一些延迟,可以轻松使用处理程序。
好的,既然没有人正确回答问题,那就开始吧!
使用处理程序并向其发送消息似乎可以解决问题。
在onCreate方法中:
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg){
switch (msg.what){
case 200:
//Got the good response
loginOK();
break;
case 401:
loginFail();
break;
default:
loginFail();
}
}
};
在我的网络逻辑中 class:
Call<Username> call = apiService.login(userObject);
call.enqueue(new Callback<Username>() {
@Override
public void onResponse(Call<Username> call, Response<Username> response) {
Log.d(TAG, "Responsecode: " + response.code());
Message msg = handler.obtainMessage(response.code());
msg.sendToTarget();
}
@Override
public void onFailure(Call<Username> call, Throwable t) {
Log.d(TAG, "Failed: " + t.getMessage());
Message msg = handler.obtainMessage(0); //0 for errors
msg.sendToTarget();
}
}
因为这是 运行 在 mainLooper 上,我可以在任何这些功能中使用我的 UI。
这应该是正确答案。
我正在制作一个简单的 material 设计登录屏幕,该屏幕显示一个进度对话框,同时改造正在获取数据。ui环。
我最近升级到改造 2,所以我是 qui新手。
我的 LoginActivity 代码:
private void login(){
Log.d(TAG, "Attempting login");
if(!validate()){
onLoginFailure();
return;
}
login_button.setEnabled(false);
progressDialog = new ProgressDialog(LoginActivity.this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Authenticating...");
progressDialog.show();
String username = _usernameText.getText().toString().toLowerCase(); //all usernames are lowercase only
String password = _passwordText.getText().toString();
//here we handle the NWL section.
startTime = System.currentTimeMillis();
NWL.login(username, password, this); //This runs async to UI anyway.
}
以及LoginActivity中的其他功能:
@BindView(R.id.login_button)
Button login_button;
public void loginOK() {
progressDialog.dismiss();
login_button.setEnabled(true);
toastCreator.showToastLong("Login OK");
Log.d(TAG, "Total time: " + (System.currentTimeMillis()-startTime));
}
我的 NetworkLogic (NWL) 代码class:
public void login(String username, String password, final LoginActivity loginActivity){
LoginUser loginUser = new LoginUser(username, password);
Call<Username> call = apiService.login(loginUser);
Log.d(TAG, call.toString());
call.enqueue(new Callback<Username>() {
@Override
public void onResponse(Call<Username> call, Response<Username> response) {
Log.d(TAG, "Responsecode : " + response.code());
try {
Thread.sleep(2000); //To test if the progressdialog actually shows up
} catch (InterruptedException e) {
e.printStackTrace();
}
if(response.code()==200){
loginActivity.loginOK();
} else {
loginActivity.loginFail();
}
}
@Override
public void onFailure(Call<Username> call, Throwable t) {
Log.d(TAG, "Failed: " + t.getMessage());
loginActivity.loginFail();
}
});
}
现在我不断收到如下错误: - android.util.AndroidRuntimeException:动画师只能在 Looper 线程上 运行(关于登录按钮) - java.lang.RuntimeException:无法在未调用 Looper.prepare() 的线程内创建处理程序(关于 toastCreator)
我明白是什么导致了这个问题(改造 2 的异步线程正在执行调用),它应该将调用传递给 ui 线程。 我的问题是,处理这个问题的最佳解决方案是什么?当然,我可以破解一些代码以及 CountdownLatch 和 运行 整个异步调用作为强制同步,但这并不是我真正想要的。 我应该使用处理程序吗?如果是这样,实现它的最佳方法是什么?
所有代码可用:https://github.com/mathieudevos/pinkiponki-app
期待答案!
Retrofit onResponse 在 UI 线程上工作,所以你的 thread.sleep() 会给你带来问题。
Thread.sleep(2000); //This line must not be on UI thread.
如果您需要一些延迟,可以轻松使用处理程序。
好的,既然没有人正确回答问题,那就开始吧!
使用处理程序并向其发送消息似乎可以解决问题。
在onCreate方法中:
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg){
switch (msg.what){
case 200:
//Got the good response
loginOK();
break;
case 401:
loginFail();
break;
default:
loginFail();
}
}
};
在我的网络逻辑中 class:
Call<Username> call = apiService.login(userObject);
call.enqueue(new Callback<Username>() {
@Override
public void onResponse(Call<Username> call, Response<Username> response) {
Log.d(TAG, "Responsecode: " + response.code());
Message msg = handler.obtainMessage(response.code());
msg.sendToTarget();
}
@Override
public void onFailure(Call<Username> call, Throwable t) {
Log.d(TAG, "Failed: " + t.getMessage());
Message msg = handler.obtainMessage(0); //0 for errors
msg.sendToTarget();
}
}
因为这是 运行 在 mainLooper 上,我可以在任何这些功能中使用我的 UI。 这应该是正确答案。