0

I got some categories from an api and trying to show them on a recycler view but it doesn't work for some reason.

Although the data appears correctly in the logcat, it is sent as null to the Category adapter.

This is the Main Activity (where I'm trying to show the data): `

@AndroidEntryPoint
 class MainActivity : AppCompatActivity() {
    private val TAG = "MEALZ"
    private lateinit var binding: ActivityMainBinding
    private val viewModel:MealsViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val adapter = CategoryAdapter(this)
        binding.categoriesRv.adapter = adapter

        viewModel.getMeals()

        lifecycleScope.launch {
            viewModel.categories.collect {
                adapter.setData(it?.categories as List<Category>)
                Log.d(TAG, "onCreate: ${it?.categories}")
            }
        }
    }
}

` This is Recycler Category Adapter :

`

class CategoryAdapter(private val context: Context?) :
    RecyclerView.Adapter<CategoryAdapter.CategoryViewHolder>() {
    private var categoryList: MutableList<Category?> = mutableListOf<Category?>()

    inner class CategoryViewHolder(itemView: CategoryLayoutBinding) :
        RecyclerView.ViewHolder(itemView.root) {
        val name = itemView.categoryNameTv
        val img = itemView.categoryIv
        val des = itemView.categoryDesTv


    }

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

    override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
        var category = categoryList[position]
        holder.name.text = category?.strCategory
        holder.des.text = category?.strCategoryDescription
        Glide.with(context as Context).load(category?.strCategoryThumb).into(holder.img)
    }

    override fun getItemCount(): Int {
        return categoryList.size
    }

    fun setData(CategoryList: List<Category>) {
        this.categoryList.addAll(CategoryList)
        notifyDataSetChanged() //to notify adapter that new data change has been happened to adapt it
    }
}

`

This is the View Model class:

@HiltViewModel
class MealsViewModel @Inject constructor(private val getMealsUseCase: GetMeals): ViewModel() {

    private val TAG = "MealsViewModel"
    private val _categories: MutableStateFlow<CategoryResponse?> = MutableStateFlow(null)
    val categories: StateFlow<CategoryResponse?> = _categories

    fun getMeals() = viewModelScope.launch {

        try {
            _categories.value = getMealsUseCase()
        } catch (e: Exception) {
            Log.d(TAG, "getMeals: ${e.message.toString()}")
        }
    }
    
}

1 Answers1

0

you create your _categories with null as initial value, so first value of categories flow will be null and only second one will contain fetched data. As a workaround, you can check that data is not null:

viewModel.categories.collect {
    if (it != null) {
        adapter.setData(it?.categories as List<Category>)
        Log.d(TAG, "onCreate: ${it?.categories}")
    }
}

or introduce some kind of "loading" state

Andrei Tanana
  • 7,932
  • 1
  • 27
  • 36