I am working on a scavenger hunt app that displays a list of the items to photograph in a recyclerview. The list is loaded from from Firebase. There is an onClickListener so that when one of the items in the list is clicked on, it opens up the camera, then you take a photo, and I want to display the image next to the item that was selected. Right now when I take a photo, it gets displayed on multiple lines in the recyclerview. For example, if I select the 0th item in the list and take a picture, the picture will be displayed on both the 0th item and the 11th item in the list. I am trying to get it to be displayed on just the selected item.
I have tried using adapter.notifyDataSetChanged() and adapter.notifyItemChanged(tmpPosition) after adding the image but both of those display the image on multiple lines. I know that just the one item in the list gets updated. The way that I am doing it right now is that I made a global int variable called tmpPosition. When you click an item in the list, I set tmpPosition equal to the index of the item picked. Then in onActivityResult, I set the image using:
scavengerHuntItemsList.get(tmpPosition).setScavengerHuntImage(imageTaken);
adapter.notifyDataSetChanged();
From my MainActivity This is the onClickListener that opens up the camera
((ScavengerHuntRecyclerAdapter) dapter).setOnItemClickListener(new
ScavengerHuntRecyclerAdapter.ClickListener() {
@Override
public void onItemClick(int position, View v) {
//Here I am saving the position of the item so later I can update the correct index in the list
tmpPosition = position;
dispatchTakePictureIntent();
}
});
scavengerHuntMainRecyclerView.setAdapter(adapter);
}
my camera stuff from MainActivity
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
photoFile = createPhotoFile();
if (photoFile != null) {
pathToFile = photoFile.getAbsolutePath(); //gets the path to the image
Uri photoURI = FileProvider.getUriForFile(ScavengerHuntMainActivity.this, "com.example.test", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
private File createPhotoFile() {
String name = new SimpleDateFormat(Constants.PHOTO_DATE_NAME_FORMAT).format(new Date());
File storageDir = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); //the directory where we will be storing the pic
File image = null;
try {
image = File.createTempFile(name, ".jpg", storageDir);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bitmap imageTaken = BitmapFactory.decodeFile(pathToFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
imageTaken.compress(Bitmap.CompressFormat.JPEG, Constants.IMAGE_THUMBNAIL_QUALITY, bos);
if (tmpPosition > -1) {
scavengerHuntItemsList.get(tmpPosition).setScavengerHuntImage(imageTaken);
adapter.notifyDataSetChanged();
tmpPosition = -1;
}
}
}
Below is my recyclerview adapter I set the image in onBindViewHolder
public class ScavengerHuntRecyclerAdapter extends RecyclerView.Adapter<ScavengerHuntRecyclerAdapter.ScavengerHuntViewHolder> {
private ArrayList<ScavengerHuntItem> scavengerHuntArrayList;
private static ClickListener clickListener;
private RecyclerView.AdapterDataObserver dataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
super.onItemRangeChanged(positionStart, itemCount, payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
super.onItemRangeMoved(fromPosition, toPosition, itemCount);
}
};
public static class ScavengerHuntViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView scavengerHuntLayoutTextView;
public ImageView scavengerHuntLayoutImageView;
public ScavengerHuntViewHolder(@NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(this);
scavengerHuntLayoutTextView = itemView.findViewById(R.id.scavengerHuntLayoutTextView);
scavengerHuntLayoutImageView = itemView.findViewById(R.id.scavengerHuntLayoutImageView);
}
@Override
public void onClick(View v) {
clickListener.onItemClick(getAdapterPosition(), v);
}
}
public void setOnItemClickListener(ClickListener clickListener) {
ScavengerHuntRecyclerAdapter.clickListener = clickListener;
}
public interface ClickListener {
void onItemClick(int position, View v);
}
public ScavengerHuntRecyclerAdapter(ArrayList<ScavengerHuntItem> scavengerHuntArrayList) {
this.scavengerHuntArrayList = scavengerHuntArrayList;
}
@NonNull
@Override
public ScavengerHuntViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.scavenger_hunt_list_layout, viewGroup, false);
ScavengerHuntViewHolder scavengerHuntViewHolder = new ScavengerHuntViewHolder(view);
return scavengerHuntViewHolder;
}
@Override
public void onBindViewHolder(@NonNull ScavengerHuntViewHolder scavengerHuntViewHolder, int i) {
ScavengerHuntItem currentItem = scavengerHuntArrayList.get(i);
scavengerHuntViewHolder.scavengerHuntLayoutTextView.setText(currentItem.getDescription());
if (currentItem.getScavengerHuntImage() != null) {
scavengerHuntViewHolder.scavengerHuntLayoutImageView.setImageBitmap(currentItem.getScavengerHuntImage());
Log.d("in adapter UPDATED POS", "position = " + i);
}
}
@Override
public int getItemCount() {
return scavengerHuntArrayList.size();
}
}
This happens because RecyclerView
reuses it's views(items/cells). The contents of cell 1 thereby get reused in cell 11 causing the photo to appear multiple times.
This can be resolved by clearing the ImageView
content.
if (currentItem.getScavengerHuntImage() != null) {
scavengerHuntViewHolder.scavengerHuntLayoutImageView.setImageBitmap(currentItem.getScavengerHuntImage());
Log.d("in adapter UPDATED POS", "position = " + i);
} else {
scavengerHuntViewHolder.scavengerHuntLayoutImageView.setImageResource(android.R.color.transparent);
//or
//scavengerHuntViewHolder.scavengerHuntLayoutImageView.setImageBitmap(null);
}
Firebase Cloud Functions: PubSub, "res.on is not a function"
TypeError: Cannot read properties of undefined (reading 'createMessageComponentCollector')
I am building a COTs product which records sales dataSince it will be used by different business owners i want to save the sales data to the owner specific tables
I am running example code from this book, Data Structures and Algorithms in Java (2nd Edition) - LaFore, that is not behaving as expectedIn the third chapter there is example code for running a visual on bubble sorts
I have a main class that accepts command line arguments and I am passing this parameter to another classNow i have to test the myClass with parameters