首页 > 解决方案 > 使用 Glide 检查两个图像是否相同

问题描述

我正在使用提供食谱信息的 Spoonacular API。自然地,API 提供了一个图像链接,类似于预览,除了有时链接是默认图像:https ://spoonacular.com/recipeImages/310822-90x90.jpg

导致:具有默认图像的 RecyclerView

我正在使用 Glide 使用 onBindViewHolder() 方法在 RecyclerView 内的 ImageView 内加载图像。但是,如果在其中加载的图像将是默认图像(上图),我不希望视图被夸大。我似乎找不到一种方法来比较将要加载的图像是否等同于默认图像。不幸的是,食谱图像的 URL 也各不相同,因此简单的字符串比较不起作用……欢迎提出任何建议。

更新:我按照您的建议进行了尝试,它有点工作?似乎正在发生一些非常奇怪的事情。因此,当视图加载时,它看起来像这样,当我向下滚动视图然后备份时,它看起来像这样,似乎已修复,但是,它只是18~22中项目的重复。这是 API 的问题吗?无法理解正在发生的事情...... package com.example.recipeapi;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import static androidx.core.content.ContextCompat.startActivity;

public class RecipesAdapter extends RecyclerView.Adapter<RecipesAdapter.RecipeViewHolder> {
    private LayoutInflater mInflater;
    private JSONArray jsonArray;
    private Context context;

    public RecipesAdapter(Context context, JSONArray jsonArray) {
        this.mInflater = LayoutInflater.from(context);
        this.jsonArray = jsonArray;
        this.context = context;
    }

    @NonNull
    @Override
    public RecipeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ConstraintLayout constraintLayout = (ConstraintLayout) mInflater.inflate(R.layout.item_view, parent, false);
        return new RecipeViewHolder(constraintLayout, this);
    }

    @Override
    public void onBindViewHolder(@NonNull final RecipeViewHolder holder, int position) {
        try {
            final String title, prepTime, servings, imageURL, TEMPNOIMAGE;
            JSONObject object = (JSONObject) jsonArray.get(position);
            imageURL = String.format("https://spoonacular.com/recipeImages/%s-90x90.jpg", object.get("id"));

//            imported code start
            final Bitmap[] defaultImg = new Bitmap[1];

            Glide.with(context).asBitmap().load("https://spoonacular.com/recipeImages/310822-90x90.jpg").listener(new RequestListener<Bitmap>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object o, Target<Bitmap> target, boolean b) {
                    Toast.makeText(context, "unexpected error, try again", Toast.LENGTH_SHORT).show();
                    System.out.println("error 1");
                    return false;
                }

                @Override
                public boolean onResourceReady(Bitmap bitmap, Object o, Target<Bitmap> target, DataSource dataSource, boolean b) {
                    defaultImg[0] = bitmap;
                    return false;
                }
            }).submit();

// before setting image use sameAs() method on bitmap
            Glide.with(context).asBitmap().load(imageURL).listener(new RequestListener<Bitmap>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object o, Target<Bitmap> target, boolean b) {
                    Toast.makeText(context, "unexpected error", Toast.LENGTH_SHORT).show();
                    System.out.println("error 2");
                    return false;
                }

                @Override
                public boolean onResourceReady(Bitmap bitmap, Object o, Target<Bitmap> target, DataSource dataSource, boolean b) {
                    if (!bitmap.sameAs(defaultImg[0]))
//                        mimageView.setImage(ImageSource.bitmap(bitmap));
//                        holder.mImageView.setImage(ImageSource.bitmap(bitmap));
                        holder.mImageView.setImageBitmap(bitmap);
                    Glide.with(context).load(bitmap).into(holder.mImageView);
                    return false;
                }
            }).submit();
//            imported code end

//            Checking to see if there is an image first!
//            TEMPNOIMAGE = "https://spoonacular.com/recipeImages/310822-90x90.jpg";
//            Glide.with(context).load(imageURL).into(holder.mImageView);

            title = position + 1 + " " + object.getString("title");
//            Check if prep time is greater than 100 minutes
            prepTime = object.getString("readyInMinutes");
            if (Integer.parseInt(prepTime) > 99)
                holder.mPrepTimeTextView.setText("99+ minutes");
            else
                holder.mPrepTimeTextView.setText(prepTime + " minutes");

            servings = "Serves: " + object.getString("servings");
            holder.mTitleTextView.setText(title);
            holder.mServingsSizeTextView.setText(servings);
//            holder.mPrepTimeTextView.setText(prepTime);
            holder.url = Uri.parse(object.getString("sourceUrl").toString());

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public int getItemCount() {
        return jsonArray.length();
    }

    public class RecipeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private Uri url;
        private ConstraintLayout view;
        private RecipesAdapter recipesAdapter;
        private TextView mTitleTextView, mPrepTimeTextView, mServingsSizeTextView;
        private ImageView mImageView;

        public RecipeViewHolder(@NonNull ConstraintLayout itemView, RecipesAdapter recipesAdapter) {
            super(itemView);
            this.recipesAdapter = recipesAdapter;
            this.view = itemView.findViewById(R.id.recipeConstraintLayout);
            this.view.setOnClickListener(this);
            this.mTitleTextView = itemView.findViewById(R.id.title_textview);
            this.mPrepTimeTextView = itemView.findViewById(R.id.time_required_textview);
            this.mServingsSizeTextView = itemView.findViewById(R.id.servings_textview);
            this.mImageView = itemView.findViewById(R.id.imageView);
        }

        @Override
        public void onClick(View view) {
            Toast.makeText(view.getContext(), ((TextView) view.findViewById(R.id.title_textview)).getText(), Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(Intent.ACTION_VIEW, url);
            if (intent.resolveActivity(view.getContext().getPackageManager()) != null) {
                startActivity(view.getContext(), intent, null);
            } else {
                Log.d("ImplicitIntents", "Intent can't be handled");
            }

        }
    }
}

标签: androidandroid-recyclerviewandroid-glide

解决方案


您可以从 url 保存位图https://spoonacular.com/recipeImages/310822-90x90.jpg,然后将其与实际图像的位图进行比较,一些建议如下 -

//get a default img to a bitmap
Bitmap defaultImg;

Glide.with(cxt).asBitmap().load("https://spoonacular.com/recipeImages/310822-90x90.jpg").listener(new RequestListener<Bitmap>() {
    @Override
    public boolean onLoadFailed(@Nullable GlideException e, Object o, Target<Bitmap> target, boolean b) {
        Toast.makeText(cxt,getResources().getString(R.string.unexpected_error_occurred_try_again),Toast.LENGTH_SHORT).show();
        return false;
    }

    @Override
    public boolean onResourceReady(Bitmap bitmap, Object o, Target<Bitmap> target, DataSource dataSource, boolean b) {
        defaultImg = bitmap;
        return false;
    }
}).submit();

// before setting image use sameAs() method on bitmap
Glide.with(cxt).asBitmap().load(imageUrl).listener(new RequestListener<Bitmap>() {
    @Override
    public boolean onLoadFailed(@Nullable GlideException e, Object o, Target<Bitmap> target, boolean b) {
        Toast.makeText(cxt,getResources().getString(R.string.unexpected_error_occurred_try_again),Toast.LENGTH_SHORT).show();
        return false; 
    }

    @Override
    public boolean onResourceReady(Bitmap bitmap, Object o, Target<Bitmap> target, DataSource dataSource, boolean b) {
        if(!bitmap.sameAs(defaultImg)) 
            imageView.setImage(ImageSource.bitmap(bitmap));
        return false;
    }
}).submit();

上面的代码也可以进行优化,但想法是一样的。

使用 Glide获取有关bitmap.sameAs()和位图的更多信息

编辑 1(复制问题)

我尝试使用以下代码重现问题,您可以检查结果

public class DashboardFragment extends Fragment {

    View root;
    private static final String TAG = "DashboardFragment";
    private Bitmap defaultImage;
    private ImageView imageView;
    private TextView textView;
    private int imageID;
    private Bitmap defaultImageBitmap;
    ...........

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        ..........

        String[] imageUrl = {"https://spoonacular.com/recipeImages/310822-90x90.jpg" //Default Image
                , "https://spoonacular.com/recipeImages/579247-90x90.jpg"             // Actual Image
                , "https://spoonacular.com/recipeImages/556247-90x90.jpg"              // Actual Image
                , "https://spoonacular.com/recipeImages/328822-90x90.jpg"             //Default Image
                , "https://spoonacular.com/recipeImages/716429-90x90.jpg"};           //Actual Image

        Button loadImage = view.findViewById(R.id.load_another);
        imageView = view.findViewById(R.id.image);
        textView = view.findViewById(R.id.image_url);
        imageID = 0;

        defaultImage = BitmapFactory.decodeResource(requireContext().getResources(), R.drawable.test_recipe_img);

        Picasso.with(requireContext()).load("https://spoonacular.com/recipeImages/310822-90x90.jpg").into(new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                defaultImageBitmap = bitmap;
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        });


        loadImage.setOnClickListener(v -> {
            if (imageID == 5)
                imageID = 0;
            loadImage(imageUrl[imageID]);
            textView.setText(imageUrl[imageID]);
            imageID++;

        });
    }

    private void loadImage(String imageUrl) {

        Glide.with(requireContext()).asBitmap().load(imageUrl).addListener(new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, com.bumptech.glide.request.target.Target<Bitmap> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, com.bumptech.glide.request.target.Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                if (defaultImageBitmap.sameAs(resource))
                    Toast.makeText(requireContext(), "Default Image", Toast.LENGTH_SHORT).show();
                else {
                    imageView.setImageBitmap(resource);
                }
//                Log.d(TAG, "Default Image: " + defaultImage.toString());
//                Log.d(TAG, "Requested Image: " + resource.toString());
                return true;
            }
        }).submit();
    }
}

我同时使用了 Picasso 和 Glide,结果非常不可预测。试过了diskCacheStrategy(DiskCacheStrategy.NONE)skipMemoryCache(true)没有成功。由于我不是图像处理专家,所以这可能需要更多关注。

快乐编码!


推荐阅读