[Android] Initialize the `Handler` fields eagerly (#4461)
## Description
`Tap`, `LongPress`, `Fling`, `Pan` and `Hover` gesture handlers kept their `Handler` as a nullable field created on first use, guarded by null checks and `!!` at every call site (with a `TODO: lazy init` left in `Tap` since the Kotlin conversion).
`Handler` object was never cleared anyway (except `LongPress`, where it used to serve as a flag, and `Hover`).
Also adds a comment explaining the 4 ms delay in `HoverGestureHandler`.
## Test plan
- `:react-native-gesture-handler:compileDebugKotlin` builds clean in basic-example
- `yarn format:android` passes
<details>
<summary>Tested on the following code:</summary>
```tsx
import React, { useCallback, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {
Directions,
GestureDetector,
useFlingGesture,
useHoverGesture,
useLongPressGesture,
usePanGesture,
useTapGesture,
} from 'react-native-gesture-handler';
import { scheduleOnRN } from 'react-native-worklets';
type Counters = { begin: number; act: number; end: number; fail: number };
type Results = Record<string, Counters>;
const EMPTY: Counters = { begin: 0, act: 0, end: 0, fail: 0 };
export default function EmptyExample() {
const [results, setResults] = useState<Results>({});
const report = useCallback((key: string, kind: keyof Counters) => {
setResults((prev) => {
const current = prev[key] ?? EMPTY;
return { ...prev, [key]: { ...current, [kind]: current[kind] + 1 } };
});
}, []);
const tap = useTapGesture({
onBegin: () => scheduleOnRN(report, 'tap', 'begin'),
onActivate: () => scheduleOnRN(report, 'tap', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'tap', e.canceled ? 'fail' : 'end'),
});
const doubleTap = useTapGesture({
numberOfTaps: 2,
onBegin: () => scheduleOnRN(report, 'doubleTap', 'begin'),
onActivate: () => scheduleOnRN(report, 'doubleTap', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'doubleTap', e.canceled ? 'fail' : 'end'),
});
const longPress = useLongPressGesture({
minDurationMs: 400,
onBegin: () => scheduleOnRN(report, 'longPress', 'begin'),
onActivate: () => scheduleOnRN(report, 'longPress', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'longPress', e.canceled ? 'fail' : 'end'),
});
const fling = useFlingGesture({
direction: Directions.RIGHT,
onBegin: () => scheduleOnRN(report, 'fling', 'begin'),
onActivate: () => scheduleOnRN(report, 'fling', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'fling', e.canceled ? 'fail' : 'end'),
});
const pan = usePanGesture({
activateAfterLongPress: 400,
onBegin: () => scheduleOnRN(report, 'pan', 'begin'),
onActivate: () => scheduleOnRN(report, 'pan', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'pan', e.canceled ? 'fail' : 'end'),
});
const hover = useHoverGesture({
onBegin: () => scheduleOnRN(report, 'hover', 'begin'),
onActivate: () => scheduleOnRN(report, 'hover', 'act'),
onFinalize: (e) =>
scheduleOnRN(report, 'hover', e.canceled ? 'fail' : 'end'),
});
const rows: { key: string; label: string; gesture: any }[] = [
{ key: 'tap', label: 'Tap', gesture: tap },
{ key: 'doubleTap', label: 'DoubleTap', gesture: doubleTap },
{ key: 'longPress', label: 'LongPress 400ms', gesture: longPress },
{ key: 'fling', label: 'Fling right', gesture: fling },
{ key: 'pan', label: 'Pan holdActivate 400ms', gesture: pan },
{ key: 'hover', label: 'Hover', gesture: hover },
];
return (
<View style={styles.container}>
{rows.map(({ key, label, gesture }) => {
const c = results[key] ?? EMPTY;
return (
<GestureDetector key={key} gesture={gesture}>
<View style={styles.box}>
<Text style={styles.label}>{label}</Text>
<Text style={styles.status}>
{`${key} b:${c.begin} a:${c.act} e:${c.end} f:${c.fail}`}
</Text>
</View>
</GestureDetector>
);
})}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 12,
gap: 10,
},
box: {
height: 88,
borderRadius: 12,
backgroundColor: '#dbe4ff',
justifyContent: 'center',
alignItems: 'center',
},
label: {
fontSize: 18,
fontWeight: '600',
},
status: {
fontSize: 15,
fontVariant: ['tabular-nums'],
},
});
```
</details> M
Michał Bert committed
8a4d05df6960199dd1d4689509bc9dec97f80aca
Parent: 156aca8
Committed by GitHub <noreply@github.com>
on 8/21/2026, 8:57:45 AM