Unable to bind data in RecyclerView - android

I'm trying to learn mobile development and got stuck trying to do a recyclerview.
I've set up the data class and also the xml file of the item.
When I try to bind the data to the xml file, in the onBindViewHolder function, the system gives me no option to select which ID I want to bind to.
Data Class
package com.example.recyclerview1
data class Todo(
val title: String,
var isChecked: Boolean
)
XML item
<?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="100dp"
android:padding="16dp">
<TextView
android:id="#+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="title"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/cbDone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<CheckBox
android:id="#+id/cbDone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Adapter Class
package com.example.recyclerview1
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
class TodoAdapter(
var todos:List<Todo>
): RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
inner class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo,parent,false)
return TodoViewHolder(view)
}
override fun getItemCount(): Int { return todos.size}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.itemView.tvTitle << right here I want to select the ID of the TextView, but the IDE does not show me
}
}

You can use the findViewById method for getting an instance of the view component and then perform some operation on them like this:
class TodoAdapter(var todos:List<Todo>) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
inner class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
var cbDone: CheckBox = itemView.findViewById(R.id.cbDone)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.tvTitle. // DO YOUR STUFF HERE
}
}
Or you can use ViewBinding capabilities for accessing view instances like is written in this post.
If you want to perform the whole data binding inside XML, then you need to use DataBinding feature. To do that, just follow this post on how to enable DataBinding and how to use it inside your project.

One cannot data-bind, while the XML will generate no data-binding. That item XML needs layout & data node and the model class might need #Bindable annotations. Better inflate with the data-binding, but for that it would need the be generated.

Related

problem, can't create an event that generates a toast message on kotlin recyclerview

I'm using Kotlin to create an event that generates a toast message on click of a recyclerview. I run into trouble making a Tost message in a recyclerview event.
I tried the following page, but couldn't solve it.
Toast message is not working in Recycler View
error code is
in kotlin & None of the following functions can be called with the arguments supplied: public open fun makeText(p0: Context!, p1: CharSequence!, p2: Int): Toast! defined in android.widget.Toast public open fun makeText(p0: Context!, p1: Int, p2: Int): Toast! defined in android.widget.Toast
PrintActivity.kt
package com.questionbank
class PrintActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val vBinding = ActivityPrintBinding.inflate(layoutInflater)
setContentView(vBinding.root)
val helper = SqliteHelper(this, "myDB.sql", 1)
var recyclerViewAdapter = CustomAdapter()
recyclerViewAdapter.listData = helper.select()
vBinding.myRecyclerView.adapter = recyclerViewAdapter
vBinding.myRecyclerView.layoutManager = LinearLayoutManager(this)
vBinding.myRecyclerView.addItemDecoration(
DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
)
}
class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>() {
var listData = ArrayList<questionType>()
inner class Holder(val vBinding: QuestionLayoutRecyclerBinding) :
RecyclerView.ViewHolder(vBinding.root) {
fun setData(id:Int?, question: String, answer: String, exp: String) {
vBinding.printId.text=id.toString()
vBinding.myLinear.setOnClickListener {
// error occur
Toast.makeText(this#PrintActivity, "test", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val vBinding = QuestionLayoutRecyclerBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return Holder(vBinding)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val question = listData[position]
holder.setData(question.id, question.question, question.answer, question.exp)
}
override fun getItemCount(): Int {
return listData.size
}
}
}
activity_print
<?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=".PrintActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/myRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="32dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
question_layout_recycler.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myLinear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/printId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
Two ways to fix,
Make CustomAdapter class as inner class.
innner class CustomAdapter : RecyclerView.Adapter<CustomAdapter.Holder>() {
So toast function it will take constant from activity class.
In viewholder, get context from view. it.context will get context from linearlayout.
vBinding.myLinear.setOnClickListener {
Toast.makeText(it.context, "test", Toast.LENGTH_SHORT).show()
}
Its recommended to place adapter logic in separate file and use second solution.
So you dont need to make adapter as inner class.

Heterogeneous Views with unknow EditText number

I'm working on a dynamicViews (not sure if that's the right word for creating a view from a json file).
I'm getting the schema from a JSON file, I've stepped up the recycleView and its adapter, so far so good, each Recycleview item (must or not) contain a number of EditText whose number is unknown in advance, so based on the Json file, I have to inflate inside.
I searched a lot but the similar solution I found for Heterogene Recycleview: the idea was to use separate layout and inflate each of them according to your needs inside onCreateViewHolder but the developer who published the solution knew in advance what is the combination of all possible views and he just switch.
class Adapter_base_Display(private val listener: Display_Fragment,
activity: FragmentActivity ,
liste_display : ArrayList<DisplaySections>)
: RecyclerView.Adapter<Base_DisplayViewHolder>() {
private val activityIns = activity
private val liste_display_Recycle_adapter = liste_display
interface Base_DisplayListener {
fun onClickeddisplay(position: Int)
}
private val items = ArrayList<DisplaySections>()
fun setItems(items: ArrayList<DisplaySections>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
fun clear() {
val size: Int = items.size
items.clear()
notifyItemRangeRemoved(0, size)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Base_DisplayViewHolder {
val binding: ItemDisplayBinding =
ItemDisplayBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Base_DisplayViewHolder(
binding,
listener as Base_DisplayListener,
activityIns,
parent,
liste_display_Recycle_adapter)
}
override fun getItemCount(): Int = items.size
override fun onBindViewHolder(holder: Base_DisplayViewHolder, position: Int) =
holder.bind(items[position])
}
class Base_DisplayViewHolder(
private val itemBinding: ItemDisplayBinding,
private val listener: Adapter_base_Display.Base_DisplayListener,
private val activityIns: FragmentActivity,
private var parent: ViewGroup,
private val items: ArrayList<DisplaySections>,
) : RecyclerView.ViewHolder(itemBinding.root),
View.OnClickListener {
init {
itemBinding.root.setOnClickListener(this)
}
fun bind(item: DisplaySections) {
itemBinding.textView2.text = item.name
}
override fun onClick(v: View?) {
listener.onClickeddisplay(adapterPosition)
}
}
The EditText I want to inflate multiple time
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/edittext_isplay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="TextView"
android:maxLines="3"
android:textColor="#color/black"
android:textSize="18sp" />
data class DisplaySections(
val id : Int,
val name : String,
val createdAt : String,
val updatedAt : String,
val displayTypeId : Int,
val displayCustomFields : List<DisplayCustomFields> // Contains the elements that will be displayed as EditText
The Base layout-Recycleview Item which is common for all scenarios
<LinearLayout
android:id="#+id/parent_edittext" // ALl EditText container
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:id="#+id/camera_linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="#+id/addphoto"
android:layout_width="316dp"
android:layout_height="250dp"
android:layout_gravity="center"
android:layout_marginTop="#dimen/_20sdp"
android:src="#drawable/ajouter_photo"
app:tint="#color/clear_grey" />
<TextView
android:id="#+id/camera_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Ajouter des photos"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/plus_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_20sdp"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/my_photo_recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
I going to post the solution I found.
To solve this problem, we absolutely must use a nested RecyclerView;
As I said above, I want to display a list of items with the same common layout (Imageview + Textview), but the tricky part here is the dynamic part of each item.
For recap:
Each element (may or may not) contain N-1 (EditText), it depends on what it gets from a json file.
if you want to solve this problem by creating multiple Viewholder and switch depending on which "ViewHolderType" you are wrong !, you will just create an infinite layout files, it doesn't make sense.
if you create more than one (EditText) and only change the visibility it may work, but if you get for example 100 EditText from the Json file you are not going to manually create 100 Edittext.
if you want to programmatically generate an EditText, you will affect every item in your view Recycle since you cannot create view inside OnbindViewHolder function.
the only way I found to solve this problem is to create a parent-child RecycleView whenever there is an (EditText) you send it to the child adapter and you keep your parent element safe in the parent adapter.
You can also put a condition (NULL tester) inside the Parent-OnbindViewholder whenever there is no data, you just don't call Child-adapter.
I hope this solution will be useful to anyone who has had this problem, and if you have another solution I will be very happy to test them.

Error in RecyclerViewAdapter's onBindViewHolder() Method ㅠㅠ [duplicate]

Why do I get a NullPointerException in my ViewHolder's bindItems() method?
I've highlighted the line where I get the NullPointerException. The blogpost_author ID exists, as you can see in the XML, so what's the problem here? How is findViewById<TextView>(R.id.blogpost_author) returning null?
Adapter and ViewHolder code:
class BlogPostAdapter(val blogList: ArrayList<BlogPost>) : RecyclerView.Adapter<BlogPostAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : BlogPostAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.blog_post_list, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return blogList.size
}
override fun onBindViewHolder(holder: BlogPostAdapter.ViewHolder, position: Int) {
holder.bindItems(blogList[position])
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(blogPost: BlogPost) {
val blogPostAuthor = itemView.findViewById<TextView>(R.id.blogpost_author) // THIS LINE - NULL POINTER EXCEPTION
val blogPostTitle = itemView.findViewById<TextView>(R.id.blogpost_title)
blogPostAuthor.text = blogPost.author
blogPostTitle.text = blogPost.title
}
}
}
Activity code:
class BlogPostListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.blog_post_list)
// Get the RecyclerView from XML itself
val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
// Add a layout manager - What does a layout manager do?
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
// Create an array list to store blogposts using the the data class blogPost
val blogPosts = ArrayList<BlogPost>()
// Add some dummy data to the list
blogPosts.add(BlogPost(123, "First Blog Post", "John"))
blogPosts.add(BlogPost(456, "Second Blog Post", "Bob"))
blogPosts.add(BlogPost(789, "Third Blog Post", "Mary"))
// Create an adapter
val adapter = BlogPostAdapter(blogPosts)
// Add the adapter to the recyclerview
recyclerView.adapter = adapter
}
}
Kotlin data class:
data class BlogPost(val id: Int, val title: String, val author: String)
XML for RecyclerView:
<?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="com.topzap.android.kotlinlistapptest.BlogPostListActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
XML for CardView layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/blogpost_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="AuthorPlaceHolder"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Large"
/>
<TextView
android:id="#+id/blogpost_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="TitlePlaceHolder"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
You may be inflating the wrong layout within your RecyclerView.
This line within your onCreateViewHolder method:
val v = LayoutInflater.from(parent.context).inflate(R.layout.blog_post_list, parent, false)
You are inflating the blog_post_list.xml, which I'm assuming is the wrong layout file due to the fact you're also inflating that layout within your BlogPostListActivity here:
setContentView(R.layout.blog_post_list)
So when this line is called:
val blogPostAuthor = itemView.findViewById<TextView>(R.id.blogpost_author)
It is looking for the id 'blogpost_author' within R.layout.blog_post_list and as you can see there is no blogpost_author TextView within that layout so it returns null.
To sort it out, it should be straight forward and just change the layout resource that you're assigning to each ViewHolder within your onCreateViewHolder method with the correct layout for your CardView layout.
Which means the line should read something like:
val v = LayoutInflater.from(parent.context).inflate(R.layout.your_card_layout, parent, false)

Cast class to its subclass in Kotlin

I have a list of a class called Opportunity, which is filled with objects that extend Opportunity. The list can have either CommunityOpportunites or SponsorshipOpportunities.
I override getItemViewType and assign a value to each item based on whichever subclass the object in the relevant postition, and have a different ViewHolder for each:
override fun getItemViewType(position: Int): Int {
return if (opportunityList[position] is SponsorshipOpportunity){
Log.i(TAG,"Item type is sponsorshipId")
SPONSORSHIP
} else{
Log.i(TAG,"Item type is community")
COMMUNITY
}
}
inner class CommunityViewHolder(var view: CommunityTileBinding):RecyclerView.ViewHolder(view.root)
inner class SponsorshipViewHolder(var view: SponsorshipTileBinding):RecyclerView.ViewHolder(view.root)
companion object{
private const val COMMUNITY = 0
private const val SPONSORSHIP = 1
}
In onCreateViewHolder() I create the proper ViewHolder for the class of the item, and in onBindViewHolder() I attempt to cast the items in the list (of type Opportunity in the constructor) to the subclass of the item in the view:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType){
COMMUNITY->CommunityViewHolder(DataBindingUtil.inflate(inflater, R.layout.community_tile, parent, false))
SPONSORSHIP-> SponsorshipViewHolder(DataBindingUtil.inflate(inflater, R.layout.sponsorship_tile, parent, false))
else-> throw IllegalArgumentException()
}
}
override fun getItemCount(): Int = opportunityList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder.itemViewType){
COMMUNITY-> {
(holder as CommunityViewHolder).view.communityOpportunity = opportunityList[position] as CommunityOpportunity
}
SPONSORSHIP->{
(holder as SponsorshipViewHolder).view.sponsorship = opportunityList[position] as SponsorshipOpportunity
holder.view.postActionText.text = context.resources.getString(R.string.watch_respond)
}
}
}
However, I get the following class cast exception
java.lang.ClassCastException: com.example.model.Opportunity cannot be cast to com.example.model.CommunityOpportunity
when I try at the relevant line in onBindViewHolder, even though the log statement confirming that the item is a CommunityOpportunity in getItemViewType() is printed.
Is there a better way to ask, or is there a better way for me to be displaying multiple ViewHolder/Object types in the RecyclerView?
Edit: Here are the relevant xml layouts:
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="sponsorship"
type="com.example.weare8sample.model.SponsorshipOpportunity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:elevation="2dp"
android:orientation="vertical"
android:background="#drawable/tile_background">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="#drawable/tile_background"
android:imageUrl="#{sponsorship.coverTileUri}">
</ImageView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:padding="10dp">
<TextView
android:id="#+id/postActionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/lato_bold"
tools:text="#string/watch_respond">
</TextView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="#drawable/ic_chevron_right_black_36dp">
</ImageView>
</RelativeLayout>
</LinearLayout>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="communityOpportunity"
type="com.example.weare8sample.model.CommunityOpportunity" />
</data>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#drawable/tile_background"
android:imageUrl="#{communityOpportunity.mediaImageUri}">
</ImageView>
Add an explicit type check for all types in getItemViewType and throw if it's an unknown type, to properly handle all cases.
As it is now, if there's a 3rd type of Opportunity, it will be assumed to be of COMMUNITY type.
Use sealed class in your Model that is best option for this case
sealed class Opportunity {
data class CommunityOpportunites(
// class fields
):Opportunity()
data class SponsorshipOpportunities(
// class fields
):Opportunity()
}
and in your getItemViewType method should be like this
override fun getItemViewType(position: Int) = when (list[position]) {
is Opportunity.CommunityOpportunites-> 0
is Opportunity.SponsorshipOpportunities-> 1
}
and onCreateViwHolder method
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
when (viewType) {
0 -> ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item1, parent,
false)
)
else->
LayoutInflater.from(parent.context).inflate(R.layout.item2, parent,
false)
)
}
you don't have to use several ViwHolders write ViewHolder inner class like these
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
val d = list[adapterPosition]
when (d) {
is Opportunity.CommunityOpportunites -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//CommunityOpportunites Kotlin smart cast does it for you
}
}
is Opportunity.SponsorshipOpportunities -> {
itemView.apply {
//bind the data in the list to view you needn't cast d to
//SponsorshipOpportunities Kotlin smart cast does it for you
}
}
}
}
}
I think this should work :)

Kotlin RecyclerView DataBindingAdapter I do not know why I get the error

I want to combine imageview with data bindingadapter. I was searching Google about my problem. The problem is databindingadapter doesn't work in my XML.
To put it easy, other views recognize well such as textView. If I enter a variable name at ImageView, the color should change but it will not change.
Here is my code
<data class> (databindingadapter)
import android.net.Uri
import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.squareup.picasso.Picasso
class Person {
val name = ""
val age = ""
var image = ""
}
object imageBindingAdapter {
val person = Person()
#JvmStatic
#BindingAdapter("image")
fun bindImage(imageView: ImageView) {
Picasso.get().load(Uri.parse(person.image))
.fit().centerCrop().into(imageView)
}
}
XML code
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable name="person"
type="com.example.kotlinerecyclerview.Person"/>
</data>
<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="wrap_content"
>
<ImageView android:layout_width="100dp" android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="#android:drawable/btn_default"
app:image="person.image"
/>
<TextView
android:text="#{person.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:text="#{String.valueOf(person.age)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/tv_name"
app:layout_constraintStart_toStartOf="parent"
android:id="#+id/tv_age"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here is my recyclerview adapter class
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.kotlinerecyclerview.databinding.ItemBinding
class ListAdapter(val items: List<Person>, private val clickListener:
(person: Person) -> Unit) :
RecyclerView.Adapter<ListAdapter.SampleViewHolder>() {
class SampleViewHolder(val binding: ItemBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
SampleViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item, parent, false)
val holder = SampleViewHolder(ItemBinding.bind(view))
view.setOnClickListener {
clickListener.invoke(items[holder.adapterPosition])
}
return holder
}
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: SampleViewHolder, position: Int) {
holder.binding.person = items[position]`enter code here`
}
}
I moved this code to another class ex) mainactivity, listadapter
but it doesn't work.
I wrote the code as described in other videos or documents about databindingadapter.
Try to pass the Image Url also to the Binding Adapter
#JvmStatic
#BindingAdapter("image")
fun bindImage(imageView: ImageView, url: String) {
Picasso.get().load(url)
.fit().centerCrop().into(imageView)
}
Also change your xml as given below
<ImageView android:layout_width="100dp" android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="#android:drawable/btn_default"
app:image="#{person.image}"
/>
Check this Guide also
First workaround:
Move binding adapter in separate file and add "app:"
ImageViewBindings.java
#BindingAdapter("app:image")
fun setImage(view: ImageView, url: String) {
Picasso.get().load(url).fit().centerCrop().into(view)
}
In
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="#android:drawable/btn_default"
app:image ="person.image"/>
android:src and app:image
try to do the same thing. It can be a reason of conflict.
If your's intent is set multiple images, consider to separate them (for example to 2 different ImageViews).
person.image is not an ObservableField so you should use executePendingBindings like
override fun onBindViewHolder(holder: SampleViewHolder, position: Int) {
holder.binding.person = items[position]
holder.binding.executePendingBindings()
}
Second workaround:
There is possibility what your urls use http protocol, not https.
In this case this link may help: Picasso not loading image from http url but loads images from https url?

Categories

Resources