0

I am trying to load images from my phone into my recyclerview.

So far, I have created a recyclerview.adapter, and a gridlayoutmanager, and attached them to my recyclerview. I can successfully retrieve full paths of the images and add them to the adapter using an async task.

 @Override
 protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_gallery);

    settingUp();
    run();

}


public void settingUp(){

    //setting up recycler view
    recyclerView = findViewById(R.id.imageGallery);
    recyclerView.setHasFixedSize(true);

    //setting up recyclerview layout manager
    RecyclerView.LayoutManager layoutManager = new      GridLayoutManager(getApplicationContext(),2);
    recyclerView.setLayoutManager(layoutManager);

    //setting up recyclerview adapter
    adapter = getInstance(getApplicationContext());

    recyclerView.setAdapter(adapter);

    // instance of load task
    loadTask = new LoadTask();
}

private void run() {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
    }
    else
    {
        loadTask.execute();
    }
}

 /**
 * Loads the images into the cursor using a background thread
 */

private class LoadTask extends AsyncTask<Void,Void, Cursor>
{

    // images are loaded into the cursor here, in the background.
    @Override
    protected Cursor doInBackground(Void... voids) {
        loadImagesIntoCursor();
        return imageCursor;
    }

    // this method runs after doInBackground finishes
    @Override
    protected void onPostExecute(Cursor cursor) {
        transferImagesToAdapter(cursor);
    }
}

//*********************************************************************************************************

/**
 * Loads all the Images from external storage into the cursor.
 */
private void loadImagesIntoCursor()
{
    imageCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA}, null, null,
            MediaStore.Images.Media.DATE_ADDED + " DESC");
}

 private void transferImagesToAdapter(Cursor imageCursor)
{
    String path;
    if(imageCursor != null)
    {
        imageCursor.moveToFirst();
        while (!imageCursor.isAfterLast()){
            path =       imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
            adapter.add(path);
            imageCursor.moveToNext();
        }
        imageCursor.close();

    }

}

/** MY ADAPTER CLASS **/

class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder>{

private ArrayList<String> images;
//private static ImageAdapter singleton = null;
Context context;

public ImageAdapter(Context context, ArrayList<String> paths)
{
    images = paths;
    this.context = context;
}

public ImageAdapter(Context context)
{

    this.context = context;
}



//--------- OVERRIDE METHODS ---------------------------------------------
@NonNull
@Override
public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_layout,parent);
    return new ImageViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
    holder.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
    // load image into image holder view using picasso library
    Picasso.with(context).load(images.get(position)).into(holder.image);
}

@Override
public int getItemCount() {
    return images.size();
}

//------------------------------------------------------------------------

public void add(String path){
    this.images.add(path);
}

//------------------------------------------------------------------------

public class ImageViewHolder extends RecyclerView.ViewHolder{
    protected ImageView image;
    public ImageViewHolder(View view){
        super(view);
        this.image = view.findViewById(R.id.img);
    }
}

}

However, after adding the imagepaths I have no clue as to what trigger the onCreateViewHolder and onBindViewHolder methods in the adapter which will display my images in the recyclerview. Any help please!

Brandon Tupiti
  • 251
  • 1
  • 3
  • 16

3 Answers3

0

Two thing you need to do to update RecyclerView list item.

  1. Update your data list inside your adapter
  2. Notify dataset change.
 private void transferImagesToAdapter(Cursor imageCursor)
{
    String path;
    if(imageCursor != null)
    {
        imageCursor.moveToFirst();
        while (!imageCursor.isAfterLast()){
            path =       imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
            adapter.add(path); // If it update data list in your adapter then fine.
            adapter.notifyDataSetChanged(); // It will do all the callbacks and update your screen.

            imageCursor.moveToNext();
        }
        imageCursor.close();

    }

}
CodeWithVikas
  • 1,105
  • 9
  • 33
0

Recycler View and the Recycler View Adapter are two different things. Simply adding data to your Adapter will do nothing but fatten up the Adapter object.

The Recycler View has to be told that the Adapter's data state has changed and that the Recycler View should pull the updated data from the Adapter.

There are 2 ways to do it:

  1. Calling the method notifyDataSetChanged method after putting in all the data changes in the Adapter's data source.
  2. Using the DiffUtil

The difference between the above mentioned techniques is that notifyDataSetChanged totally resets the data to the current data source's data, all of it whereas DiffUtil changes only the data that has been updated and doesn't bother with the ones that haven't been changed.

So, if your data source has around a 1000 objects and you change only one if them, it's better to use DiffUtils because notifyDataSetChanged will recreate all the views even the ones that didn't change, which affects performance.

Also, the problem with @vikas jha's answer is that if there are many images, there will be substantial performance bottlenecks because for even a single image addition, the entire data source will be reloaded and the fact that it's inside a loop aggravates the problem. So move the adapter.notifyDataSetChanged(); call outside the loop. I'm assuming that you have a List of images as your data source, where the add method simply adds an image to the List.

It's best to have an overloaded add method for your adapter which accepts a list of images, append them to the end of the existing list of images in your adapter (assuming that you have previously loaded images) and then calling notifyDataSetChanged.

Shankha057
  • 1,296
  • 1
  • 20
  • 38
0

your activity class

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    run();
    setContentView(R.layout.activity_gallery);
    settingUp();
}


public void settingUp(){

    //setting up recycler view
    recyclerView = findViewById(R.id.imageGallery);

    //setting up recyclerview layout manager
    RecyclerView.LayoutManager layoutManager = new      GridLayoutManager(getApplicationContext(),2);
    recyclerView.setLayoutManager(layoutManager);

    // instance of load task
    loadTask = new LoadTask();
}

private void run() {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
    }
  }

 /**
 * Loads the images into the cursor using a background thread
 */

private class LoadTask extends AsyncTask<Void,Void, List<String>
{ 

    // images are loaded into the cursor here, in the background.
    @Override
    protected List<String> doInBackground(Void... voids) {
        return getAllImages();
    }

    // this method runs after doInBackground finishes
    @Override
    protected void onPostExecute(List<String imagesList>) {
        ImageAdapter imageAdapter = new ImageAdapter(getActivity, magesList);
        recyclerview.setAdapter(imageAdapter);
    }
}

//*********************************************************************************************************

/**
 * Loads all the Images from external storage into the cursor.
 */
private void getAllImages()
{
   List<String> imagesList = new ArrayList<>();
   Cursor imageCursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA}, null, null,
            MediaStore.Images.Media.DATE_ADDED + " DESC");
    if(imageCursor != null)
    {
        imageCursor.moveToFirst();
        while (!imageCursor.isAfterLast()){

    String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
            imagesList.add(path);
            imageCursor.moveToNext();
        }
        imageCursor.close();

    }
    return imagesList;
}

Your adapter

/** MY ADAPTER CLASS **/

class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder>{

private List<String> images;
Context context;

public ImageAdapter(Context context, List<String> paths)
{
    this.images = paths;
    this.context = context;
}

//--------- OVERRIDE METHODS ---------------------------------------------
@NonNull
@Override
public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_layout,parent);
    return new ImageViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
    holder.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
    // load image into image holder view using picasso library
    Picasso.with(context).load(images.get(position)).into(holder.image);
}

@Override
public int getItemCount() {
    return images.size();
}

public class ImageViewHolder extends RecyclerView.ViewHolder{
    protected ImageView image;
    public ImageViewHolder(View view){
        super(view);
        this.image = view.findViewById(R.id.img);
    }
}
kam1234
  • 574
  • 2
  • 5
  • 9