Getting started with Firebase Realtime Database and LiveData

Firebase is a cross-platform service that works on Android, iOS and the web. Firebase Realtime Database is a solution that stores data in the cloud and provides an easy way to sync your data among various devices.

The Firebase console is where you set up and manage your apps. From there, you can view all of your projects as well as create new ones.

To add the Realtime Database service to your app, you only need to add one more dependency. Open up build.gradle file, if you haven't got it open and add the following dependency, making sure you're using the latest version:

implementation 'com.google.firebase:firebase-database:19.2.0'

You need a way to talk to the Realtime Database. Let's create RealtimeDatabaseManager class that helps us to manage connection and value fetching.

private const val POSTS_REFERENCE = "posts"

class RealtimeDatabaseManager {
    private val database = FirebaseDatabase.getInstance()
    private val postsValues = MutableLiveData<List<Post>>()
    private lateinit var postsValueEventListener: ValueEventListener

    private fun createPost(key: String, content: String): Post {
        val user = authenticationManager.getCurrentUser()
        val timestamp = System.currentTimeMillis()
        return Post(key, content, user, timestamp)
    }

    fun addPost(content: String, onSuccessAction: () -> Unit, onFailureAction: () -> Unit) {
        val postsReference = database.getReference(POSTS_REFERENCE)
        val key = postsReference.push().key ?: ""
        val post = createPost(key, content)

        postsReference.child(key)
            .setValue(post)
            .addOnSuccessListener { onSuccessAction() }
            .addOnFailureListener { onFailureAction() }
    }

    fun onPostsValuesChange(): LiveData<List<Post>> {
        listenForPostsValueChanges()
        return postsValues
    }

    private fun listenForPostsValueChanges() {
        postsValueEventListener = object: ValueEventListener {
            override fun onCancelled(databaseError: DatabaseError) {}

            override fun onDataChange(dataSnapshot: DataSnapshot) {
                if (dataSnapshot.exists()) {
                    val posts = dataSnapshot.children
                        .mapNotNull { it.getValue(Post::class.java) }.toList()
                    postsValues.postValue(posts)
                } else {
                    postsValues.postValue(emptyList())
                }
            }
        }
        database.getReference(POSTS_REFERENCE)
            .addValueEventListener(postsValueEventListener)
    }

    fun deletePost(key: String) {
        database.getReference(POSTS_REFERENCE)
            .child(key)
            .removeValue()
    }

    fun removePostsValuesChangesListener() {
        database.getReference(POSTS_REFERENCE).removeEventListener(postsValueEventListener)
    }

    fun updatePostContent(key: String, content: String) {
        database.getReference(POSTS_REFERENCE)
            .child(key)
            .child(POST_CONTENT_PATH)
            .setValue(content)
    }    
}

We can use this help class like so

class MainActivity : AppCompatActivity() {
    private val rdm by lazy { RealtimeDatabaseManager() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        super.onStart()
        listenForPostsUpdates()
    }

    override fun onStop() {
        super.onStop()
        rdm.removePostsValuesChangesListener()
    }

    private fun listenForPostsUpdates() {
        rdm.onPostsValuesChange()
            .observe(this, Observer(::onPostsUpdate))
    }

    private fun onPostsUpdate(posts: List<Post>) {
        Log.d("TAG", posts)
    }
}