Search code examples
androidkotlinandroid-livedataandroid-viewmodel

RecycledView adapter doesnt notify DataSetChanged


I have MainActivity with NavigationDrawer, when I pressed "AddNewDevice" i would like to achieve Fragment called "AddNewDeviceFragment" with empty RecycledView. Then when i pressed "refreshButton" my RecycledView should be updated through LiveData.

Instead of this when I pressed button nothing happened. Looks like Live data observer doesn't work because If I add data by NewDeviceAdapter method called addDevice recycled view notify change.

My code below:

MainActivity

lateinit var auth: FirebaseAuth
lateinit var toolbar: Toolbar
lateinit var drawerLayout: DrawerLayout
lateinit var navView: NavigationView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    auth = FirebaseAuth.getInstance()

    toolbar = findViewById(R.id.toolbar)
    setSupportActionBar(toolbar)

    drawerLayout = findViewById(R.id.drawer_layout)
    navView = findViewById(R.id.nav_view)

    val toggle: ActionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, 0, 0)
    drawerLayout.addDrawerListener(toggle)
    toggle.syncState()
    navView.setNavigationItemSelectedListener(this)

    supportFragmentManager.beginTransaction().replace(R.id.content_layout,
        AllDevicesFragment()
    ).commit()
    navView.setCheckedItem(R.id.nav_allDevices)
    Validator.validateInternetConnection(baseContext)

}

override fun onBackPressed() {
    if(supportFragmentManager.backStackEntryCount == 0){
        supportFragmentManager.popBackStack()
    } else {
        super.onBackPressed()
    }
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    updateHeader()

    var fragment : Fragment = Fragment()
    item.setChecked(true)

    when (item.itemId) {
        R.id.nav_profile -> {
            fragment = ProfileFragment()
        }
        R.id.nav_allDevices -> {
            fragment = AllDevicesFragment()
        }
        R.id.nav_addNewDevice -> {
            fragment = AddNewDeviceFragment()
        }
        R.id.nav_contact -> {
            fragment = ContactFragment()
        }
        R.id.nav_updateUser -> {
            fragment = UpdateUserFragment()
        }
        R.id.nav_logout -> {
            auth.signOut()
            finish()
            startActivity(Intent(this, LoginActivity::class.java))
        }
    }

    supportFragmentManager
        .beginTransaction()
        .replace(R.id.content_layout,fragment)
        .addToBackStack("fragments")
        .commit()

    drawerLayout.closeDrawer(GravityCompat.START)
    return true
}

fun updateHeader(){

    //TODO Zrobić tak żeby aktualizowało header jak się otwiera navigation drawer

    var username : TextView = navView.getHeaderView(0).findViewById(R.id.navUsername)
    var email : TextView = navView.getHeaderView(0).findViewById(R.id.navEmmailAddres)
    var profilePicture : ImageView = navView.getHeaderView(0).findViewById(R.id.navProfilePicture)

    username.setText(auth.currentUser?.displayName)
    email.setText(auth.currentUser?.email)
    Glide.with(this)
        .load(auth.currentUser?.photoUrl)
        .into(profilePicture)
}

AddNewDeviceFragment

class AddNewDeviceFragment : Fragment() {

    private var newDevices: MutableList<NewDevice> = arrayListOf()
    private var adapter: NewDeviceAdapter = NewDeviceAdapter(arrayListOf())
    private lateinit var model: NewDeviceViewModel
    private lateinit var rootView: View

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        rootView = inflater.inflate(R.layout.fragment_addnewdevice, container, false)

        return rootView
    }

    override fun onStart() {
        super.onStart()


        var newDevicesRecycledView = rootView.findViewById(R.id.newDevicesRecycledView) as RecyclerView
        newDevicesRecycledView.layoutManager = LinearLayoutManager(activity)
        newDevicesRecycledView.adapter = adapter

        //ViewModel
        model = ViewModelProviders.of(this).get(NewDeviceViewModel::class.java)

        //LiveData
        model.getNewDevices().observe(viewLifecycleOwner, Observer<MutableList<NewDevice>> { newDevices ->
            adapter.addDevice(newDevices)
        })

        refreshButton.setOnClickListener{addToRecycledView()}
    }

    fun addToRecycledView(){
        model.addNewDevice(NewDevice("10.121.125.57"))
    }
}

NewDeviceAdapter

package com.example.lightmeup.NewDevice

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.lightmeup.Entity.NewDevice
import com.example.lightmeup.R

class NewDeviceAdapter(var newDevices: MutableList<NewDevice>):     RecyclerView.Adapter<NewDeviceViewHolder>() {


    //number of items
    override fun getItemCount(): Int {
       return newDevices.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewDeviceViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val cellForRow = layoutInflater.inflate(R.layout.device_in_acces_point_state_item, parent ,false)
        return NewDeviceViewHolder(cellForRow)
    }

    override fun onBindViewHolder(holder: NewDeviceViewHolder, position: Int) {
        holder.bind(newDevices[position])
    }

    fun addDevice( data: MutableList<NewDevice>){
        this.newDevices = data
        notifyDataSetChanged()
    }
}

NewDeviceViewHolder

package com.example.lightmeup.NewDevice

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.example.lightmeup.Entity.NewDevice
import kotlinx.android.synthetic.main.device_in_acces_point_state_item.view.*

class NewDeviceViewHolder(val view: View): RecyclerView.ViewHolder(view){

    fun bind(newDevice: NewDevice) = with(view){
        device_name.text = newDevice.name
    }
}

NewDeviceViewModel

package com.example.lightmeup.NewDevice

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.example.lightmeup.Entity.NewDevice

class NewDeviceViewModel(application: Application) : AndroidViewModel(application) {

    val allNewDevices: MutableLiveData<MutableList<NewDevice>> by lazy {MutableLiveData<MutableList<NewDevice>>()}
    val newDevices: MutableList<NewDevice> = arrayListOf()

    init {
        addNewDevice(NewDevice("JAJko"))
    }

    fun getNewDevices(): MutableLiveData<MutableList<NewDevice>>{
        return allNewDevices
    }

    fun addNewDevice(newDevice: NewDevice) {
        newDevices.add(newDevice)
    }
}


Solution

  • You are updating the newDevices inside addNewDevice function, but you don't update your LiveData anywhere. You must update allNewDevices, for example inside of addNewDevice function as bellow :

        fun addNewDevice(newDevice: NewDevice) {
            newDevices.add(newDevice)
            allNewDevices.value = newDevices
        }