Android AsyncTask onPostExecute 方法

发布于 2024-12-07 07:23:03 字数 2839 浏览 0 评论 0原文

编辑:如果我根本不使用进度,只显示对话框,那么一切都可以正常工作。但是如果我添加进度,则对话框不会关闭(方法 onPostExecute() 不会被触发)。


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

这是目前的粗略解决方案。它每次都有效,但不是正确的,也不是很好的。 我在做什么: * 我使用 tabgroupactivity 启动子活动 * 然后我导航到子活动中的另一个活动,因此它是父活动的当前子活动 * 有一个网络视图,我在其中显示有关一条评论的信息..无论如何 * 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(bytes amount),但它不起作用,也许下载文件时它们彼此不精确匹配

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

EDIT: If I do not use the progress at all, just showing the dialog, then everything works without any problems. But if i add progress, then dialog doesn't close(method onPostExecute() is not fired).


onPostExecute method is not executed. Where do I have a mistake? (Same result on emulator and on the device)
I am also not sure if I should use Override notation for these methods

This is the rough solution for now. It works every time, but is not the proper and not the nice one.
What I am doing:
* I start a child activity using tabgroupactivity
* Then i navigate to another activity in the child activity, so it is a current child of a parent
* There is a webview, where I display information about one comment.. whatever
* There is a link in the content displayed by the webView
* when i click it, i start downloading the PDF file.

When the file is downloaded:

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

My Dialog object is disapeared, so if I try to call Dialog after the While loop, i just don't get it. So what I did is that every time i get new buffer from website, i check if the dialog is still visible and if the current byte together with the amount of bytes read up to now are greater than the full size of the file, then I close the dialog in the while loop.
I tried using fileSize == read(amount of bytes), but it did not work, maybe they are not precisely mach each other when the file is downloaded

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

献世佛 2024-12-14 07:23:04

我发现这个线程正在寻找同样的问题。经过多次尝试和错误,我发现了两个问题:

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

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

    protected void onPostExecute(Void v)

不是很直观,并且未在 API 中显示,但一旦我这样做了,就成功了。

I found this thread searching for the same problem. After much trial and error, I found two issues:

  1. I was sometimes canceling my Task in doInBackground instead of letting the method complete normally, causing onCancelled() to fire instead of onPostExecute(). Thanks for the tip, Kasper!

  2. I was apparently using the wrong method signature for onPostExecute. If you do not have a return type, it needs to be:

    protected void onPostExecute(Void v)

Not very intuitive, and not shown in the API, but once I did this that did the trick.

睫毛上残留的泪 2024-12-14 07:23:04

恕我直言,您只需要删除 super 呼叫即可。

IMHO, you just need to remove super call.

別甾虛僞 2024-12-14 07:23:03

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

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

Is the parent of the AsyncTask cancelled/paused/destroyed before the AsyncTask finishes?

If yes, the AsyncTask might recieve a cancel() which results in onPostExecute() never to be run. To verify this, try overriding onCancelled()-method and check if it is run.

俯瞰星空 2024-12-14 07:23:03

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

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

第二种方法:将所有与 UI 线程相关的方法移至 onPostExecute() 中。这是线程安全的,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 而是使用 Task,并使用 ThreadPoolExecutor 来包装他们。

这就是为什么你不应该使用 Asynctask如何在 Android 上建立异步 URL 连接?
在答案中查找我的名字。

Funny how you can post 3 times the same answer because people does not search before they post...
You are NOT allowed to access the UI thread from anywhere but the UI Thread... That means that your Dialog.dismiss and Dialog.cancel can't be executed since it is not Thread safe...

To fix your problem you have several ways. First way : do NOT use AsyncTask as you will have 5 tasks (at max) running at every time... I send you to the Android Doc of AsyncTask, and the guidelines to Processes and Threads attached for further info.

Second way : Move all of your UI Thread-related methods in the onPostExecute(). This is thread-safe, and the result of doInBackground() is automatically transmitted to it.

Third way : use on of the following

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

The Runnable will be executed inside the UI Thread. So again. Thread-safe.

I recommend the second solution if you really do not need your app to be thoroughly optimized. If it does, use tasks manually added to a manually created ThreadPoolExecutor (again, see the doc of ThreadPoolExecutor).

While searching through the doc I found This :

There are a few threading rules that must be followed for this class to work properly:

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

If not on UI Thread, do not use AsyncTask but Task instead, with a ThreadPoolExecutor to wrap them.

This is why you should NOT use Asynctask : How can I make asynchronous URL connections on Android?
look for my name in the answers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文