12

我正在开发的应用程序使用后台线程通过 API 下载图像列表,然后以幻灯片形式显示图像。

有一个后台任务(当前为 AsyncTask)来定期获取新图像。

我没有收到关于错误线程等的任何错误消息,只是 AsyncTasks 的第二个实例不会运行 doInBackground 方法。

以下是 Activity 中的一些代码:

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 相关。

感谢您的任何提示。


更新当我收到 Handler 可能不在 UI 线程中的评论时(这很奇怪,Thread.currentThread在 onCreate 和 HandlershandleMessage方法中都是一样的,我将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);
    }
}
4

2 回答 2

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我将在一段时间后简单地重新创建下载线程以刷新数据。

感谢所有评论和答案。

于 2012-05-02T02:20:15.773 回答
3

Handler是android中的一种线程,AsyncTask也运行在不同的线程中。当您使用 AsyncTask 时,规则很少..

要使此类正常工作,必须遵循一些线程规则:

任务实例必须在 UI 线程上创建。必须在 UI 线程上调用 execute(Params...)。不要手动调用 onPreExecute()、onPostExecute(Result)、doInBackground(Params...)、onProgressUpdate(Progress...)。该任务只能执行一次(如果尝试第二次执行将引发异常。)

所以它清楚地说 AsyncTAsk 必须从 UI 线程调用。当你从不是 UI 线程的 Handler 调用它时……

也试试这个

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) 安排消息和可运行文件作为未来某个时间点执行;(2) 将要在与您自己的线程不同的线程上执行的操作排入队列。

于 2012-04-26T07:09:27.283 回答