2

I have a code in Java that i want to change to Kotlin syntax. The jave code is:

  public class CountryDataItem (String countryNane,String countryUrl)
{
    public static RecyclerView.ViewHolder onCreateViewHolder (ViewGroup parent)
    {
        new ViewHolder (parent);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder
    {
        private TextView countryTextView;
        private ImageView countryImageView;
     
        public ViewHolder(@NonNull View view)
        {
            super(view);
            view.findViewById...
            ...
        }
    } 
}

Code is related to RecyclerView. I want to be able to create as many as ViewHolder's as i want from the static nested class type. I wrote the following code, but it feels me like a bad code, unreadable (I prefer not to write anonymous class but didn't know how to write the "static" ViewHolder Class and also always return the same field.

Code I have wrote:

   class CountryDataItem (val countryName :String, var countryFlagUrl )
{
    companion object
    {

         fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
             return object : RecyclerView.ViewHolder(parent) {
                 val countryNameTextView: TextView = parent.findViewById(R.id.country_name_tv)
                 val countryFlagUrl: ImageView = parent.findViewById(R.id.country_iv)
             }
         }
    }

I prefer to write a code with a companion object that extends RecyclerView.ViewHolder class buy since writing:

object ViewHolder: RecyclewView.ViewHolder enforce me the provide () and argument of type View to RecyclewView.ViewHolder

i can't do it

Eitanos30
  • 1,331
  • 11
  • 19

2 Answers2

3

Nested classes are static by default in Kotlin. You have to mark them inner to make them not static. So your Java class could be like this in Kotlin:

class CountryDataItem (val countryName: String, var countryFlagUrl: String) {

    companion object {
        fun onCreateViewHolder(parent: ViewGroup) = ViewHolder(parent)
    }

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val countryTextView: TextView = view.findViewById...
        val countryImageView: ImageView = view.findViewById...
    } 
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • god bless you mate!!! i like the way you explain things and not only write the code :) Although it seems you are missing the inflate :) – Eitanos30 Nov 10 '20 at 17:38
  • I was doing a direct port of your class above, which doesn't show inflation. I guess you could do it in `onCreateViewHolder` if you pass a Context or LayoutInflater parameter to the function. – Tenfour04 Nov 10 '20 at 17:41
  • just to solve my curious. Can you please tell me if my original code will work with more than one item? – Eitanos30 Nov 10 '20 at 18:07
  • It won’t be usable because the properties are declared in an anonymous class, so they are not retrievable. – Tenfour04 Nov 10 '20 at 18:09
1

You should have the companion object within the ViewHolder class. Like so:

class CountryDataItem(countryName: String, countryUrl) {

    class ViewHolder private constructor(view: View): RecyclerView.ViewHolder(view) {
        private val textView: TextView = view.findViewById(R.id.textView)
        private val imageView: ImageView = view.findViewById(R.id.imageView)

        fun bind(model: Model) {
            textView.text = ...
        }

        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val view = layoutInflater.inflate(R.layout.list_item, parent, false)
                
                return ViewHolder(view)
            }
        }
    }
}

Now to create the ViewHolder you can just call the from method. Like so:

CountryDataItem.ViewHolder.from(parent)
Xid
  • 4,578
  • 2
  • 13
  • 35
  • thanks. but:1. Why the constructor is private? 2.Doesn't the bind function need to be part of **CountryDataItem and not part of ViewHolder class?** – Eitanos30 Nov 10 '20 at 17:37
  • 1. I'm sorry that I modified your code but I believe the `ViewHolder` class should be responsible for the creation of the view and not receive the view from another class. 2. No, I believe that what happens to the views (the logic) should remain within the `ViewHolder` class, the data may be set by an external entity. My beliefs are based on the Single Responsibility Principle – Xid Nov 10 '20 at 17:44
  • This way any changes to the ViewHolder will have no effect on any other class. The way you have designed the code, a change in the layout will mean changes in multiple classes. – Xid Nov 10 '20 at 17:47
  • i understand the reason you gave for section 1. But for section 2, All the data is part of the CountryDataItem (get in in the constructor) so i am not sure the logic should be part of the *ViewHolder* – Eitanos30 Nov 10 '20 at 17:48
  • i must say that all the examples i saw in RecyclerView implementatin, all the logic isn't inside the ViewHolder class. But i'm programming only one year so i can't argue with an expert – Eitanos30 Nov 10 '20 at 17:50
  • Haha, I'm no expert. I'm just saying, the class is called `ViewHolder` so I believe it should be responsible for the view changes. Of course, data should not be manipulated within the ViewHolder. I know almost all examples do not follow this. It is just my point of view – Xid Nov 10 '20 at 17:52