Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Android crash when navigating back from screen with MapView component

未关闭
#5,814 13 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
45/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
android, react-native, typescript
领域
mobile

调研方向

Reproduce the crash by opening the screen containing CustomSmallMap and triggering router.back() on Android. Start with the detachment path reported at MapView.java:341 and the Google Maps onSaveInstanceState stack; done means navigating back unmounts the MapView without a crash or logged exception.

由索引模型根据 Issue 内容生成。

描述

bug
Summary

The app crashes on Android when I navigate back from a screen that contains a CustomSmallMap component. The crash occurs only on Android and is related to the Google Maps MapView.

Reproducible sample code
import { MapStyle } from '@/src/themePaper/MapStyles';
import React, { useEffect, useState } from 'react';
import { Keyboard, Pressable, StyleSheet, View } from 'react-native';
import MapView, { Marker, Region } from 'react-native-maps';
import { Icon, Text, useTheme } from 'react-native-paper';
import { spacing } from '../spacing';
import { typography } from '../typography';
import CustomIconAvatar from './CustomIconAvatar';
import { MapStyleLight } from '../MapStylesLight';

interface CustomSmallMapProps {
  style?: object;
  useInitialRegion?: boolean;
  coordinate: {
    latitude: number;
    longitude: number;
  };
  onMarkerChange?: (newCoordinate: {
    latitude: number;
    longitude: number;
  }) => void;
  draggable?: boolean;
  label?: string;
  mapType?: 'standard' | 'satellite' | 'hybrid' | 'terrain' | 'none';
  testID?: string;
  staticMap?: boolean;
  height?: number;
  onPress: () => void;
}

const CustomSmallMap: React.FC<CustomSmallMapProps> = ({
  style,
  useInitialRegion,
  coordinate,
  onMarkerChange,
  draggable = false,
  label,
  height = 144,
  mapType = 'standard',
  testID = 'map',
  staticMap = false,
  onPress,
}) => {
  const { colors, dark } = useTheme();

  const parseCoordinate = (coord: {
    latitude: number | string;
    longitude: number | string;
  }) => ({
    latitude: parseFloat(coord.latitude.toString()),
    longitude: parseFloat(coord.longitude.toString()),
  });

  const [markerPosition, setMarkerPosition] = useState(parseCoordinate(coordinate));

  const [mapRegion, setMapRegion] = useState<Region>({
    ...parseCoordinate(coordinate),
    latitudeDelta: 0.0092,
    longitudeDelta: 0.0092,
  });

  useEffect(() => {
    const parsedCoordinate = parseCoordinate(coordinate);
    setMarkerPosition(parsedCoordinate);
    setMapRegion({
      ...parsedCoordinate,
      latitudeDelta: 0.0032,
      longitudeDelta: 0.0032,
    });
    Keyboard.dismiss();
  }, [coordinate]);

  const onMarkerDragEnd = (e: any) => {
    const { latitude, longitude } = e.nativeEvent.coordinate;
    const newCoordinate = { latitude, longitude };
    setMarkerPosition(newCoordinate);
    onMarkerChange?.(newCoordinate);
  };

  const onMapPress = (e: any) => {
    if (!draggable) return;
    const { latitude, longitude } = e.nativeEvent.coordinate;
    const newCoordinate = { latitude, longitude };
    setMarkerPosition(newCoordinate);
    onMarkerChange?.(newCoordinate);
  };

  const onRegionChangeComplete = (region: Region) => {
    setMapRegion(region);
  };

  return (
    <View>
      <Pressable onPress={onPress}>
        {label && (
          <Text
            style={{
              fontWeight: typography.fontVariants.system.medium,
              fontSize: typography.fontSize.label.md,
              marginBottom: spacing.xxs,
            }}
          >
            <Icon source="map-marker" color={colors.primary} size={20} />
            {label}
          </Text>
        )}
      </Pressable>
      <View style={[styles.container, { height }, style]} collapsable={false}>
        <MapView
          style={[styles.map, { height }]}
          customMapStyle={!dark ? MapStyleLight : MapStyle}
          mapType={mapType}
          {...(useInitialRegion ? { initialRegion: mapRegion } : { region: mapRegion })}
          onRegionChangeComplete={onRegionChangeComplete}
          onPress={onMapPress}
          accessible
          accessibilityLabel={testID}
          scrollEnabled={!staticMap}
          zoomEnabled={!staticMap}
          rotateEnabled={!staticMap}
          pitchEnabled={!staticMap}
        >
          <Marker
            flat
            tracksViewChanges={false}
            coordinate={markerPosition}
            draggable={draggable}
            onDragEnd={onMarkerDragEnd}
            centerOffset={{ x: 0, y: -25 }}
          >
            <CustomIconAvatar
              icon="map-marker"
              color={colors.onPrimary}
              size={35}
              backgroundColor={colors.primary}
            />
          </Marker>
        </MapView>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    height: 140,
    width: '100%',
    borderRadius: 12,
    overflow: 'hidden',
  },
  map: {
    flex: 1,
    width: '100%',
  },
  markerContainer: {
    borderRadius: 100,
    justifyContent: 'center',
    alignItems: 'center',
  },
  markerInnerCircle: {
    width: 40,
    height: 40,
    borderRadius: 100,
    borderWidth: 2,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default CustomSmallMap;
Steps to reproduce
  1. Open the screen containing the CustomSmallMap component (the screen renders a MapView).
  2. Tap a button that triggers router.back() from Expo Router.
  3. The app crashes immediately on Android.
Expected result
  • The app should navigate back to the previous screen without crashing.
  • The CustomSmallMap component should unmount safely on Android.
  • No errors or exceptions should appear in the log.
Actual result
 ERROR  Your app just crashed. See the error below.
java.lang.NullPointerException: Attempt to invoke interface method 'void com.google.maps.api.android.lib6.impl.co.C(android.os.Bundle)' on a null object reference
  com.google.maps.api.android.lib6.impl.ef.k(:com.google.android.gms.policy_maps_core_dynamite@234910201@234910200049.587833741.587833741:3)
  com.google.android.gms.maps.internal.s.bp(:com.google.android.gms.policy_maps_core_dynamite@234910201@234910200049.587833741.587833741:110)
  m.bay.onTransact(:com.google.android.gms.policy_maps_core_dynamite@234910201@234910200049.587833741.587833741:21)
  android.os.Binder.transact(Binder.java:667)
  com.google.android.gms.internal.maps.zza.zzJ(com.google.android.gms:play-services-maps@@19.1.0:2)
  com.google.android.gms.maps.internal.zzl.onSaveInstanceState(com.google.android.gms:play-services-maps@@19.1.0:3)
  com.google.android.gms.maps.zzah.onSaveInstanceState(com.google.android.gms:play-services-maps@@19.1.0:3)
  com.google.android.gms.dynamic.DeferredLifecycleHelper.onSaveInstanceState(com.google.android.gms:play-services-base@@18.4.0:1)
  com.google.android.gms.maps.MapView.onSaveInstanceState(com.google.android.gms:play-services-maps@@19.1.0:1)
  com.rnmaps.maps.MapView.onDetachedFromWindow(MapView.java:341)
  android.view.View.dispatchDetachedFromWindow(View.java:18413)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3777)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3769)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.clearDisappearingChildren(ViewGroup.java:6852)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3771)
  android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3769)
  android.view.ViewGroup.endViewTransition(ViewGroup.java:6963)
  com.swmansion.rnscreens.ScreenStack.endViewTransition(ScreenStack.kt:76)
  androidx.fragment.app.DefaultSpecialEffectsController$AnimationEffect$onCommit$1.onAnimationEnd$lambda$0(DefaultSpecialEffectsController.kt:553)
  androidx.fragment.app.DefaultSpecialEffectsController$AnimationEffect$onCommit$1.$r8$lambda$6fa8Ib9U-odOeQPVWaNv8aZmow0(Unknown Source:0)
  androidx.fragment.app.DefaultSpecialEffectsController$AnimationEffect$onCommit$1$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
  android.os.Handler.handleCallback(Handler.java:873)
  android.os.Handler.dispatchMessage(Handler.java:99)
  android.os.Looper.loop(Looper.java:193)
  android.app.ActivityThread.main(ActivityThread.java:6846)
  java.lang.reflect.Method.invoke(Native Method)
  com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:518)
  com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
React Native Maps Version

^1.26.18

What platforms are you seeing the problem on?

Android

React Native Version

0.81.5

What version of Expo are you using?

SDK 53

Device(s)

Samsung

Additional information

Additional notes / possible cause:

  • The crash seems related to MapView’s lifecycle when the view is being detached.
  • It only happens on Android, not iOS.
  • The component works fine when mounted but crashes on navigation back.
主要语言
TypeScript
星标
16k
派生
5k
平均合并
17 小时 45 分钟
30 天内合并 PR
2

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

react-native-maps/react-native-maps 的其他 Issue

查看 react-native-maps/react-native-maps 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。