简体   繁体   English

在不阻塞线程的情况下获取AsyncTask的结果

[英]Get AsyncTask's result without blocking the thread

I have the code that sends requests to REST API in AsyncTask. 我有将请求发送到AsyncTask中的REST API的代码。 Also, I have a ProgressDialog initialization in preExecute() and its dismission in postExecute() . 另外,我有一个ProgressDialog初始化preExecute()及其在解聘postExecute()

I want ProgressDialog to show an indeterminate spinner (you know, that loading animation), but I need to get a result too. 我希望ProgressDialog显示一个不确定的微调器(您知道正在加载动画),但是我也需要获得结果。 get() blocks the main thread where I'm invoking it in - what's the workaround for that case? get()在我调用它的地方阻塞了主线程-这种情况的解决方法是什么?

Main thread (main activity) 主线程(主要活动)

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

}

You can use AsyncTask's onProgressUpdate() method to perform the actions on the UI thread (such as showing or updating a loading animation) while doInBackGround() does the background work on another thread. 您可以使用AsyncTask的onProgressUpdate()方法在UI线程上执行操作(例如显示或更新加载动画),而doInBackGround()在另一线程上执行后台工作。

Basically you invoke the publishProgress() method from within doInBackGround(), which in turn calls onProgressUpdate(). 基本上,您从doInBackGround()中调用publishProgress()方法,该方法又调用onProgressUpdate()。

Check out the Android reference page on AsyncTask for an example. 请查看AsyncTask上的Android参考页面以获取示例。

1 - You can use a callback method. 1-您可以使用回调方法。 but keep in mind you should call it in your main thread. 但请记住,您应该在主线程中调用它。

2 - you can use LocalBroadcastManager in order to send your result through Intent . 2-您可以使用LocalBroadcastManager来通过Intent发送结果。

3 - you might want to use in application messaging libraries which are more reliable in my opinion. 3-在我看来,您可能想在应用程序消息传递库中使用更可靠的消息。 one example which I use very often is EventBus . 我经常使用的一个示例是EventBus

Please look at the usage of AsyncTask https://developer.android.com/reference/android/os/AsyncTask#usage 请查看AsyncTask的用法https://developer.android.com/reference/android/os/AsyncTask#usage

There is a callback function onPostExecute which returns (as parameter) the value you requested: 有一个回调函数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);
    }
}

Usage: 用法:

new RestTask().execute()

As you edited the question, this: 当您编辑问题时,这是:

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

should be called in previous Tasks onPostExecute method, this way you will not block you UI with get method waiting on login result. 应该在先前的Tasks onPostExecute方法中调用,这样您就不会使用get方法等待登录结果来阻止UI。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM