Android OkHttp 异步回调中的 SetText 导致崩溃

Android SetText in OkHttp Async callback causing crash

我有一个 android activity 执行异步 Okhttp 调用,当加载 activity 时(从 onStart 方法作为 getActiveRequests()).

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

Button btLogout;
UserLocalStore userLocalStore;
String username;
String userEmail;
String recentAppName;
String recentRequestTime;
String isExpired;
TelephonyManager telephonyManager;
OkHttpClient client;
TextView tvRecentAppName, tvRecentRequestTime, tvIsExpired;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    userLocalStore = new UserLocalStore(this);
    telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

    TextView tvUserName = (TextView) findViewById(R.id.userName);
    TextView tvUserEmail = (TextView) findViewById(R.id.userEmail);

    tvRecentAppName = (TextView) findViewById(R.id.recentAppName);
    tvRecentRequestTime = (TextView) findViewById(R.id.recentRequestTime);
    tvIsExpired = (TextView) findViewById(R.id.isExpired);

    client = new OkHttpClient();
    username = userLocalStore.getLoggedInUser().name;
    userEmail = userLocalStore.getLoggedInUser().email;

    tvUserEmail.setText(userEmail);
    tvUserName.setText(username);

    btLogout = (Button) findViewById(R.id.btLogout);
    btLogout.setOnClickListener(this);
}

@Override
protected void onStart() {
    super.onStart();

    if(authenticateUser() == true){
        getActiveRequests();
    }else{
        startActivity(new Intent(this, LoginActivity.class));
    }
}

我想做的是在使用 SetText 方法进行 Http 调用后更新 UI。这是我的调用,在 GetActiveRequests() 方法中实现。

client.newCall(request)
            .enqueue(new Callback() {

                @Override
                public void onFailure(Call call, IOException e) {
                    String hello = "failed call";
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    final String responseData = response.body().string();

                    if (responseData != null) {
                        Gson gson = new Gson();
                        JsonElement element = gson.fromJson(responseData, JsonElement.class);
                        JsonObject jsonObject = element.getAsJsonObject();
                        final AccessRequest request = gson.fromJson(jsonObject, AccessRequest.class);

                        recentAppName = request.AppName.toString();
                        recentRequestTime = request.RequestTime.toString();
                        if (request.IsExpired)
                            isExpired = "Has Expired";
                        else isExpired = "Active";

                        tvRecentAppName.setText(recentAppName);
                        tvRecentRequestTime.setText(recentRequestTime);
                        tvIsExpired.setText(isExpired);
                    }
                }
            });

我遇到的问题是,当调试器到达 SetText 行代码时,它会导致应用程序崩溃并关闭。我不知道如何解决这个问题,但我认为它与无法更新 UI 的 Okhttp Async 调用有关,因为我的 setText 方法在 [=17] 中工作正常=].

这是因为视图的更新只能在 UI 线程和 OkHttp 的 onResponse 运行 后台线程上完成。像这样在主线程上尝试 运行:

@Override
public void onResponse(Call call, Response response) throws IOException {
     final String responseData = response.body().string();

     if (responseData != null) {
        Gson gson = new Gson();
        JsonElement element = gson.fromJson(responseData, JsonElement.class);
        JsonObject jsonObject = element.getAsJsonObject();
        final AccessRequest request = gson.fromJson(jsonObject, AccessRequest.class);

        recentAppName = request.AppName.toString();
        recentRequestTime = request.RequestTime.toString();
        if (request.IsExpired)
            isExpired = "Has Expired";
        else isExpired = "Active";

        MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
               //Handle UI here                        
               tvRecentAppName.setText(recentAppName);
               tvRecentRequestTime.setText(recentRequestTime);
               tvIsExpired.setText(isExpired);                
            }
       });
    }
}

同样,如果您在 onFailure 上更新了任何视图,请在 UI 线程上进行。