はじめに
最近、個人でReact Native+Typescript+expoを使ってアプリ開発をしています。
現在地情報を使って、近くの店をリストとして出力する機能を入れたいなと思い、がちゃがちゃ実装していました。するとやたら処理が遅く、お店リストの取得が遅かったので、この問題に対処するにあたり調べたことを記事にしたいと思います。
現在使用しているのは、以下のLocation
APIのgetCurrentPositionAsync
というメソッドです。
import * as Location from 'expo-location';
let location = await Location.getCurrentPositionAsync({});
結論
iOSでは
位置情報の精度を求めるが速度は遅くてもよい
→ getCurrentPositionAsync
位置情報の精度は落ちるが、速さを求める
→ getLastKnownPositionAsync
同じ問題にぶつかっている人の記事があったので見てみると、Andoroidでは前者でも2秒とかで取得できるらしい。。
詳細
以下公式ドキュメントを見てみるとgetCurrentPositionAsync
は、現在のデバイスの位置情報をメソッド実行と同時に取得しているようです。一方で、getLastKnownPositionAsync
はデバイスの最後の既知の位置情報を取得するようです。デバイスにキャッシュされている位置情報を取得するので早いんですね。
ここからは推測ですが、instagramを使っていると近くの情報がすぐに取得されるのは後者のようになっているのではと思ったりします。感覚的に、現在の位置に対して違和感のある情報を出してきたりしますしね。位置情報の精度と取得速度はトレードオフとして、どちらを採用するかを考える必要がありますね。
検証
取得に要する時間の検証もしてみました。
const startTime = performance.now();
let location = await Location.getCurrentPositionAsync({});
// let location = await Location.getLastKnownPositionAsync({});
const endTime = performance.now();
console.log("位置情報取得時間検証");
console.log(endTime - startTime);
細かい条件の記載は割愛しましたが、10秒ほど違いました。
私の作成中のアプリは、起動直後にリストを表示し、そこから選択するようなアプリなので、この差はかなり大きいと感じます。
getLastKnownPositionAsync
はデバイスに保持されている値を取得しているので早いのはわかりますが、getCurrentPositionAsync
はリスト取得ロジックの中に組み込まれている場合ちょっと遅すぎる気がします。
現在地情報取得
せっかくなので以下に実際に現在地情報を取得するコード例を載せておきます。
今回Reactでカスタムフックとして定義しています。
import { useEffect, useState } from "react";
import * as Location from "expo-location";
// 現在地の緯度経度情報の型定義
type LocationType = {
latitude: number | null,
longitude: number | null;
};
// 現在地を取得するカスタムフック
function useCurrentLocation() {
const [currentLocation, setCurrentLocation] = useState<LocationType>({
latitude: null,
longitude: null,
});
const [error, setError] = useState<string | null>(null);
useEffect(() => {
(async () => {
// 位置情報を使ってよいかの判定を返す
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
setError("Permission to access location was denied");
return;
}
// let location = await Location.getCurrentPositionAsync({});
let location = await Location.getLastKnownPositionAsync({});
setCurrentLocation({
latitude: location?.coords.latitude ?? null,
longitude: location?.coords.longitude ?? null,
});
})();
}, []);
return { currentLocation, error };
}
export default useCurrentLocation;
まとめ
現在地情報をexpoなどを使って取得するための実装の中で、調べたことを色々書きました。
同じような課題にぶつかった方の参考になれば幸いです。
上記のアプリは完成したらまとめ記事書きたい。
参考