在AsyncTask中使用ProgressDialog

65

我正在尝试从HTTP服务器加载RSS feed时显示自定义进度对话框,我进行了艰苦的搜索,但没有什么帮助我完成这个任务,唯一我知道的是解决方案应该使用AsyncTask,但是我对传递给这个AsyncTask的参数感到困惑。 这是我的活动:

public class Soirees extends ListActivity {

    private List<Message> messages;
    private TextView tvSorties;
    private MyProgressDialog dialog;

    @Override
    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);
        setContentView(R.layout.sorties);

        tvSorties=(TextView)findViewById(R.id.TVTitle);
        tvSorties.setText("Programme des soirées");

        loadFeed();

    }

    private void loadFeed(){

        try{
            BaseFeedParser parser = new BaseFeedParser();
            messages = parser.parse();
            List<Message> titles = new ArrayList<Message>(messages.size());
            for (Message msg : messages){
                titles.add(msg);
            }
            MessageListAdapter adapter = new MessageListAdapter(this,titles);
            this.setListAdapter(adapter);
            adapter.notifyDataSetChanged();

        } catch (Throwable t){
            Log.e("ImageLoader",t.getMessage(),t);
        }
    }

}

你能帮我将 AsyncTask 添加到这里吗?

7个回答

128
/**
 * this class performs all the work, shows dialog before the work and dismiss it after
 */
public class ProgressTask extends AsyncTask<String, Void, Boolean> {

    public ProgressTask(ListActivity activity) {
        this.activity = activity;
        dialog = new ProgressDialog(activity);
    }

    /** progress dialog to show user that the backup is processing. */
    private ProgressDialog dialog;
    /** application context. */
    private ListActivity activity;

    protected void onPreExecute() {
        this.dialog.setMessage("Progress start");
        this.dialog.show();
    }

        @Override
    protected void onPostExecute(final Boolean success) {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }


        MessageListAdapter adapter = new MessageListAdapter(activity, titles);
        setListAdapter(adapter);
        adapter.notifyDataSetChanged();


        if (success) {
            Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
        }
    }

    protected Boolean doInBackground(final String... args) {
       try{    
          BaseFeedParser parser = new BaseFeedParser();
          messages = parser.parse();
          List<Message> titles = new ArrayList<Message>(messages.size());
          for (Message msg : messages){
              titles.add(msg);
          }
          activity.setMessages(titles);
          return true;
       } catch (Exception e)
          Log.e("tag", "error", e);
          return false;
       }
    }
}

public class Soirees extends ListActivity {
    private List<Message> messages;
    private TextView tvSorties;
    private MyProgressDialog dialog;
    @Override
    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);

        setContentView(R.layout.sorties);

        tvSorties=(TextView)findViewById(R.id.TVTitle);
        tvSorties.setText("Programme des soirées");

        // just call here the task
        AsyncTask task = new ProgressTask(this).execute();
   }

   public void setMessages(List<Message> msgs) {
      messages = msgs;
   }

}

谢谢大家,我正在尝试这个,正如我所问的,我应该传递哪些参数?因为这行代码MessageListAdapter adapter = new MessageListAdapter(this,titles)会抛出错误。 - Houssem
错误:只有创建视图层次结构的原始线程才能触摸其视图。 - Houssem
2
无法在未调用Looper.prepare()的线程中创建处理程序。 我遇到了这个错误,如何解决? - Noby
你的例子没有回答问题,你从哪里得到上下文变量的? - Mehdi
不要在asynctask中创建progressDialog等UI元素。这可能会导致配置更改时出现问题,或者如果doInBackground方法内部出现故障,则onPostexecute不会被调用,在这种情况下,您的对话框永远不会被关闭。有更好更清晰的方法来解决这个问题。这篇文章解释了如何处理asynctask和屏幕方向:https://androidresearch.wordpress.com/2013/05/10/dealing-with-asynctask-and-screen-orientation/ - Prakash
显示剩余3条评论

44

通过将视图修饰符移动到onPostExecute中进行修复,因此修复后的代码如下:

public class Soirees extends ListActivity {
    private List<Message> messages;
    private TextView tvSorties;

    //private MyProgressDialog dialog;
    @Override
    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);

        setContentView(R.layout.sorties);

        tvSorties=(TextView)findViewById(R.id.TVTitle);
        tvSorties.setText("Programme des soirées");

        new ProgressTask(Soirees.this).execute();


   }


    private class ProgressTask extends AsyncTask<String, Void, Boolean> {
        private ProgressDialog dialog;
        List<Message> titles;
        private ListActivity activity;
        //private List<Message> messages;
        public ProgressTask(ListActivity activity) {
            this.activity = activity;
            context = activity;
            dialog = new ProgressDialog(context);
        }



        /** progress dialog to show user that the backup is processing. */

        /** application context. */
        private Context context;

        protected void onPreExecute() {
            this.dialog.setMessage("Progress start");
            this.dialog.show();
        }

            @Override
        protected void onPostExecute(final Boolean success) {
                List<Message> titles = new ArrayList<Message>(messages.size());
                for (Message msg : messages){
                    titles.add(msg);
                }
                MessageListAdapter adapter = new MessageListAdapter(activity, titles);
                activity.setListAdapter(adapter);
                adapter.notifyDataSetChanged();

                if (dialog.isShowing()) {
                dialog.dismiss();
            }

            if (success) {
                Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
            }
        }

        protected Boolean doInBackground(final String... args) {
            try{    
                BaseFeedParser parser = new BaseFeedParser();
                messages = parser.parse();


                return true;
             } catch (Exception e){
                Log.e("tag", "error", e);
                return false;
             }
          }


    }

}

@Vladimir,谢谢你的代码,非常有帮助。


无法在未调用Looper.prepare()的线程中创建处理程序,我遇到了这个错误。如何解决? - Noby
我认为你需要在这里添加一件事情。 你需要在你的AsyncTask中创建一个全局私有对象,并且当活动被销毁时,你需要取消AsyncTask。在你的情况下,如果用户在AsyncTask完成之前按下返回按钮,应用程序很可能会崩溃。 - tasomaniac
我一直在尝试使用类似的实现,但是一直出现错误,因为asynctask不是一个activity,所以我无法显示对话框。我有什么遗漏吗? - Moises Jimenez

9

AsyncTask非常有用!

class QueryBibleDetail extends AsyncTask<Integer, Integer, String>{
        private Activity activity;
        private ProgressDialog dialog;
        private Context context;

        public QueryBibleDetail(Activity activity){
            this.activity = activity;
            this.context = activity;
            this.dialog = new ProgressDialog(activity);
            this.dialog.setTitle("查询经文");
            this.dialog.setMessage("正在查询:"+tome+chapterID+":"+sectionFromID+"-"+sectionToID);
            if(!this.dialog.isShowing()){
                this.dialog.show();
            }
        }

        @Override
        protected String doInBackground(Integer... params) {
            Log.d(TAG,"经文doInBackground");
            publishProgress(params[0]);

            if(sectionFromID > sectionToID){
                return "";
            }

            String queryBible = "action=query_bible&article="+chapterID+"&id="+tomeID+"&verse_start="+sectionFromID+"&verse_stop="+sectionToID+"";
            try{
                String bible = (Json.getRequest(HOST+queryBible)).trim();
                bible = android.text.Html.fromHtml(bible).toString();
                return bible;
            }catch(Exception e){
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String bible){
            Log.d(TAG,"经文onPostExecute");
            TextView bibleBox = (TextView) findViewById(R.id.bibleBox);
            bibleBox.setText(bible);
            this.dialog.dismiss();
        }
    }

3

几天前我发现了一个非常好的解决方法。在这里阅读有关它的内容。简单来说,Mike创建了一个AsyncTaskManager,它调解了ProgressDialog和AsyncTask之间的关系。使用这个方法非常容易。您只需要在项目中包含一些接口和类,并在活动中编写一些简单的代码并将您的新AsyncTask嵌套在BaseTask中即可。我还建议您阅读评论,因为其中有一些有用的技巧。


3

不知道应该使用哪个参数?

许多开发人员在编写AsyncTask时,在参数的歧义性方面会遇到很大的困难。主要原因是我们试图记住AsyncTask中使用的参数。关键是不要记忆。如果您可以将您的任务真正需要做什么可视化,那么编写具有正确签名的AsyncTask将非常容易。

什么是AsyncTask?

AsyncTask是在后台线程中运行的后台任务。它接受输入,执行进度并给出输出。

AsyncTask<Input,Progress,Output>

只需找出您的输入、进度和输出,就可以开始了。

例如

enter image description here

doInbackground()如何随着AsyncTask参数而变化?

enter image description here

doInBackground()onPostExecute()onProgressUpdate()之间有何关系?

enter image description here

如何在代码中编写这个?

 DownloadTask extends AsyncTask<String,Integer,String>{

    @Override
    public void onPreExecute(){
    }

    @Override
    public String doInbackGround(String... params)
    {
         // Download code
         int downloadPerc = // calculate that
         publish(downloadPerc);

         return "Download Success";
    }

    @Override
    public void onPostExecute(String result)
    {
         super.onPostExecute(result);
    }

    @Override
    public void onProgressUpdate(Integer... params)
    {
         // show in spinner, access UI elements
    }

}

您将如何在您的活动中运行此任务?
new DownLoadTask().execute("Paradise.mp3");

很好的解释。 - waghydjemy
如果您能提供一个简单的示例代码,那就更好了。 - Ümañg ßürmån

0

这个问题被提出已经有几年了(也是自那时以来有人发布回复)。从那时起,根据Android官方文档,ProgressDialog在API级别O中已被弃用。因此,您可以考虑使用内联进度条代替ProgressDialog,正如文档作者建议的那样。


-2

谁曾经对此进行了反对投票,请告诉我这个答案有什么问题。这是我读过的好文章之一,我想与中级开发人员分享。 - Prakash
锁定屏幕方向以防止异步任务被销毁或出于其他目的是一个糟糕的主意。这就是我猜的原因。 - Mehmet Katircioglu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接