欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于kotlin泛型的使用

程序员文章站 2022-03-12 23:01:01
...

因为之前一直想用kotlin开发,正好现在要开一个新项目,所以准备用kotlin来做。把我之前用的mvvm框架的java代码自动转成kotlin以后,有很多地方都报了异常,主要都是泛型的部分,由于框架的基础部分应用了很多泛型,导致自动转了以后很多地方都不符合语法,所以努力的查阅了很多资料,终于修改成了kotlin的代码。

网上很多关于kotlin的泛型的教程都讲的很复杂,形变,投影,协变,逆变,看了半天看的很迷惑。所以这块我把自己改好的源码贴出来,底下会放我整个框架的链接,kotlin的部分为了方便直接上传到了之前的mvvm框架练习的代码里面,这样对照java的源码,可以看一下比较复杂的情况,kotlin的代码是应该如何写的。我个人认为比看那些很多专业名词的教程要直观。下面先贴一个比较复杂的一个adapter的基类的java源码和kotlin源码。两个类是一样的只是语法实现不同。不太会用kotlin泛型的人。翻到这篇可以用来参考一下。上面是kotlin代码,下面是java的代码,这是一个recyclerview的适配器积累,包含footer的那种。也就是说会有两种不同的布局。加上我的框架使用了viewbinding。所以这一个文件用了三个泛型,算是比较复杂的。通过对比可以很好的掌握kotlin泛型的写法。文章最底下是整个框架的源码包含java和kotlin的。直接运行的话,是java的代码。kotlin部分也有使用的实例但是布局文件并没有放进来。也是非常的简单,可以根据代码推测出布局文件的样子。主要是比较懒不想单独传一个项目。所以只是在之前的框架的源码建了一个目录把这次改成kotlin的上传了。

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding

abstract class BaseHaveFooterAdapter<T,  B:ViewBinding, F : ViewBinding> :RecyclerView.Adapter<BaseHaveFooterAdapter.ViewHolder<in ViewBinding>>{
    var onItemClick: OnItemClick? = null


    protected var mDatas:List<T>? = null
    protected var context: android.content.Context
    fun getmDatas(): List<T>? {
        return mDatas
    }

    fun setmDatas(mDatas:List<T>?) {
        this.mDatas = mDatas
    }

    constructor(context: android.content.Context) {
        this.context = context
    }

    constructor(context: android.content.Context, mDatas: kotlin.collections.List<T>?) {
        this.mDatas = mDatas
        this.context = context
    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder<in ViewBinding> {
        val inflater = LayoutInflater.from(context)
       if (viewType == 0) {
            val binding = setBinding(inflater, parent)
            val viewHolder =   BaseHaveFooterAdapter.ViewHolder<B>(binding!!.root)
            viewHolder.binding=binding;
            if (onItemClick != null) {
                viewHolder.onItemClick = onItemClick
            }
           return viewHolder as ViewHolder<in ViewBinding>;
        } else {
            val binding = setFootBinding(inflater, parent)
            val viewHolder =
                BaseHaveFooterAdapter.ViewHolder<F>(binding!!.root)
            viewHolder.binding=binding;
            if (onItemClick != null) {
                viewHolder.onItemClick = onItemClick
            }
            return viewHolder as ViewHolder<in ViewBinding>;
        }
    }

    override fun onBindViewHolder(
        holder: BaseHaveFooterAdapter.ViewHolder<ViewBinding>,
        position: Int
    ): kotlin.Unit {
        if (position == mDatas?.size) {
            val myholder =
                holder as BaseHaveFooterAdapter.ViewHolder<B>
            onBindFooterHolder(myholder, position)
        } else {
            val myholder =
                holder as BaseHaveFooterAdapter.ViewHolder<F>
            onBindHolder(myholder, position)
        }
    }

    protected abstract fun onBindHolder(
        holder: ViewHolder<F>,
        position: Int
    ): kotlin.Unit

    protected abstract fun onBindFooterHolder(
        holder: ViewHolder<B>,
        position: Int
    ): kotlin.Unit

    override fun getItemViewType(position: Int): Int {
        return if (position == mDatas!!.size) 1 else 0
    }

    override fun getItemId(position: Int): kotlin.Long {
        return position.toLong()
    }

    protected abstract fun setBinding(inflater: LayoutInflater?, parent: ViewGroup?): B
    protected abstract fun setFootBinding(inflater: LayoutInflater?, parent: ViewGroup?): F
    override fun getItemCount(): Int {
        return if (mDatas == null) 1 else mDatas!!.size + 1
    }

    class ViewHolder<in ViewBinding>(itemView: android.view.View) :
        RecyclerView.ViewHolder(itemView), android.view.View.OnClickListener {
        var onItemClick: com.dsf.dsfwarehouse.base.BaseHaveFooterAdapter.OnItemClick? =
            null
        var binding: androidx.viewbinding.ViewBinding? = null


        fun setClick(vararg views: android.view.View): kotlin.Unit {
            if (onItemClick != null) {
                for (view in views) {
                    view.setOnClickListener(this)
                }
            }
        }

        fun setOnFooterClick(vararg views: android.view.View) {
            if (onItemClick != null) {
                for (view in views) {
                    view.setOnClickListener { v -> onItemClick?.onFooterClick(v) }
                }
            }
        }

        override fun onClick(v: android.view.View){
            onItemClick?.onClick(v, getAdapterPosition())
        }
    }

    interface OnItemClick {
        fun onClick(view: android.view.View, position: Int)
        fun onFooterClick(view: android.view.View)
    }
}
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;

/**
 * Created by Administrator on 16-7-18.
 */
public abstract class BaseHaveFooterAdapter<T, B extends ViewBinding,F extends  ViewBinding> extends RecyclerView.Adapter<BaseHaveFooterAdapter.ViewHolder> {
    protected OnItemClick onItemClick;
    protected List<T> mDatas;
    protected Context context;

    public List<T> getmDatas() {
        return mDatas;
    }

    public void setmDatas(List<T> mDatas) {
        this.mDatas = mDatas;
    }

    public BaseHaveFooterAdapter(Context context) {
        this.context = context;
    }

    public BaseHaveFooterAdapter(Context context, List<T> mDatas) {
        this.mDatas = mDatas;
        this.context = context;
    }

    public OnItemClick getOnItemClick() {
        return onItemClick;
    }

    public void setOnItemClick(OnItemClick onItemClick) {
        this.onItemClick = onItemClick;

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        LayoutInflater inflater = LayoutInflater.from(context);
        if(viewType==0) {

            B binding = setBinding(inflater, parent);
            ViewHolder<B> viewHolder = new ViewHolder<B>(binding.getRoot());
            viewHolder.setBinding(binding);


            if (onItemClick != null) {
                viewHolder.setOnItemClick(onItemClick);
            }
            return viewHolder;
        }else{
            F binding = setFootBinding(inflater, parent);
            ViewHolder<F> viewHolder = new ViewHolder<F>(binding.getRoot());
            viewHolder.setBinding(binding);


            if (onItemClick != null) {
                viewHolder.setOnItemClick(onItemClick);
            }
            return viewHolder;
        }


    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        if(position==mDatas.size()){
            ViewHolder<F> myholder = (ViewHolder<F>) holder;
            onBindFooterHolder(myholder, position);
        }else {
            ViewHolder<B> myholder = (ViewHolder<B>) holder;
            onBindHolder(myholder, position);
        }
    }

    protected abstract void onBindHolder(ViewHolder<B> holder, int position);

    protected abstract void onBindFooterHolder(ViewHolder<F> holder, int position);

    @Override
    public int getItemViewType(int position) {
        return  position == mDatas.size() ? 1 : 0;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    protected abstract B setBinding(LayoutInflater inflater, ViewGroup parent);

    protected abstract F setFootBinding(LayoutInflater inflater, ViewGroup parent);

    @Override
    public int getItemCount() {
        return mDatas == null  ? 1: mDatas.size() + 1;
    }

    public static class ViewHolder<B extends ViewBinding> extends RecyclerView.ViewHolder implements View.OnClickListener {
        protected OnItemClick onItemClick;
        public B binding;

        public OnItemClick getOnItemClick() {
            return onItemClick;
        }

        public void setOnItemClick(OnItemClick onItemClick) {
            this.onItemClick = onItemClick;
        }

        public B getBinding() {
            return binding;
        }

        public void setBinding(B binding) {
            this.binding = binding;
        }

        public ViewHolder(View itemView) {
            super(itemView);
        }

        public void setClick(View... views) {
            if (onItemClick != null) {
                for (View view : views) {
                    view.setOnClickListener(this);
                }
            }
        }
        public void setOnFooterClick(View... views) {
            if (onItemClick != null) {
                for (View view : views) {
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            onItemClick.onFooterClick(v);
                        }
                    });
                }
            }
        }

        @Override
        public void onClick(View v) {
            onItemClick.onClick(v, getAdapterPosition());
        }
    }

    public static interface OnItemClick {
        void onClick(View view, int position);
        void onFooterClick(View view);
    }

}

源码已经上传github

地址:https://github.com/roofroot/test_view_binding