お気持ちの表明

思考を雑に外出していきます

ReactNativeのアプリをバックグラウンドにするとJSのコードが動作しない(Android)

ReactNativeで書いたコードが、アプリをバックグラウンドにした時、動作しないと気づいた。

ネイティブコードで非同期処理をして、その結果を こんなかんじで JS側にイベント投げて、stateの更新を行うみたいなことをしていたときに、アプリがバックグラウンドになってるとイベントのキャッチができてなくて、stateが更新されず、はあ...?となっていた。

テキトーなコードを書いてみたところ、バックグラウンド時にはJSのコードが動いていない様子だった(0.44.0と0.49.3で確認した)。

例えば、以下のようなコード。
1秒ごとに「wei」とログを吐き続けるウェイなアプリを作ったとする。
フォアグラウンドのときは動作するが、バックグラウンドにしたあと、ウェイしてくれなくなる...。

App.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  Text,
} from 'react-native';

export default class App extends Component<{}> {
  componentWillMount() {
    console.log('App.js: componentWillMount()');

    setInterval(
    () => { console.log('App.js: wei') }
    , 1000);
  }

  render() {
    console.log('App.js: render()');
    return (
      <Text>Wei</Text>
    );
  }

  componentDidMount() {
    console.log('App.js: componentDidMount()');
  }

  componentWillUnmount() {
    console.log('App.js: componentWillUnmount()');
  }
}

index.js

import { AppRegistry } from 'react-native';
import App from './App';

AppRegistry.registerComponent('CheckBackground', () => App);

以下がその時のログ

バックグラウンドにするとウェイウェイしてくれなくなった

// フォアグラウンドのとき

10-22 22:31:41.910 30529-30578/com.checkbackground I/ReactNativeJS: App.js: componentWillMount()
10-22 22:31:41.914 30529-30578/com.checkbackground I/ReactNativeJS: App.js: render()
10-22 22:31:41.948 30529-30578/com.checkbackground I/ReactNativeJS: App.js: componentDidMount()
10-22 22:31:42.925 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:43.940 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:45.031 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:45.975 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:46.989 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:48.010 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei
10-22 22:31:49.031 30529-30578/com.checkbackground I/ReactNativeJS: App.js: wei

// ここでバックグラウンドにした ウェイしてくれなくなる

ドキュメント等できちんとしたエビデンスが得られていないが、バックグラウンド時には、JSコードは動作しなくなる的なコメントがStackOverFlowにあった でもこれ2年前近いコメントなんだよな...。挙動的に今もそうなってるぽいけど...。

There is a limitation in React Native wherein when the app is in the background the js bridge stops getting messages. This means if you are trying to send the data from js then you won't be able to count on the data making it. Alternatively you could write the code to send the updates in native code and that should do the trick javascript - How can I run background tasks in React Native? - Stack Overflow

認識が間違ってたり、ドキュメント等をご存知でしたら、コメントで教えてもらえると泣いて喜びます

staticフィールドは、意図せず初期化されることがある

概要

  • AndroidJavaで書くマンしている
  • 今まで、staticに突っ込んだ値は、アプリのプロセスが終わるまでは生きていると思っていた
  • プロセスが終わるまで生きてるんだから、staticに値つっこんで管理せばええやろ〜〜〜と思って、そういったコードを書いている箇所があった
    • 今回の場合、staticフィールドに状態を持たせるようなコードを書いていた
  • 「staticの値って、ホントにプロセス終わるまで生きてるの?」「その理解、ホント?」とレビューで突っ込まれた
  • 先に書いていた理解してた事柄は、学生の時に「そうなんだ〜。ふ〜ん。」程度に覚えていた知識で自信もなかったので、調べたのでそのメモ

先に結論

  • staticも初期化される可能性は普通にある
  • staticとするのは定数のみにして、状態管理に使わないほうが良さそう

(この理解に間違いがあれば、何かしらでツッコミを入れてもらえると、とてもありがたいです)

Staticな変数ってそもそもなに

インスタンスではなく、クラスに紐付けられた変数
インスタンス変数 ↔ クラス変数

JVMの概要

じゃ、そのクラスの情報はどう管理されているか。 JVMがどうなっているか調べてた。

JVM | Java Virtual Machine - Javatpoint

ざっくり

  1. JVMが起動すると、ClassLoaderなるものが動作し、アプリケーションで利用するクラスを読み込む
  2. 読み込んだ内容は、メモリに展開され、画像中央の白枠のようにそれぞれ領域別に展開される
    • アプリケーションに含まれているクラスの中身は、Class Areaに読み込まれる
      • staticな変数(クラス変数)はこの領域に格納される
    • 生成したインスタンスHeapにつっこまれる

クラスローダーとかいうやつが、鍵っぽい

クラスローダー

JVM起動時にアプリケーションで利用するクラスを読み込んで、メモリに展開するくん

クラスローダにはいくつか種類がある

  • ブートストラップ・クラス・ローダー

    • 起動時にまず呼び出されるクラスローダ
    • JVM自体の実行に必要となるシステム・クラスをロードするのが役割
    • 注意として、読み込めるすべてのクラスをロードするのではなく、アプリケーションからのクラス参照があった時にロードされる
    • JDKディストリビューションによって提供されているすべてのクラスがこのクラス・ローダーによってロードされると理解して問題ないとのこと
    • オプション-Xbootclasspathをいじると、ブートストラップ・クラス・ローダーがロードできるクラス・セットの範囲を変更できる
  • 拡張クラス・ローダー

    • ブートストラップ・クラス・ローダの子にあたる
    • 最初に親に委譲し、その後必要なら、そこではじめて対象のクラスを検索し、解決する
    • 拡張ディレクトリという領域からクラスをロードする
      • これは、java.ext.dirsシステム・プロパティで指定する
    • ロードされたクラスは、JVM固有の構成を指定するために使用でき、JVMプロセスに追加でロードするライブラリを変更できる
  • システム・クラス・ローダー

    • アプリケーション・クラスおよびクラスパス上にあるクラスをロードする
    • 拡張クラス・ローダーと同様に、最初に親に委譲し、その後必要なら、そこではじめて対象のクラスを検索し、解決する
    • オプション-cpでクラスパスを指定できる

ロードについて

大きく4つのフローがある static変数に値を突っ込むのは、準備の段階らしい

  • 検証
    • クラスが破損していないこと、および構造的に正しいことを検証する
    • 実行時コンスタント・プールが妥当
    • 変数の型が正しいこと
    • 変数がアクセスされる前に初期化されている
  • 準備
    • 静的フィールドをそれぞれの型に合うデフォルト値に初期化する処理が含まれる
    • 例:準備後はint型のフィールドには0、参照はnullになる
  • 解決
    • 実行時コンスタント・プール内のシンボリック参照が、実際に必要とされる型の妥当なクラスを指し示していることをチェックする
    • シンボリック参照の解決が契機となり、参照先のクラスのロードが行われる
  • 初期化子群の実行
    • クラスが準備済み、検証済みであることを前提として、クラスの初期化子(イニシャライザ)を実行する
    • すべての静的初期化ブロックのコードを結合した静的初期化子(スタティック・イニシャライザ)メソッドも実行される
      • 初期化プロセスは、ロードされたクラスごとに1回のみ実行すべきものであり、同期的に処理される
      • これは特に、クラスの初期化によって他のクラスの初期化が起動される恐れがあるため、デッドロックに注意して初期化を行う必要があるから
        • 初期化処理が重複して行われないようにしたいから、という理解でいいんだろかな

アンロードについて

ロードはJVMの起動時に行われ、不要となったクラスのアンロードは、そのクラスが利用されなくなったときに行われる
これが実行されるとクラスのデータも破棄されるので、staticフィールドも破棄される
どういったときにアンロードされるのかは、以下のとおりらしい。

クラスのアンロードは、そのクラスが不要になった時に起こる。 クラスが不要になる条件は、以下の 3 つの条件を全て満たす必要がある。

  1. ヒープ中からそのクラスのインスタンスがなくなること。
  2. そのクラスの static メソッドを実行中のスレッドがいないこと。
  3. そのクラスをロードしたクラスローダーを現わす ClassLoader 派生型のインスタンスがヒープ中からなくなること。

クラスが 1. ~ 3. の条件を満たしているかどうかの判断は、実装的な理由により GC 時に行われる Java VM が多い。

Java のクラスアンロード (Class Unloading)

アンロードが起こるとstaticフィールドの値も吹き飛ぶことがわかった。

でもそれ、AndroidJVMだと、どれぐらいの頻度でおこるもんなの...?
公式には以下のように書いてあった
先の1~3と同じ条件と思っていれば良さそうな気がした

The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded. Classes are only unloaded if all classes associated with a ClassLoader can be garbage collected, which is rare but will not be impossible in Android. Note however that the jclass is a class reference and must be protected with a call to NewGlobalRef (see the next section).

JNI Tips | Android Developers

ただ、DalvikとARTどっちもそういう理解でいいのか...?

Dalvikについては、以下のStack OverflowにDalvikのエンジニアやってた人がコメントしている
先の1~3と同じ条件と思っていれば良さそうな気がした

ARTについては、それらしい文献を見つけれていない
明示的にARTって書いていないけど、公式にアンロードされることがあるって書いてあるし、そう思っておくことにする

また、以下の記事があった
公式ドキュメントでは「あんまりアンロード起こらんよ」とはいいつつ、わりと普通にunloadされているらしい

ご存知の通り、Androidはメモリが逼迫するとバックグラウンドにあるActivityやらServiceやらを殺していく。 殺されるのはそういったAndroid特有のオブジェクトだけではなく、 アプリのライフサイクルとは無縁の上記ContextHolderのようなオブジェクトも例外では無い…ように感じる。 というのも、実際に上記のようにstaticで参照を保持しているフィールドにアクセスするアプリで、 ぬるぽでクラッシュしたレポートがコンスタントに上がってきているので。 クラスがUnloadされると、次回必要になった際に再Loadされる。 その時に初期値を設定していないstaticフィールドはnullで初期化される。 そこで本来はApplicationクラスのonCreate()でContextを設定したいところが、 プロセスまでは殺されていないためにApplicationクラスのonCreate()が再度呼ばれず、 staticフィールドはnullのままになってしまうのである。

Androidアプリでstaticフィールドは絶対ではない - PEEE802.11

結論

  • staticも初期化される可能性は普通にある
  • staticとするのは定数のみにして、状態管理に使わないほうが良さそう

(この理解に間違いがあれば、何かしらでツッコミを入れてもらえると、とてもありがたいです)

参考

NativeBaseを導入しようとしたら、無限に怒られた

怒られるまでの流れ

error: bundling: UnableToResolveError: Unable to resolve module `AccessibilityInfo` from `/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/Libraries/react-native/react-native-implementation.js`: Module does not exist in the module map or in these directories:
  /Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/node_modules
,   /Users/symmt/Program/Study/ReactNative/Molpe/node_modules
,   /Users/symmt/node_modules

This might be related to https://github.com/facebook/react-native/issues/4968
To resolve try the following:
  1. Clear watchman watches: `watchman watch-del-all`.
  2. Delete the `node_modules` folder: `rm -rf node_modules && npm install`.
  3. Reset packager cache: `rm -fr $TMPDIR/react-*` or `npm start -- --reset-cache`.
    at ResolutionRequest._resolveNodeDependency (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:394:11)
    at tryResolveSync (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:136:20)
    at tryResolveSync (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:66:12)
    at ResolutionRequest.resolveDependency (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:134:22)
    at dependencyNames.map.name (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:145:59)
    at Array.map (<anonymous>)
    at ResolutionRequest.resolveModuleDependencies (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:145:42)
    at module.read.then (/Users/symmt/Program/Study/ReactNative/Molpe/node_modules/react-native/packager/src/node-haste/DependencyGraph/ResolutionRequest.js:172:40)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

解決策

以下、動くようになるまで調べたりやったことのまとめ

ReactNativeのバージョンとNativeBaseのバージョンがあっているかを確認

NativeBaseのリポジトリに、ReactNativeのバージョンとそれに対応するNativeBaseのバージョンが書いてあるので、合致しているか確認

この時点で、自分の環境が以下のようになっていることに気付く

  • ReactNative: 0.44.0
  • NativeBase: 2.3.2

NativeBaseの2.3.+では、ReactNativeの0.46.0以上を使ってね!!と書いてあった ReactNativeのバージョンが低いやん...!となり、以下の感じでReactNativeのバージョンを更新した

$ yarn upgrade react-native@^0.48.0

またられる

今度は、undefined is not an object (evaluating 'ReactInternals.ReactCurrentOwner')と怒られた

ファーーーーーーとなりながら、ggったところ、以下のIssueを見つけた

@winterrain5 As I mentioned, make sure you've installed the correct version of React. If you're using React Native 0.45:

yarn add react@16.0.0-alpha.12

undefined is not an object (evaluating 'ReactInternals.ReactCurrentOwner') · Issue #13874 · facebook/react-native

なるほど? そのまま、reactを更新したところ、動きましたとさ。

なお、この記事を書いた段階だと、NativeBaseがreact@16.0.0-alpha.13をサポートしていないと書いていたので、注意。

f:id:symmt9302:20170930164239p:plain

ReactNativeさわりはじめて思うのは、エラーログから何を対処すればいいか、サクッとわからないので、つらい

おしまい。

Slackのクライアントアプリが重くてつらいので、ブラウザで運用することにした

Android開発をするようになってから、作業中に「PCが重いな〜〜〜〜」と思う率が高い気がする。 で、アクティビティモニタを見てみたら、Slackがなかなか重そうなことに気づく。

ggってみると、クライアントつかわず、専用ブラウザで運用する人もいるそうな?

自分でもやってみるか〜〜〜〜〜〜〜と思って、ごにょごにょしたので、そのまとめ

やったこと

  • Slackの専用ブラウザとしてSafariを使った
  • 今まで開いてたSlackのチームをSafariで開きまくった
  • Safari Standを入れて、左端にタブを表示するようにした

Slackの専用ブラウザとしてSafariを使った

そのままです。 Chromeよりは軽いと思うから、Safariで運用していこう!!と決めただけ。

今まで開いてたSlackのチームをSafariで開きまくった

たくさんチャンネル入ってるとダルそうな作業です Slackで利用しているメアドを統一していれば、以下の記事を読むと幸せになります

https://slack.com/signin/find にアクセスして、メールアドレスを送れば、 JoinしているチームのURLが記載されたメールが受け取れます。最高に便利。

あとは、そこからポチポチしてけば良し。

Safari Standを入れて、左端にタブを表示するようにした

当たり前ですが、ブラウザで運用するとなると、開いた各チームはタブになります。 元のクライアントアプリみたく、左サイドに欲しい……..。

Safari Standを入れるとできるとのこと。 以下を参考に導入しました。

なお、これで導入して表示したサイドバーを移動させたいときは、右クリックすると出てくる Move Sidebar To Far Side をクリックすると移動できます。 (最初右側に表示されてしまって、左に移動させようにも、ドラッグ移動できるわけでもなくびびったのでメモ)

おわりに

とりあえず、これで開発中に「パソコン重い!!!!!!!!!!」とイライラしなくなるといいですね

IoTなLED電球をもらった

1ヶ月前、誕生日でした。
いろいろと、ありがとうございました。

そのときに、気になっていたBluetooth接続できるLED電球をいただきました。
ありがとうございます!!!!!!!!!

こういう電球は、Hueが有名ですが、
気になるけどくっそ高くて、なかなか手を伸ばせないな〜〜〜〜と思っていたので、
2000円かからないでゲットできるなら触ってみたいと思ってたのです。

と、いうわけで、遊びました。

とりあえず、電球を設置するのに、IKEAでウォールブラケットを買ってきました。

で、買ってきて気づいたのですが、このウォールブラケットは電球の型がE17のものでした…………… このLED電球の型はE26でした………………

変換コネクタを買って、かまして、つけたのですが、不格好に………………………….

うぐーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
気になるけど、まあ、いいか、うん

で、Bluetoothで接続してアプリいじると調光ができるそうなので、やってみた
ディスコ感(?)があります

色も好き勝手に変えれるし、輝度も調整できるので、すっごく楽しいです

夜、シーリングライトつけると明るすぎるな〜〜と思ってたので、
夜の部屋の照明として使っていきたいな、という感じです。

Hue的な電球欲しい人には、おすすめできるかと思います👌👌👌

ストレングスファインダーをやってみた

就職して1年たったけど、私より歴の長いエンジニアとお話をしていると、 あたりまえですが、めーっちゃできる人ばかりで、 「自分ダメダメだけど、長所ってどこなんだろ」って思いました。

そう思ったからと言って、他の人に「私の長所ってどこ?」って聞いてみても、 一緒に仕事してる人にそれって聞きにくかったりするし、 仕事してない人だと、エンジニアリング的な長所を聴くことは難しい気がしている。 (勤務先、エンジニア少なくて、母数が少ないってのもある。)

ちょっと前ぐらいに、F太×jMatsuzaki Radio 第1回 『ストレングスファインダー』を聞いていて、 「そういえば、そんなのあったなあ」と思い出したので、やってみた。

ストレングスファインダーとは

30分ぐらいアンケートに答えていくと、34個ある強みから、その人の強みを教えてくれるやーつ。 課金額に応じて、自分の強みをランキング形式で確認できるやーつ。

やりかた

長そうなので、端折ります。 以下のサイトをご参照くださいませ。

ちなみに私は、書籍版を買いました。

さあ、才能(じぶん)に目覚めよう―あなたの5つの強みを見出し、活かす

さあ、才能(じぶん)に目覚めよう―あなたの5つの強みを見出し、活かす

そして、この記事書いてるタイミングで、
新板が出ることを知って、かなしいお気持ちになっております。

書籍版だと、後ろのほうに、シリアルナンバーがあるので、それを本家サイトに入力して30分ぐらいポチポチしていく感じです。 私は、オフトゥンにもぐりつつ、iPadでポチポチやっていきました。

やった結果

iPadでポチポチして、最後までやってすぐに寝落ちして目覚めると、以下のレポートが返ってきました。

  1. 運命思考
    • 運命思考という資質を持つ人は、あらゆる人や物事は互いに結びついていると考えています。この世に偶然というものはほとんど存在せず、ほぼあらゆる出来事には何らかの理由が存在すると確信しています。
  2. 個別化
    • 個別化という資質を持つ人は、一人一人が持つユニークな個性に興味をひかれます。異なるタイプの人たちの集団をまとめ、生産性の高いチームを作ることに長けています。
  3. 学習欲
    • 学習欲という資質を持つ人は、学習意欲が旺盛で、常に向上を望んでいます。特に結果よりも学習すること自体に意義を見出します。
  4. 内省
    • 内省という資質を持つ人は、頭脳活動に多くの時間を費やします。内省的で、自分の頭の中で考えるのが好きで、知的な討論が好きです。
  5. 回復志向
    • 回復志向という資質を持つ人は、問題を解決するのが大好きです。どこに問題があるのかを探りあて、それを解決することに長けています。

結果を見てみて

見てて「それな〜〜〜」感はあるので、当たってると思う。
なんか、エンジニアっぽいなあ、と思いました。

「運命的思考」は、「何をしたくて、これやってんだろ〜〜。」って考えるのはエンジニアとして普通の習慣っぽいし、 「個別化」は、お話する時「この人何考えているんだろ〜〜。」って話聞きながら考える事多いからあたってるっぽいし、 「学習欲」は、「これ作るのに勉強しなきゃな〜〜。身についたら楽しそうだな〜〜。」って思えるあたり当たってるっぽいし、 「内省」は、あれこれ考えつつコード書いたり、料理したりするのすきだし、 「回復志向」は、「このコード治したら、これが良くなるから、テンション上がるわ〜〜。」ってなるので、当たってるっぽい。

そんな感じで、エンジニア向いてそうだなあ、ってちょっと元気になりました(?)。

まとめ

ストレングスファインダーやってみたら、自分の強みがわかったぞー。

自分の強みTOP5は以下の5つらしいぞ。

  • 運命思考
  • 個別化
  • 学習欲
  • 内省
  • 回復志向

これ見ると、自分はエンジニアに向いてそうな気がした。

この強みを活かした思考をしたいと思ったら、
以下の感じで考えるクセをつければ、いい感じになる気がしました。

  • コードを読むときは解決しようとしている背景を想像して、
  • そのコードで解決しようとしているドメインを理解して、
  • 必要な知識は都度取り入れつつ、
  • 得た知識で良さそうな解決策を内省して、
  • 問題の解決に取り組むようにする

余談

これ書いてて、Fate/stay night の士郎さんの投影みたいな感じで、かっこいい気がした。

・創造理念
・基本骨子
・構成材質
・製作技術
・憑依経験
・蓄積年月
以上の要素を再現するという工程を経ているそうな。
もっと詳しく書くと、創造の理念を鑑定し、基本となる骨子を想定し、構成された材質を複製し、製作に及ぶ技術を模倣し、成長に至る経験に共感し、蓄積された年月を再現する、との事。
Fate辞典-ト