Kotlin Recyclerview row item selection background color change - android

I am able to change the color of the text and background of row clicked of my recyclerview in my recyclerview.
But my problem is after clicking for example on the 2th item,the 10st item also gets selected.Likewise after clicking my 5th item the 3nd item is selected.
How do i solve this?
in fact my question is that how to change background color of recyclerview item that click on it in Kotlin?
I also followed the instructions in this link. But it did not worked correctly!!
AllChanelAdapter.kt
class AllChanelAdapter(private val datalist:MutableList<AllChanelModel>, var clickListener: OnItemClickListener):RecyclerView.Adapter<AllChanelHolder>() {
private lateinit var context:Context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllChanelHolder {
context = parent.context
return AllChanelHolder(LayoutInflater.from(context).inflate(R.layout.allchanel_singleitem,parent,false))
}
override fun getItemCount(): Int = datalist.size
override fun onBindViewHolder(holder: AllChanelHolder, position: Int) {
val data = datalist[position]
val txt_title = holder.itemView.txt_title
val txt_body = holder.itemView.txt_body
val img_chanel = holder.itemView.img_chanel
txt_title.setText(data.title)
txt_body.setText(data.body)
Glide
.with(context)
.load("...")
.centerCrop()
.into(img_chanel);
}
holder.initialize(datalist.get(position),clickListener)
}
interface OnItemClickListener {
fun onItemClick(item: AllChanelModel, position: Int, view: View)
}
AllChanelHolder.kt
class AllChanelHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun initialize(item:AllChanelModel,action:OnItemClickListener){
itemView.setOnClickListener {
action.onItemClick(item,adapterPosition,itemView)
}
}
}
MainPageActivity.kt
class MainPageActivity : AppCompatActivity(),OnItemClickListener {
private val datalist:MutableList<AllChanelModel> = mutableListOf()
lateinit var allchaneladapter : AllChanelAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_page)
send_request()
allchaneladapter = AllChanelAdapter(datalist,this)
all_chanel_recycler.layoutManager = LinearLayoutManager(this)
all_chanel_recycler.adapter = allchaneladapter
}
private fun send_request(){
val url = "http://10.0.2.2:8000/getsamplejson" // localhost api
val que = Volley.newRequestQueue(this#MainPageActivity)
val req = JsonArrayRequest(Request.Method.GET,url,null,
Response.Listener {
response->
for(i in 0..response.length()-1){
var chanel_obj = response.getJSONObject(i)
datalist.add(
AllChanelModel(
chanel_obj.getString("body"),
chanel_obj.getString("title"),
chanel_obj.getString("userId")
)
)
}
allchaneladapter.notifyDataSetChanged()
}, Response.ErrorListener {
error->
Log.e("",error.message)
})
que.add(req)
}
override fun onItemClick(item: AllChanelModel, position: Int, view: View) {
view.setBackgroundColor(Color.YELLOW)
}
}
AllChanelModel.kt
data class AllChanelModel(
#SerializedName("body")
val body: String,
#SerializedName("title")
val title: String,
#SerializedName("userId")
val userId: String
)
activity_main_page.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainPageActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/all_chanel_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
allchanel_singleitem.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/linear_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="#+id/txt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="TextView"
android:textColor="#000000" />
<TextView
android:id="#+id/txt_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|right"
android:text="TextView"
android:textColor="#000000" />
</LinearLayout>
<ImageView
android:id="#+id/img_chanel"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_weight="1"
app:srcCompat="#mipmap/ic_launcher" />
</LinearLayout>
please help me
thank you

After a thorough search on the Internet, I was finally able to solve this problem.
I put the code step by step and give explanations if needed.
1 - create new android studio project
2 - cods for activity_main.xml as below:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainPageActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:drawable/screen_background_light_transparent"
tools:listitem="#layout/item_list" />
</androidx.constraintlayout.widget.ConstraintLayout>
3 - create a layout for recycler view row(item) with name item_list.xml as bellow
item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/linear_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
android:background="#FFFFFF"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="#+id/tv_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="TextView"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|right"
android:text="TextView"
android:textColor="#000000" />
</LinearLayout>
<ImageView
android:id="#+id/img_chanel"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_weight="1"
app:srcCompat="#mipmap/ic_launcher" />
</LinearLayout>
4 - create data class(Based on the data you want to bind in RecyclerView) as bellow
My Model(UserModel.kt)
public data class UserModel(var title:String,var name:String,var isSelected:Boolean=false)
5 - create Adapter for your RecyclerView as bellow
CustomAdapter.kt
class CustomAdapter(private val context: Context, private val list: ArrayList<UserModel>,
private val listener: OnItemClickListener
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView),View.OnClickListener {
internal var tvLabel: TextView
internal var tvName: TextView
init {
tvLabel = itemView.findViewById(R.id.tv_label) // Initialize your All views prensent in list items
tvName = itemView.findViewById(R.id.tv_name) // Initialize your All views prensent in list items
itemView.setOnClickListener(this)
}
internal fun bind(position: Int) {
// This method will be called anytime a list item is created or update its data
//Do your stuff here
tvLabel.text = list[position].title
tvName.text = list[position].name
}
override fun onClick(v: View?) {
val position:Int = adapterPosition
if(position != RecyclerView.NO_POSITION) {
listener.onItemClick(position,this#CustomAdapter,itemView)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_list, parent, false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(list[position].isSelected){
holder.itemView.setBackgroundColor(Color.YELLOW)
holder.itemView.findViewById<LinearLayout>(R.id.linear_content).setBackgroundColor(Color.YELLOW)
} else{
holder.itemView.setBackgroundColor(Color.WHITE)
holder.itemView.findViewById<LinearLayout>(R.id.linear_content).setBackgroundColor(Color.WHITE)
}
(holder as ViewHolder).bind(position)
}
override fun getItemCount(): Int {
return list.size
}
interface OnItemClickListener{
fun onItemClick(position: Int,adapter:CustomAdapter,v:View)
}
}
6 - codes for MainActivity.kt as bellow:
MainActivity.kt
class MainActivity : AppCompatActivity(),CustomAdapter.OnItemClickListener {
private val data = arrayListOf<UserModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_page)
val recyclerview = findViewById<RecyclerView>(R.id.recycler_view)
data.add(UserModel(title = "item 1",name = "name 1"))
data.add(UserModel(title = "item 2",name = "name 2"))
data.add(UserModel(title = "item 3",name = "name 3"))
data.add(UserModel(title = "item 4",name = "name 4"))
data.add(UserModel(title = "item 5",name = "name 5"))
data.add(UserModel(title = "item 6",name = "name 6"))
data.add(UserModel(title = "item 1",name = "name 1"))
data.add(UserModel(title = "item 2",name = "name 2"))
data.add(UserModel(title = "item 3",name = "name 3"))
data.add(UserModel(title = "item 4",name = "name 4"))
data.add(UserModel(title = "item 5",name = "name 5"))
data.add(UserModel(title = "item 6",name = "name 6"))
val adapter = CustomAdapter(this,data,this)
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerview.adapter = adapter
recyclerview.setHasFixedSize(true)
}
override fun onItemClick(position: Int,adapter: CustomAdapter,v:View) {
val clicked_item:UserModel = data[position]
clicked_item.title = "clicked"
clicked_item.isSelected = !clicked_item.isSelected
if(clicked_item.isSelected){
recycler_view.getChildAt(recycler_view.indexOfChild(v)).setBackgroundColor(Color.YELLOW)
recycler_view.getChildAt(recycler_view.indexOfChild(v)).findViewById<LinearLayout>(R.id.linear_content).setBackgroundColor(Color.YELLOW)
}else{
recycler_view.getChildAt(recycler_view.indexOfChild(v)).setBackgroundColor(Color.WHITE)
recycler_view.getChildAt(recycler_view.indexOfChild(v)).findViewById<LinearLayout>(R.id.linear_content).setBackgroundColor(Color.WHITE)
}
}
}
I hope you find it useful

You have to set color for other items when you cal

Related

How Can I achieve this layout by using the recycler view in android?? when I was passing list of String image url to the adapter ? layout in Image

[enter image description here][1]
[enter image description here][2]VHFV.png
strong text
[2]: https://i.stack.imgur.com/YJOpm.png
activity_main
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#170628"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_images"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
image_layout.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="5dp"
app:cardCornerRadius="10dp"
android:layout_height="100dp">
<ImageView
android:id="#+id/big_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/zone_images" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var zoneBinding: ActivityMainBinding
var image = ArrayList<String>()
lateinit var zoneAdapter:ZoneImagesAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
zoneBinding= DataBindingUtil.setContentView(this,R.layout.activity_main)
buildData()
setRecyclerView()
}
private fun buildData() {
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
}
private fun setRecyclerView() {
zoneAdapter = ZoneImagesAdapter(image)
val flexboxLayoutManager = FlexboxLayoutManager(this)
flexboxLayoutManager.flexDirection =FlexDirection.ROW
flexboxLayoutManager.flexWrap = FlexWrap.WRAP
flexboxLayoutManager.justifyContent = JustifyContent.CENTER
flexboxLayoutManager.alignItems = AlignItems.STRETCH
zoneBinding.rvImages.apply {
adapter=zoneAdapter
layoutManager=flexboxLayoutManager
}
}
Adapter
class ZoneImagesAdapter (var listOfImageUrl:ArrayList<String>):
RecyclerView.Adapter<ZoneImagesAdapter.ImageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.big_image_layout, parent, false)
return ImageViewHolder(view)
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val image = listOfImageUrl[position]
holder.setImages(image)
}
override fun getItemCount(): Int {
return listOfImageUrl.size
}
class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var zoneImage:ImageView=itemView.findViewById(R.id.big_image)
fun setImages(images: String) {
Glide.with(zoneImage).load(images).into(zoneImage)
val layoutParams:ViewGroup.LayoutParams = zoneImage.layoutParams
if (layoutParams is FlexboxLayoutManager.LayoutParams){
val flexboxLp:FlexboxLayoutManager.LayoutParams= layoutParams as FlexboxLayoutManager.LayoutParams
flexboxLp.flexGrow= 1.0f
}
}
}
}
How can I achieve this layout that is showing inside image using recyclerView, ?? I use flexboxLayoutManager for this but I do not know how can I used, Can anyone help me to make this layout that is showing inside image

I m geting only one item back to recyclerview my from Room datatabase

As I have implemented a room library in my project ,
I add data to database , But Recyclerview is showing only one item .
class NotesAdapter : RecyclerView.Adapter<NotesAdapter.NotesViewHolder>() {
class NotesViewHolder(val binding: NotesCardLayoutBinding) :
RecyclerView.ViewHolder(binding.root)
private val differCallback = object : DiffUtil.ItemCallback<Notes>() {
override fun areItemsTheSame(oldItem: Notes, newItem: Notes): Boolean {
return oldItem.noteId == newItem.noteId
}
override fun areContentsTheSame(oldItem: Notes, newItem: Notes): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this,differCallback)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotesViewHolder {
val view =
NotesCardLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return NotesViewHolder(view)
}
override fun onBindViewHolder(holder: NotesViewHolder, position: Int) {
val notes = differ.currentList[position]
holder.binding.tvTitle.text = notes.noteTitle.toString()
holder.binding.tvDesc.text = notes.notesDesc.toString()
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
" My Notes Fragment where recylerview is intialized "
class NotesFragment : Fragment() {
private lateinit var binding: FragmentNotesBinding
private lateinit var notesViewModel: NotesViewModel
private lateinit var notesAdapter : NotesAdapter
private fun recyclerviewSetup() {
notesAdapter = NotesAdapter()
val recyclerView = binding.rvNotes
recyclerView.adapter = notesAdapter
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
activity?.let {
notesViewModel.getAllNotes.observe(viewLifecycleOwner , Observer { noteList->
notesAdapter.differ.submitList(noteList)
})
}
}
}
It may be the problem of database or Adapter
please gyzz help me out
github
The problem is not with fetching data, I've cloned your repo and checked, it is while inserting, do not user Int? for primary key, just use Int
Notes.kt
#Entity(tableName = "Notes Table")
data class Notes(
#PrimaryKey(autoGenerate = true)
var noteId: Int,
#ColumnInfo(name = "Title of Notes")
val noteTitle: String?,
#ColumnInfo(name = "Description of Notes")
val notesDesc: String?
)
Also you have another problem is notes_card_layout, you are setting height to match_parent which is not correct, use below
notes_card_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardElevation="5dp"
app:cardCornerRadius="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginVertical="5dp"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:text="#string/title_card" />
<TextView
android:id="#+id/tvDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:text="#string/desc_card" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
replace above two code snippets and try, below is a snapshot from my modified changes

The image does not appear - Android

I wrote this code using recyclerview and I got the image that I got from the url why, my picture didn't appear
this is my activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/item_hero"
/>
</RelativeLayout>
this is my tools:listitem
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<ImageView
android:id="#+id/imgHeroes"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="centerCrop"/>
<TextView
android:id="#+id/txtHeroName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp" />
</LinearLayout>
this is my MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listHeroes = listOf(
Hero(
name = "Thor",
image = "https://media.skyegrid.id/wp-content/uploads/2019/06/Thor-4-1.jpg"
),
Hero(
name = "Captain America",
image = "https://i.annihil.us/u/prod/marvel/i/mg/1/c0/537ba2bfd6bab/standard_xlarge.jpg"
),
Hero(
name = "Iron Man",
image = "https://i.annihil.us/u/prod/marvel/i/mg/6/a0/55b6a25e654e6/standard_xlarge.jpg"
)
)
val heroesAdapter = HeroAdapter(listHeroes) {hero ->
Toast.makeText(this, "hero clicked ${hero.name}", Toast.LENGTH_SHORT).show()
}
rvMain.apply {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = heroesAdapter
}
}
}
this is my adapter
class HeroAdapter(
private val heroes: List<Hero>,
private val adapterOnclick: (Hero) -> Unit
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeroAdapter.HeroHolder {
return HeroHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_hero,
parent,
false
)
)
}
override fun getItemCount(): Int = heroes.size
override fun onBindViewHolder(holder: HeroAdapter.HeroHolder, position: Int) {
holder.binHero(heroes[position])
}
inner class HeroHolder(view: View) : RecyclerView.ViewHolder(view) {
fun binHero(hero: Hero) {
itemView.apply {
txtHeroName.text = hero.name
Picasso.get().load(hero.image).into(imgHeroes)
setOnClickListener {
adapterOnclick(hero)
}
}
}
}
}
this is my emulator
https://i.stack.imgur.com/0ePUC.png
I wrote this code using recyclerview and I got the image that I got from the url, why my image didn't appear, I wrote this code using the kotlin programming language
please help me

RecyclerView shows just one item from Firebase

I know there are few questions about this problem. But none of them didn't solve my problem especially my code is in Kotlin and new working with Fragments. Don't rush to say my question is duplicated.
My problem is exactly what title said, my RecyclerView is populated just with one item(child) from Firebase in my Fragment.
Adapter:
class NewsList(private val userList: List<News>) : RecyclerView.Adapter<NewsList.ViewHolder>() {
private val Context = this
override fun onBindViewHolder(p0: ViewHolder?, p1: Int) {
val news: News = userList[p1]
p0?.mesajTextView?.text = news.text
val time = news.time
val getTimeAgo = GetTimeAgo()
val lastMsg = getTimeAgo.getTimeAgo(time, Context)
p0?.timeNewsTextView!!.text = lastMsg
}
override fun onCreateViewHolder(p0: ViewGroup?, p1: Int): ViewHolder {
val v = LayoutInflater.from(p0?.context).inflate(R.layout.news_layout, p0, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return userList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val mesajTextView = itemView.findViewById(R.id.mesajTextView) as TextView
val timeNewsTextView = itemView.findViewById(R.id.timeNewsTextView) as TextView
}
}
My fragment where ReyclerView is populated:
override fun onActivityCreated(savedInstanceState: Bundle?) {
newsRecyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
}
private fun populalteQuestionsList() {
val mChatDatabaseReference = FirebaseDatabase.getInstance().reference.child(Constants.NEWS)
mListenerPopulateList = mChatDatabaseReference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (convSnapshot in dataSnapshot.children) {
val news = ArrayList<News>()
val conv = convSnapshot.getValue(News::class.java)
news.add(conv!!)
val adapter = NewsList(news)
newsRecyclerView!!.adapter = adapter
adapter.notifyDataSetChanged()
}
}
override fun onCancelled(databaseError: DatabaseError) {
}
})
mChatDatabaseReference.addListenerForSingleValueEvent(mListenerPopulateList)
}
Layout for items:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp"
card_view:cardElevation="10dp">
<RelativeLayout
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<TextView
android:id="#+id/mesajTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="64dp"
android:textAppearance="?android:attr/textAppearanceLarge"
tools:text="Mesaj" />
<TextView
android:id="#+id/timeNewsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="16dp"
android:layout_marginTop="4dp"
android:maxLength="15"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="14:20" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Hope you understand, please help me I really need to finish this app.
You are creating new list with having single element in loop and passing it to adapter so it has only one element to show so
Move this outside loop
val adapter = NewsList(news)
newsRecyclerView!!.adapter = adapter
adapter.notifyDataSetChanged()
and initialise list outside for loop
val news = ArrayList<News>()
for (convSnapshot in dataSnapshot.children) {
val conv = convSnapshot.getValue(News::class.java)
news.add(conv!!)
}
val adapter = NewsList(news)
newsRecyclerView!!.adapter = adapter
adapter.notifyDataSetChanged()
Note : fill_parent has been deprecated so us match_parent
You're recreating the dataset at every iteration, so it will always have the last added item, move the instantiation of the datasource to outside the loop. Also, try not adding the values for the adapter at every iteration. When you're done adding items to the datasource, then you should add them to the adapter and set the adapter in the recyclerview. :
val news = ArrayList<News>()
for (convSnapshot in dataSnapshot.children) {
val conv = convSnapshot.getValue(News::class.java)
news.add(conv!!)
}
val adapter = NewsList(news)
newsRecyclerView!!.adapter = adapter
adapter.notifyDataSetChanged()

How to display data in RecyclerView using Retrofit2 API?

First of all, I'm new to Android/Java/Kotlin development. I'm using Retrofit2 to retrieve data from Udacity API. I can see the response in the Logcat, but when I try to display it in RecyclerView there is just a blank screen. I think the error is in the MainActivity, but I'm still clueless and need help.
My model classes
class Course(var title: String,
var subtitle: String,
var key: String,
var instructors: List<Instructor>,
var expected_learning: String,
var required_knowledge: String)
class Instructor(var name: String,
var bio: String)
My interface
interface ApiServiceInterface {
#GET("courses")
fun list() : Call<UdacityCatalog>
}
My adapter
class CourseAdapter(val listCourses: ArrayList<Course?>, val context: Context) : RecyclerView.Adapter<CourseAdapter.CourseViewHolder>() {
class CourseViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem) {
val courseTitle = viewItem.findViewById<TextView?>(R.id.tv_title) as TextView
val courseSubtitle = viewItem.findViewById<TextView?>(R.id.tv_subtitle) as TextView
val courseKey = viewItem.findViewById<TextView?>(R.id.tv_course_key) as TextView
val instructorName = viewItem.findViewById<TextView?>(R.id.tv_instructor_name) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): CourseViewHolder {
val viewHolder = LayoutInflater.from(parent?.context).inflate(R.layout.activity_item_list, parent, false)
val itemViewHolder = CourseViewHolder(viewHolder)
return itemViewHolder
}
override fun onBindViewHolder(holder: CourseViewHolder?, position: Int) {
holder?.courseTitle?.text = listCourses[position].title
holder?.courseSubtitle?.text = listCourses[position].subtitle
holder?.courseKey?.text = listCourses[position].key
holder?.instructorName?.text = listCourses[position].instructors.toString()
}
override fun getItemCount(): Int = listCourses.size
}
My MainActivity -- I think the error is in here, but I haven't figured it out yet
class MainActivity : AppCompatActivity() {
internal val TAG = "Testing Retrofit2 API"
lateinit var mRecyclerView: RecyclerView
lateinit var mCourseAdapter: RecyclerView.Adapter<CourseAdapter.CourseViewHolder>
val listCourse = arrayListOf<Course?>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_recyclerview)
mRecyclerView = findViewById<RecyclerView?>(R.id.id_recycler_view) as RecyclerView
val mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
mRecyclerView.layoutManager = mLayoutManager
mRecyclerView.setHasFixedSize(true)
mCourseAdapter = CourseAdapter(listCourse, applicationContext)
mRecyclerView.adapter = mCourseAdapter
mCourseAdapter.notifyDataSetChanged()
val call = RetrofitInitializer().createService().list()
call.enqueue(object : Callback<UdacityCatalog> {
override fun onResponse(call: Call<UdacityCatalog>, response: Response<UdacityCatalog>) {
response.body()
if (!response.isSuccessful) {
Log.i(TAG, "[ ERROR ] " + response.code())
} else {
if (listCourse.isEmpty()) {
Toast.makeText(applicationContext, "Empty list!", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(applicationContext, "Full list!", Toast.LENGTH_LONG).show()
}
val catalog = response.body()
for (c in catalog!!.courses!!) {
Log.i(TAG, String.format("%s: %s", c.title, c.subtitle, c.key, c.required_knowledge, c.expected_learning))
for (i in c.instructors!!) {
Log.i(TAG, i.name)
}
Log.i(TAG, "\n****************************************************************************************************\n")
}
}
}
override fun onFailure(call: Call<UdacityCatalog>?, t: Throwable?) {
Log.d(TAG, "onFailure() : " + t?.message)
}
})
}
}
An initializer class for Retrofit instance
class RetrofitInitializer {
companion object Factory {
val BASE_URL = "https://www.udacity.com/public-api/v0/"
}
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun createService(): ApiServiceInterface = retrofit.create(ApiServiceInterface::class.java)
}
My RecyclerView xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context="activities.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/id_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
My CardView xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/udacity_catalog"
android:textAppearance="?android:textAppearanceLarge"
android:textColor="#9C27B0"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_title"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_subtitle"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_course_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_key"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
<TextView
android:id="#+id/tv_instructor_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="start"
android:hint="#string/hint_name"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#000000" />
</LinearLayout>
</android.support.v7.widget.CardView>
You have an empty list of courses (listCourse) in your Activity. You pass that empty list to the adapter via it's constructor.
That list stays empty even after you fetched the courses. So the adapter / RecyclerView stays empty.
Try creating the adapter after you fetched the courses, with
mCourseAdapter = CourseAdapter(catalog!!.courses!!, applicationContext)
or have a courses property in your adapter lile
YourAdapter(...) {
var courses = listOf(Course)
}
and then in your Activity (after fetching the courses):
adapter.courses = catalog!!.courses!!
adapter.notifyDataSetChanged()

Categories

Resources