0

Pretty new to Firebase here, I'm developing an Android app for events going on in my city with Associations and regular Users either posting or saving events. This said, I got a problem with my Realtime Database not writing an imageUrl field inside my Event documents.

This my createEvent() method:


private void createEvent(View view) {
    if(!checkDateIsNotInThePast())
        return;

    FirebaseUser user = mAuth.getCurrentUser();
    String uid = null;
    final String[] author = new String[1];
    if(user != null) {
        uid = user.getUid();
        assocRef.child(uid).child("nome").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                author[0] = snapshot.getValue().toString();
                Log.d("author", author[0]);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });
    }

    String titolo = title.getText().toString();
    String desc = description.getText().toString();
    String add = address.getText().toString();
    final String[] imageUrl = new String[1];
    String data = date.getText().toString();
    String timeStart = timeFrom.getText().toString();
    String timeEnd = timeTo.getText().toString();
    String tick = ticket.getText().toString();

    if(tick.equals("")) {
        ticket.setText(R.string.hint_free);
        tick = "Free";
    }

    StorageReference assocFolderRef = storageRef.child(uid);
    StorageReference fileRef = assocFolderRef.child(System.currentTimeMillis() + "." + getFileExtension(uri));

    String finalUid = uid;
    String finalTick = tick;
    fileRef.putFile(uri)
            .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    Log.d("Upload success", taskSnapshot.toString());
                    fileRef.getDownloadUrl().addOnCompleteListener(new OnCompleteListener<Uri>() {
                        @Override
                        public void onComplete(@NonNull Task<Uri> task) {
                            imageUrl[0] = task.getResult().toString();
                            Log.d("imageUrl", "onComplete: " + imageUrl[0]);
                        }
                    });

                    String eventId = eventRef.push().getKey();
                    eventRef.child(finalUid).child(eventId).setValue(new Evento(
                            author[0],
                            titolo,
                            desc,
                            add,
                            imageUrl[0],
                            data,
                            timeStart,
                            timeEnd,
                            finalTick
                    ));
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.e("Upload failure", e.getMessage());
                }
            });
    
    title.setText(null);
    description.setText(null);
    address.setText(null);
    date.setText(null);
    timeFrom.setText(null);
    timeTo.setText(null);
    ticket.setText(null);

    Toast.makeText(getContext(), "Evento creato con successo", Toast.LENGTH_SHORT).show();
}

I really don't know where I messed up since the constructor expects all fields to be passed inside of it, but for some reason every field gets written except the imageUrl one and gives me no errors? I'm utterly confused.

Any kind of help and/or pointing into any other question if this a duplicate is very well accepted. Thanks in advance.

Tried to pass an Object into a Realtime Database but it passes with a field less than those expected.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
msp7
  • 5
  • 3

1 Answers1

0

This is an ordering problem: since the getDownloadUrl method is asynchronous your setValue call runs before the imageUrl[0] = task.getResult().toString() ever executes. You can most easily validate this by adding some logging to the code, or by setting breakpoints on these lines and running in a debugger.

Also see:

The fix for such problems is always the same: any code that needs a value, needs to be inside the callback that is executed when that value is available. In your case that means:

fileRef.putFile(uri)
    .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            Log.d("Upload success", taskSnapshot.toString());
            fileRef.getDownloadUrl().addOnCompleteListener(new OnCompleteListener<Uri>() {
                @Override
                public void onComplete(@NonNull Task<Uri> task) {
                    Log.d("imageUrl", "onComplete: " + imageUrl[0]);

                    String eventId = eventRef.push().getKey();
                    eventRef.child(finalUid).child(eventId).setValue(new Evento(
                            author[0],
                            titolo,
                            desc,
                            add,
                            task.getResult().toString(), // 
                            data,
                            timeStart,
                            timeEnd,
                            finalTick
                    ));
                }
            });
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.e("Upload failure", e.getMessage());
        }
    });
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Totally thought I checkmarked this after reading it, sorry for the late feedback. Anyway worked like a charm, thank you very much. I'll make sure to give your linked method a try as well :) – msp7 Feb 23 '23 at 16:58