kotlin recyclerview data not showing

后端 未结 3 1396
臣服心动
臣服心动 2020-12-04 04:22

Our question is how to show Parent and Child data from two SQLite DB tables?

We have two tables that are added to two ArrayLists childList and par

相关标签:
3条回答
  • 2020-12-04 04:38

    In the ViewActivity class, you have first set the recyclerView adapter to ViewAdapter and then to ViewChildAdapter thus, now, the adapter of recyclerView is ViewChildAdapter instead of ViewAdapter. Remove this line and the problem will be resolved.

    0 讨论(0)
  • 2020-12-04 04:42

    The way I would do it is flatten the list edit: like this in the constructor

    val items : MutableList<Any> = mutableListOf<Any>()    
    
    init() {
       parents //parents should be passed as a constructor argument
             .asSequence() //this is only needed if you want to also order them
             .sortedBy { it.idD } //again only if you want to sort them
             .forEach { 
                  items.add(it)
                  items.addAll(it.children)
              }
    }
    

    I would create a List < Any > (or if both parent and child implement an interface a List< IItem > ) that would contain all the data as you wish to see it, so for example it could look like this:

    val items : List<Any> = listOf(parent1, child11,child12,child13,parent2,child12,child13,child14.....etc)
    

    then I would implement a single adapter with multiple view types like this:

    override fun getItemCount(): Int {
        return items.size
    }
    
    fun getItem(position: Int) : Any { //or the interface 
        return items[position]
    }
    
    override getItemViewType (position: Int) : Int {
        if (getItem(position) is ModelParent)
            return 0
        return 1
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        var view : View? = null
        if (viewType == 0) {
            view = LayoutInflater.from(parent.context).inflate(R.layout.parent_layout,parent,false)
            return ParentViewHolder(view);
        } else {
           view = LayoutInflater.from(parent.context).inflate(R.layout.child_layout,parent,false)
            return ChildViewHolder(view);
        }
    }
    

    and then I would use two view holders to represent how the data is shown for the specific item

     inner class ParentViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ ...}
     inner class ChildViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ ...}
    

    after that I could perform different bindings by getting the type of the view ,something like this:

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        if (getItemType(position) == 0) {
            (holder as ParentViewHolder).bindData(....)
        } else {
            (holder as ChildViewHolder).bindData(....)
        }
    }
    

    edit: Here is the complete adapter I built, it is based on two layout files:

    list_item_child:

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="2dp"
        card_view:cardBackgroundColor="#fff"
        card_view:cardCornerRadius="5dp"
        card_view:cardElevation="4dp"
        card_view:cardUseCompatPadding="true">
    
        <TextView
            android:id="@+id/child_item"
            style="@style/Base.TextAppearance.AppCompat.Display3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:padding="20dp"
            android:textSize="24sp"
            android:textStyle="bold"
            tools:text="Dept Header" />
    
    </android.support.v7.widget.CardView>
    

    list_item_parent:

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="2dp"
        card_view:cardBackgroundColor="#fff"
        card_view:cardCornerRadius="5dp"
        card_view:cardElevation="4dp"
        card_view:cardUseCompatPadding="true">
    
        <TextView
            android:id="@+id/parent_department"
            style="@style/Base.TextAppearance.AppCompat.Headline"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:padding="20dp"
            tools:text="Dept Header"
            android:textSize="24sp"
            android:textStyle="bold" />
    
    </android.support.v7.widget.CardView>
    

    and the adapter would look something like this:

    import android.content.Context
    import android.support.v7.widget.RecyclerView
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.widget.TextView
    
    data class ModelParent(val id: Int, val children: List<ModelChild>)
    data class ModelChild(val id: Int)
    
    
    class JoinAdapter(internal var context: Context, val parents: List<ModelParent>) : RecyclerView.Adapter<JoinAdapter.MyViewHolder>() {
        val items = mutableListOf<Any>()
    
        init {
            parents //parents should be passed as a constructor argument
                    .forEach {
                        items.add(it)
                        items.addAll(it.children)
                    }
        }
    
        override fun getItemCount(): Int = items.size;
    
    
        fun getItem(position: Int): Any = items[position]
    
        override fun getItemViewType(position: Int): Int = if (getItem(position) is ModelParent) 0 else 1
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            var view: View? = null
            if (viewType == 0) {
                view = LayoutInflater.from(parent.context).inflate(R.layout.rv_list_item_parent, parent, false)
                return ParentViewHolder(view!!)
            } else {
                view = LayoutInflater.from(parent.context).inflate(R.layout.rv_list_item_child, parent, false)
                return ChildViewHolder(view!!)
            }
        }
    
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) = holder.bindData(position, getItem(position))
    
        inner abstract class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            abstract fun bindData(position: Int, item: Any)
    
        }
    
        inner class ParentViewHolder(view: View) : MyViewHolder(view) {
            var parentDept: TextView = view.findViewById(R.id.parent_department) as TextView
    
            override fun bindData(position: Int, item: Any) {
                val parent = item as? ModelParent ?: return
                parentDept.text = parent.dept
            }
        }
    
        inner class ChildViewHolder(view: View) : MyViewHolder(view) {
            var childItem: TextView = view.findViewById(R.id.child_item) as TextView
    
            override fun bindData(position: Int, item: Any) {
                val child = item as? ModelChild ?: return
                childItem.text = child.item
            }
        }
    
    }
    

    this when used on a single recyclerview will display all children under their parent in a list

    0 讨论(0)
  • 2020-12-04 04:47

    Here is a answer and some observations about the design of this app
    The answer does NOT place both the parent and child data on the same Recycler View List
    But the answer may help to solve the issue With further exploration!
    What we did was create the parent list and when the Parent Dept is clicked on the corresponding Child Items will be displayed. This may be a more functional design while shopping you only need to look at Produce items while in that section. This means less scrolling through a single master list of Parents and Children.

    A word or two about the design we are guessing a grocery store might have 20 or more Departments (Parents) so how you plan to know which Items (Child data) is connected to the appropriate Dept (Parent) needs drastic redesign when building these two lists.

    If you downloaded the code from GitHub you will have a better grasp about this design deficiency

    Here is all the code with the XML files

    Main Activity navigates to View Activity

        fun onViewAll(view: View){
        val intent = Intent(this,ViewActivity::class.java)
        intent.putExtra("pickADAPTER",2)
        startActivity(intent)
    }
    

    Here is the View Activity

    class ViewActivity : AppCompatActivity() {
    
    lateinit var recyclerView: RecyclerView
    
    private var RecyclerAdapter1: ViewAdapter? = null
    private var RecyclerAdapter2: ViewChildAdapter? = null
    private var linearLayoutManager: LinearLayoutManager? = null
    
    private val db = DBHelper(this)
    
    private var parentList:List<ModelParent> = ArrayList()
    private var childList:List<ModelChild> = ArrayList()
    
    var idD = 0
    var whichADAPTER = 0
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view)
        val bundle: Bundle = intent.extras
        idD = bundle.getInt("BIGi", 0)
        whichADAPTER = bundle.getInt("pickADAPTER",0)
    
        initRecycler()
    
    }// end onCreate
    
    override fun onResume() {
        super.onResume()
        initDB()
    }
    
    private fun initDB() {
        parentList = db.queryDEPT()
        childList = db.queryCHILD(idD)
        // queryCHILD only selects records with a fkI equal to idD
        // SEE THE ModelChild and ModelParent
        if(parentList.isEmpty()){
            title = "No Records in DB"
        }else{
            title = "Parent List"
        }
    
        if(whichADAPTER == 2) {
            RecyclerAdapter1 = ViewAdapter(parents = parentList, context = applicationContext)
            (recyclerView as RecyclerView).adapter = RecyclerAdapter1
        }else{
            RecyclerAdapter2 = ViewChildAdapter(children = childList)
            (recyclerView as RecyclerView).adapter = RecyclerAdapter2
        }
    }
    
    private fun initRecycler() {
        val db = DBHelper(this)
        childList = db.queryITEM()
        parentList = db.queryDEPT()
    
        recyclerView = rv_parent
    
        recyclerView = this.findViewById(R.id.rv_parent)
        RecyclerAdapter1 = ViewAdapter(parents = parentList, context = applicationContext)
        linearLayoutManager = LinearLayoutManager(applicationContext)
        (recyclerView as RecyclerView).layoutManager = linearLayoutManager!!
    
    }
    

    Here the XML file for View Activity

    <android.support.v7.widget.RecyclerView
    android:id="@+id/rv_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    

    Here is the View Adapter

    class ViewAdapter(private val parents: List<ModelParent>, internal var context: Context):RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.the_view,parent,false)
        return ViewHolder(view)
    }
    
    override fun getItemCount(): Int {
        return parents.size
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val parent = parents[position]
        holder.textView.text = parent.dept
    
        holder.editCLICK.setOnClickListener {
            val i = Intent(context, ViewActivity::class.java)
            i.putExtra("BIGi",parent.idD)
            i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            context.startActivity(i)
        }
    }
    
    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
        //val recyclerView : RecyclerView = itemView.rv_child
        val textView: TextView = itemView.textView
        var editCLICK: RelativeLayout = itemView.findViewById(R.id.editCLICK) as 
        RelativeLayout
    

    And the inflated XML

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_margin="2dp"
    card_view:cardBackgroundColor="#FF0000"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="4dp"
    card_view:cardUseCompatPadding="true">
    
    <RelativeLayout
        android:id="@+id/editCLICK"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/textView"
            style="@style/Base.TextAppearance.AppCompat.Subhead"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignStart="@+id/rv_child"
            android:layout_alignParentTop="true"
            android:padding="10dp"
            android:background="@color/color_lightGray"
            android:text="Dept Header"
            android:textColor="@color/color_Purple"
            android:textSize="24sp"
            android:textStyle="bold" />
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_child"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_alignParentBottom="true"
            android:layout_marginTop="50dp"
            android:layout_marginBottom="0dp"
            android:orientation="horizontal"
            android:paddingLeft="4dp"
            android:paddingTop="6dp"
            tools:layout_editor_absoluteX="74dp" />
    
    </RelativeLayout>
    

    This is the search routine in DBHelper

        fun queryCHILD(fkI: Int): List<ModelChild> {
        val db = this.writableDatabase
        val childList = ArrayList<ModelChild>()
        val selectQuery = "SELECT  * FROM $CHILD_TABLE WHERE $colCFK = ?"
        val cursor = db.rawQuery(selectQuery, arrayOf(fkI.toString()))
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                do {
                    val contact = ModelChild()
                    contact.idI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colidI)))
                    contact.item = cursor.getString(cursor.getColumnIndex(colItem))
                    contact.fkI = Integer.parseInt(cursor.getString(cursor.getColumnIndex(colCFK)))
                    childList.add(contact)
                } while (cursor.moveToNext())
            }
        }
        cursor.close()
        return childList
    }
    

    One thing to make note of we attached the OnClickListener to a Relative Layout

     holder.editCLICK.setOnClickListener
    

    Why we are not sure you can obtain parent.idD type information from a RecyclerView set as a listener?
    We need to explore this but in our testing the code failed when we tried.

    0 讨论(0)
提交回复
热议问题