Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
370 views
in Technique[技术] by (71.8m points)

android - kotlin recyclerview data not showing

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 parentList.

Here are the Model Class's for each

class ModelParent {
    var idD:Int = 0
    var dept:String = ""
    var fkD:Int = 0
    var children: List<ModelChild> = mutableListOf()
    //var children: ArrayList<ModelChild>? = null
    //var children: List<ModelChild>  by Delegates.notNull()
    constructor (children: List<ModelParent>) : this()
    companion object {
       var globalVar = 1
   }
}

class ModelChild {
    var idI:Int = 0
    var item:String = ""
    var fkI:Int = 0
}

We have two Adapters for each table and will post that code
We are able to iterate through the two ArrayList with this code and display the data in the format we would like to show in the ViewActivity.

fun theGET(){
    val db = DBHelper(this)
    childList = db.queryITEM()
    parentList = db.queryDEPT()
    var PL = parentList.size

    do {
        var DEPT: String = parentList[z].dept
        var PARENT_LIST_FK = parentList.get(z).fkD
            println("========== Dept " + DEPT + " fkD " + PARENT_LIST_FK)
        val FK = PARENT_LIST_FK
        childList = db.queryALL(FK)
        var CL = childList.size
        for (a in 0..CL - 1) {
            var CHILD_ITEM = childList[a].item
            var CHILD_LIST_FK = childList[a].fkI
            println("========== item " + CHILD_ITEM+" fkI "+CHILD_LIST_FK)
        }
        z++
    }
    while (z <= PL-1)
}

We will post the View Activity

class ViewActivity : AppCompatActivity() {
    lateinit var recyclerView: RecyclerView

    private var parentList:List<ModelParent> = ArrayList()
    private var childList:List<ModelChild> = ArrayList()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view)

        initRecycler()

    }// end onCreate

    private fun initRecycler() {
        val db = DBHelper(this)
        childList = db.queryITEM()
        parentList = db.queryDEPT()

        recyclerView = rv_parent

        recyclerView.apply{
            layoutManager = LinearLayoutManager(this@ViewActivity, LinearLayout.VERTICAL, false)
            adapter = ViewAdapter(parentList)
            adapter = ViewChildAdapter(children = childList)
        }
    }
}

ViewActivity has this XML file

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ViewActivity">

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

The Two Adapters and coresponding XML files

class ViewAdapter(private val parents:List<ModelParent>):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.recyclerView.apply {
            layoutManager = LinearLayoutManager(holder.recyclerView.context, LinearLayout.VERTICAL, false) as RecyclerView.LayoutManager?
            adapter = ViewChildAdapter(parent.children!!)
        }
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
        val recyclerView : RecyclerView = itemView.rv_child
        val textView: TextView = itemView.textView
    }
}
class ViewChildAdapter(private val children:List<ModelChild>):RecyclerView.Adapter<ViewChildAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.child_recycler,parent,false)
        return ViewHolder(view)
    }
    override fun getItemCount(): Int {
        return children.size
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val child = children[position]
        holder.textView.text = child.item
    }

    inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
        val textView : TextView = itemView.child_textView
    }
}

Inflated XML files

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

    <RelativeLayout
        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="20dp"
            android:background="@color/color_super_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="70dp"
            android:layout_marginBottom="0dp"
            android:orientation="horizontal"
            android:paddingLeft="4dp"
            android:paddingTop="8dp"
            tools:layout_editor_absoluteX="74dp" />
    </RelativeLayout>
</android.support.v7.widget.CardView>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/child_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:background="@color/color_Transparent"
        android:padding="10dp"
        android:text="TextView"
        android:textColor="@color/color_Black"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

When the ViewActivity is loaded ONLY the childList is displayed.

We have tried various changes and can not display the parent List though using theGET fun the parentList data is displayed so we know it is in the list.

We can run the fun theGET and crate a new ArrayList that seems futile.

Our concern is that the parentList is displayed and then removed when the childList is displayed.

We do not know how to prove this.

So our question is how to show Parent and Child data in a organized fashion in the View Activity?

We are adding New CODE based on @Cruces answer
Some issues with this code are beyond out understanding
1. We have no way to run the fun join to create the newList
2. Parent and Child ViewHolder can be called only with receiver of containing Class
3. Too many inner Class's and do we need an Outer Nested annotation?
4. or if both parent and child implement an interface a List< IItem > )
We do not know how to write an interface and connect it to the JoinAdapter

While the answer poses new question we feel it better to ask with in this context = Context HUMOR Here is the FIX for the JoinAdapter

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.the_view, parent, false)
        return ParentViewHolder(view!!)
    } else {
        view = LayoutInflater.from(parent.context).inflate(R.layout.child_recycler, 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) {
    override fun bindData(position: Int, item: Any) {
        val parent = item as? ModelParent ?: return
        parent.dept
        parent.fkD
        parent.children
        //bind the data here
    }

    init {
        val textView: TextView = view.textView
        var editCLICK: RelativeLayout = view.findViewById(R.id.editCLICK) as RelativeLayout
        //do the view setup here
    }

}

inner class ChildViewHolder(view: View) : MyViewHolder(view) {
    init {
        val textView : TextView = itemView.child_textView
  

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...