无法使用 URI 在 RecyclerView 中设置图像
Can't set image in RecyclerView using URI
我正在开发一个从 SQLite 数据库中提取信息并将其显示在 RecyclerView 中的应用程序。我无法使用 URI 在 RecyclerView 中设置图像。
Uri mImageUri=data.getData();
imgUri = data.getData();
// Get path (Path will be stored in database)
String imgToString = imgUri.toString();
// Get URI back from path
imgUri = Uri.parse(imgToString);
// Set ImageView
plainImage.setImageURI(imgUri);
// Set Glide image
Glide.with(this)
.asBitmap()
.load(imgUri)
.into(image);
这是从图库中选择图片后我的 OnActivityResult() 的片段。使用此代码可以在基本 activity 中设置图像。我从 URI 中获取 toString() 并将其保存在我的数据库中。 (在最终版本的应用程序中获取 URI 之前,我会将选定的图片移动到应用程序文件夹)
然而,当我从数据库中检索 URI 字符串,将它们解析回 URI,并尝试在 RecyclerView 中设置图像时,此方法不再有效。
这是来自 RecyclerAdapter 的 OnBindViewHolder()
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
holder.weight.setText(mWeights.get(position).toString());
holder.location.setText(mLocations.get(position));
holder.confidence.setText(mConfidences.get(position).toString());
// Open item view
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ItemView.class);
// Attach additional data to intent
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("location", mLocations.get(position));
intent.putExtra("confidence", mConfidences.get(position));
intent.putExtra("weight", mWeights.get(position));
mContext.startActivity(intent);
}
});
}
检查变量时 URI 似乎没问题。可能是什么原因造成的,我怎样才能在 RecyclerView 中设置图像?
谢谢
编辑
这是适配器代码
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private static final String TAG = "RecyclerViewAdapter";
private ArrayList<ArrayList<String>> mImages;
private ArrayList<Float> mWeights;
private ArrayList<Float> mConfidences;
private ArrayList<String> mLocations;
private ArrayList<Integer> mSharkEntryIds;
private Context mContext;
private Uri tempUri;
public RecyclerViewAdapter(Context context, ArrayList<Integer> ids, ArrayList<ArrayList<String>> images, ArrayList<Float> weights
, ArrayList<Float> confidences, ArrayList<String> locations) {
this.mContext = context;
this.mSharkEntryIds = ids;
this.mImages = images;
this.mWeights = weights;
this.mLocations = locations;
this.mConfidences = confidences;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
}
holder.weight.setText(mWeights.get(position).toString() + " kg");
holder.location.setText(mLocations.get(position));
holder.confidence.setText(mConfidences.get(position).toString() + " %");
// Open item view
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ItemView.class);
// Attach additional data to intent
intent.putExtra("id", mSharkEntryIds.get(position));
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("location", mLocations.get(position));
intent.putExtra("confidence", mConfidences.get(position));
intent.putExtra("weight", mWeights.get(position));
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mImages.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
CircleImageView image;
TextView weight;
TextView confidence;
TextView location;
RelativeLayout parentLayout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.thumbnail);
weight = itemView.findViewById(R.id.biomassText);
confidence = itemView.findViewById(R.id.confidenceText);
location = itemView.findViewById(R.id.locationText);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
}
这是我初始化 RecyclerView 的代码
// Vars
private ArrayList<Integer> mSharkEntryIds = new ArrayList<>();
private ArrayList<String> mLocations = new ArrayList<>();
//private ArrayList<String> mImageUrls = new ArrayList<>();
private ArrayList<ArrayList<String>> mImagePaths = new ArrayList<>();
private ArrayList<Float> mConfidences = new ArrayList<>();
private ArrayList<Float> mWeights = new ArrayList<>();
private DatabaseHelper mDatabaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
mDatabaseHelper = new DatabaseHelper(this);
Log.d(TAG, "onCreate: started");
//initImageBitmaps();
// Populate list view
Cursor data = mDatabaseHelper.getSharkEntriesFromDatabase();
while(data.moveToNext()){
mSharkEntryIds.add(data.getInt(0));
mWeights.add(data.getFloat(1));
mLocations.add(data.getString(2));
mConfidences.add(data.getFloat(3));
}
Log.d(TAG, "onCreate: test");
// Get associated image paths
ArrayList<String> photosForEntry;
for(Integer id : mSharkEntryIds){
data = mDatabaseHelper.getPhotosWithSharkID(id);
photosForEntry = new ArrayList<>();
while(data.moveToNext()){
photosForEntry.add(data.getString(0));
}
mImagePaths.add(photosForEntry);
}
initRecyclerView();
}
private void initRecyclerView(){
Log.d(TAG, "initRecyclerView: init recyclerview");
RecyclerView recyclerView = findViewById(R.id.recycler_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mSharkEntryIds, mImagePaths, mWeights, mConfidences, mLocations);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
我认为你做错了,我假设你在 mImages
中得到了字符串形式的路径
你看到你的这一部分了吗onBindViewHolder
:
...................
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
..................
改成这样:
........
// Load only first image for now
if(position == 0) {
tempUri = Uri.parse(mImages.get(position));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
..............
更新:
你的代码看起来不错,你说 Uri 出现在列表中,所以我的猜测是在设置适配器之前设置布局管理器:
我的意思是在你的 initRecyclerView()
:
..........
//add this first
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//add this next
recyclerView.setAdapter(adapter);
......
我已经解决了这个问题:
日志包含此消息:
java.lang.SecurityException(Permission Denial: opening provider com.android.providers.downloads.DownloadStorageProvider from ProcessRecord{985e802 27308:com.oshea.sharkbiomass/u0a82} (pid=27308, uid=10082) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs)
问题出在我的 select 照片按钮的点击侦听器中。
// Select photo button listener
btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 1);
}
});
我将其更改为:
// Select photo button listener
btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
startActivityForResult(intent, 1);
}
});
(将 ACTION_GET_CONTENT 更改为 ACTION_OPEN_DOCUMENT)并且有效。
我正在开发一个从 SQLite 数据库中提取信息并将其显示在 RecyclerView 中的应用程序。我无法使用 URI 在 RecyclerView 中设置图像。
Uri mImageUri=data.getData();
imgUri = data.getData();
// Get path (Path will be stored in database)
String imgToString = imgUri.toString();
// Get URI back from path
imgUri = Uri.parse(imgToString);
// Set ImageView
plainImage.setImageURI(imgUri);
// Set Glide image
Glide.with(this)
.asBitmap()
.load(imgUri)
.into(image);
这是从图库中选择图片后我的 OnActivityResult() 的片段。使用此代码可以在基本 activity 中设置图像。我从 URI 中获取 toString() 并将其保存在我的数据库中。 (在最终版本的应用程序中获取 URI 之前,我会将选定的图片移动到应用程序文件夹)
然而,当我从数据库中检索 URI 字符串,将它们解析回 URI,并尝试在 RecyclerView 中设置图像时,此方法不再有效。
这是来自 RecyclerAdapter 的 OnBindViewHolder()
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
holder.weight.setText(mWeights.get(position).toString());
holder.location.setText(mLocations.get(position));
holder.confidence.setText(mConfidences.get(position).toString());
// Open item view
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ItemView.class);
// Attach additional data to intent
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("location", mLocations.get(position));
intent.putExtra("confidence", mConfidences.get(position));
intent.putExtra("weight", mWeights.get(position));
mContext.startActivity(intent);
}
});
}
检查变量时 URI 似乎没问题。可能是什么原因造成的,我怎样才能在 RecyclerView 中设置图像?
谢谢
编辑
这是适配器代码
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private static final String TAG = "RecyclerViewAdapter";
private ArrayList<ArrayList<String>> mImages;
private ArrayList<Float> mWeights;
private ArrayList<Float> mConfidences;
private ArrayList<String> mLocations;
private ArrayList<Integer> mSharkEntryIds;
private Context mContext;
private Uri tempUri;
public RecyclerViewAdapter(Context context, ArrayList<Integer> ids, ArrayList<ArrayList<String>> images, ArrayList<Float> weights
, ArrayList<Float> confidences, ArrayList<String> locations) {
this.mContext = context;
this.mSharkEntryIds = ids;
this.mImages = images;
this.mWeights = weights;
this.mLocations = locations;
this.mConfidences = confidences;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called.");
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
}
holder.weight.setText(mWeights.get(position).toString() + " kg");
holder.location.setText(mLocations.get(position));
holder.confidence.setText(mConfidences.get(position).toString() + " %");
// Open item view
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ItemView.class);
// Attach additional data to intent
intent.putExtra("id", mSharkEntryIds.get(position));
intent.putExtra("image_url", mImages.get(position));
intent.putExtra("location", mLocations.get(position));
intent.putExtra("confidence", mConfidences.get(position));
intent.putExtra("weight", mWeights.get(position));
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mImages.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
CircleImageView image;
TextView weight;
TextView confidence;
TextView location;
RelativeLayout parentLayout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.thumbnail);
weight = itemView.findViewById(R.id.biomassText);
confidence = itemView.findViewById(R.id.confidenceText);
location = itemView.findViewById(R.id.locationText);
parentLayout = itemView.findViewById(R.id.parent_layout);
}
}
}
这是我初始化 RecyclerView 的代码
// Vars
private ArrayList<Integer> mSharkEntryIds = new ArrayList<>();
private ArrayList<String> mLocations = new ArrayList<>();
//private ArrayList<String> mImageUrls = new ArrayList<>();
private ArrayList<ArrayList<String>> mImagePaths = new ArrayList<>();
private ArrayList<Float> mConfidences = new ArrayList<>();
private ArrayList<Float> mWeights = new ArrayList<>();
private DatabaseHelper mDatabaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
mDatabaseHelper = new DatabaseHelper(this);
Log.d(TAG, "onCreate: started");
//initImageBitmaps();
// Populate list view
Cursor data = mDatabaseHelper.getSharkEntriesFromDatabase();
while(data.moveToNext()){
mSharkEntryIds.add(data.getInt(0));
mWeights.add(data.getFloat(1));
mLocations.add(data.getString(2));
mConfidences.add(data.getFloat(3));
}
Log.d(TAG, "onCreate: test");
// Get associated image paths
ArrayList<String> photosForEntry;
for(Integer id : mSharkEntryIds){
data = mDatabaseHelper.getPhotosWithSharkID(id);
photosForEntry = new ArrayList<>();
while(data.moveToNext()){
photosForEntry.add(data.getString(0));
}
mImagePaths.add(photosForEntry);
}
initRecyclerView();
}
private void initRecyclerView(){
Log.d(TAG, "initRecyclerView: init recyclerview");
RecyclerView recyclerView = findViewById(R.id.recycler_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mSharkEntryIds, mImagePaths, mWeights, mConfidences, mLocations);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
我认为你做错了,我假设你在 mImages
你看到你的这一部分了吗onBindViewHolder
:
...................
// Load only first image for now
if(mImages.get(position).size() > 0) {
tempUri = Uri.parse(mImages.get(position).get(0));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
..................
改成这样:
........
// Load only first image for now
if(position == 0) {
tempUri = Uri.parse(mImages.get(position));
// Make glide work with image
Glide.with(mContext)
.asBitmap()
.load(tempUri)
.into(holder.image);
// With regular ImageView
holder.imageViewTest.setImageURI(tempUri);
}
..............
更新:
你的代码看起来不错,你说 Uri 出现在列表中,所以我的猜测是在设置适配器之前设置布局管理器:
我的意思是在你的 initRecyclerView()
:
..........
//add this first
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//add this next
recyclerView.setAdapter(adapter);
......
我已经解决了这个问题:
日志包含此消息:
java.lang.SecurityException(Permission Denial: opening provider com.android.providers.downloads.DownloadStorageProvider from ProcessRecord{985e802 27308:com.oshea.sharkbiomass/u0a82} (pid=27308, uid=10082) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs)
问题出在我的 select 照片按钮的点击侦听器中。
// Select photo button listener
btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 1);
}
});
我将其更改为:
// Select photo button listener
btnSelectPhotos.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
startActivityForResult(intent, 1);
}
});
(将 ACTION_GET_CONTENT 更改为 ACTION_OPEN_DOCUMENT)并且有效。