Android AsyncTask onPostExecute方法

时间:2011-09-29 08:08:06

标签: android android-asynctask

编辑:如果我根本不使用进度,只显示对话框,那么一切正常,没有任何问题。但是,如果我添加进度,则对话框不会关闭(方法onPostExecute()不会被触发)。


不执行onPostExecute方法。我哪里弄错了? (仿真器和设备上的结果相同) 我也不确定是否应该对这些方法使用覆盖表示法

这是目前的粗略解决方案。它每次都有效,但不是正确而不是好的。 我在做什么: *我使用tabgroupactivity启动子活动 *然后我导航到子活动中的另一个活动,因此它是父项的当前子项 *有一个webview,我在其中显示有关一条评论的信息......无论如何 * webView显示的内容中有一个链接 *当我点击它时,我开始下载PDF文件。

下载文件时:

    while ((current = bis.read()) != -1) {
        read = read + current;
        baf.append((byte) current);
        Dialog.setProgress(read);

        if(Dialog.isShowing() && read+2*current>file_size){
            Dialog.dismiss();
            Dialog.cancel();
        }
    }

我的Dialog对象消失了,所以如果我尝试在While循环后调用Dialog,我就是没有得到它。所以我做的是每次我从网站获得新的缓冲区时,我检查对话框是否仍然可见,如果当前字节连同当前读取的字节数大于文件的完整大小,那么我关闭while循环中的对话框。 我尝试使用fileSize == read(字节数),但它不起作用,也许它们在下载文件时并不是精确匹配的

private class DownloadPDFFile extends AsyncTask<String, Integer, Void> {
    private ProgressDialog Dialog = new ProgressDialog(getParent());

    protected void onPreExecute() {
        Dialog.setMessage("Downloading PDF file..");
        Dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        Dialog.setCancelable(false);
        // Dialog.setMax(1000);
        Dialog.setProgress(0);
        Dialog.show();
    }

    protected Void doInBackground(String... urls) {
        File file=null;
        int file_size = 0;
        try {
            URL url = new URL(urls[0]);
            URLConnection urlConnection = url.openConnection();
            urlConnection.connect();
            file_size = urlConnection.getContentLength();
            Dialog.setMax(file_size);
        } catch (IOException e) {

        }

        try {
            URL url1 = new URL(urls[0]); // you can // link

            file = new File("skm_intern_pdf.pdf");

            URLConnection ucon = url1.openConnection();

            InputStream is = ucon.getInputStream();

            BufferedInputStream bis = new BufferedInputStream(is);

            ByteArrayBuffer baf = new ByteArrayBuffer(5000);
            int read = 0;
            int current = 0;
            while ((current = bis.read()) != -1) {
                read = read + current;
                baf.append((byte) current);
                Dialog.setProgress(read);

                if(Dialog.isShowing() && read+2*current>file_size){
                    Dialog.dismiss();
                    Dialog.cancel();
                }
            }

            FileOutputStream fos = openFileOutput("skm_pdf.pdf",
                    Context.MODE_WORLD_WRITEABLE);
            fos.write(baf.toByteArray());
            fos.flush();
            fos.close();

        } catch (IOException e) {

        }

        return null;
        }

4 个答案:

答案 0 :(得分:2)

在AsyncTask完成之前是否取消/暂停/销毁了AsyncTask的父级?

如果是,AsyncTask可能会收到cancel(),导致onPostExecute()永远无法运行。要验证这一点,请尝试覆盖onCancelled() - 方法并检查它是否已运行。

答案 1 :(得分:1)

有趣的是,你可以发布3次相同的答案,因为人们在发布之前不会搜索... 除了UI线程之外,你不能从任何地方访问UI线程...这意味着你的Dialog.dismiss和Dialog.cancel不能被执行,因为它不是线程安全的......

要解决您的问题,您有几种方法。第一种方式:不要使用AsyncTask,因为每次都会运行5个任务(最多)...我将您发送到AsyncTask的Android文档,以及附加的进程和线程的指南了解更多信息。

第二种方式:onPostExecute()中移动所有与UI线程相关的方法。这是线程安全的,doInBackground()的结果会自动传输给它。

第三种方式:使用以下

Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)

Runnable将在UI线程内执行。再说一遍。线程安全的。

如果您确实不需要对应用进行彻底优化,我建议使用第二种解决方案。如果是,请使用手动添加到手动创建的ThreadPoolExecutor的任务(再次参见ThreadPoolExecutor的文档)。

在搜索文档时,我发现了这个:

  

此类必须遵循一些线程规则才能正常工作:

The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), 
doInBackground(Params...), onProgressUpdate(Progress...) 
manually.
The task can be executed only once (an exception will be thrown  
if a second execution is attempted.)

如果不在UI线程上,请不要使用AsyncTask,而是使用ThreadPoolExecutor来包装它们。

这就是为什么你不应该使用AsynctaskHow can I make asynchronous URL connections on Android? 在答案中寻找我的名字。

答案 2 :(得分:0)

我发现这个帖子正在寻找同样的问题。经过多次反复试验,我发现了两个问题:

  1. 我有时在doInBackground中取消我的任务而不是让方法正常完成,导致onCancelled()触发而不是onPostExecute()。谢谢你的提示,卡斯帕!

  2. 我显然是对onPostExecute使用了错误的方法签名。如果您没有返回类型,则需要:

    protected void onPostExecute(Void v)

  3. 不是非常直观,并且没有在API中显示,但是一旦我这样做了就行了。

答案 3 :(得分:-1)

恕我直言,你只需要删除超级电话。