[개인 Project] SQLite vs AsyncStorage

김민성·2021년 7월 4일
0

알GO누비자

목록 보기
19/25
post-thumbnail

무엇이 좋을까요?

리액트 네이티브로 어플을 만들고 있는데 현재는 어플을 실행하면 누비자 공지사항 크롤링 데이터, 누비자 api 데이터, 날씨 데이터 3개의 데이터를 비동기로 불러오고 있습니다. 문제는 터미널api에 있는데요. 터미널 api가 1000번이 하루 호출 제한 수가 아니라 전체 호출 제한 수 였습니다.

이상한 것은 1000번이 넘었는데 계속 호출이 된다는 것이죠. 그리고 갑자기 호출이 안됩니다. 1000번의 호출을 넘긴 상태에서는 어떠한 기준에 맞춰서 호출이 제한되는 것 같습니다.

이를 해결하기 위해 하루에 특정시간마다 데이터를 불러와 저장소에 저장하는 방식으로 수정을 하기위해 검색을 해보았습니다. 그래서 찾은 것이 SQLite 과 AsyncStorage 입니다. 그외에도 realm이 있는데요. realm은 expo에서 작동이 되지 않는다고 합니다. 저는 expo로 어플을 만들고 있기 때문에 realm은 제하기로 하고 두 개 중 가장 적합한 것을 찾아봐야겠씁니다..!
참고 : https://peakd.com/kr/@anpigon/reactnative-asyncstorage-sqlite-realm


2021/07/04

background fetch

  // 터미널 정보 가져오기
  async function getTerminalData() {
    //asyncStorage에 저장한 값을 불러오는 방식으로 수정
    AsyncStorage.getItem('terminal_data', (err, res) => {
      if (err) {
        // const API_KEY = '내가 받은 api';
        // const TermianlData = await fetch(
        //   `http://api.nubija.com:1577/ubike/nubijaInfoApi.do?apikey=${API_KEY}`,
        // )
        //   .then((res) => res.json())
        //   .then((json) => {
        //     const result = json.TerminalInfo;
        //     return result;
        //   });
        // AsyncStorage.setItem(
        //   'terminal_data',
        //   JSON.stringify(TermianlData),
        //   () => {
        //     console.log('터미널 정보 저장');
        //   },
        // );
        // AsyncStorage.getItem('terminal_data', (err, res) => {
        //   const data = JSON.parse(res);
        //   setTerminalData(data);
        // });
        // //리렌더링되야한다.
        console.log(err);
      } else {
        const data = JSON.parse(res);
        setTerminalData(data);
      }
    });
  }
  //데이터 불러오기
  async function fetchData() {
    AsyncStorage.getItem('notice_data', (err, res) => {
      if (err) {
        // const notice = await getPage(1);
        // notice.sort((a, b) => {
        //   //id를 오름차순으로 정렬하는 방법
        //   return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
        // });
        // AsyncStorage.setItem('notice_data', JSON.stringify(notice), () => {
        //   console.log('공지사항 저장');
        // });
        // AsyncStorage.getItem('notice_data', (err, res) => {
        //   const data = JSON.parse(res);
        //   setNoticeData([...data]);
        // });
        console.log(err);
      } else {
        const data = JSON.parse(res);
        setNoticeData([...data]);
      }
    });
  }

데이터를 불러오는 부분을 이와 같이 변경했습니다. 그리고 백그라운드에서 특정 시간마다 데이터를 AsyncStorage에 저장하기 위해 expo-background-fetch, expo-task-manager을 사용해 보았지만 마음처럼 잘 되지 않습니다..

const BACKGROUND_FETCH_TASK = 'background-fetch';

// 1. Define the task by providing a name and the function that should be executed
// Note: This needs to be called in the global scope (e.g outside of your React components)
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
  const now = Date.now();
//이 부분에 fetch 함수를 작성하면 되는데 콘솔로그를 확인할 방법을 모르겠다.
  console.log(
    `Got background fetch call at date: ${new Date(now).toISOString()}`,
  );

  // Be sure to return the successful result type!
  return BackgroundFetch.Result.NewData;
});

async function registerBackgroundFetchAsync() {
  return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
    minimumInterval: 5, // 5초
    stopOnTerminate: false, // android only,
    startOnBoot: true, // android only
  });
}

난관 봉착

코드에 콘솔로그가 적혀있는 자리에 데이터를 fetch하는 함수를 작성하면 minimumInterval마다 함수를 실행할 수 있다고 합니다. 그러면 특정 시간마다 fetch함수를 실행하고 AsyncStorage에 저장이 되겠지요.

일단은 테스트 삼아 콘솔로그를 확인하려 했지만 표시가 되지 않습니다. 이 부분만 해결되면 데이터를 저장하는 것은 걱정없고 더욱 빠른 속도로 앱을 실행할 수도 있습니다.


2021/07/05

검색을 해보다가 문서에서 이상한 문장을 발견했습니다.
https://github.com/transistorsoft/react-native-background-fetch

?? ios는 머신러닝 알고리즘으로 인해 이 작업을 실행되는데 몇일 걸린다고 합니다. android는 headlessjs를 사용하라고 하네요. 그러면 일단 작업을 해놓고 몇일 기다려 보겠습니다. 일단은 안드로이드를 구현하는게 먼저가 되겠네요. 저번에 안드로이드는 expo-location부터 에러가 났으니 그 부분부터 해결하겠습니다.


위치가 잡히지 않는다.


사진을 보면 위도, 경도 값은 잘 구해오지만 해당 값을 initialRegion에 입력해도 위치가 올바르게 잡히지 않습니다. 제 아이폰에서는 잘 되는데 말이죠. 시뮬레이터에서만 에러가 나는 것 같습니다.


실기기에서는 잘 작동합니다. 에러를 도저히 잡을 방법이 떠오르지 않아서 안드로이드 공기계를 얻어오기로 했습니다.. 시뮬레이터 너무 어렵..


카드 값에 따른 터미널 위치를 보여주는 코드를 작성했습니다.
참고: https://www.youtube.com/watch?v=2vILzRmEqGI

에러

문제는 올바른 터미널 좌표가 입력되지 않습니다. 문제가 뭔지는 아직 확인을 하지 못했습니다.


에러 해결 과정

마커를 클릭하면 클릭한 터미널 카드로 이동하고 좌표 또한 이동하도록 만들려고 했습니다.

//index의 초기값 설정
let mapAnimation = new Animated.Value(0);


  useEffect(() => {
  
    mapAnimation.addListener(({ value }) => {
      //여기가 문제!!! index값이 value을 기반으로 카드들의 x값과 같아야한다. 이 값을 찾는 것이 어렵다. 15는 아무값이나 넣었다.
      let index = 15;
      console.log(value, CARD_WIDTH);
      if (index >= terminalData.length) {
        index = terminalData - 1;
      }
      if (index <= 0) {
        index = 0;
      }

      clearTimeout(regionTimeout);

      const regionTimeout = setTimeout(() => {
        if (mapIndex !== index) {
          mapIndex = index;
          const { Latitude, Longitude } = terminalData[index];
          // console.log(terminalData[index]);
          _map.current.animateToRegion(
            {
              latitude: parseFloat(Latitude),
              longitude: parseFloat(Longitude),
              latitudeDelta: 0.048,
              longitudeDelta: 0.04,
            },
            350,
          );
        }
      }, 10);
    });
  });
  

value를 해당 마커의 index로 바꾸는 특정식을 찾으면 해결된다. 아직 못찾음

//터미널 생성 시 마커의 배율이 커진다.
const interpolations = terminalData.map((marker, index) => {
  const inputRange = [
    (index - 1) * CARD_WIDTH,
    index * CARD_WIDTH,
    (index + 1) * CARD_WIDTH,
  ];

  const scale = mapAnimation.interpolate({
    inputRange,
    outputRange: [1, 1.5, 1],
    extrapolate: 'clamp',
  });

  return { scale };
});

interpolation으로 해당 마커가 선택되면 크기가 1.5배 커졌다가 넘어가면 다시 원래 크기가 되도록 설정했다.

  const onMarkerPress = (mapEventData) => {
  //index값 받아온다.
    const markerID = mapEventData._targetInst.return.index;

    let x = markerID * (CARD_WIDTH + 20);
    if (Platform.OS === 'ios') {
      x = x - SPACING_FOR_CARD_INSET;
    }
    // console.log(mapEventData._targetInst);
    //선택한 마커의 카드로 이동시킨다.
    _scrollView.current.scrollTo({ x: x, y: 0, animated: true });
  };

//ref로 함수를 생성할 수 있도록 한다.
  const _map = useRef(null);
  const _scrollView = useRef(null);
  
  ...
  
        <Animated.ScrollView
        ref={_scrollView}
  ...
        onScroll={Animated.event(
          [{ nativeEvent: { contentOffset: { x: mapAnimation } } }],
          { useNativeDriver: true },
        )}
      >
  ...

value를 어떻게 index로 바꾸어야할지 감이 안잡힌다.


let index = Math.floor(value / 351.083333) + 1;

로 바꾸면 제가 클릭한 값으로 옮겨집니다. 카드의 한 페이지 width가 약 331.20000..인데 약 19.8정도 차이가 나네요. 하지만 정확한 값이 아니라 오차는 있습니다. 그런데 또다른 오류로 마커의 크기가 이제는 제대로 작동이 안합니다 ㅠ 다른 인덱스의 마커가 커지는 것 같습니다.

profile
https://github.com/alstjd8826

0개의 댓글