我正在处理的应用程序是使用后台线程通过API下载图像列表,然后以幻灯片形式显示图像。
有一个后台任务(当前是AsyncTask)来定期获取新图像。
我没有收到有关错误的Thread等的任何错误消息,只是AsyncTasks的第二个实例不会运行doInBackground方法。
以下是活动的一些代码:
private DownloadTask mDownloadTask = null;
private Handler mHandler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(mDownloadTask != null) {
mDownloadTask.cancel(true);
}
mDownloadTask = new DownloadTask();
mDownloadTask.execute((Void[]) null);
}
};
mDownloadTask = new DownloadTask();
mDownloadTask.execute((Void[]) null);
}
DownloadTask
看起来像这样:
@Override
protected List<String> doInBackground(Void... voids) {
// Download list of URLs from server, etc.
}
@Override
protected void onPostExecute(List<String> urls) {
mHandler.sendEmptyMessageDelayed(111, 5000);
}
将调用处理程序,将调用onPreExecute(在AsyncTask中),并且DownloadTask的初始运行(在onCreate
中)也可以。
根据这个问题:Android SDK AsyncTask doInBackground not running (subclass),它可能与SDK15相关。
感谢任何提示。
更新当我收到评论时,处理程序可能不在UI线程中(这很奇怪,因为Thread.currentThread
在onCreate和处理程序handleMessage
中都是相同的方法,我将handleMessage
方法修改为:
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mDownloadTask != null) {
mDownloadTask.cancel(true);
}
mDownloadTask = new DownloadTask();
mDownloadTask.execute((Void[]) null);
}
});
}
};
仍然没有成功。
更新完整的DownloadTask类
class DownloadTask extends AsyncTask<Void, Void, List<String>> {
@Override
protected void onPreExecute() {
// Cancel the animation.
if (mSlideshowAnimation != null) {
mSlideshowAnimation.cancel(true);
}
mImageView1.setVisibility(View.GONE);
mImageView2.setVisibility(View.GONE);
animate(mProgressBar).alpha(1.0f).setDuration(500).start();
Log.d(TAG, "Download preparation done.");
}
@Override
protected List<String> doInBackground(Void... voids) {
Log.d(TAG, "Download");
SharedPreferences s = getSharedPreferences("access", Context.MODE_PRIVATE);
String token = s.getString("token", null);
Log.d(TAG, "Downloading slideshows.");
List<String> urls = new ArrayList<String>();
Slideshow[] slideshows = new Api(SlideshowActivity.this).getSlideshows(token);
for (Slideshow slideshow : slideshows) {
urls.addAll(slideshow.getAllPhotoUrls());
}
Log.d(TAG, "Downloading slideshows: " + slideshows.length);
for (String url : urls) {
try {
url = Api.HOST + url;
if (!Cache.fileExists(Cache.getCacheFilenameForUrl(SlideshowActivity.this, url))) {
Cache.cacheStream(SlideshowActivity.this, HttpHelper.download(SlideshowActivity.this, url), url);
} else {
Log.d(TAG, "Cached: " + url);
}
} catch (IOException e) {
Log.e(TAG, "Error while downloading.", e);
}
}
Log.d(TAG, "Downloading slideshows finished.");
return urls;
}
@Override
protected void onPostExecute(List<String> urls) {
Log.d(TAG, "download successful");
animate(mProgressBar).alpha(0.0f).setDuration(500).start();
mCurrentImageIndex = -1;
mImageUrls = urls;
mSlideshowAnimation = new SlideshowAnimation();
mSlideshowAnimation.execute((Void[]) null);
mHandler.sendEmptyMessageDelayed(111, 5000);
}
}
答案 0 :(得分:14)
感谢与Waqas的一次有益的讨论(谢谢!)我终于在我的代码中发现了错误。事实上,上述所有内容都是正确的并且按原样工作。我的问题是第二个任务阻止了第一个任务,反之亦然。
在Google网上论坛找到这篇文章可能是巧合:http://groups.google.com/group/android-developers/browse_thread/thread/f0cd114c57ceefe3?tvc=2&q=AsyncTask+in+Android+4.0。建议参与线程的每个人都仔细阅读本讨论。
AsyncTask将线程模型切换到串行执行器(再次),这与我看来有2个AsyncTasks的方法不兼容。
最后,我将“下载”的处理切换为经典Thread
,并使用Handler
发布消息,以便在必要时取消幻灯片。使用处理程序sendEmptyMessageDelayed
我将在一段时间后简单地重新创建下载线程以刷新数据。
感谢所有评论&amp;答案。
答案 1 :(得分:3)
Handler
是android中的一种线程,AsyncTask也在不同的线程中运行。当您使用AsyncTask时,几乎没有规则..
此类必须遵循一些线程规则 正常工作:
必须在UI线程上创建任务实例。执行(参数...) 必须在UI线程上调用。不要调用onPreExecute(), onPostExecute(Result),doInBackground(Params ...), onProgressUpdate(Progress ...)手动。该任务只能执行 一次(如果尝试第二次执行,将抛出异常。)
所以它清楚地说必须从UI线程调用AsyncTAsk ..从Handler调用它,而不是UI线程......
好好试试这个
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mDownloadTask != null) {
mDownloadTask.cancel(true);
}
if([isCancelled()][1]){
mDownloadTask = new DownloadTask();
mDownloadTask.execute((Void[]) null);
} // i assume your task is not getting cancelled before starting it again..
}
});
}
};
并且文档也说明了这个..
Handler有两个主要用途:
(1)安排消息和runnables作为某个点执行 在将来; (2)将要执行的动作排入队列 与你自己不同的线索。