android - 使用 Glide 检查两个图像是否相同
问题描述
我正在使用提供食谱信息的 Spoonacular API。自然地,API 提供了一个图像链接,类似于预览,除了有时链接是默认图像:https ://spoonacular.com/recipeImages/310822-90x90.jpg
我正在使用 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");
}
}
}
}
解决方案
您可以从 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)
没有成功。由于我不是图像处理专家,所以这可能需要更多关注。
快乐编码!
推荐阅读
- java - 为什么 List.contains(Object) 的行为不同?
- r - 如何在同一个数据帧上做colsum和average
- powerbi - 使用 DAX 生成日期系列
- javascript - 仅在服务器上需要一个包
- java - Intellij IDEA 仅针对所有未提交的更改运行测试
- regex - 在换行符之前匹配字符,不包括空格?
- macos - MacOS - 使用带有launchd的脚本 - 启动,登录,注销,关闭?
- service-worker - Workbox 的服务人员在更改时未更新
- python - AllenNLP 共指分辨率的多 GPU 训练
- reactjs - 事件处理程序中带有 [name] 的 PrevState