【问题标题】:Get AsyncTask's result without blocking the thread在不阻塞线程的情况下获取 AsyncTask 的结果
【发布时间】:2018-07-12 08:03:08
【问题描述】:

我有向 AsyncTask 中的 REST API 发送请求的代码。 另外,我在preExecute() 中有一个 ProgressDialog 初始化,在postExecute() 中有一个将其关闭。

我希望 ProgressDialog 显示一个不确定的微调器(你知道,加载动画),但我也需要得到一个结果。 get() 阻塞了我调用它的主线程 - 这种情况的解决方法是什么?

主线程(主要活动)

LoginTask task_login = new LoginTask();
                AsyncTask<String, Void, JSONObject> response = task_login.execute(et_username.getText().toString(), et_password.getText().toString());
                try {
                    JSONObject json = response.get();
                    Toast.makeText(MainActivity.this, json.toString(), Toast.LENGTH_SHORT).show();
                } catch (InterruptedException e) {
                    Toast.makeText(MainActivity.this, "Interrupted.", Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    e.printStackTrace();
                }

AsyncTask(虚拟 doInBackground):

public class LoginTask extends AsyncTask<String, Void, JSONObject> {
    private LoginTask self = this;
    private ProgressDialog progressDialog;

    @Override
    protected JSONObject doInBackground(String... params) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

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

        progressDialog = ProgressDialog.show(MainActivity.context,
                "Logging in...", "");
        progressDialog.setButton(DialogInterface.BUTTON_NEUTRAL,
                MainActivity.context.getResources().getResourceEntryName(R.string.dialog_button_cancel), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });

        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                self.cancel(true);
            }
        });
    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        progressDialog.dismiss();
    }

}

【问题讨论】:

  • 在此处显示您的代码。所以我可以建议你更新。
  • 顺便说一下,当有众所周知的库 Volley 和 Retrofit 时,为什么要通过 HTTP 实现 Api 调用。
  • 我使用okhttp发送请求
  • 在 onPostExecute 中可以获取数据时,为什么还要使用.get();?你完全破坏了 AsyncTask 的目的。
  • Welp,我不知道我应该把代码放到postExecute中。

标签: java android multithreading user-interface android-asynctask


【解决方案1】:

您可以使用 AsyncTask 的 onProgressUpdate() 方法在 UI 线程上执行操作(例如显示或更新加载动画),而 doInBackGround() 在另一个线程上执行后台工作。

基本上,您从 doInBackGround() 中调用 publishProgress() 方法,该方法又调用 onProgressUpdate()。

查看 AsyncTask 上的 Android reference page 以获取示例。

【讨论】:

    【解决方案2】:

    请看AsyncTask的用法https://developer.android.com/reference/android/os/AsyncTask#usage

    有一个回调函数onPostExecute,它返回(作为参数)您请求的值:

    private class RestTask extends AsyncTask<Object, Object, String> {
        protected String doInBackground(Object... args) {
            // this happend on background thread
            return downloadData();
        }
    
        protected void onPreExecute() {
            // this happend on UI thread
            showSpinner();
        }
    
        protected void onPostExecute(String result) {
            // this happend on UI thread
            hideSpinner();
            doSomethingWithDownloadResult(result);
        }
    }
    

    用法:

    new RestTask().execute()
    

    当你编辑问题时,这个:

    try {
        JSONObject json = response.get();
        Toast.makeText(MainActivity.this, json.toString(), Toast.LENGTH_SHORT).show();
    } catch (InterruptedException e) {
        Toast.makeText(MainActivity.this, "Interrupted.", Toast.LENGTH_SHORT).show();
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    应该在之前的TasksonPostExecute方法中调用,这样你就不会用get方法阻塞你的UI等待登录结果。

    【讨论】:

      【解决方案3】:

      1 - 您可以使用回调方法。 但请记住,您应该在主线程中调用它。

      2 - 您可以使用LocalBroadcastManager 通过Intent 发送您的结果。

      3 - 您可能希望在我认为更可靠的应用程序消息传递库中使用。我经常使用的一个例子是EventBus。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-08
        • 1970-01-01
        • 2016-07-04
        相关资源
        最近更新 更多