RETROFIT 2与UI线程回调问题



我正在制作一个简单的材料设计登录屏幕,该屏幕显示了改造正在获取数据时的进度对话框。

我最近升级为Raturofit 2,所以我是新手。

我的登录代码:

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.
    }

和登录方面的其他功能:

@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));
 }

我的网络列表(NWL)类的代码:

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线程上运行(关于loginbutton)-java.lang.runtimeException:无法创建尚未称为looper.prepare()(关于toastCreator)

的Handler内部线程。

我了解导致问题的原因(Raterofit 2的异步线程正在执行呼叫),何时应将呼叫传播到UI线程。我的问题是,处理此问题的最佳解决方案是什么?当然,我可以将一些代码与CountDownLatch一起入侵,并将整个异步调用作为强制同步,但这并不是我要寻找的。我应该使用处理程序吗?如果是这样,实施此功能的最佳方法是什么?

所有代码可用:https://github.com/mathieudevos/pinkiponki-app

期待答案!

好吧,因为没有人正确回答这个问题,所以它去了!

使用处理程序和向其发布消息似乎可以解决问题。

在ongreate方法中:

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();
            }
        }
    };

和我的网络循环类:

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播放。这应该是正确的答案。

改造onResponse在UI线程上工作,因此您的thread.sleep()将为您创建问题。

 Thread.sleep(2000); //This line must not be on UI thread.

如果您需要一些延迟,则可以轻松使用处理程序。

最新更新