Expo has stopped Android

#1

Environment

“axios”: “^0.18.0”,
“expo”: “^26.0.0”,
“expo-cli”: “^2.1.3”,
“global”: “^4.3.2”,
“jwt-decode”: “^2.2.0”,
“lodash”: “^4.17.10”,
“moment-timezone”: “^0.5.23”,
“native-base”: “^2.5.2”,
“react”: “16.3.0-alpha.1”,
“react-native”: “0.54.0”,
“react-native-animatable”: “^1.3.0”,
“react-native-maps”: “^0.21.0”,

Steps to Reproduce

When the component loads and create the markers after that the expo stop and ask to reopen the application.

Expected Behavior

The right behavior is show the markers and the map fit in then.

Actual Behavior

The application stop just for android platform and gives this error in adb logcat

12-03 08:14:23.564 3588 3588 D AndroidRuntime: Shutting down VM
12-03 08:14:24.134 3588 3588 E AndroidRuntime: FATAL EXCEPTION: main
12-03 08:14:24.134 3588 3588 E AndroidRuntime: Process: host.exp.exponent, PID: 3588
12-03 08:14:24.134 3588 3588 E AndroidRuntime: java.lang.RuntimeException: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child’s parent first.
12-03 08:14:24.134 3588 3588 E AndroidRuntime: at abi26_0_0.com.facebook.react.bridge.ReactContext.handleException(ReactContext.java:313)
12-03 08:14:24.134 3588 3588 E AndroidRuntime: at abi26_0_0.com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:33)
12-03 08:14:24.134 3588 3588 E AndroidRuntime: at abi26_0_0.com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:136)
12-03 08:14:24.134 3588 3588 E AndroidRuntime: at abi26_0_0.com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:107)

Reproducible Demo

Here is the code of this component.

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  ActivityIndicator,
  AsyncStorage,
  Dimensions,
  Platform,
  Image,
  ScrollView
} from 'react-native';
import MapView, {
  Marker,
  Callout,
  AnimatedRegion,
  Animated
} from 'react-native-maps';
import {
  Container,
  Content,
  Right,
  Header,
  Body,
  Button,
  Item,
  Input,
  Card,
  CardItem,
  Icon
} from 'native-base';
import _ from 'lodash';
import moment from 'moment-timezone';
import SocketIOClient from 'socket.io-client';
import jwtDecode from 'jwt-decode';
import axios from 'axios';

const { width, height } = Dimensions.get('window');
const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 0.004757;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

class Home extends Component {
  mapMarkers = [];
  constructor(props) {
    super(props);
    this.state = {
      markers: [],
      isLoaging: true
    };
    this.exibirMarcadores = this.exibirMarcadores.bind(this);

    this.centralizarMarker = this.centralizarMarker.bind(this);
  }

  componentWillMount() {
    this.carregarVeiculos(true);
  }
  carregarVeiculos = fitToElements => {
    this.setState({ isLoaging: true });
    AsyncStorage.getItem('token').then(token => {
      let dados = jwtDecode(token);
      axios
        .get('api/home', {/
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            Authorization: 'Bearer ' + token
          }
        })
        .then(res => {
          //alert(JSON.stringify(res.data));
          this.setState({ markers: res.data, isLoaging: false });
          if (fitToElements == true) {
            this.map.fitToElements(false);
          }
          /*Platform.select({
            ios: this.map.fitToElements(true)
          });*/
        });
    });
  };
  componentDidMount() {
 
  }

  zoom(latitude, longitude) {
    let newRegion = {
      latitude: parseFloat(latitude),
      longitude: parseFloat(longitude),
      latitudeDelta: parseFloat(LATITUDE_DELTA),
      longitudeDelta: parseFloat(LONGITUDE_DELTA)
    };
    this.map.animateToRegion(newRegion, 1000);
  }
  centralizarMarker(veiculo) {
    let ids = [];
    ids.push(veiculo.id);
    this.setState({
      filtrados: null
    });

    Platform.select({
      ios: this.map.fitToSuppliedMarkers(ids)
    });
    this.mapMarkers[veiculo.id].showCallout();
    this.zoom(veiculo.latitude, veiculo.longitude);
  }

  carregarIcone(icone) {
    let path = null;
    switch (icone) {
      case 'carro.png':
        path = require('../../images/icones/carro.png');
        break;
      case 'ambulancia.png':
        path = require('../../images/icones/ambulancia.png');
        break;
      case 'caminhao.png':
        path = require('../../images/icones/caminhao.png');
        break;
      case 'caminhonete.png':
        path = require('../../images/icones/caminhonete.png');
        break;
      case 'carregadeira.png':
        path = require('../../images/icones/carregadeira.png');
        break;
      case 'empilhadeira.png':
        path = require('../../images/icones/empilhadeira.png');
        break;
      case 'escavadeira.png':
        path = require('../../images/icones/escavadeira.png');
        break;
      case 'moto.png':
        path = require('../../images/icones/moto.png');
        break;
      case 'munk.png':
        path = require('../../images/icones/munk.png');
        break;
      case 'onibus.png':
        path = require('../../images/icones/onibus.png');
        break;
      case 'van.png':
        path = require('../../images/icones/van.png');
        break;
      default:
        path = require('../../images/icones/carro.png');
        break;
    }
    return path;
  }
  exibirMarcadores() {
    if (this.state.markers.length > 0) {
      let markers = this.state.markers.map(marker => {
        if (marker.latitude && marker.longitude) {
          let pathIcone = this.carregarIcone(marker.icone);
          return (
            <Marker
              key={marker.id}
              identifier={marker.id}
              image={pathIcone}
              identifier={marker.id.toString()}
              ref={ref => {
                this.mapMarkers[marker.id.toString()] = ref;
              }}
              coordinate={
                new AnimatedRegion({
                  latitude: parseFloat(marker.latitude),
                  longitude: parseFloat(marker.longitude)
                })
              }
            >
              <Callout>
                <View>
                  <Right />
                  {Platform.OS === 'ios' ? (
                    <Button
                      light
                      style={{ width: 50, borderRadius: 10 }}
                      onPress={() => {
                        this.mapMarkers[marker.id].hideCallout();
                      }}
                    >
                      <Text>Fechar</Text>
                    </Button>
                  ) : (
                    <View />
                  )}
                  <Text style={{ fontWeight: 'bold', fontSize: 18 }}>
                    Informações do Veículo {marker.placa}
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Placa:</Text>
                    {marker.placa}
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>
                      Data Recebimento:
                    </Text>
                    {moment
                      .utc(marker.data_recebimento)
                      .tz('America/Sao_Paulo')
                      .format('DD/MM/YYYY HH:mm:ss')}
                  </Text>
                  <Text style={{ fontWeight: 'bold' }}>Motorista:</Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Localização:</Text>
                    {marker.referencia}
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Ignição:</Text>
                    {marker.ignicao == '1' ? (
                      <Icon name="key" style={{ color: 'green' }} />
                    ) : (
                      <Icon name="key" style={{ color: 'black' }} />
                    )}
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Sinal GPS:</Text>
                    {marker.sinalGPS > 0 ? (
                      <Icon name="wifi" style={{ color: 'green' }} />
                    ) : (
                      <Icon name="wifi" style={{ color: 'black' }} />
                    )}
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Hodometro: </Text>
                    {marker.hodometro.split('.')[0]} Km e{' '}
                    {marker.hodometro.split('.')[1]} m
                  </Text>
                  <Text>
                    <Text style={{ fontWeight: 'bold' }}>Horimetro:</Text>
                    {(marker.horimetro / 60).toFixed(0)} hrs e{' '}
                    {marker.horimetro % 60} min
                  </Text>
                </View>
              </Callout>
            </Marker>
          );
        }
      });

      return markers;
    }
  }

  pesquisar(valor) {
    if (valor != '') {
      let filtrados = this.state.markers.filter(veiculo => {
        if (
          veiculo.placa.toLowerCase().indexOf(valor.toLowerCase()) !== -1 ||
          veiculo.descricao.toLowerCase().indexOf(valor.toLowerCase()) !== -1
        ) {
          return true;
        } else {
          return false;
        }
      });

      let list = filtrados.map((veiculo, index) => {
        return (
          <CardItem
            style={{ flexGrow: 1, borderColor: 'black' }}
            button
            bordered
            onPress={() => {
              this.centralizarMarker(veiculo);
            }}
          >
            <Image
              source={this.carregarIcone(veiculo.icone)}
              style={{ padding: 5, margin: 5 }}
            />
            <View style={styles.cardItem}>
              <Text style={{ fontWeight: 'bold', fontSize: 14 }}>
                {veiculo.placa}
              </Text>
              <Text style={{ fontSize: 12 }}>{veiculo.descricao} </Text>
            </View>
          </CardItem>
        );
      });
      this.setState({
        filtrados: (
          <Card style={styles.searchList}>
            <ScrollView>{list}</ScrollView>
          </Card>
        )
      });
    } else {
      this.setState({
        filtrados: null
      });
    }
  }
  render() {
    const { width, height } = Dimensions.get('window');
    const ratio = width / height;

    return (
      <Container>
        <Header iosBarStyle="light-content" style={styles.header}>
          <Body>
            <Item>
              <Input
                style={{ color: 'white' }}
                onChangeText={valor => this.pesquisar(valor)}
                placeholderTextColor="white"
                placeholder="Pesquisar"
              />
            </Item>
          </Body>
        </Header>
        <Content scrollEnabled={false}>
          <View style={{ width, height }}>
            {this.state.filtrados}

            <MapView
              showsUserLocation={true}
              userLocationAnnotationTitle="Minha Localização"
              showsMyLocationButton={true}
              style={styles.map}
              zoomEnabled={true}
              fitToElements={true}
              //provider="google"
              ref={ref => {
                this.map = ref;
              }}
              loadingEnabled={this.state.isLoaging}
            >
              <Button
                iconLeft
                white
                light
                style={styles.atualizar}
                disabled={this.state.isLoaging}
                onPress={() => {
                  this.carregarVeiculos(false);
                }}
              >
                <Icon name="refresh" />
              </Button>
              {this.exibirMarcadores()}
            </MapView>
          </View>
        </Content>
      </Container>
    );
  }
}

export default Home;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
    justifyContent: 'flex-end',
    alignItems: 'center'
  },
  header: {
    backgroundColor: '#325b84',
    ...Platform.select({
      android: {
        marginTop: 25
      }
    })
  },
  cardItem: {
    ...Platform.select({
      ios: {
        justifyContent: 'left'
      }
    })
  },
  map: {
    marginTop: 1.5,
    ...StyleSheet.absoluteFillObject
  },
  atualizar: {
    width: 45,
    borderRadius: 40,
    color: '#53b2e0',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.8,
    shadowRadius: 2,
    position: 'absolute',
    bottom: 150,
    right: 10
  },
  searchList: {
    zIndex: 2
  }
});
#2

I recently had an issue where android would crash immediately (only standalone version) if the map was on the first page that appeared on the screen (I was also using react-native-navigation). This might be a similar issue? My solution was just to add an intermittent screen immediately before the map page that then transitioned into the map and now it’s fine. Not sure why it was an issue to start with.

#4

Thanks for the answer,

I have an intermediate screen before the map that would be the login screen but in some cases, if the user’s token is valid the app directs direct to the map screen.

closed #5

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.