androidfirebasefirebase-realtime-databasekotlinandroid-mvp

Firebase not getting data from onDataChange method


I understand that Firebase gets the data asynchronously and I'm trying to set the data before it gets loaded into my recyclerView adapter so that it shows up in the recyclerview. But when I launch the app, it only gets the "EMPTY" string that I initially set, and it seems like firebase is not even going to the onDataChange method

CoursesFragment.kt

class CoursesFragment : android.support.v4.app.Fragment(), Contract.View {
    val TAG: String = CoursesFragment::class.java.name
    val presenter: Contract.Presenter.CoursePresenter = CoursePresenter(this)
    var tempDataList: MutableList<String> = mutableListOf()
    var dataArray: Array<String> = arrayOf("EMPTY")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tempDataList = presenter.retrieveCourseNames()
        for (i in 0 until tempDataList.size) dataArray[i] = tempDataList[i]
    }

    override fun onCreateView(inflater: android.view.LayoutInflater?, container: android.view.ViewGroup?,
                              savedInstanceState: Bundle?): android.view.View? {
        // Inflate the layout for this fragment
        val v = inflater!!.inflate(R.layout.fragment_courses, container, false)

//        Gets cardview widget and sets property
        val rView = v.findViewById<RecyclerView>(R.id.recyclerView_courses)
        rView.setHasFixedSize(true)

//        Creates the 2 column recycler view with the cards
        val layoutMan = GridLayoutManager(context, 1)
        rView.layoutManager = layoutMan
        //        Sets up cardview in recycler view

        val adapter = CourseRecyclerAdapter(dataArray, presenter)
        adapter.notifyDataSetChanged()
        rView.adapter = adapter

//        actually inflates view
        return v
    }

    //    ======================== INTERFACE OVERRIDE METHODS ========================

    //    CourseContract
    override fun showToastMessage(message: String) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
    }

    //    ======================== USER METHODS ========================
//    New Instance Method
    companion object {
        fun newInstance(page: Int = 0): CoursesFragment {
            val argPage: String = "ARG_PAGE"
            val args: Bundle = Bundle()
            args.putInt(argPage, page)
            val fragment = CoursesFragment()
            fragment.arguments = args
            return fragment
        }
    }
}

CoursePresenter.kt

class CoursePresenter(val courseView: Contract.View) : Contract.Presenter.CoursePresenter {
    val courseInstance = com.alexoladele.cvap.MVP.Course.Model.Course()
    override fun retrieveCourseNames(): MutableList<String> {
        val returnList: MutableList<String> = mutableListOf()
        courseInstance.getCourseNamesFromDB(object : MyCallBack{
            override fun doCallback(dbValue: String) {
                returnList.add(dbValue)
            }
        })
        return returnList
    }

    fun testToast() {
        courseView.showToastMessage("TOAST TEST")
    }
    override fun onCourseClick(cardPosition: Int) {
        testToast()
    }
}

Course.kt

class Course (val name: String = "GENERIC", val content: String = "PLACEHOLDER") : Contract.Model.CourseModel {
    val dbReference: DatabaseReference = FirebaseDatabase.getInstance().reference
    val courseRef = dbReference.child("Course")
    val courseNames = mutableListOf<String>()

    override fun getCourseNamesFromDB(callback: MyCallBack) {
        courseRef.addValueEventListener(object : ValueEventListener {
            override fun onCancelled(p0: DatabaseError?) {
//                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            override fun onDataChange(p0: DataSnapshot) {
                val tempString = p0.value as String
                Log.d(TAG, "onDataChange: Value from DB is: $tempString");

                callback.doCallback(tempString)
            }
        })
    }
}
interface MyCallBack {
    fun doCallback(dbValue: String)
}

EDIT: I've tried this in the CoursePresenter

override fun retrieveCourseNames(dataArray: Array<String>): Array<String> {
//        val returnList: MutableList<String> = mutableListOf()
        courseInstance.getCourseNamesFromDB(object : MyCallBack{
            override fun doCallback(dbValue: String) {
                val returnList = mutableListOf<String>()
                returnList.add(dbValue)
                for (i in 0 until returnList.size)
                     dataArray[i] = returnList[i]
            }
        })

        return dataArray
    }

Solution

  • I fixed it by doing away with the callback completely! I set the recyclerView adapter inside the onDataChange() method, therefore I'm not setting the layout before I get data which might cause it to load a bit slow and probably violates MVP, but it works!!!