【问题标题】:universal image loader wrong thumbnail in listview列表视图中的通用图像加载器错误缩略图
【发布时间】:2014-10-31 16:08:55
【问题描述】:

这个问题是在这里提出的:Universal-Image-Loader: wrong Bitmaps are attached to ImageView

我使用的是最新的 1.9.3。我通过在我的应用程序类中实现了这个解决方案:

@Override
public void onCreate() {
    super.onCreate();

    DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder().resetViewBeforeLoading(true).build();
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
        .defaultDisplayImageOptions(defaultOptions)
        .build();
    ImageLoader.getInstance().init(config);
}

根据Android-Universal-Image-Loader doesn't keep loaded images on scroll in gridview,我在我的适配器中加载图像:

ImageAware imageAware = new ImageViewAware(viewHolder.profileIV, false);
ImageLoader.getInstance().displayImage(imgUrl, imageAware);

还是不行;我想知道是不是因为提供模型数据的 api 不包含图像 url,所以我必须调用来获取图像 url。

所以在我的适配器的 getView() 中,在我使用带有图像 url 的 imageloader 之前,我会执行另一个异步调用来获取图像 url,如下所示:

 APIclient.getImageJson(getContext(), googleUrl, new JsonHttpResponseHandler() {
        @Override
        public void onSuccess(JSONObject imgJson) {
            try {
                JSONObject responseDataValue = imgJson.getJSONObject("responseData");
                JSONArray resultsValue = responseDataValue.getJSONArray("results");
                JSONObject result = resultsValue.getJSONObject(0);
                String imgUrl = result.getString("url");

                ImageAware imageAware = new ImageViewAware(viewHolder.profileIV, false);
                ImageLoader.getInstance().displayImage(imgUrl, imageAware);
                //ImageLoader.getInstance().displayImage(imgUrl, viewHolder.profileIV);
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }

这里的谷歌网址看起来像:https://ajax.googleapis.com/ajax/services/search/images?rsz=1&start=1&v=1.0&q=%22barack%20obama%22

每一行都有不同的 url,因为名称不同。我不知道问题是否仍然是通用图像加载器库中未修复的列表视图回收器问题,或者罪魁祸首是否在于额外的网络调用。如何使缩略图与旁边的数据保持一致?

【问题讨论】:

  • APIclient.getImageJson(...) 是任何图书馆吗?您可以同步执行 JSON 请求吗?如果你这样做了,那么我可以为你提供一个解决方案,只需编写同步 JSON 加载的代码。

标签: android image listview universal-image-loader


【解决方案1】:

我认为这是因为 getView() 中的异步调用 APIclient.getImageJson(...)。触发onSuccess() 回调的时间未知,因此您可以为已回收的ImageView 调用ImageLoader.getInstance().displayImage(...)

我可以建议您按照以下方式加入这两个异步操作(通过 APIclient 获取 JSON,通过 ImageLoader 加载图像)。实现自己的 ImageDoanloader,它将处理 google JSON URL (https://ajax.googleapis.com/ajax/services/search/images?rsz=1&start=1&v=1.0&q=%22barack%20obama%22),提取图像 URL 并加载图像。

让我们介绍一下我们自己的 URI 方案 - “json”。所以我们知道像“json://...”这样的传入 URI 对应的是 JSON 链接。

  1. 准备自己的下载器:

    public class JsonImageDownloader extends BaseImageDownloader {
    
        public static final String SCHEME_JSON = "json";
        public static final String SCHEME_JSON_PREFIX = SCHEME_JSON + "://";
    
        public JsonImageDownloader(Context context) {
            super(context);
        }
    
        public JsonImageDownloader(Context context, int connectTimeout, int readTimeout) {
            super(context, connectTimeout, readTimeout);
        }
    
        @Override
        public InputStream getStream(String uri, Object extra) throws IOException {
            if (uri.startsWith(SCHEME_JSON_PREFIX)) {
                String jsonUri = uri.substring(SCHEME_JSON_PREFIX.length());
                JSONObject imgJson = APIclient.getImageJson(context, jsonUri); // sync JSON loading
                try {
                    JSONObject responseDataValue = imgJson.getJSONObject("responseData");
                    JSONArray resultsValue = responseDataValue.getJSONArray("results");
                    JSONObject result = resultsValue.getJSONObject(0);
                    String imgUrl = result.getString("url");
                    return super.getStream(imgUrl, extra);
                } catch (JSONException e) {
                    throw new RuntimeException(e);
                }
            } else {
                return super.getStream(uri, extra);
            }
        }
    }
    
  2. 设置成配置

    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
            .imageDownloader(new JsonImageDownloader(context))
            ....
            .build();
    
  3. getView(...)中使用ImageLoader而不使用APIclient

    ImageAware imageAware = new ImageViewAware(viewHolder.profileIV, false);
    ImageLoader.getInstance().displayImage("json://" + googleUrl, imageAware);
    

【讨论】:

  • 感谢您的回复,但是进行同步网络调用不是不好的做法吗?它会阻止用户界面。
  • getStream() 在单独的线程上调用。在我的回答中,UI 线程上没有网络调用。
  • APIclient.getImageJson 是获取图像 url 的网络请求,在您提到的 cmets 中是同步的,而不是异步的。当异步请求完成以获取图像 url 时,您对问题的看法是正确的。 UniversalImageLoader 将该 url 呈现给由于行回收而不匹配的视图。
  • 所以APIclient不可能同步调用getImageJson()
  • 如果我想获取图像 json(获取图像 json 的网络调用)并阻止 UI,我可以在适配器 getView 中执行此操作而无需执行任何其他操作。这就是问题的核心,图片的 url 是未知的,所以需要另一个网络调用来获取它。
猜你喜欢
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 2013-04-29
  • 1970-01-01
  • 2014-07-25
相关资源
最近更新 更多