简体   繁体   中英

Get AsyncTask's result without blocking the thread

I have the code that sends requests to REST API in AsyncTask. Also, I have a ProgressDialog initialization in preExecute() and its dismission in postExecute() .

I want ProgressDialog to show an indeterminate spinner (you know, that loading animation), but I need to get a result too. get() blocks the main thread where I'm invoking it in - what's the workaround for that case?

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):

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.

Basically you invoke the publishProgress() method from within doInBackGround(), which in turn calls onProgressUpdate().

Check out the Android reference page on AsyncTask for an example.

1 - You can use a callback method. 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 .

3 - you might want to use in application messaging libraries which are more reliable in my opinion. one example which I use very often is EventBus .

Please look at the usage of AsyncTask https://developer.android.com/reference/android/os/AsyncTask#usage

There is a callback function onPostExecute which returns (as parameter) the value you requested:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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