AsyncTask阻止UI线程并显示带延迟的进度条

时间:2011-04-07 14:57:02

标签: android android-asynctask

我的AsyncTask阻塞块按钮元素,同时下载图像和进度对话框显示延迟 - 显示图像前显示一段时间,但下载需要很长时间,按钮被阻止(橙色)并且不显示对话框。

 public  Bitmap download(String url, ProgressBar progressbar) throws InterruptedException, ExecutionException {
     BitmapDownloaderTask task = new BitmapDownloaderTask(progressbar);
     task.execute(url);
     return task.get();
}

class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {



    public BitmapDownloaderTask(ProgressBar progressbar) {

    }
    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(ShowActivity.this);
        dialog.setMessage("Loading");
        dialog.setIndeterminate(true);
        dialog.setCancelable(false);
        dialog.show();
    }

    @Override
    protected Bitmap doInBackground(String... Params) {
        return imageLoader.getBitmap(params[0]);

    }
    @Override
    protected void onPostExecute(Bitmap bitmap) {
         dialog.dismiss();


    }
}    

在按钮监听器中,只需调用下载功能,进度参数是因为我在imageview中有进度条圆 - 该对话框仅用于测试,找到为什么有延迟和阻塞。在另一个应用程序中我使用runable并且线程和元素没有被阻止,但在教程中提到的AsyncTask是更好的解决方案。

3 个答案:

答案 0 :(得分:13)

图像下载确实是在后台线程中执行的,但是return task.get();只是等待它完成,这就是阻止你的主线程。

您应该使用onPostExecute()作为任务完成时的回调,因此不仅要关闭对话框,还要使用doInBackground()返回的位图执行所需操作。

答案 1 :(得分:2)

这是因为您正在呼叫AsyncTask#get

  

如果需要等待计算完成,然后检索其结果。

您应该在onPostExecute()

范围内执行使用图像所需的任何操作

答案 2 :(得分:0)

旧问题,但已经遇到此问题。 是的,AsyncTask.get将阻塞UI线程,直到结果到达为止,没有为您的对话框提供处理空间来显示,我也遇到了使用更通用的解决方案来解决相同的问题。基本上,我使用接收到AsyncTaskData的构造函数创建AsyncTasks(AsyncTaskData是我创建的类,如下所示),其中包含所有必需的数据和回调。我给你我的课和一个例子。

AsyncTaskData.java

public class AsyncTaskData {

    private Context activityContext;
    private Object inputData; // whatever you want
    private AsyncTaskCallback callback;

    public AsyncTaskData(Context activityContext, Object inputData, AsyncTaskCallback callback) {
        this.activityContext = activityContext;
        this.inputData = inputData;
        this.callback = callback;
    }

    // getters and setters
}

AsyncTaskCallback.java

public interface AsyncTaskCallback {
    // method to be called when the task is finished (onPostExecute)
    void onAsyncTaskTerminated(Object result);
}

例如,如果我有一个AsyncTask进行登录,它将被声明为:

public class LoginAsyncTask extends AsyncTask<Void, Void, Boolean> {

    private AsyncTaskData asyncTaskData;
    private ProgressDialog progressDialog;

    public LoginAsyncTask (AsyncTaskData asyncTaskData) {
        this.asyncTaskData = asyncTaskData;
    }

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

        progressDialog = new ProgressDialog(asyncTaskData.getActivityContext(), R.style.AppTheme);
        progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(Void... voids) {
        // if needed, get your data with asyncTaskData.getInputData()
        AuthenticationData authData = (AuthenticationData) asyncTaskData.getInputData();
        boolean loggedIn = // your heavy authentication process goes here
        return loggedIn;
    }

    @Override
    protected void onPostExecute(Boolean loggedIn) {
        super.onPostExecute(searchResponse);

        progressDialog.dismiss();

        if(asyncTaskData.getCallback() == null) return;

        asyncTaskData.getCallback().onAsyncTaskTerminated(loggedIn);
    }
}

最后,要使用它,只需在您的“片段/活动”中执行此操作:

AsyncTaskData asyncTaskData = new AsyncTaskData(
    getActivity(), // or this if you are calling from an Activity
    new AuthenticationData("username", "password"), 
    result -> {
        boolean loggedIn = (boolean) result;
        // your login logic goeas here
    });

new SearchAsyncTask(asyncTaskData)
    .execute();

经过很多方法后,我最终使用了这一方法,因为它是通用的,将代码保持整洁,并解决了调用.get()方法和阻塞UI线程的问题。 希望对您有所帮助。