Android 实现防抖动(防快速点击)的最优雅做法

版权声明:本文为博主原创文章,未经博主允许,也可以随意转载。但麻烦,加个友情链接,增加点人气。 https://blog.csdn.net/l_o_s/article/details/80204099

前言:

对于很多安卓开发者来说,防快速点击的实现,并不是一件难事。难的是,如何优雅的实现。现在,主流的做法,有自己在onClick方法的顶部加时间判断。也有通过,第三方注解框架去解决。但是,如果你既不想在onClick里面加,又不想用第三方框架,又想以最少的改动,来实现,咋办?干大事的人,都是直接上使用案例的,无Code,无JB。

Here is the code shows you How to use it:

 // 这是findView的代码,但请注意,这不是findViewById,这是findClickView。
 Button btnTest = findClickView(R.id.btn_test);

 // 这是Activity的onClick方法。
 public void onClick(View view) {

        switch (view.getId()) {

            case R.id.btn_test:
            // todo
            break;
        }

    }

就是这么简单,findClickView方法,会帮你setOnClickListener,并做防抖实现。让我们一起来看看findClickView的内部实现。

    /**
     * Find出来的View,自带防抖功能
     */
    public <T extends View> T findClickView(int id) {

        T view = (T) findViewById(id);
        view.setOnClickListener(new EventListener(this));
        return view;
    }

可以看到,这个方法,内部调用的,还是findViewById。不同的是,里面设置onClick的时候,传了一个EventListener的实例。而这个类,也是防抖的关键。废话不多说,直接看代码:

package com.laka.androidlib.listener;

import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;

import java.lang.reflect.Method;


/**
 * 防抖事件
 * 用法setOnClickListener(new EventListener(obj));
 * obj类,必须得有clickMethod(View)方法。默认是onClick(View)方法。
 */
public class EventListener implements OnClickListener,
        OnLongClickListener, OnItemClickListener, OnItemSelectedListener,OnItemLongClickListener {

    private Object handler;

    // 点击事件的方法,默认是onClick
    private String clickMethod = "onClick";

    private String longClickMethod;
    private String itemClickMethod;
    private String itemSelectMethod;
    private String nothingSelectedMethod;
    private String itemLongClickMethod;

    // 间隔时间
    private final static int INTERVAL_TIME = 1000;

    public EventListener(Object handler) {
        this.handler = handler;
    }

    public EventListener click(String method){
        this.clickMethod = method;
        return this;
    }

    public EventListener longClick(String method){
        this.longClickMethod = method;
        return this;
    }

    public EventListener itemLongClick(String method){
        this.itemLongClickMethod = method;
        return this;
    }

    public EventListener itemClick(String method){
        this.itemClickMethod = method;
        return this;
    }

    public EventListener select(String method){
        this.itemSelectMethod = method;
        return this;
    }

    public EventListener noSelect(String method){
        this.nothingSelectedMethod = method;
        return this;
    }

    public boolean onLongClick(View v) {
        return invokeLongClickMethod(handler,longClickMethod,v);
    }

    public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        return invokeItemLongClickMethod(handler, itemLongClickMethod,arg0,arg1,arg2,arg3);
    }

    public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

        invokeItemSelectMethod(handler,itemSelectMethod,arg0,arg1,arg2,arg3);
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        invokeNoSelectMethod(handler,nothingSelectedMethod,arg0);
    }

    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

        invokeItemClickMethod(handler,itemClickMethod,arg0,arg1,arg2,arg3);
    }

    public void onClick(View v) {

        invokeClickMethod(handler, clickMethod, v);
    }

    //上一次点击时间
    static long lastclicktime=0;
    /**
     * 点击事件
     * @param handler
     * @param methodName
     * @param params
     * @return
     */
    private static Object invokeClickMethod(Object handler, String methodName, Object... params){
        if(handler == null)
            return null;
        Method method = null;
        try{

            if(System.currentTimeMillis()-lastclicktime > INTERVAL_TIME){
                method = handler.getClass()
                        .getDeclaredMethod(methodName,View.class);
                Object result = method.invoke(handler, params);
                lastclicktime = System.currentTimeMillis();
                return result;
            }
        }catch(Exception e1){
            handlerException(e1);
        }

        return null;
    }

    public static void handlerException(Exception e){

    }

    /**
     * 长按事件
     * @param handler
     * @param methodName
     * @param params
     * @return
     */
    private static boolean invokeLongClickMethod(Object handler, String methodName, Object... params){
        if(handler == null) return false;
        Method method = null;
        try{   
            //public boolean onLongClick(View v)
            method = handler.getClass().getDeclaredMethod(methodName,View.class);
            if(method!=null){
                Object obj = method.invoke(handler, params);
                return obj==null?false: Boolean.valueOf(obj.toString());
            }else{
                method = handler.getClass().getDeclaredMethod(methodName);
                if(method!=null){
                    Object obj = method.invoke(handler);
                    return obj==null?false: Boolean.valueOf(obj.toString());
                }
                else
                    throw new RuntimeException("no such method:"+methodName);
            }

        }catch(Exception e){
            e.printStackTrace();
        }

        return false;

    }



    private static Object invokeItemClickMethod(Object handler, String methodName, Object... params){
        if(handler == null) return null;
        Method method = null;
        try{   

            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class);
            if(method!=null){
                if(System.currentTimeMillis()-lastclicktime > INTERVAL_TIME){
                    Object result= method.invoke(handler, params);
                    lastclicktime= System.currentTimeMillis();
                     return result;
                }
            }else{
                method = handler.getClass().getDeclaredMethod(methodName,int.class,long.class);
                if(method!=null){
                    Object result=  method.invoke(handler, params[2],params[3]);
                    lastclicktime= System.currentTimeMillis();
                    return result;
                }else
                throw new RuntimeException("no such method:"+methodName);
            }
        }catch(Exception e){
            e.printStackTrace();
        }

        return null;
    }


    private static boolean invokeItemLongClickMethod(Object handler, String methodName, Object... params){
        if(handler == null) throw new RuntimeException("invokeItemLongClickMethod: handler is null :");
        Method method = null;
        try{   
            ///onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,long arg3)
            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class);
            if(method!=null){
                Object obj = method.invoke(handler, params);
                return Boolean.valueOf(obj==null?false: Boolean.valueOf(obj.toString()));
            }
            else{
                method = handler.getClass().getDeclaredMethod(methodName, int.class,long.class);
                if(method!=null){
                    Object obj = method.invoke(handler,params[2],params[3]);
                    return Boolean.valueOf(obj==null?false: Boolean.valueOf(obj.toString()));
                }else

                throw new RuntimeException("no such method:"+methodName);
            }
        }catch(Exception e){
            e.printStackTrace();
        }

        return false;
    }


    private static Object invokeItemSelectMethod(Object handler, String methodName, Object... params){
        if(handler == null) return null;
        Method method = null;
        try{   
            ///onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3)
            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class,View.class,int.class,long.class);
            if(method!=null)
                return method.invoke(handler, params);  
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }

        return null;
    }

    private static Object invokeNoSelectMethod(Object handler, String methodName, Object... params){
        if(handler == null) return null;
        Method method = null;
        try{   
            //onNothingSelected(AdapterView<?> arg0)
            method = handler.getClass().getDeclaredMethod(methodName,AdapterView.class);
            if(method!=null)
                return method.invoke(handler, params);  
            else
                throw new RuntimeException("no such method:"+methodName);
        }catch(Exception e){
            e.printStackTrace();
        }

        return null;
    }



}

代码,复制粘贴,即可用。0 warnings, 0 errors。


好了,到此为止,我们已经讲解了,如何优雅的实现防抖。注意:如果某个View不需要点击事件或防抖,还是用原来的findViewById,不要调这个findClickView,因为findClickView会增加点击事件的监听。

猜你喜欢

转载自blog.csdn.net/l_o_s/article/details/80204099