0

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
    }
Alex oladele
  • 69
  • 11

2 Answers2

0

To solve this, you need declare and use val returnList inside the overriden doCallback function in your CoursePresenter.kt file. In this way won't get empty String because you wait for that in order to use it.

For more informations, you can see my answer from the following post:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
0

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!!!

Alex oladele
  • 69
  • 11
  • Setting the adapter inside a background thread isn't such a good idea because you'll get a warning such as [No Adapter attached :skipping layout](https://stackoverflow.com/q/54677804/5246885). Beside that, this answer doesn't solve the asynchronous part of the problem at all. – Alex Mamo Jul 29 '19 at 09:30
  • Please also take a look at the link from my edited answer. – Alex Mamo Jul 29 '19 at 09:51