【问题标题】:AsyncTask and Thread won't run twice in java / android applicationAsyncTask 和 Thread 不会在 java / android 应用程序中运行两次
【发布时间】:2012-08-18 21:18:08
【问题描述】:

我有一个 android 应用程序,用 java 编写,它使用 AsyncTask 来下载数据。 AsyncTask 是处理整个下载过程中显示的进度对话框 所必需的。

实际下载是通过一个单独的线程 downloadAllUpdater 启动的。虽然我知道这不是惯例,但需要一个线程,因为下载过程分布在 7 个类中,并且在下载过程中没有其他方法可以更新进度条,因为我无法运行 publishProgress 来自任何其他类的调用。

我的主要活动如下所示:

private Download downloadAll;

private int totalBlocksLeft;

private boolean downloadComplete;
private boolean downloadFailed;

private PerformTask currentPerformTask;

public void downloadAllClick(View view) //When the download all button is clicked
{
    currentPerformTask = new PerformTask();

    currentPerformTask.execute();
}

private class PerformTask extends AsyncTask<Void, Integer, Integer>
{
    protected void onPreExecute()
    {
        usingDialog = new ProgressDialog(WifiAudioActivity.this);

        usingDialog.show();
    }

    protected Integer doInBackground(Void... voi) 
    {
        downloadAll = new Download();

        downloadComplete = false;   //Assume the download is not complete

        downloadAllUpdater.start(); 

        downloadFailed = false;

        while ((downloadComplete == false) && (downloadFailed == false))   
        {
            blocksDownloaded = downloadAll.getTotalBlocksLeft();

            publishProgress(blocksDownloaded);
        }

        return 0;
    }

    protected void onProgressUpdate(Integer... progress) 
    {
        usingDialog.setProgress(progress[0]);
    }

    protected void onPostExecute(Integer result) 
    {
        usingDialog.dismiss();
    }
}

Thread downloadAllUpdater = new Thread()
{
    public void run() 
    {
        int runRetryCount = 0;

        while ((!(downloadComplete)) && (!(downloadFailed)))
        {
            downloadComplete = download.downloadAudio(totalBlocksLeft);  //Download the audio

            if (!(downloadComplete))
            {
                runRetryCount++;
            }

            if (runRetryCount > Consts.RETRY_TOTAL)
            {
                downloadFailed = true;
            }
        }
    }
};

通过单击按钮启动下载,这会启动 downloadAllClick() 方法。

第一次按下按钮时,这一切都很好。

但是,当第二次按下按钮时(第一次完成后),我收到一个错误并且程序强制关闭。

我很确定错误是因为我正在运行线程,downloadAllUpdater 第二次,因为如果我有一个单独的方法,只有 downloadAllUpdater.start() ,它也会因同样的错误而崩溃。

有人可以帮忙吗?以下是错误日志:

08-23 11:22:34.954: W/dalvikvm(1485): threadid=14: thread exiting with uncaught exception (group=0x400259f8)

08-23 11:22:35.014: E/AndroidRuntime(1485): FATAL EXCEPTION: AsyncTask #5

08-23 11:22:35.014: E/AndroidRuntime(1485): java.lang.RuntimeException: An error occured while executing doInBackground()

08-23 11:22:35.014: E/AndroidRuntime(1485):     at android.os.AsyncTask$3.done(AsyncTask.java:200)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.lang.Thread.run(Thread.java:1102)

08-23 11:22:35.014: E/AndroidRuntime(1485): Caused by: java.lang.IllegalThreadStateException: Thread already started.

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.lang.Thread.start(Thread.java:1331)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at com.que.wifiaudio.WifiAudioActivity$PerformTask.doInBackground(WifiAudioActivity.java:518)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at com.que.wifiaudio.WifiAudioActivity$PerformTask.doInBackground(WifiAudioActivity.java:1)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at android.os.AsyncTask$2.call(AsyncTask.java:185)

08-23 11:22:35.014: E/AndroidRuntime(1485):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

08-23 11:22:35.014: E/AndroidRuntime(1485):     ... 4 more

【问题讨论】:

    标签: java android multithreading android-asynctask


    【解决方案1】:

    不确定这是否与您看到的错误有关,但您当前的代码不是线程安全的。您当前正在从两个不同的线程(PerformTaskdownloadAllUpdater)分配成员变量 downloadCompletedownloadFailed。这种用法将导致竞争条件和意外结果。请阅读concurrency in Java(即synchronized关键字),以同步您的线程。

    【讨论】:

    • 谢谢 - 我知道同步方法,不知道变量
    【解决方案2】:
    runOnUiThread(new Runnable() {
    
                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
    
                            //do you download here
    
                        }
                    });
    

    在 Asyctask 中,您无法访问发生在不同线程中的内容

    【讨论】:

      【解决方案3】:

      你不能start一个线程两次。您可以将 downloadAllUpdater 改为 Runnable:

      Runnable downloadAllUpdater = new Runnable() { //rest unchanged
      

      并将doInBackground中的代码替换为:

      new Thread(downloadAllUpdater).start();
      

      这样,每次都会创建一个新线程,运行相同的任务。

      但是doInBackground 已经在后台线程上运行,您确定需要创建一个新线程吗?如果没有,只需运行 runnable:downloadAllUpdater.run();,而不创建新线程。

      【讨论】:

      • 抱歉,似乎都不起作用。如果我尝试新的 Thread(downloadAllUpdater).start();,它会给出同样的错误,并且 downloadAllUpdater.run() 不会更新进度条。
      • 如果您将downloadUpdater 设为Runnable 并每次都启动一个新线程,您应该不会得到相同的错误,也许是不同的错误?此外,您跨线程共享的所有变量(downloadCompletetotalBlocksLeftdownloadFailed)都应该是 volatile。
      • 这绝对是同一个错误,确切地说——显然不是线程?我会让变量变得易变,以防万一有帮助。
      • 好的,我无法正确更新代码。你是对的,它现在第二次不会抛出错误,但是线程不会重新启动。
      • 要么start 被调用并且它会重新开始,要么它没有被调用。您应该在代码中添加一些日志,以更好地了解执行的内容和时间。
      猜你喜欢
      • 2012-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多