Android Create Delete in Firebase Realtime Database & Storage

In almost all of the applications there is a requirement to save or store data in database. In Android we can use SQLite database or database hosted remotely. Google Firebase provides real time database access that can be implemented for all the CRUD activities. In previous articles we discussed how to connect Android application with Firebase realtime database. In another article we saw how to display images from firebase storage and Firebase Cloud Functions. Now we will extend those examples with write and update operations. By the end of this article we will learn basic CRUD (Create, Read, Update and Delete) operations using Firebase Realtime Database.

In this example we will take use of Firebase Storage to upload User uploaded images and save path in database to display in list view.

 

Flow

  1. Fetch user data from database and display in recycler view
  2. User selects and upload image to Firebase Storage
  3. On successfully upload of image, save path in Firebase Database
  4. Refresh new data

Create JSON POJO classes:

Create java POJO class for our database.

UserImageList

package com.codeexa.com.firebasedatabaseexample.database;

import com.google.firebase.database.IgnoreExtraProperties;

import java.util.Map;

@IgnoreExtraProperties
public class UserImageList {

    public Map<String, UserDbData> user ;

    public UserImageList() {
    }

    public Map<String, UserDbData> getUser() {
        return user;
    }

    public UserImageList(Map<String, UserDbData> user) {
        this.user = user;
    }
}

User Image Data

import com.google.firebase.database.IgnoreExtraProperties;

@IgnoreExtraProperties
public class UserDbData {

    private String imageUrl;

    public UserDbData() {
    }
    public UserDbData(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    @Override
    public String toString() {
        return "UserDbData{" +
                "imageUrl='" + imageUrl + '\'' +
                '}';
    }
}

Read data from Database:

Read user saved data from the database to show in recycler view. Check out this article to find out how to display images stored in cloud storage.

If the data needs to be read only once then use SingleValueEvent listener.

     private void fetchData() {
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference();
        ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                UserImageList target =  dataSnapshot.getValue(UserImageList.class);

                if(target!=null &&  target.getUser()!=null) {

                    Collection<UserDbData> data = target.getUser().values();
                    mTargetData.addAll(new ArrayList<>(data));

                    mAdapter.notifyDataSetChanged();
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // Getting Post failed, log a message
                Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
                // ...
            }
        };
        myRef.addListenerForSingleValueEvent(postListener);
    }

If continuous updates are desired then use ChildEvent listener to listen to onChildAdded event.

ChildEventListener onChildAdded()
Retrieve lists of items or listen for additions to a list of items. This callback is triggered once for each existing child and then again every time a new child is added to the specified path. The DataSnapshot passed to the listener contains the the new child’s data.

    private void attachChildListener(){
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference().child("user");
        ChildEventListener listener = new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                UserDbData target =  dataSnapshot.getValue(UserDbData.class);
                mTargetData.add(target);
                mAdapter.notifyDataSetChanged();
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

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

            }
        };
        myRef.addChildEventListener(listener);
    }

 

Select and upload image to Storage

Firebase Storage Rule

Update rules of Firebase Storage to support write operation.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
      allow write;
    }
  }
}

Android upload code snippet

Save and upload user selected image to firebase storage

    private void selectImageFromGallery() {
        Intent intent = new Intent();
        // This will select only images
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select Picture"), REQUEST_SELECT_IMAGE);
    }

Convert selected image to byte array by converting and compressing bitmap to binary format.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_SELECT_IMAGE && resultCode == RESULT_OK) {

            if(data != null && data.getData() != null) {
                Uri uri = data.getData();

                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                    byte[] byteData = baos.toByteArray();

                    uploadImageToStorage(byteData);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else{
                Snackbar.make(fab, "Failed to select image", Snackbar.LENGTH_LONG)
                        .setAction("Ok", null).show();
            }
        }
    }

Save converted bitmap to firebase storage bucket.

    private void uploadImageToStorage(byte[] byteData) {
        StorageReference storageRef = FirebaseStorage.getInstance().getReference();
        storageRef = storageRef.child("images/Image-" +Calendar.getInstance().getTimeInMillis() +".jpg");

        UploadTask uploadTask = storageRef.putBytes(byteData);
        uploadTask.addOnFailureListener(exception -> {
            // Handle unsuccessful uploads
        }).addOnSuccessListener(taskSnapshot -> {
            // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
            // ...

            saveMetaInfoInDatabase(Objects.requireNonNull(taskSnapshot.getMetadata()));

        });
    }

 

Update File Metadata in Database:

Get storage reference url of the uploaded image and save path in database.

    private void saveMetaInfoInDatabase(@NonNull StorageMetadata metadata) {
        Log.e("TAG", "Meta Data:" + metadata.getPath());
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference().child("user");
        UserDbData data = new UserDbData(metadata.getPath());
        String key = myRef.push().getKey();
        Map<String, Object> postValues = new HashMap<>();
        postValues.put(key, data);

        myRef.updateChildren(postValues).addOnCompleteListener(task -> {
            if(task.isSuccessful()){

            }else{

            }
        });

    }

The reason why we have saved image paths in the database is because firebase storage do not provide any api to list files or folders. The only way to get the storage files is by keeping an index of files in our database.

Delete file from Storage and File entry from Database:

Let’s see how to delete an item from storage as well as database.

    private void deleteImage(int position) {
        AlertDialog.Builder builder = new AlertDialog.Builder(mContext).setMessage("Do you want to delete this image?")
                .setPositiveButton("Yes", (dialog, which) -> {
                    FirebaseDatabase database = FirebaseDatabase.getInstance();
                    UserDbData data = mTargetData.get(position);
                    DatabaseReference myRef = database.getReference().child("user").child(data.getKey());
                    myRef.removeValue((databaseError, databaseReference) -> {
                        if(databaseError == null){
                            StorageReference ref = FirebaseStorage.getInstance().getReference().child(data.getImageUrl());
                            ref.delete().addOnCompleteListener(task -> {
                                mTargetData.remove(position);
                                mAdapter.notifyDataSetChanged();
                            });
                        }
                    });

                    dialog.dismiss();

                }).setNegativeButton("Cancel", (dialog, which) -> {
                    dialog.dismiss();

                });
        builder.show();
    }

 

If you are facing permission issues or failure to upload data to storage/database then do check the rules tab in firebase dashboard.

 

FirebaseDatabaseStorage
FirebaseDatabaseStorage
FirebaseDatabaseStorage.zip
215.4 KiB
225 Downloads
Details

Leave a Reply