通过AsyncTask下载图像时ListView滚动滞后

时间:2013-07-12 12:10:32

标签: android

我想要显示包含一些文本和图像的列表视图。当我为listview创建一个视图时,我正在调用我的PictureImageView的方法show,它会下载并显示图像。下载正在AsyncTask中的新线程中运行。但是图像下载时我无法正常滚动列表视图,这是抽搐。 要在新线程中运行AsyncTask,我调用executeOnExecutor方法。我试图调用execute方法,但滚动停止,直到下载结束。

我的班级。

public class PictureImageView extends LinearLayout {

private Drawable image_drawable = null;

private ImageView image = null;

...

protected String getImageURL() {

    ...

    return uri;

}

public void show() {

    if (image_drawable != null) {

        image.setImageDrawable(image_drawable);

        addView(image);

    } else {

        // target Android API >= 14 so executeOnExecutor works in another thread
        new RequestTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getImageURL());

    }

}

protected void onResponse(Drawable image) {

    if (image != null) {

        image_drawable = image;

        show();

    }

}

class RequestTask extends AsyncTask<String, String, Drawable> {

    @Override
    protected Drawable doInBackground(String... urls) {

        Drawable image = null;

        HttpURLConnection connection = null;

        InputStream connection_stream = null;

        try {

            URL url = new URL(urls[0]);

            connection = (HttpURLConnection) url.openConnection();

            connection.setRequestMethod("GET");

            connection.setUseCaches(true);

            connection.connect();

            int response_code = connection.getResponseCode();

            //@see http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html
            if (response_code == HttpURLConnection.HTTP_OK || response_code == -1) {

                connection_stream = connection.getInputStream();

                image = Drawable.createFromStream(connection_stream, null);

            }

        } catch (MalformedURLException e) {
        } catch (IOException e) {
        } finally {

            if (connection != null) {

                connection.disconnect();

            }

            if (connection_stream != null) {

                try {

                    connection_stream.close();

                } catch (IOException e) {
                }

            }

        }

        return image;

    }

    @Override
    protected void onPostExecute(Drawable image) {

        PictureImageView.this.onResponse(image);

    }

}

}

我该如何解决?我想,问题是没有任何其他线程,但如何检查它?

1 个答案:

答案 0 :(得分:1)

我亲自解决了这个确切的问题。每次下载图片时都会更新ListView。我采取了两种不同的方法来解决这个问题。根据您的项目设置我的工作

方法1:只更新一次

,尽量减少抽搐

在我的情况下,我使用AsyncTask作为单独的类,并回调起始活动。我所做的是使用singleThreadExecutor,以便下载每个用户的图片的任务被串行执行,并且计数器跟踪有多少踏板被启动/离开 - 每次我向执行器添加一个踏板时递增,每次递减回电被叫了。例如

@Override
public void userPic(Bitmap pic){
    if(pic != null){
       //use picture
    }
    taskCounter--
    if(taskCounter == 0){
        updateUserListView();
    }
} 

通过更新所有线程完成后,我可以通过仅刷新列表一次来最小化抽搐,从而允许滚动并仅在完成所有图片后跳回到顶部

方法2:使用mem cache消除抽搐

最终我所做的就是使用缓存来存储位图。这种方法完全消除了跳转问题,因为列表不再被刷新,而是适配器仅在视图被回收时才从缓存加载位图。我仍然使用单独的任务回调

 @Override
public void userPic(Bitmap pic){
    if(pic != null){
        memCache.addPicture(pic);         
    }
 } 

只是这次而不是直接更新列表,如果下载了图片,我将其存储到缓存中。然后在我的适配器代码中,我将picutre字段设置为从缓存中更新(如果存在)

if(picture_view != null){
    if(memCache.contains(u.getId()){
        picture_view.setImageBitmap(memCache.getPicture(u.getId()));
    } else {
        picture_view.setImageBitmap(memCache.getPicture("default"));
}

这种方法优先考虑这样一个事实,即视图在被回收后自动更新为ListView。滚动并重建视图时,适配器将自动使用新数据填充字段(如果已更改)。

下行 - 列表不会自动升级。如果为当前可见的字段下载图片,则在您从该视图滚动之前不会更新这些图片。此外,在创建缓存时稍微设置一下。我选择使用singelton模式来执行此操作,因为我从多个位置访问缓存(例如,在一个位置添加图片并进入另一个位置)。