Home > database >  RecyclerView with coroutines, using Fragment doesn't populate data Kotlin
RecyclerView with coroutines, using Fragment doesn't populate data Kotlin

Time:08-10

I am trying to work wih courutines and recycler view. I've done everything necessary to send requests to the API, but I still can't get the list that should be inside the recycler view. I am using fragment to create list and bottom nav. When I go to the fragment where my list should be, then I get the error: RecyclerView: No layout manager attached; skipping layoutand nothing more. I googled about this error and it says I should define the layout manager in xml, but it alreadt has layuout manager in my fragment

<androidx.recyclerview.widget.RecyclerView 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:id="@ id/list_item"  
    app:layoutManager="LinearLayoutManager"

Also my adapter and fragment for recycler view look like this:

class MyItemRecyclerViewAdapter(
) : RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
    
     var userNameResponse = mutableListOf<UsersNameItem>()
    
    fun setNamesList(names: List<UsersNameItem>) {
        this.userNameResponse = userNameResponse.toMutableList()
        notifyDataSetChanged()
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            FragmentItemBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = userNameResponse[position]
        holder.idView.text = item.id
        holder.contentView.text = item.name
    }

    override fun getItemCount(): Int = userNameResponse.size

     class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
        val idView: TextView = binding.itemNumber
        val contentView: TextView = binding.content
    }

}

Fragment:

class ItemFragment : Fragment() {

    private var layoutManager: RecyclerView.LayoutManager? = null
    private var adapter: RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_item_list, container, false)
    }

    override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
        super.onViewCreated(itemView, savedInstanceState)
        layoutInflater.apply {
            layoutManager = LinearLayoutManager(activity)
            adapter = MyItemRecyclerViewAdapter()
        }
    }

    companion object {
        fun newInstance() = ItemFragment()
    }
}


And MainActivity where I set up courutines and trying to make a request: 

class MainActivity : AppCompatActivity() {


    private lateinit var binding: ActivityMainBinding
    lateinit var nameviewModel: ListNamesViewModel
    val adapter = MyItemRecyclerViewAdapter()

    ///trying to create http-request for lists
    val retrofitService = BasicApiService.getInstance()
    val mainRepository = MainRepository(retrofitService)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        nameviewModel = ViewModelProvider(
            this,
            MyViewModelFactory(mainRepository)
        )[ListNamesViewModel::class.java]

        nameviewModel.userName.observe(
            this, Observer {
                adapter.setNamesList(it)
            })
        nameviewModel.message.observe(this) {
            Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
        }

        nameviewModel.loadUsers()

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home,
                R.id.navigation_dashboard,
                R.id.navigation_notifications,
                R.id.list_name_navig
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }
}

Also I wanted to ask (I am very new to Kotlin nad just trying to make things work) if it is a good practice to leave request to API in the MainActivity ot I should do it in another way?

CodePudding user response:

try changing in xml

app:layoutManager="LinearLayoutManager"

to

app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"

CodePudding user response:

I see some confusion in your code, try to apply the next:

  1. Why are you creating the layoutManager and adapter in the ItemFragment?
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
    super.onViewCreated(itemView, savedInstanceState)
    layoutInflater.apply {
        layoutManager = LinearLayoutManager(activity)
        adapter = MyItemRecyclerViewAdapter()
    }
}

You need to move it and RecyclerView to your activity.

  1. The using layoutInflater.apply {} doesn't make sense, it's doing nothing in your case. You need to set layoutManager and adapter to recyclerView then in the activity it should look like that (and rename list_item to recyclerView)
binding.recyclerView.apply {
    layoutManager = LinearLayoutManager(this)
    adapter = MyItemRecyclerViewAdapter()
}
  1. Remove app:layoutManager="LinearLayoutManager" from XML.
  2. It looks like you don't need to use ItemFragment for your purpose because you use it just like a view and binding in the ViewHolder
class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
    val idView: TextView = binding.itemNumber
    val contentView: TextView = binding.content
}
  • Related