When I try to display an image taken from the camera on a recyclerview, the image appears multiple lines

166
July 07, 2019, at 9:50 PM

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();
}

}

Answer 1

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);
} 
Rent Charter Buses Company
READ ALSO
How to use different tables for entity on runtime using JPA?

How to use different tables for entity on runtime using JPA?

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

173
Faulty code from book on viewing bubble sort

Faulty code from book on viewing bubble sort

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

197
How to pass command line arguments to Junit Test

How to pass command line arguments to Junit Test

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

1677