androidfirebase-realtime-databaseandroid-viewholderfirebase-storagefastadapter

ViewHolder not setting the string as text of a TextView. Please see details


I am using FastAdapter in my android project.

This is how I am using it:

    public class HRequest extends AbstractItem<HRequest, HRequest.ViewHolder> {

        public String imageURL;

        public HRequest() {

        }

        public HRequest(String imageURL) {
            this.imageURL = imageURL;
        }

        // Fast Adapter methods
        @Override
        public int getType() {
            return R.id.recycler_view;
        }
        @Override
        public int getLayoutRes() {
            return R.layout.h_request_list_row;
        }
        @Override
        public void bindView(ViewHolder holder) {
            super.bindView(holder);

            holder.imageURL.setText(imageURL);

        }
        // Manually create the ViewHolder class
        protected static class ViewHolder extends RecyclerView.ViewHolder {

            TextView imageURL;

            public ViewHolder(View itemView) {
                super(itemView);
                imageURL = (TextView)itemView.findViewById(R.id.imageURL);

if (!imageURL.getText().toString().isEmpty()) {

                Toast.makeText(itemView.getContext(), imageUID.getText().toString(), Toast.LENGTH_SHORT).show();

if (imageURL.getText().toString().startsWith("https://firebasestorage.googleapis.com/") || imageURL.getText().toString().startsWith("content://")) {
                    Picasso.with(itemView.getContext())
                            .load(imageURL.getText().toString())
                            .into(homelessImage);
                } else {
                    Toast.makeText(itemView.getContext(), "some problem", Toast.LENGTH_SHORT).show();
                }

            } else {
                Toast.makeText(itemView.getContext(), "no imageUID found", Toast.LENGTH_SHORT).show();
            }

            }
        }

    }

Here is R.layout.h_request_list_row:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              xmlns:ads="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              xmlns:tools="http://schemas.android.com/tools">

            <TextView
                android:id="@+id/imageURL"
                android:text="imageURL"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

</LinearLayout>

The problem here is that imageURLis not getting set as the imageURL retrieved from the database but as imageURL defined in the layout file and thus no image is getting downloaded. I followed this gist: https://gist.github.com/puf/f49a1b07e92952b44f2dc36d9af04e3c

I am sure that String imageURL here:

public HRequest(String imageURL) {
            this.imageURL = imageURL;
        }

has successfully fetched the urls retrieved from Firebase database.

Please let me know what's going wrong here.

Sorry for bad formatting of the question. I'm still a beginner here.


Solution

  • The problem is that you try to load the image in the ViewHolder.

    At the time when the ViewHolder is created there was not yet an ImageUrl set via the bindView method, as this will be called after the ViewHolder was created.

    So you have to move the image loading logic to the bindView method. The ViewHolder is just there for the RecyclerView to efficiently cache the views, have listeners defined and everything which keeps "fixed" over all the view's which are used in the RecyclerView.

    To get your code working you have to change it as following:

    public class HRequest extends AbstractItem < HRequest, HRequest.ViewHolder > {
        public String imageURL;
        public HRequest() {}
        public HRequest(String imageURL) {
            this.imageURL = imageURL;
        }
        // Fast Adapter methods
        @Override
        public int getType() {
            return R.id.recycler_view;
        }
        @Override
        public int getLayoutRes() {
            return R.layout.h_request_list_row;
        }
        @Override
        public void bindView(ViewHolder holder) {
            super.bindView(holder);
            holder.imageURL.setText(imageURL);
    
            if (!imageURL.isEmpty()) {
                Toast.makeText(holder.itemView.getContext(), imageURL, Toast.LENGTH_SHORT).show();
                if (imageURL.startsWith("https://firebasestorage.googleapis.com/") || imageURL.startsWith("content://")) {
                    Picasso.with(holder.itemView.getContext()).cancelRequest(holder.myImageView);
                    Picasso.with(holder.itemView.getContext()).load(imageURL).into(holder.myImageView);
                } else {
                    Toast.makeText(holder.itemView.getContext(), "some problem", Toast.LENGTH_SHORT).show();
                }
            } else {
                Toast.makeText(holder.itemView.getContext(), "no imageUID found", Toast.LENGTH_SHORT).show();
            }
        }
        // Manually create the ViewHolder class
        protected static class ViewHolder extends RecyclerView.ViewHolder {
            TextView imageURL;
            ImageView myImageView;
            public ViewHolder(View itemView) {
                super(itemView);
                imageURL = (TextView) itemView.findViewById(R.id.imageURL);
                myImageView = (ImageView) itemView.findViewById(R.id.myImageView);
            }
        }
    }
    

    So basically the RecyclerView will call bindView each time the item will come visible in the list and the data has to be applied to it. Also add the ImageView itself to the ViewHolder and you should also cancel the request on the ImageView with picasso first before a new image is getting applied (I added this code snippet too)