【问题标题】:Picasso library is not loading images from the server correctly in a listviewPicasso 库未在列表视图中正确从服务器加载图像
【发布时间】:2014-11-19 17:27:26
【问题描述】:

我正在尝试使用 Google 最近推出的RecylerView。我在那里有一组行,现在是 7-8 行,每一行都有一个我从服务器获取的图像。为此,我正在使用 Picasso 库,但这对我不起作用。我不确定我是否遗漏了什么或配置了什么。

屏幕正确显示每一行的默认图像,但不从服务器下载图像,如果服务器响应缓慢,我会等待超过 5 分钟,但事实并非如此。

代码

public DemoRecyclerAdapter(List<DemoRowModel> items, int itemLayout, final Context mContext) {
    this.items = items;
    this.itemLayout = itemLayout;
    this.mContext = mContext;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
    DemoRowModel item = items.get(position);

    holder.mDemoNameTextView.setText(item.getDemoName());
    holder.mDemoDateTextView.setText(item.getDemoDate());

    Target mTarget = new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
            holder.mImageView.setImageBitmap(bitmap);
        }

        @Override
        public void onBitmapFailed(Drawable drawable) {
            Logger.d(TAG, "Failed! Bitmap could not downloaded.");
        }

        @Override
        public void onPrepareLoad(Drawable drawable) {
        }
    };

    Picasso.Builder builder = new Picasso.Builder(mContext);
    Picasso picasso = builder.downloader(new OkHttpDownloader(mContext) {
        @Override
        protected HttpURLConnection openConnection(Uri uri) throws IOException {
            HttpURLConnection connection = super.openConnection(uri);
            // fetch the auth value
            SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext.getApplicationContext());
            connection.setRequestProperty(Constant.HEADER_X_API_KEY, mSharedPreferences.getString(SharedPreferenceKeys.JSESSIONID, ""));
            return connection;
        }
    }).build();

    picasso.load(item.getImagePath()).into(mTarget);

    // here set the value
    holder.itemView.setTag(item);

}

提前致谢。

【问题讨论】:

  • 正如下面的一个答案指出的那样:“另一种方法:将目标对象保存在 ViewHolder 中。” - 我(我想我)已经成功地使用了一个ViewHolder,它甚至不包含对 ImageView 的引用——只有一个 Target。见这里:stackoverflow.com/questions/29717617/…

标签: android image picasso android-recyclerview image-caching


【解决方案1】:

如果您使用Target's - 它们应该是强引用对象。在您的类中创建字段mTaget 并从onBindViewHolder 方法中移动Target 的初始化。

编辑:将身份验证密钥保存在安全的地方,例如keystore。不要将它们保存在SharedPreferences,这是一种不好的做法。

更新:

1) 创建自定义目标类

public class CommonImageTarget implements Target {
    private final ImageView imageView;

    public CommonImageTarget(final ImageView imageView) {
        this.imageView = imageView;
    }

    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        this.imageView.setImageBitmap(bitmap);
    }

    @Override
    public void onBitmapFailed(Drawable errorDrawable) {
        Logger.d(TAG, "Failed! Bitmap could not downloaded.");
    }

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {
    }
}

2) 创建自定义ImageView

public class ImageViewWithTarget extends ImageView{
    /**
     * Required for Bitmap loading using Picasso. Picasso uses weak references in into() method and Target's are garbage collected, save them in object.
     */
    private Target target;

    public ImageViewWithTarget(Context context) {
        super(context);
    }

    public ImageViewWithTarget(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ImageViewWithTarget(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public Target getTarget() {
        return target;
    }

    public void setTarget(Target target) {
        this.target = target;
    }
}

3)当你在viewHolder中初始化你的imageView时,在里面设置自定义Target

viewHolder.mImageView.setTarget(new CommonImageTarget(viewHolder.mImageView));

4) 更新ViewHolder

public class ViewHolder{
       ...
       private ImageViewWithTarget mImageView;
   }

5) 在您的布局中将 ImageView 替换为 ImageViewWithTarget

6) 更新onBindViewHolder方法

picasso.load(item.getImagePath()).into(viewHolder.mImageView.getTarget());

现在每个ImageView 都将拥有自己的Target 对象,并且Target 不会被垃圾回收。

另一种方式:将Target对象保存在ViewHolder中。

【讨论】:

  • 我没有完全理解“从 onBindViewHolder 方法中移动 Target 的初始化”。
  • 您在 onBindViewHolder 中创建您的 mTarget 对象。不要那样做。
  • 那我应该在哪里创建呢?
  • 好的,非常感谢,我会在接下来的 5-6 小时内尝试更新您。如果这项工作,那么我肯定会接受它:)
  • 好。请记住主要思想 - 目标对象被垃圾收集,以防止这种情况 - 将其保存在您的模型对象或其他地方的某个地方,但不要在 onBindViewHolder 中创建本地 Target 变量。
【解决方案2】:

你应该使用 ImageView 的 setTag(Object tag) 方法

这个案例:

......

Target mTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
        holder.mImageView.setImageBitmap(bitmap);
    }

    @Override
    public void onBitmapFailed(Drawable drawable) {
        Logger.d(TAG, "Failed! Bitmap could not downloaded.");
    }

    @Override
    public void onPrepareLoad(Drawable drawable) {
    }
};

holder.mImageView.setTag(mTarget);// Target isn't garbage collected

Picasso.Builder builder = new Picasso.Builder(mContext);

......

它对我有用

【讨论】:

    猜你喜欢
    • 2023-03-28
    • 2018-07-14
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多