1

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

这里是我的课。

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);

    }

}

}

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

4

1 回答 1

1

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

方法 1:通过仅更新一次来最小化抽搐

在我的例子中,我使用了AsyncTask一个单独的类,并回调了起始活动。我所做的是使用 a singleThreadExecutor,以便连续执行下载每个用户图片的任务,并使用一个计数器来跟踪启动/离开了多少踏板 - 每次我向执行程序添加一个时递增,每次回调时递减被调用。例如

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

通过在所有线程完成后进行更新,我能够通过仅刷新一次列表来最小化抽搐,因此只有在所有图片完成后才允许滚动和跳回顶部

方法2:使用mem缓存消除twitch

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

 @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这种方法利用了视图一旦被回收就会自动更新的事实。当您滚动并重建视图时,如果字段发生更改,适配器将自动使用新数据填充字段。

缺点 - 列表不会自动更新。如果为当前可见的字段下载图片,则在您滚动离开该视图之前,它们不会更新。此外,在创建缓存时进行了更多设置。我选择使用单例模式来执行此操作,因为我从多个地方访问缓存(例如,在一个地方添加图片并进入另一个地方)。

于 2013-07-12T12:54:02.617 回答