WindowsのNTFSはtree()が遅い
起きた事象
- Windows版Android StudioのGradle Sync(像のアイコン押すと走るやつ)が異様に遅い
- 普通に
gradlew
実行だけでも遅い - MacやUbuntuだと早い
- 具体的にはこのくらい
遅かった理由
- CIのキャッシュキーにするため、特定ファイル名のハッシュ値を計算していた
- ハッシュ計算を(やり忘れないように)gradleのビルドスクリプトの中で(常に)起動していた
- ファイル一覧を列挙するとき、(実装を面倒くさがって)fileTree()によるリポジトリの全探索を行った
- 結果として、NTFSの上でファイルツリーの単純全検索が走ることとなった
- 特に
build/
配下の検索が走ってしまったのが痛かったと思われる
改善
反省点
結論
Protocol BuffersのAndroid向け実装としてSquare Wireを採用した所感
Protocol Buffersを採用した理由
- 大量のデータを扱う処理で、画面外の情報を一時的にファイルやDBに退避したい
- ついでにIntentで渡したりするのも簡単にやりたい
- モデルの定義を簡素化したい
- 銀の弾丸を求めて色々検証した結果、Protocol Buffers+Wireプラグインに落ち着いた
Protocol Buffers公式プラグイン(javaliteとか)の採用を見送った理由
- AndroidのBundleやIntentにモデルを直接putできない
- 自分でByteArrayにエンコード/デコードしなければならない
- やってやれないことはないけどそこまで手間をかけたくない
- javalite実装が3.0.0(2016年頃)で止まっている
- Firestoreとかでまだ使われているから、何かあればメンテするとは思われるが。
Wireプラグインを採用した理由
- Proto3に対応している
- Android Parcelizeをimplしたモデルを出力してくれる
- 実装を見ると、ByteArrayにエンコード(Protocol Buffers形式として)してputしている
- kotlin-parcelizeを使うことで簡単にIntentに乗せられる
- コミット履歴からみて、アクティブにメンテされている
Wireプラグインの問題
追記: Wire プラグインの不具合
- Windows版で
import "path/to/other.proto"
のように相対パスを記述するとWindowsのセパレータ(\)として認識されないためファイルが見つからなくてビルドができない - issue: https://github.com/square/wire/issues/1325
AndroidアプリプロジェクトのJDK11対応
AndroidのJDK
- Android Studioに付属しているJDKはJava8相当
- なので、公式にはJava8でビルドするのが良いと思われる
なぜJava11対応が必要になったのか
- CircleCIが用意しているAndroidビルド用Docker Imageが突然Java11になった
- ああもうしゃーないなぁとか思いながらも、変更することにした
- RobolectricがAPI29以降Java9以上必須となっていたので、まあいい機会だと
JDKインストール
Android Studioの設定変更
- Project Structureから使用するJDKを切り替える
- デフォルトはAndroid Studio付属になっている
- build.gradleの構成?によってはProject Structureが開かない不具合があるので、その場合はDefault Project Structureで切り替え、.ideaディレクトリを削除して再度プロジェクトファイルを生成させれば良い
_JAVA_OPTIONSの設定
- 初めて知ったが、
JAVA_OPTIONS
と_JAVA_OPTIONS
は明示的に異なり、通常ユーザー向けのRuntimeは前者を、開発者向けのJDKは後者をロードする - _JAVA_OPTIONSに
-Djavax.net.ssl.trustStoreType=JKS
を追加する
robolectricの設定
sdk=28
とかで固定を入れている場合、sdk=29
に変更して実行環境を調整
CircleCI設定
circleci/android:api-30
とか切り替えちゃっていいんじゃないかな
dokka設定
- ドキュメントをdokka出力しているなら、バージョンを変更する必要がある
- JDKのClass名が変わったりとかしたので
// /build.gradle classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.4.0-rc"
dokkaHtml { outputFormat = 'javadoc' outputDirectory = "$buildDir/dokka" noStdlibLink = true dokkaSourceSets { noAndroidSdkLink = true configureEach { noStdlibLink = true noJdkLink = true noAndroidSdkLink = true } } } }
メイン開発PCのパーツ交換をした
メイン開発マシンのスペックアップのため、一部のパーツを入れ替えたので今後のためにメモ。
メイン開発マシンのスペック(2017~)
基本スペック
- Ryzen 1950X
- メモリ 2400MHz / 8GB×8
- GeForce GTX 1060
- NVMe SSD 512GB×2
表OS / Windows 10 / ストレージ512GB割当
裏OS / Ubuntu 20.04 / ストレージ512GB割当
- Android(Kotlin) / Flutter / Go Serverあたりの開発に使用
- 特にAndroid Studioで顕著だが、Windowsでの動作が緩慢なため切り替える場合が多い
不満だった点
- Windows 10の動作が遅い
- Git For Windows由来のbashを使用していたが、動作が緩慢
- Android Studioのビルドが遅い
- module分割を多用するアーキテクチャなので、 ビルド速度=シングルスレッド性能 の頭打ちが気になる
アップグレード計画
乗り換え先選定
- 2017年購入時と同じく、サイコム の水冷BTOが第一候補
- 予算的にはまあギリいけるか、的な範囲
- 筐体がかっこ悪くなっている
- 追加購入して、デスクトップ2台分の接地面積を取ることも難しい
- 中古で売るにしても面倒だけが多い
- 筐体を変えない(Fractal DesignDefine R5)ため、パーツ交換を行うことにする
交換内容
- Ryzen 3950Xを導入することにした
- TRを使うと、「長く使わないともったいない」ってなってしまう
- Ryzen進化速度早いので、まあ2~3年もしたらRyzen9系に追い抜かれるだろう
- シングルスレッド性能も3950Xと3960Xはほとんど変わらない
- ソケットが異なるため、自動的にマザーボードも交換することになる
- 元々の水冷クーラーがAM4非対応(オプション別売り、終売)のため、水冷クーラーも交換することになる
- 最大メモリスロットが8スロット -> 4スロットに半減するため、メモリも交換することになる
- PCIe 4が使えることと、Windowsの動作速度向上のためストレージも買い換えることになる
- 後々グラボを載せ替えるのも面倒なので、グラフィックボードも交換しておく
- という理由でドミノ倒しのように殆どの機材が入れ替えとなる
嘆き
- タイムセールで買っておきゃよかったぁ!!!!
AmazonのタイムセールでRyzen 3950Xが3万円台になってる
— 川峠@Andriders (@eaglesakura) 2020年6月27日
最終的な構成変更
- Ryzen 1950X -> Ryzen 3950X
- 水冷クーラー Corsairの昔の -> Corsair h100i Pro RGB
- メモリ 2400MHz 8GB×8 -> 3600MHz 16×4
- マザーボード X399 Taichi -> X570 Taichi
- ストレージ NVMe 512GB×2(PCIe 3.0) -> NVMe 512×2(PCIe 4.0)
- グラボ GTX 1060 -> RTX 2080 Super
交換後の感触
Mac版IntellijでGradle Syncが出来なくなった場合の対処
発生した問題
- 最近購入したMac Book Pro 13inch / 2020 / RAM32GBでIntellijをインストール
- gradle syncが行えない
- 必ず失敗し、ログも表示されない
- IntelliJ自体のログを見ると、
Java home is different
と言われてDaemon接続に失敗しているらしい
解決
- Androidアプリビルドのために、
Java Zulu 1.8.0_252
をsdkmanを通して利用している - 最近のバージョンから、JAVA_HOMEが変更になった
- 間違ったJAVA_HOMEを指定していたので、正常にgradle syncできなかった
zulu-8.jdk
をIntellijに読ませることで解決
まじかよ
- 何じゃこりゃ
- 半日潰してしまった
Intellij Idea 日本語EAP版が配信されているので試した結果、アンインストールした
日本語化の利点
- 日本語話者なので、自然に使えるでしょう
- 初学者に勧めやすい
- これは重要。超重要
- 日本語Visual Studioから、英語Eclipseに移った当時(10年以上前)、必死に日本語パックの初期設定とか探した
EAP版の問題点
- フィードバック済み
Run...
とか、たまに使う(けどショートカットを覚えるほど使ってない)アクションの検索(Ctrl+Shift+Aに割り当ててる)も日本語化されてしまうRun...
ではヒットせず、実行...
と検索しなければならない- 翻訳されたキーワードを知らなければ使えないし、日本語・英語を検索時に切り替えるのはちょっと面倒
- 日本語化が完全でないため、英語メニューと日本語メニューが混在
Build
はビルドではなくBuildである- が、メニューには
ビルド
もあるので、どっちのBuildかビルドか選ぼう
- せめて英語メニューと日本語メニューを同時に検索してほしい
結論
- まだIntellijを触ったことがない人で、英語だとちょっと。。。みたいな感触であれば入れてあげるがよし
ChildFragmentのViewが一部条件で表示されない場合のワークアラウンド
問題点
- MotionLayoutの中にChildFragmentでConstraintLayoutの中にFragmentの中にカメラプレビューを置いた
- ユーザーの操作にあわせてアニメーションしたり、Viewを入替えたりする
- サムスン、Huaweiの端末(もしくはAndroid 8以上?)でChildFragment.replace()すると、カメラが表示されない
場合がある
原因
- onCreateView後、なぜかViewのmeasure, width, heightが全部0になっている
- Viewがレイアウトされず放置されるらしい
- Activity.onPause/onResumeを経由(Fragment開いているときに他のActivityからonActivityResultで結果を受け取ったり)すると100%再現
- どこが原因か、正直不明だった
ワークアラウンド
- 自動でViewの配置やViewレイアウトの構築をトリガーしてくれないなら、手動トリガーすればいいじゃない
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 親FragmentのViewを経由して再度レイアウトさせる. this.viewをやっても無駄 requireParentFragment().requireView().requestLayout() }
どこが原因だ?
- MotionLayoutか?
- ChildFragment 2段階入れ子だからか?
- ConstraintLayout in MotionLayoutだからか?
- わからないが、コレで逃げられることはわかった