Cloud Storage for Firebase - Code to Write Data

In previous posts we’ve been writing files to Cloud Storage for Firebase. This post contains the code.

Caveat: in this example we upload images taken on a mobile phone camera. Most modern mobile phones have high resolution images which translates to large files. You would typically want to resize these image (and files) before uploading them. We'll leave that exercise to a future blog post.


At the top of the Activity we have

  • FirebaseAuth variables (so that we can get the UID),

  • A constant to identify our ActivityResults

  • A String to store our filename

  • Two Cloud Storage references

  • A button to upload a photo

    private FirebaseAuth mAuth;
    private FirebaseAuth.AuthStateListener mAuthListener;

    private int CHOOSE_PHOTO = 5555;
    private String mPhotoFilename;

    private StorageReference mStorageRootRef, mMyPhotosStorageRef;

    private Button mUploadPhoto;

Get the current user:

        mAuthListener = new FirebaseAuth.AuthStateListener() {
            @Override
            public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                FirebaseUser user = firebaseAuth.getCurrentUser();
                if (user == null) {
                    // User is signed out
                    finish();
                } 
            }
        };

        mAuth = FirebaseAuth.getInstance();

Get a reference to the root of the Storage:

        mStorageRootRef = FirebaseStorage.getInstance().getReference();

Establish a filename and form a full path to the Cloud Storage reference for this filename that results in the path: /Photos/<userUUID>/<filename>

        mPhotoFilename = new Long(System.currentTimeMillis()).toString() + ".jpg";

        mMyPhotosStorageRef = mStorageRootRef.child("Photos")
                .child(mAuth.getCurrentUser().getUid())
                .child(mPhotoFilename);

Set an onClickListener() for the button that will launch the chooser for picking a photo on the device:

 mUploadPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent, "Choose A Photo"), CHOOSE_PHOTO);
            }
        });

Override onActivityResult(), check for our CHOOSE_PHOTO operation that is returning successfully and then extract the photo URI from the returned data:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == CHOOSE_PHOTO && resultCode == RESULT_OK && data != null && data.getData() != null) {
            Uri theUri = data.getData();

            uploadImageToCloudStorage(theUri);
        }
    }

Great! We have a reference to the photo on our device! Next, finish off by uploading to Cloud Storage in the method named uploadImageToCloudStorage().

We’re going to call putFile() on our Cloud Storage reference, passing in the URI to the file on our device. putFile() will return an UploadTask.

When the UploadTask completes successfully, indicating the file was written to Cloud Storage successfully, then we will call another method named writePhotoMetaDataToDb().

The job of writePhotoMetaDataToDb() is to obtain the reference to the Cloud Storage location and then write this metadata to our Realtime Database - this is how we access the file in Cloud Storage later!

    private void uploadImageToCloudStorage(Uri uri) {
        UploadTask task = mMyPhotosStorageRef.putFile(uri);

        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // do something
            }
        }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @SuppressWarnings("VisibleForTests")
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                taskSnapshot.getMetadata().getReference().getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                    @Override
                    public void onSuccess(Uri uri) {
                        writePhotoMetaDataToDb(uri.toString());
                    }
                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // do something
                    }
                });
            }
        });
    }

And here are the contents of writePhotoMetaDataToDb(). We’ll create a model representing the photo file in Cloud Storage (URL, ownerUUID, filename) and then write it to the Realtime Database under /PhotoModels/<userUUID>/<pushID>

    private void writePhotoMetaDataToDb(String uri) {
        
        PhotoModel photoModel = new PhotoModel();
        photoModel.setUrl(uri);
        photoModel.setOwnerUUID(mAuth.getCurrentUser().getUid());
        photoModel.setFilename(mPhotoFilename);

        DatabaseReference photosDbRef = FirebaseDatabase.getInstance()
                .getReference().child("PhotoModels")
                .child(mAuth.getCurrentUser().getUid())
                .push();


        photosDbRef.setValue(photoModel).addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                finish();
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // do something
            }
        });
    }

That’s it!

Oh but don’t forget the big caveat.: In this example the file is a photo on a phone and likely a very large file. The photo should be resized before uploading. Resizing of photos will be left to a future blog article.