需求:按住按钮,每200ms执行一次命令。
public class MainActivity8 extends AppCompatActivity {
private static final String TAG = "MainActivity888";
//长按时间阈值
private static final long LONG_PRESS_TIMEOUT = 200L;
//长按消息标识
private static final int MSG_LONG_PRESS = 1;
//线程池
private ScheduledExecutorService delMsgExecutor = null;
//线程安全类型Int
private AtomicInteger mLongNumber = new AtomicInteger(0);
//按下时间
private long downTime = 0;
//Handler
private MyHandler mHandler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main8);
}
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onResume() {
super.onResume();
Button button1 = findViewById(R.id.button1);
initHandler();
button1.setOnTouchListener((v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downTime = System.currentTimeMillis();
sendLongPress();
break;
case MotionEvent.ACTION_UP:
if ((System.currentTimeMillis() - downTime) < LONG_PRESS_TIMEOUT) {
Log.d(TAG, "短按操作");
}
downTime = 0L;
removeMessage();
break;
}
return false;
});
}
/**
* 初始化Handler
*/
private void initHandler() {
if (mHandler == null)
mHandler = new MyHandler();
}
/**
* 长按事件方法
*/
private void sendLongPress() {
//初始化线程池
if (delMsgExecutor == null) {
delMsgExecutor =
new ScheduledThreadPoolExecutor(1, r -> new Thread(r, "LongPressThread"));
}
//执行周期任务
delMsgExecutor.scheduleWithFixedDelay(() -> {
Message longPressMsg = mHandler.obtainMessage(MSG_LONG_PRESS, mLongNumber.addAndGet(1));
mHandler.sendMessageDelayed(longPressMsg, LONG_PRESS_TIMEOUT);
}, 1, LONG_PRESS_TIMEOUT, TimeUnit.MILLISECONDS);
/*
scheduleWithFixedDelay和scheduleFixedRate的区别:
scheduleWithFixedDelay:
从字面意义上可以理解为就是以固定延迟(时间)来执行线程任务,
它实际上是不管线程任务的执行时间的,每次都要把任务执行完成后再延迟固定时间后再执行下一次。
scheduleFixedRate:
是以固定频率来执行线程任务,固定频率的含义就是可能设定的固定时间不足以完成线程任务,
但是它不管,达到设定的延迟时间了就要执行下一次了。
*/
}
/**
* 通知结束长按事件
*/
private void removeMessage() {
if (mHandler != null)
mHandler.removeMessages(MSG_LONG_PRESS);
mLongNumber.set(0);
releaseExecutor();
}
/**
* 释放线程池
*/
private void releaseExecutor() {
if (delMsgExecutor == null) return;
delMsgExecutor.shutdown();
delMsgExecutor = null;
}
private static class MyHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == MSG_LONG_PRESS) {
Log.d(TAG, "长按操作 >> message obj: " + msg.obj);
}
}
}
}
可封装成方法,通过接口回调直接使用。
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Author: MoMo
* description:
* Create: 2022/9/21
*/
public class MyLongTouchListener implements View.OnTouchListener {
private static final String TAG = "MyLongTouchListener";
//长按时间阈值
private static final long LONG_PRESS_TIMEOUT = 200L;
//长按消息标识
private static final int MSG_LONG_PRESS = 1;
//线程池
private ScheduledExecutorService delMsgExecutor = null;
//线程安全类型Int
private AtomicInteger mLongNumber = new AtomicInteger(0);
//按下时间
private long downTime = 0;
//Handler
private MyHandler mHandler = null;
//
public interface OnLongTouchListener {
void onClick();
void onLongClick();
}
private OnLongTouchListener onLongTouchListener;
public MyLongTouchListener(OnLongTouchListener onLongTouchListener) {
this.onLongTouchListener = onLongTouchListener;
initHandler(onLongTouchListener);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downTime = System.currentTimeMillis();
sendLongPress();
break;
case MotionEvent.ACTION_UP:
if ((System.currentTimeMillis() - downTime) < LONG_PRESS_TIMEOUT) {
//短按操作
if (onLongTouchListener != null)
onLongTouchListener.onClick();
}
downTime = 0L;
removeMessage();
break;
}
return false;
}
/**
* 初始化Handler
*/
private void initHandler(OnLongTouchListener onLongTouchListener) {
if (mHandler == null)
mHandler = new MyHandler(onLongTouchListener);
}
/**
* 长按事件方法
*/
private void sendLongPress() {
//初始化线程池
if (delMsgExecutor == null) {
delMsgExecutor =
new ScheduledThreadPoolExecutor(1, r -> new Thread(r, "LongPressThread"));
}
//执行周期任务
delMsgExecutor.scheduleWithFixedDelay(() -> {
Message longPressMsg = mHandler.obtainMessage(MSG_LONG_PRESS, mLongNumber.addAndGet(1));
mHandler.sendMessageDelayed(longPressMsg, LONG_PRESS_TIMEOUT);
}, 1, LONG_PRESS_TIMEOUT, TimeUnit.MILLISECONDS);
/*
scheduleWithFixedDelay和scheduleFixedRate的区别:
scheduleWithFixedDelay:
从字面意义上可以理解为就是以固定延迟(时间)来执行线程任务,
它实际上是不管线程任务的执行时间的,每次都要把任务执行完成后再延迟固定时间后再执行下一次。
scheduleFixedRate:
是以固定频率来执行线程任务,固定频率的含义就是可能设定的固定时间不足以完成线程任务,
但是它不管,达到设定的延迟时间了就要执行下一次了。
*/
}
/**
* 通知结束长按事件
*/
private void removeMessage() {
if (mHandler != null)
mHandler.removeMessages(MSG_LONG_PRESS);
mLongNumber.set(0);
releaseExecutor();
}
/**
* 释放线程池
*/
private void releaseExecutor() {
if (delMsgExecutor == null) return;
delMsgExecutor.shutdown();
delMsgExecutor = null;
}
private static class MyHandler extends Handler {
private OnLongTouchListener onLongTouchListener;
public MyHandler(OnLongTouchListener onLongTouchListener) {
this.onLongTouchListener = onLongTouchListener;
}
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == MSG_LONG_PRESS) {
//长按操作
if (onLongTouchListener != null)
onLongTouchListener.onLongClick();
}
}
}
}
使用
button.setOnTouchListener(new MyLongTouchListener(new MyLongTouchListener.OnLongTouchListener() {
@Override
public void onClick() {
Log.d(TAG, "短按回调");
}
@Override
public void onLongClick() {
Log.d(TAG, "长按回调");
}
}));