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

前言:

对于很多安卓开发者来说,防快速点击的实现,并不是一件难事。难的是,如何优雅的实现。现在,主流的做法,有自己在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会增加点击事件的监听。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
以下是一个简单的 Android UVCCamera 实现视频防抖动的示例代码: ```java public class UvcCameraPreview implements SurfaceHolder.Callback, Camera.PreviewCallback { private static final String TAG = "UvcCameraPreview"; private SurfaceHolder mHolder; private Camera mCamera; private ByteBuffer mPreviewBuffer; private byte[] mPreviewFrame; private int mPreviewWidth; private int mPreviewHeight; private int mFrameSize; private boolean mIsPreviewing = false; private Handler mHandler = new Handler(); private Runnable mStabilizationRunnable = new Runnable() { @Override public void run() { stabilizeFrame(); } }; public UvcCameraPreview(SurfaceView surfaceView) { mHolder = surfaceView.getHolder(); mHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { mCamera = Camera.open(); mCamera.setPreviewCallbackWithBuffer(this); Camera.Parameters params = mCamera.getParameters(); List<Camera.Size> sizes = params.getSupportedPreviewSizes(); Camera.Size size = sizes.get(0); params.setPreviewSize(size.width, size.height); mCamera.setParameters(params); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } mPreviewWidth = size.width; mPreviewHeight = size.height; mFrameSize = mPreviewWidth * mPreviewHeight * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8; mPreviewBuffer = ByteBuffer.allocate(mFrameSize); mCamera.addCallbackBuffer(mPreviewBuffer.array()); mCamera.startPreview(); mIsPreviewing = true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsPreviewing = false; mCamera.stopPreview(); mCamera.setPreviewCallback(null); mCamera.release(); mCamera = null; } @Override public void onPreviewFrame(byte[] data, Camera camera) { mPreviewFrame = data; mHandler.post(mStabilizationRunnable); if (mCamera != null && mIsPreviewing) { mCamera.addCallbackBuffer(mPreviewBuffer.array()); } } private void stabilizeFrame() { // 实现视频防抖动的代码 // 将 mPreviewFrame 中的数据进行防抖动处理 // 处理后的数据可以进行显示或者存储 // 处理完成后,可以继续进行下一帧的处理 mHandler.post(mStabilizationRunnable); } } ``` 在这个示例中,我们使用了 `SurfaceView` 来显示预览画面,并通过 `SurfaceHolder.Callback` 监听 `SurfaceView` 的生命周期。在 `surfaceCreated` 方法中,我们打开了相机,设置了预览的参数和大小,并将预览的数据回调设置为 `this`,即当前类。我们还创建了一个 `ByteBuffer` 来存储预览数据,并将其添加到相机的回调缓冲区中。 在 `onPreviewFrame` 方法中,我们将相机返回的预览数据存储到 `mPreviewFrame` 数组中,并通过 `Handler` 在另一个线程中调用 `stabilizeFrame` 方法对预览数据进行防抖动处理。在 `stabilizeFrame` 中,我们可以对 `mPreviewFrame` 数组中的数据进行防抖动处理,并将处理后的数据显示或者保存。最后,我们通过 `Handler` 的方式在处理完成后继续对下一帧数据进行处理,从而实现视频防抖动的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值