0

I am trying to fetch image from my firebase storage of which location is stored in a field of firestore doc, convert it into a bitmap and then set it to recycler view imageview.

This is my onBindViewHolder method :

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

    //This is an executor task for fetching image from firebase storage
    setImageTask = Executors.newFixedThreadPool(4);

    //contactToShow is a contact class object which has id, name and ph no. as fields
    contactToShow = Objects.requireNonNull(contactList.get(position));
    //setting name and ph no in recycler view
    holder.name.setText(contactToShow.getName());
    holder.phoneNumber.setText(contactToShow.getPhoneNumber());

    //This is for fetching image location from firebase document for corresponding contact
    db.collection("ContactData").document(String.valueOf(contactToShow.getId())).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
        @Override
        public void onSuccess(DocumentSnapshot documentSnapshot) {
            //this fetches location and saves it in contactProfileImageLocation
            contactProfileImageLocation = documentSnapshot.getString("IMAGE LOCATION");
            Log.d("AppLogs", "ImageLocFromAdapter : " + contactProfileImageLocation);

            //executor class for fetching image from location got from above code
            setImageTask.execute(() -> {
                
                //imageRef is a storage reference and storage is a firebase storage instance
                //These are the following Global Variables :
                //    FirebaseFirestore db = FirebaseFirestore.getInstance();
                //   FirebaseStorage storage = FirebaseStorage.getInstance();
                //Contact contactToShow;
                //String contactProfileImageLocation;
                //ExecutorService setImageTask;
                
                //setting imageRef
                imageRef = storage.getReference(contactProfileImageLocation);
                try {
                    //creating a local file to store downloaded image
                    File localFile = File.createTempFile("tempFile",".jpg");
                    //downloading image
                    imageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
                        @Override
                        public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
                            //creating bitmap out of image file on success
                            Bitmap bitmap = BitmapFactory.decodeFile(localFile.getAbsolutePath());
                            //setting bitmap to image view
                            holder.contactImageView.setImageBitmap(bitmap);
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }

            });
        };
    });
}

and I am getting this error :

2022-07-31 16:46:49.872 19977-19977/com.example.contactroom E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.contactroom, PID: 19977
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference
    at com.example.contactroom.adapter.RecyclerViewAdapter$1$1.onSuccess(RecyclerViewAdapter.java:106)
    at com.example.contactroom.adapter.RecyclerViewAdapter$1$1.onSuccess(RecyclerViewAdapter.java:102)
    at com.google.firebase.storage.StorageTask.lambda$new$0$com-google-firebase-storage-StorageTask(StorageTask.java:123)
    at com.google.firebase.storage.StorageTask$$ExternalSyntheticLambda12.raise(Unknown Source:6)
    at com.google.firebase.storage.TaskListenerImpl.lambda$onInternalStateChanged$2$com-google-firebase-storage-TaskListenerImpl(TaskListenerImpl.java:90)
    at com.google.firebase.storage.TaskListenerImpl$$ExternalSyntheticLambda2.run(Unknown Source:6)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

2022-07-31 16:46:49.893 19977-19977/com.example.contactroom I/Process: Sending signal. PID: 19977 SIG: 9

My Debug log is showing :

2022-07-31 16:19:58.028 19382-19382/com.example.contactroom D/AppLogs: ImageLocFromAdapter : images/1659264211278

this means image is getting saved on firebase and location for the corresponding contact is being fetched correctly and getting stored in contactProfileImageLocation

Then where i am going wrong ?

ViewHolder Class :

ViewHolderClass

ContactRow.xml :

ContactRow.xml

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
vibhum mohan
  • 25
  • 1
  • 6
  • Please tell me if anything else is needed :) – vibhum mohan Jul 31 '22 at 11:34
  • Also i have initialized image view with find view by id still its giving NPE – vibhum mohan Jul 31 '22 at 12:03
  • 1) can you show the holder class where you set the view, 2) can you show the row xml, 3) have you tried using something like Glide or Picasso to do this? It would be a lot easier than writing your own image loader. – Tyler V Jul 31 '22 at 13:53
  • @TylerV Attaching View holder Class in above question – vibhum mohan Jul 31 '22 at 14:32
  • In general, you should post code/text as images. I don't see anything that would make it null from what you posted... If you log `holder.contactImageView` before launching the Firebase call is it null there? (or right before you call `setImageTask.execute`) – Tyler V Jul 31 '22 at 14:39
  • @TylerV I've pasted xml also as image if you say i can edit it – vibhum mohan Jul 31 '22 at 14:42
  • Also, I would expect your current code to give you an error from modifying views off the UI thread even without the NPE. Try using [Glide or Picasso](https://stackoverflow.com/questions/72930584/firestore-recycleview-image-holder/72930828#72930828) instead of your own thread pool. – Tyler V Jul 31 '22 at 14:46
  • One other note, you seem to be using adapter class variables in this, which is dangerous when making async calls. In general you should only use local variables in `onBindViewHolder` since the class members will be reset when it binds a different row. – Tyler V Jul 31 '22 at 14:55
  • @TylerV ohh, yes you're right, I shouldn't do that I'll implement local variables in onBindViewHolder and picasso library... thanks for the info : ) I'll use and tell if it works or not. Thanks a ton! – vibhum mohan Jul 31 '22 at 18:51
  • Glad to help. If you use Glide you can also pass a firebase StorageReference to it directly to load (makes the code simpler). There's some details on that [here](https://stackoverflow.com/questions/48762263/using-firebase-storage-image-with-glide). – Tyler V Jul 31 '22 at 18:57
  • @TylerV thanks for your help, I dont how but without doing any changes code started to work properly... but as you said I changed variables from global to local and used picasso it is now working fine... – vibhum mohan Aug 02 '22 at 07:10
  • @TylerV I have an issue though, every time i add contact it uploads the image data on firestore and then when the add contact activity finishes the main activity is called recycler view fetches data back from the cloud to set to the corresponding contact but the contact image does not appear (I think it is because contact row is created quickly but fetching image from cloud takes time) so thats why i guess pic does not set but when i restart the app that is when main activity is recreated all the contact rows have their images.... how can i fix this ? – vibhum mohan Aug 02 '22 at 07:14

0 Answers0