异步任务和线程赢得';t在java/android应用程序中运行两次
我有一个android应用程序,用java编写,它使用AsyncTask下载数据。异步任务用于处理整个下载过程中显示的进度对话框 实际下载是通过一个单独的线程启动的,DownloadAllUpdate。虽然我知道这不是惯例,但需要一个线程,因为下载过程分布在7个类中,并且在下载过程中没有其他方法更新进度条,因为我无法运行来自任何其他类的publishProgress调用 我的主要活动如下:异步任务和线程赢得';t在java/android应用程序中运行两次,java,android,multithreading,android-asynctask,Java,Android,Multithreading,Android Asynctask,我有一个android应用程序,用java编写,它使用AsyncTask下载数据。异步任务用于处理整个下载过程中显示的进度对话框 实际下载是通过一个单独的线程启动的,DownloadAllUpdate。虽然我知道这不是惯例,但需要一个线程,因为下载过程分布在7个类中,并且在下载过程中没有其他方法更新进度条,因为我无法运行来自任何其他类的publishProgress调用 我的主要活动如下: private Download downloadAll; private int totalBlock
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;
}
}
}
};
一个线程不能启动两次。您可以将
downloadAllUpdater
改为可运行:
Runnable downloadAllUpdater = new Runnable() { //rest unchanged
并将doInBackground
中的代码替换为:
new Thread(downloadAllUpdater).start();
这样,每次都会创建一个新线程,运行相同的任务
但是,doInBackground
已在后台线程上运行,是否确实需要创建新线程?如果没有,只需运行runnable:downloadAllUpdater.run()代码>而不创建新线程
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//do you download here
}
});
在Asyctask中,您无法访问在不同线程中发生的内容,不确定这是否与您看到的错误有关,但您当前的代码不是线程安全的。您当前正在从两个不同的线程(PerformTask
和DownloadAllUpdate
)分配成员变量downloadComplete
和DownloadAllUpdate
)。这种用法将导致竞争条件和意外结果。请阅读有关同步线程的信息(即synchronized
关键字)。对不起,这两种方法都不起作用。如果我尝试新线程(DownloadAllUpdate).start();,它会给出相同的错误,并且downloadAllUpdater.run()不会更新进度条。如果您使downloadUpdater
处于可运行状态并每次启动一个新线程,则不应该出现相同的错误,可能是不同的错误?另外,您在线程之间共享的所有变量(downloadplete
、totalBlocksLeft
和downloadfiled
)都应该是易变的。这肯定是同一个错误,很明显,它不是线程?我会让变量变得易变,以防万一。好吧,我不能正确地更新代码。您是对的,它现在不会在第二轮抛出错误,但线程不会重新启动。调用start
并再次启动,或者不调用。您应该在代码中添加一些日志,以便更好地了解执行的内容和时间。谢谢-我知道同步方法,但不知道变量
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//do you download here
}
});