1

just a quick explanation of my project before I get to my question so you can get the gist of everything. I'm currently working on this real-estate application with android and Firebase. I have been using Firebase to store my data of my app and to authenticate users. I can add real estate objects to the database and retrieve the all the added real estates in a list view. When I click on one list item I'm getting a more detailed version of the real estate. The details of the real estates are shown in four different tabs. In one of the tabs I give the user the oppertunity to add attachments like pictures to the real estate. I added the functionality to add the pictures just fine. They are stored in the database as shown in the following screenshot.

The eBncv5ke05ZxR32AiRoP9gSyPkO2 is the user_id and the "-L38Qe8GEo33i5roKOCi" the Realestate id. the keys are the name of the image and the values the urls.

Here is the code that shows how I add the pictures to the database:

private void saveImage() {

    // get the expose id
    bundle = getArguments();
    immoID = bundle.getString("exposeID");
    Toast.makeText(getContext(), immoID, Toast.LENGTH_SHORT).show();


    // get an reference to the current user and his id
    user = FirebaseAuth.getInstance().getCurrentUser();
    user_id = user.getUid();

    imageName = imageNameInput.getText().toString();

    if (!TextUtils.isEmpty(imageName)) {

        //displaying progress dialog while image is uploading
        final ProgressDialog progressDialog = new ProgressDialog(getContext());
        progressDialog.setTitle("Bild wird hochgeladen");
        progressDialog.show();



        // uploading the Picture
        pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS).child(immoID);
        pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user.getUid()).child(immoID);
        //checking if file is available
        if (filePath != null) {


            //getting the storage reference
            StorageReference sRef = pictureStorageRef.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));

            //adding the file to reference
            sRef.putFile(filePath)
                    .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {


                            String imageName = imageNameInput.getText().toString().trim();
                            String imageDownloadURL = taskSnapshot.getDownloadUrl().toString();

                            //creating the upload object to store uploaded image details
                            PictureUpload upload = new PictureUpload(imageName, imageDownloadURL);


                            //adding an upload to firebase database
                            pictureDataRef.child(imageName).setValue(imageDownloadURL);
                            string_immo_image_url = imageDownloadURL;


                            //dismissing the progress dialog
                            progressDialog.dismiss();

                            changeFragment();


                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception exception) {
                            progressDialog.dismiss();
                            Toast.makeText(getContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
                        }
                    })
                    .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                        @Override
                        public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                            //displaying the upload progress
                            double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                            progressDialog.setMessage(((int) progress) + "% wurden hochegeladen");
                        }
                    });
        }
    }else{
        imageNameInput.setError("Geben Sie einen Namen ein");
        imageNameInput.requestFocus();

    }
}

Now I'm trying to show the pictures using Glide inside my Fragment in a ListView. Therefore I added an adapter for my ListView AttachmentList

public class AttachmentList extends ArrayAdapter <PictureUpload> {

List <PictureUpload> pictureUploads;
DatabaseReference pictureDatabase;
FirebaseUser user;
String userid;
private Activity context;

// Constructor
public AttachmentList (Activity context, List<PictureUpload> pictureUploads){
    super (context, R.layout.layout_expose_list, pictureUploads);
    this.context = context;
    this.pictureUploads = pictureUploads;

}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    // inflate the custom layout for the listitems
    LayoutInflater inflater= context.getLayoutInflater();
    final View listViewItem = inflater.inflate(R.layout.layout_expose_list, null, true);

    // get the data item for this position
    PictureUpload pictureUpload = pictureUploads.get(position);


    user = FirebaseAuth.getInstance().getCurrentUser();
    userid = user.getUid();


    // get references to the view elements in the layout for populating the data
    TextView textViewTitle = listViewItem.findViewById(R.id.imageNameDisplay);
    ImageView attachmentImage = listViewItem.findViewById(R.id.attachmentImage);


    // set the most relevant information of the immo object to the textviews
    textViewTitle.setText(pictureUpload.getName());

    Glide.with(getContext()).load(pictureUpload.getUrl()).into(attachmentImage);


    // return the listview item to render
    return listViewItem;
}
}

The PictureUpload class looks like the following:

public class PictureUpload {

public String name;
public String url;

// Default constructor required for calls to
// DataSnapshot.getValue(User.class)
public PictureUpload() {
}

public PictureUpload(String name, String url) {
    this.name = name;
    this.url = url;
}

public String getName() {
    return name;
}

public String getUrl() {
    return url;
}
}

And here is the code to the Fragment where I'm trying to display the list:

package com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments;



public class AttachmentTabFragment extends Fragment {
private static final String TAG = "ATTACHMENT_TAB";

FirebaseUser user;
String user_id;

Bundle bundle, newBundle;
String immoID;

// Button to add Attachments to the Expose
Button addAtachments;

private DatabaseReference immoDataRef, pictureDataRef, contactDataRef;
private StorageReference pictureStorageRef;


ListView show_all_attachments_list;
List<PictureUpload> pictureUploads;

public AttachmentTabFragment() {
    // Required empty public constructor
}


// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_attachment_tab, container, false);

    // get reference to the view elements
    addAtachments = view.findViewById(R.id.addAtachments);
    show_all_attachments_list = view.findViewById(R.id.show_all_attachments_list);


    // get the current user
    user = FirebaseAuth.getInstance().getCurrentUser();
    user_id = user.getUid();


    // get the expose id
    bundle = getArguments();
    immoID = bundle.getString("exposeID");

    // set the on ClickListener to the addAttachments Button
    addAtachments.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // change the fragment
            Fragment addAttachmentFragment = new AddAttachmentFragment();
            FragmentManager manager = getFragmentManager();
            newBundle = new Bundle();
            newBundle.putString("exposeID", immoID);
            addAttachmentFragment.setArguments(newBundle);
            manager.beginTransaction().replace(R.id.content_frame, addAttachmentFragment).addToBackStack(null).commit();

        }
    });

    // get reference to the database and storage
    immoDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_IMMOBILIEN).child(user_id).child(immoID);
    pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user_id).child(immoID);
    contactDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_CONTACTS).child(user_id).child(immoID);
    pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS);


    //return the view
    return view;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.showexposemenu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    final FragmentManager manager = getFragmentManager();
    // get the expose id
    bundle = getArguments();
    immoID = bundle.getString("exposeID");


    switch (item.getItemId()) {
        case R.id.edit_expose:
            Toast.makeText(getContext(), "Expose bearbeiten geklickt.", Toast.LENGTH_SHORT).show();

            // put the immoID into new Bundle
            newBundle = new Bundle();
            newBundle.putString("exposeID", immoID);
            // get a new instance of editExposeFragment
            Fragment editExpose = new EditExposeFragment();
            // set the newBundle as Arguments to the fragement
            editExpose.setArguments(newBundle);
            // switch the fragment
            manager.beginTransaction().replace(R.id.content_frame, editExpose).commit();

            break;
        case R.id.delete_expose:
            Toast.makeText(getContext(), "Expose wurde gelöscht.", Toast.LENGTH_SHORT).show();

            immoDataRef.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    immoDataRef.removeValue();
                    pictureDataRef.removeValue();
                    contactDataRef.removeValue();

                    Fragment showAllExpose = new ShowAllExposeFragment();
                    manager.beginTransaction().replace(R.id.content_frame, showAllExpose).commit();
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });

            break;

    }
    return super.onOptionsItemSelected(item);
}

@Override
public void onStart() {
    super.onStart();
    // attaching the ValueEventListener
    pictureDataRef.addValueEventListener(new ValueEventListener() {


        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // check if there are values in the database
            if (dataSnapshot.getValue() != null) {

                // clear the list of immos
                pictureUploads.clear();

                for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
                    // getting the immo
                    PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
                    // adding the immo to the list
                    pictureUploads.add(pictureUpload);
                }

                // creating the List Adapter and add him to the Listview
                final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
                show_all_attachments_list.setAdapter(attachmentAdapter);


            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {


        }

    });


}
}

when I try to run my app on my device I'm always getting the following error:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.webgalaxie.blischke.bachelortakesix, PID: 14901
                  java.lang.NullPointerException: Attempt to invoke interface method 'void java.util.List.clear()' on a null object reference
                      at com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments.AttachmentTabFragment$3.onDataChange(AttachmentTabFragment.java:191)
                      at com.google.android.gms.internal.zzegf.zza(Unknown Source)
                      at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source)
                      at com.google.android.gms.internal.zzeig.run(Unknown Source)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6682)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

Does anyone have an idea why this happens. I'm a bit stuck on this issue.

Thank you very much for your help. If you need more information on the project do not hesitate to ask.

I also have the code to the project on GitHub if you need more information. Link to GitHub: https://github.com/BexxBl/BachelorTakeSix

Bexx
  • 47
  • 1
  • 10
  • `pictureUploads =new ArrayList<>();` inside `AttachmentTabFragment()` – Pavneet_Singh Jan 18 '18 at 16:19
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Pavneet_Singh Jan 18 '18 at 16:21

1 Answers1

1

That's because in your onStart() method you're calling clear() on a list that hasn't been initialized yet. You should initialize it instead of clearing it:

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            // check if there are values in the database
            if (dataSnapshot.getValue() != null) {

                // clear the list of immos
                pictureUploads = new ArrayList();

                for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
                    // getting the immo
                    PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
                    // adding the immo to the list
                    pictureUploads.add(pictureUpload);
                }

                // creating the List Adapter and add him to the Listview
                final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
                show_all_attachments_list.setAdapter(attachmentAdapter);


            }

        }

EDIT: The value of your snapshot is a String. You need to get the key as well and pass it to your PictureUpload class.

String val = postSnapshot.getValue(String.class);
PictureUpload pictureUpload = new PictureUpload(postSnapshot.getKey(), val);
pictureUploads.add(pictureUpload);
  • okay. I did that but now it tells me the following `com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.webgalaxie.blischke.bachelortakesix.models.PictureUpload` on the following line `PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);` any idea why??? thank you for your help – Bexx Jan 18 '18 at 17:24
  • That's because that DataSnapshot contains a `String` and you're trying to cast it to `PictureUpload`. Check my edited answer – Rosário Pereira Fernandes Jan 18 '18 at 17:32