SIGN IN SIGN UP

[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