PR
AppStateReact Native activebackgroundinactive

[ReactNative] Androidのinactive状態を確認する方法〜AppState〜

atlanta-g630a8172f_1280 AppState

この記事は 2024 年 3 月時点の記録です(2026 年 7 月 追記)

本文のコードは今も動きますが、なぜこう書く必要があるのかを公式ドキュメントの記述で補っておきます。理由が分かると応用が利きます。

1. blur・focus は AppState の値を変えません

ここが混乱しやすいところです。公式ドキュメントには、blur について次のように書かれています。

  • ユーザーがアプリを積極的に操作していないときに受け取る
  • 通知ドロワーを引き下げたときなどが該当する
  • AppState は変化しないが、blur イベントは発火する

つまり blurfocus は「状態」ではなく「通知」です。AppState.currentState を見ていても検知できません。本文で focus を受け取ったときに自分で 'active' をセットしているのは、そのためです。表示用の状態を自前で組み立てていると考えると分かりやすいと思います。

2. 起動直後の null は、レガシーアーキテクチャ限定になりました

以前は「起動時、ネイティブ側から値を取得するまで currentState は null になる」と案内されていました。現在の公式ドキュメントでは、この注意書きが「レガシーアーキテクチャを使っている場合」に限定されています。

New Architecture が既定になった環境では、起動直後の null を意識した書き分けは不要になります。逆に、null チェックを入れているコードが動かないように見えたら、どちらのアーキテクチャで動いているかを確認してください。

3. Modal や Alert で blur が発火するという報告があります

Android で ModalAlert を表示した際に blur イベントが発火する、という報告が React Native のリポジトリに上がっています。アプリを離れていないのに離れた扱いになるため、画面を隠す・タイマーを止めるといった処理を入れていると誤動作します

該当する挙動が出たら、blur だけで判断せず AppState.currentState と併せて見る、あるいは Modal の表示中はフラグで除外する、といった対処が必要になります。

4. 何に使うのか

この判定が必要になる場面は、たとえば次のようなものです。

  • アプリ切り替え画面に出るときに、表示中の内容を隠す(銀行アプリなどでよく見る挙動)
  • フォアグラウンドに戻ったタイミングでデータを再取得する
  • 離れている間はタイマーやポーリングを止めて、電池の消費を抑える

※ 上記のうち 1 と 2 は 2026 年 7 月時点の React Native 公式ドキュメントの記述に基づきます。3 は報告されている事象の紹介であり、当方の環境で再現・検証したものではありません。

ケースによってアンドロイドでもアプリの inactive 状態をチェックする必要がある。React NativeのApp StateではiOSのみinactive状態が確認できるのでアンドロイドのためには、下記のようにコードを追加して使用する。

// app/_layout.tsx

import {AppState} from 'react-native';
...
export default function RootLayout() {
  const appState = React.useRef(AppState.currentState);
  const [appStateVisible, setAppStateVisible] = useState(appState.current);
...
  useEffect(() => {
    const subscription = AppState.addEventListener('change', nextAppState => {
      appState.current = nextAppState;
      setAppStateVisible(appState.current);
    });
    return () => subscription.remove();
  }, []);

  useEffect(() => {
    if (Platform.OS === 'android') {
      const subscription = AppState.addEventListener('focus', () => {
        setAppStateVisible('active');
      });
      return () => subscription.remove();
    }
  }, []);

  useEffect(() => {
    if (Platform.OS === 'android') {
      const subscription = AppState.addEventListener('blur', () => {
        setAppStateVisible('inactive');
      });
      return () => subscription.remove();
    }
  }, []);
...

Android で AppState 値が activeinactivebackground に変更される事を確認する。

コメント

タイトルとURLをコピーしました