jatwing
jatwing

Reputation: 63

kotlin abstract static fun in companion objects

I learn the use of ViewHolder from an offical sample named UserViewHolder.

public class UserViewHolder extends RecyclerView.ViewHolder {

static UserViewHolder create(LayoutInflater inflater, ViewGroup parent) {
    UserItemBinding binding = UserItemBinding
        .inflate(inflater, parent, false);
    return new UserViewHolder(binding);
  } 

  private UserItemBinding mBinding;

  private UserViewHolder(UserItemBinding binding) {
    super(binding.getRoot());
    mBinding = binding;
  }

  public void bindTo(User user) {
    mBinding.setUser(user);
    mBinding.executePendingBindings();
  }

}

I'm going to write many ViewHolder classes, so I hope I can write an abstract class. In Java, it looks like:

public abstract  static class BaseViewHolder {

abstract static BaseViewHolder create()

abstract void bindTo()

}

I try to write it using Kotlin , but finally I find that it's not as simple as it in Java.

abstract class BaseViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {

abstract fun bindTo(viewModel: BaseViewModel)

}

In Kotlin, if I want a static function, I need to write the function in "companion objects". But it can't be a "abstract".

In Java, a abstract class with abstract classes is common.

But how can I write it in Kotlin?

update:

I have wrote my own SleepViewHolder. I'm going to write lots of ViewHolder, such as AppleViewHolder, BananaViewHolder and so on. So I want to build a BaseViewHolder as a pattern. My question is that, in that case, what's the best way to write the pattern BaseViewHolder? Should I change the constrcuter of it, or make the create function public?

open class SleepViewHolder private constructor(private val binding: ItemSleepBinding)
: RecyclerView.ViewHolder(binding.root) {

companion object {
    @JvmStatic
    fun create(inflater: LayoutInflater, parent: ViewGroup): SleepViewHolder {

        val binding: ItemSleepBinding
                = DataBindingUtil.inflate(inflater, R.layout.fragment_base, parent, false)

        return SleepViewHolder(binding)
    }
}

open fun bindTo(viewmodel: SleepViewModel) {
    binding.vm = viewmodel
    binding.executePendingBindings()
}

}

Upvotes: 6

Views: 12185

Answers (2)

Farid
Farid

Reputation: 2553

By default, nested classes are static in Kotlin. So you don't have to add any modifier before your class name. You can refer to the example I presented below as a starting point.

Note: ItemFruit is superclass of both ItemApple and ItemBanana

class ExampleAdapter: RecyclerView.Adapter<ExampleAdapter.BaseViewHolder<ItemFruit>>(){

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DynamicSpinnerAdapter.ViewHolder {
        when(viewType){
            VIEW_TYPE_BANANA -> BananaViewHolder(....)  // Inflate your view Banana layout here
            VIEW_TYPE_APPLE  -> AppleViewHolder(....)   // Inflate your view Banana layout here
            else             ->                         // Do something for default case
        }
    }

    override fun onBindViewHolder(holder: BaseViewHolder<ItemFruit>, position: Int){
        holder.bind(itemAppleOrBanana)      // binds your item to corresponding view
    }

    override fun getItemViewType(position: Int): Int {
        return when (position){
            condition_banana -> VIEW_TYPE_BANANA
            condition_apple  -> VIEW_TYPE_BANANA
            else             -> VIEW_TYPE_NONE
        }
    }

    inner class BananaViewHolder(itemView: View): BaseViewHolder<ItemBanana>(itemView) {
        override fun bind(item: ItemBanana) {
            // Implement your logic
        }

    }
    inner class AppleViewHolder(itemView: View): BaseViewHolder<ItemApple>(itemView) {
        override fun bind(item: ItemApple) {
            // Implement your logic
        }

    }
    inner abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView){

        internal abstract fun bind(item: T)
    }

    internal abstract inner class GenericViewHolder<T>(itemView: View) :
        RecyclerView.ViewHolder(itemView) {

        internal abstract fun bind(item: T, position: Int)
    }
}

Upvotes: 0

Suryakant Sharma
Suryakant Sharma

Reputation: 3960

In Kotlin, unlike Java or C#, classes do not have static methods. In most cases, it's recommended to simply use package-level functions instead.

If you need to write a function that can be called without having a class instance but needs access to the internals of a class (for example, a factory method), you can write it as a member of an object declaration inside that class.

Even more specifically, if you declare a companion object inside your class, you'll be able to call its members with the same syntax as calling static methods in Java/C#, using only the class name as a qualifier.

This is how you can write a companion class

class MyClass {
   companion object { } // will be called "Companion"
}
fun MyClass.Companion.foo() { // ...
}

this is how you call foo() function...

MyClass.foo()

Upvotes: 5

Related Questions