androidfirebasekotlinfirebase-realtime-database

RecyclerView not showing in design mode or in the emulator in android studio


I'm trying to figure out on what to do as my recyclerview seems to be not working. I'm still fairly new to mobile development so I'm not exactly sure I'm gonna do. There was no error/warning messages in the logs regarding recyclerview and it still was able to run the build however my only issue is the said recyclerview not being visible.

At first I thought it was because there was no data yet as when I dragged the recyclerview to the component tree, it was supposed to show a preview of items 0-9 in the design mode even though there was no data as from what I've observed watching videos that discuss about recyclerview. Then I did the backend of the activity I was working on and have my firebase connected to it but still, the recyclerview is not showing.

Here is my code:

MainActivity.kt

package com.example.dashboard.Activity

import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.dashboard.Activity.BaseActivity
import com.example.dashboard.Adapter.CategoryAdapter
import com.example.dashboard.R
import com.example.dashboard.ViewModel.MainViewModel
import com.example.dashboard.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val viewModel = MainViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)

        setContentView(binding.root)

        initCategory()

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
    }

    private fun initCategory() {
        binding.progressBarCategory.visibility = View.VISIBLE
            viewModel.category.observe(this, Observer{
                binding.viewCategory.layoutManager = LinearLayoutManager(this@MainActivity,
                    LinearLayoutManager.HORIZONTAL,false)
                binding.viewCategory.adapter= CategoryAdapter(it)
                binding.progressBarCategory.visibility= View.GONE
            })
        viewModel.loadCategory()
    }

}

CategoryAdapter.kt

package com.example.dashboard.Adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.dashboard.Domain.CategoryModel
import com.example.dashboard.databinding.ViewholderCategoryBinding

class CategoryAdapter(val items: MutableList<CategoryModel>):
    RecyclerView.Adapter<CategoryAdapter.Viewholder>() {
    private lateinit var context: Context

    inner class Viewholder(val binding: ViewholderCategoryBinding): RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryAdapter.Viewholder {
        context=parent.context
        val binding=ViewholderCategoryBinding.inflate(LayoutInflater.from(context),parent,false)
        return Viewholder(binding)
    }

    override fun onBindViewHolder(holder: CategoryAdapter.Viewholder, position: Int) {
        val item=items[position]
        holder.binding.titleText.text=item.Name
        Glide.with(context)
            .load(item.Picture)
            .into(holder.binding.img)
    }

    override fun getItemCount(): Int =items.size
}

CategoryModel.kt

package com.example.dashboard.Domain

data class CategoryModel(
    val Id:Int=0,
    val Name: String="",
    val Picture: String=""
)

MainViewModel.kt

package com.example.dashboard.ViewModel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.dashboard.Domain.CategoryModel
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener


class MainViewModel() : ViewModel() {

    private val firebaseDatabase = FirebaseDatabase.getInstance()

    private val _category = MutableLiveData<MutableList<CategoryModel>>()

    val category: LiveData<MutableList<CategoryModel>> = _category
    fun loadCategory(){
        val ref=firebaseDatabase.getReference("Category")
        ref.addValueEventListener(object :ValueEventListener{
            override fun onDataChange(snapshot: DataSnapshot) {
                val lists =  mutableListOf<CategoryModel>()
                    for (childSnapshot in snapshot.children){
                        val list=childSnapshot.getValue(CategoryModel::class.java)
                        if(list!=null){
                            lists.add(list)
                        }
                    }
                _category.value=lists
            }

            override fun onCancelled(error: DatabaseError) {
                TODO("Not yet implemented")
            }
        })
    }

}

activity_main.xml (The relevant part of main.xml regarding the question. I used ScrollView on top of it as well)

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minHeight="100dp">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/viewCategory"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="16dp"
        android:clipToPadding="false"
        android:paddingStart="16dp"
        android:paddingEnd="16dp"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </androidx.recyclerview.widget.RecyclerView>
    <ProgressBar
        android:id="@+id/progressBarCategory"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

viewholder_category.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraintLayout"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:background="@drawable/light_purple_oval_bg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        <ImageView
            android:id="@+id/img"
            android:layout_width="30dp"
            android:layout_height="30dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:srcCompat="@tools:sample/avatars" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    <TextView
        android:id="@+id/titleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="title"
        android:textColor="@color/darkPurple"
        app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
        app:layout_constraintStart_toStartOf="@+id/constraintLayout"
        app:layout_constraintTop_toBottomOf="@+id/constraintLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>

build.gradle.kts(Module :app)

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.google.gms.google.services)
}

android {
    namespace = "com.example.dashboard"
    compileSdk = 36

    defaultConfig {
        applicationId = "com.example.dashboard"
        minSdk = 36
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = "11"
    }
    buildFeatures {
        viewBinding = true
    }
}

dependencies {

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation(libs.material)
    implementation(libs.firebase.database)
    implementation(libs.androidx.activity)
    implementation(libs.androidx.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    implementation(libs.androidx.recyclerview)
    implementation(libs.glide.v4160)
}

Solution

  • I have found out why I was not getting the RecyclerView to work. Make sure to add your firebase url in the getInstance parenthesis. Mine was set in Singapore while the getInstance() is defaulted to us-central1. That is why I was not seeing anything:

    MainViewModel.kt:

    private val firebaseDatabase = FirebaseDatabase.getInstance("[your firebase url]")
    

    Please check logcat located at the bottom-left corner of Android Studio. This was a rookie mistake of mine as I was looking for errors in the build section.