【Android-Kotlin】匿名内部类与Lambda 表达式(附RecycleView监听)

一:匿名内部类

  1. 一个Test类,里面
    1)1个属性
    2)1个方法
    a.该方法传递的参数是一个接口对象,目的是在这个方法中可以通过这个对象来调用接口方法
  2. 接口对象的接口TestInterFace内部有一个方法test(供其他的对象/类调用)
  3. Main函数中,先创建一个Test的对象,并实现这个方法,那我们知道参数内部是一个接口对象,但是呢,这个对象的作用只在这里有用,仅仅起到一个中转站的作用,那我们就可以免去命名,使用匿名内部类({
    直接复写功能就好了
    })
class Test {
    var v = "成员属性"

    fun setInterFace(test: TestInterFace) {
        test.test()//写法规范,实现时直接复写fun test()就好
    }
}

/**
 * 定义接口
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()

    /**
     * 采用对象表达式来创建接口对象,即匿名内部类的实例。
     */
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}

二.Lambda基础这位作者的返回值写的也很清楚

() -> Unit//表示无参数无返回值的Lambda表达式类型

(T) -> Unit//表示接收一个T类型参数,无返回值的Lambda表达式类型

(T) -> R//表示接收一个T类型参数,返回一个R类型值的Lambda表达式类型

(T, P) -> R//表示接收一个T类型和P类型的参数,返回一个R类型值的Lambda表达式类型

(T, (P,Q) -> S) ->
R//表示接收一个T类型参数和一个接收P、Q类型两个参数并返回一个S类型的值的Lambda表达式类型参数,返回一个R类型值的Lambda表达式类型

三.lambda表达式/匿名函数 1参1返回样例

当然也可以println这个参数测试
1.这段是RecyleView中的一个方法,listener不知道是啥类型,那就写一个lambeda表达式定义函数类型变量
(1参)->Unit,既然是无返回值,那怎么做到类型赋值呢,就类似set方法,函数类型this赋值
2.我们观察发现这个函数对象是没有名字的

  //kotlin方法
    //直接定义函数类型的变量 传入参数,所需的数据类型,无返回值
    var listener:((itembean:ITEMBEAN)->Unit)?=null
    //写个方法定义函数
    fun setMyListener(listener:(itemBean:ITEMBEAN)->Unit){
        this.listener=listener
    }

四.Lambda进阶使用

  1. 如果需要参数(没有参数可以写()),就在小括号里写明参数类型,参数名可以省略,然后小括号后面加上->{},

  2. ->后面如果没有返回值就写Unit(见我们的样例3)

  3. 然后在大括号{}里面写上具体的方法实现

  4. 作为参数传递给高阶函数的时候,只需要写大括号{}方法体

五.来点夜里猛,lambda表达式结合点击传参【RecycleView点击事件】

在这里插入图片描述
刚开始adapter调用,进行lanmbda一参赋值
在这里插入图片描述
这边进行初始化,并且设定了listener这个函数型变量
在这里插入图片描述
我们点击后,先打印了4444,其次我们listener是赋值了一参的函数,并且这个函数体->println也会一起执行,那就打印了111111,

最后打印33333在这里插入图片描述

六.补充说明

1. java设置点击事件(RecycleView)

1)《第一行代码》中介绍了RV没有setonItemClickListener(),我们可以自己根据需求对子项进行监听即抛去子项点击监听,点击事件右具体的View注册
a. onCreateViewHolder中定义的holder对象,可以setonClickListener监听其内部的任意属性(例如文字或图片)
b. 监听内部复写onClick方法即可

package com.example.recyclerviewtest;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitView = view;
            fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            fruitName = (TextView) view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(), "you clicked view " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(), "you clicked image " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }

}

2.Faraway当中holder只有一个view属性监听方式

1)实现
a. 来到BaseListFragment 里面有个getSpecialAdapter(),我们发现,所有显示条目的fragment,其adapter都是这个的子类
b.进入BaseListAdapter中,进入onBindView可以直接获取每个条目的View,(这里的holder只有一个属性view)那就给这里的itemView进行监听设置,setonClickListener()方法,我们发现其内部实际要传一个匿名类

**public void setOnClickListener(@Nullable OnClickListener l) 我们点开这个匿名内部类,发现他还是个只有一个待实现方法的接口,于是我们可以直接打开这个最深层接口,实现条目点击事件**

在这里插入图片描述

3.代码展示

详细说明 条目点击事件

  1. java传递数据做法(定义一个接口,用于和主界面的调用,但耦合高)
    1)定义LIstener接口,内部一个方法实现data数据的监听,并制定泛型是传入的泛型,
    2)定义setMyListener供主界面交互(拿数据)
    3)在itemview的监听中,调用click(data)方法设定数据

  2. kotlin方法(目的是存入,拿到数据,具体见五)
    a.定义listener对象是一个传入ITEMBEAN的无返回类型函数对象,
    b.同样一个setMylistener取数据
    c.监听,比较严格+空校验
    c1)?.let
    listener?.let { it(data) } 这里的it就是指当前的listener
    c2)?.invokelistener?.invoke(data) 就是调用看1参函数进行赋值
    d.内部it就代表了listener,传入data(c2好理解)


//所有下拉刷新和上拉加载更多列表界面adapter基类 再添加一个泛型
abstract class BaseListAdapter<ITEMBEAN,ITEMVIEW:View> : RecyclerView.Adapter<BaseListAdapter.BaseListHolder>(){
    //直接复制会报错,因为原HomeHolde这里引用变成HomeAdapter.HomeHolder


    //add 1.更新数据的操作   刷新操作建立List集合 接收数据
    private var list=ArrayList<ITEMBEAN>()//用里面的list匿名内部类
    //在集合中先清空  再添加
    fun updateList(list: List<ITEMBEAN>?){//传入一个对应集合 到时候侧试一下传原lei还是内部类
        /*封装后可空判断
        if (list==null) return */
        list?.let {
            this.list.clear()
            this.list.addAll(list)//牛逼
            notifyDataSetChanged()//刷新一下
        }

    }
    //上拉加载更多 在集合中添加即可
    fun loadMore(list: List<ITEMBEAN>?){
        list?.let {
            this.list.addAll(list)
            notifyDataSetChanged()
        }

    }

    //调用HomeItemView进行home页面的填充 创建了条目view
//1.需要一个HomeHolder

    class BaseListHolder(itemView: View): RecyclerView.ViewHolder(itemView){

    }
    //2.复写三个次级构造方法
    //2.1 条目初始化进行数据绑定
    override fun onBindViewHolder(holder: BaseListAdapter.BaseListHolder, position: Int) {
        //如果是最后一条就不刷新view
        if(position==list.size)
            return
        //拿到条目数据
        val data=list.get(position)
        //拿到条目View
        val itemView=holder.itemView as ITEMVIEW
        //条目刷新
//和之前一样 用泛型不知道该类型有没有这个方法  setDate
       // itemView.setDate(data)
        //定义一个方法

        refreshItemView(itemView,data)
        //条目点击事件

        //设置点击事件 点开发现()是一个接口,并且只有一个方法 直接打开就行
        itemView.setOnClickListener {
          //  listener.let(data) 空异常
            listener?.let {
                it(data)
            }
           //或者
            /*
            listener?.invoke(data)
            * */



            //java 做法,定义一个接口,回调给主界面
            /* 3.回调 java式传参
             if (listener!=null)
                   listener?.onClick(data)*/


        }

    }
    //kotlin方法
    //直接定义函数类型的变量 传入参数,所需的数据类型,无返回值
    var listener:((itembean:ITEMBEAN)->Unit)?=null
    //写个方法定义函数
    fun setMyListener(listener:(itemBean:ITEMBEAN)->Unit){
        this.listener=listener
    }
/*2.定义listener接口对象   SOClick中利用其接口实现监听data的click方法
    var listener:Listener<ITEMBEAN>? = null

    //1.javaj接口 click和ITEMBean耦合高
    interface  Listener<ITEMBEAN>{//定义接口 监听条目data
        fun onClick(data:ITEMBEAN)
    }
    2.传递listener 赋值
    fun setMyListener(listener:Listener<ITEMBEAN>){
        this.listener=listener
    }
*/

    //2.2返回条目数量-指的是产生fragment条目
    override fun getItemCount(): Int {
        /*在抓取类中限定size 最后的+1的空间放一个进度条,实现上拉加载更多的条目
        * 进度条可以提取一个单独的view显示*/
        return list.size+1  //用1.add建立的列表就可以调用list了
        //最后一条显示进度条
    }
    //2.3 拿到homeView
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseListHolder {
        if(viewType==1){
            //最后一条
            return BaseListHolder(LoadMoreView(parent?.context))
        }
        else{
            //其他条目
            return BaseListHolder(getItemView(parent.context))
        }

    }


    //2.4根据位置返回type值 绝对界面或刷新框
    override fun getItemViewType(position: Int): Int {
        if(position==list.size)
            return 1
        else
            return 0
    }
    //   通过Holder将view保存下来 要将当前类变为抽象类
    abstract fun refreshItemView(itemView: ITEMVIEW,data:ITEMBEAN)
    //获取条目View(泛型)
    abstract fun getItemView(context: Context?): ITEMVIEW


}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值