visible true

技術的なメモを書く

Kotlin Coroutine 1.0.0までに夏から変わったところ

日進月歩。夏に話した頃とは大きく変わってしまったKotlinコルーチン。

Kotlin Fest 2018でコルーチンの話をしてきた - visible true

↑はコルーチンの概念と実現の仕組みを中心に置いたので、その辺はまぁ変わってないんで問題ないんですが、後半の実際にコルーチンを使う場面に関してはすでにdeprecatedっていうか、そのまま書いても動かないくらい変化してしまいました。

ということでざっくりメモ

0.25.xから1.0.0までの主要な変化

基本的にはリリースノートと関連するissueの議論を読めば大体わかります。 https://github.com/Kotlin/kotlinx.coroutines/releases

[0.26.0] CoroutineScopeを導入し既存の書き方がdeprecatedに

9/12にリリース。kotlin festから2週間やん。

CoroutineScopeという概念が追加された。既存のコルーチンはすべてGlobalScopeとして扱うことになった。そのほか構造的並行性(Structured concurrency)が基本的な考え方となり、スコープの階層を適切に構築しようなみたいな話になったぽい。

もともとは全部グローバルコルーチンだったので単純だけどリークの可能性もあった(永遠に生きるコルーチンとかのケアがあんまりなかった)が、構造的並行性によってrootスコープから末端まで親子関係を適切に構築することでライフサイクルの伝搬をいい感じにしていこうなという感じ。

parent jobで親子関係をやりくりしていたのを、CoroutineScopeでデフォルトで必ず親子になるようにしたため、書きやすくなったと言えるし設計もしやすくなったなと思う。大変だけど。

ちょっと追記

CoroutineScopeによってコルーチンのライフサイクルを構築しやすくなった。これによってAndroidとの親和性が上がったと言える。ActivityのライフサイクルやFragmentのライフサイクルなどに合わせてそこにぶら下がるコルーチン全体を停止できるようになるから。なのでコルーチンをガシガシ書ける空間(Activity, Fragment, ViewModelなどのライフサイクルに合わせて動くCoroutineScopeを実装できる)を提供できて、アプリに導入するハードルが下がる。実際CoroutineScope導入後にJetpackコンポーネントでどんどんコルーチンサポートが入ってきている。この点はすごく良かったのでは〜って思う。

[0.26.0] Dispatchersを導入

CoroutineScopeの動きとは別でDispatcherの名前がバラバラ(CommonPool, UI, JavaFx...)なのでなんとかしない?みたいな議論のなかでDispatchersオブジェクトが導入され、そこに生やす形になった。

  • CommonPool -> Dispatchers.Default
  • UI -> Dispatchers.Main
  • _ -> Dispatchers.IO

など。まぁこれは名前変わったね程度の理解で大体よさそう。CommonPoolはいずれなくなるらしいけどまぁよしなにやってくれるみたいなので頼むみたいな感想。

[0.30.0] 例外伝搬の仕様が変わった

9/29リリース。矢継ぎ早〜

コルーチンが例外を投げたときにどこまでどう伝搬するかみたいな話。たとえば次のコード

suspend fun foo() = coroutineScope<Unit> {
  val one = async {
    delay(Int.MAX_VALUE) // suspend until cancellation
  }

  val two = async { throw MyException() }

  one.await()
}

oneとtwoが同時に動きだすけどtwoはすぐに例外を起こす。しかしDeferredはawait()しないと例外が飛ばないので、oneが長いとtwoが死んでるのにずっと待っちゃうみたいな動きは問題だ、ってことで、即時に親をキャンセルする形になった。

これが怖いのは次ようなコードは書いちゃ駄目になったということ

val job = Job()
val scope = CoroutineScope(Dispatchers.Main + job)
scope.launch {
  try {
    val a = async { // launchの中でasync起動したらあかん
      delay(1000)
      throw Exception()
    }.await()
  } catch (e: java.lang.Exception) {
    e.printStackTrace()
  }
}

launchとasyncは親子関係を持っているがasyncは親をcancelにするのでlaunchもcanceledになり、さらにその上まで例外を伝搬する。アプリでこういう呼び出しをしていると例外補足できずにクラッシュしてしまう。

明確な理由はわからないが、スコープビルダー(coroutineScope{})は親をキャンセルしないことになっていて、次のように書けば解決する。

val job = Job()
val scope = CoroutineScope(Dispatchers.Main + job)
scope.launch {
  try {
    // ※クラッシュしないけどこのケースでは非推奨なのでこれは使わないでください
    coroutineScope { 
      async {
        delay(1000)
        throw Exception()
      }
    }.await()
  } catch (e: java.lang.Exception) {
    e.printStackTrace()
  }
}

ただほとんどのワンショット継続はwithContext(Dispatchers.IO)でまかなえるので次に書くようにしたほうがよさそう

val job = Job()
val scope = CoroutineScope(Dispatchers.Main + job)
scope.launch {
  try {
    withContext(Dispatchers.IO) {
        delay(1000)
        throw Exception()
    }
  } catch (e: java.lang.Exception) {
    e.printStackTrace()
  }
}

coroutineScope{}の使い所はスコープを切り換える時、つまりそのスコープの中で別のコルーチンを起動する時。async複数呼び出して並行で実行しまとめて待ち合わせる場合はcoroutineScope{}を使う必要がありそう。

この辺ややこしいし言語化するの大変なので大幅に省くけど、さらにSupervisorという考え方も導入されて混乱に拍車がかかっている。Supervisorはスコープ内のコルーチンがエラーになっても親がキャンセルされずに、他の子コルーチンを継続するやつ。実際使う機会はAndroidではほとんどないよな〜というのが個人的な見解。並行で複数リクエストするけど投機的で相互の失敗に依存しないケースとか。

[1.0.0] experimental packageを廃止 🎊

10/30 🎊

https://github.com/Kotlin/kotlinx.coroutines/releases/tag/1.0.0

experimentalパッケージからはずれてkotlinx.coroutinesになった!めでたい。 マイグレーションも1.3マイグレーションの中でやってくれるので移行も楽。楽しい。

おわりに

リリースノートはしっかり読んだほうがよいですね 😵

ノンアルコールビールで晩酌すると風呂上がりにさっぱりプログラミングできて助かる

adventar.org

タイトルですでに完結していますが。

アルコール飲むと寝る前にプログラミングできない

年齢の所為もあるんでしょうけど、夕飯時にアルコール飲んじゃうと風呂上がって、さ〜てプログラム書こうかってなっても酔っ払っているのでついつい漫画読んだり映画見たりゲームしたりしてゴロゴロしてあーまぁアルコール入れたしもう寝るか〜みたいになってプログラミングせずに寝がちなんですよね。

じゃあ飲まなければいいのでは?という事なんですが、しかし、アルコールっておいしいですよね。ビールだとサントリー ザ・プレミアム・モルツ 〈香る〉エールとか好きなんですよ。なので飲みたいは飲みたい。でもプログラミングもしたい。

ノンアルコールビールを飲むと酔った気がするけど実際は酔ってない

当たり前なんですがノンアルコールビールはビールの味わいやのどごしがありながらもノンアルコールなので酔わないんですよ。ところが飲んで見るとカーッとくるものがあってあたかもアルコール飲んでる感覚があるんですよね。プラシーボ的ななにかなんでしょうか?ということで割とノンアルコールビールでも体験としてはビールとそんなに変わりがないんですよね。で、飲んで夕飯食べてつまみも食べてあ〜飲んだ呑んだって満足したあと風呂入って机に向かうと全く飲んでない状態に復帰できるので問題なくプログラミングができるわけです。

ノンアルコールビールは以前は飲めたものじゃない感じがあったんですが最近はいろいろ発達していて大分美味しく飲めるようになりました。個人的にはアサヒ ドライゼロが好きです。

ノンアルコールビールで晩酌すると風呂上がりにさっぱりプログラミングできて助かる

肝臓にも負担かからないし、酔わないし、プログラミングもできて良いっす。

Robolectricで複数のLocaleをテストしたい時はEnclosedで頑張るしかないのか

RobolectricでLocaleを指定するには@Config(qualifiers)を使う

テストで特定のLocaleで実行したいときってありますよね。Robolectric*1だと@Config(qualifiers)*2を使うことでテストのLocaleを指定できます。

@RunWith(RobolectricTestRunner::class)
@Config(qualifiers = "zh-rCN")
class HogeTest {

ただこれだとテストケース全体に適用されるので、ある言語の時だけ特殊な表記をするケースなんかを書くのには適しません。

複数のLocaleで回したい場合はEnclosedを使う?

Enclosedを使えば一つのクラスのなかで複数のテストクラスを書けるので、qualifiersを分けてテストを書けます。

@RunWith(Enclosed::class)
class HogeTest {
  @RunWith(RobolectricTestRunner::class)
  @Config(qualifiers = "ja")
  class JaTest {
  }

  @RunWith(RobolectricTestRunner::class)
  @Config(qualifiers = "zh-rCN")
  class CnTest {
  }
}

しかし...

いちいちクラス切るのめんどくさいなぁ

同じテスト内容でロケールだけ変えて結果の違いをテストしたいみたいな場合にもいちいちクラス切って書かないといけないのでめんどくさいな〜ということでどうしたらいいんだろう。なにかいい方法あるかな〜って思った話です。

*1:4.0-beta-1を使ってますがそれ以前でも使えるはずです

*2:locale以外にもいろいろ指定できます http://robolectric.org/using-qualifiers/

mockkとかでモック書く時にalsoと組み合わせると読みやすくなりそうな気がした

mockk便利ですよね。suspend関数のモック*1までサポートしてるしstatic, objectのモックもサポートしているのでいろいろはかどります。

github.com

alsoと組み合わせるとよさそう

mockitoと大体同じなんですがモック作る時ってだいたいこんな感じになります。

val yearly: Sku = mockk()
every { yearly.priceAmountMicros } returns 600000

every関数はmockitoにおけるwhenみたいなもんです。returnsが中置関数になっていて.を省けるんですがまぁあんまりどうでもいいです。 ところでモックオブジェクトとその振る舞いの定義ってバラバラに書くことになっていつももやもやするんですよね。 ということでalso使ってこう書くといいんじゃないかと思いました。

val yearly = mock<Sku>().also { mock ->
  every { mock.priceAmountMicros } returns 600000
}

よく考えたらmockitoでも同じようにできそうですね。 also関数*2便利。

追記

ウボォー「たまに こういう奴が いるから やめられねェ ブログはな」 デフォルトでblock渡せるとは!ありがとうございます。

*1:coEvery, coVerifyなど

*2:apply関数でもいいんですが空間がthisになっちゃうんでalso関数のほうがいろいろ複雑に書く時に楽かなと思ってalso関数にしました

Kotlin Fest 2018でコルーチンの話をしてきた

kotlin.connpass.comでコルーチンに関する話をしてきました。

Kotlin コルーチンを理解しよう

スライドはコチラ。音声や動画が無くても大体読めばわかる内容になっていると思います。

流れ

6月末にひつじさんからお手紙がとどく

f:id:sys1yagi:20180827130403p:plain

直前の技術書典4Kotlinのコルーチンを使う前に自前で実装してみるという話を書いていたこともあり、 その辺をベースにした話の組み立てでできそうな気がするということでシュッと受けた。 結果的にめちゃくちゃ大変でしたが最終形はなんとかまとまったので良かったです。

調べたことや登壇時は触れられなかったことなど

話のベースは頭の中にあったものの、コルーチンの概念そのものが一体どういうものなのかあまり深く理解していなかったこともあり、その辺の調査もしなきゃな〜と手を動かし始めるとそのままどツボへ真っ逆さま。今回話の流れや時間的に触れられなかったことなんかをここにメモっておきます。

コルーチンとはなにか

昨年の6月頃に話したもうAndroidの非同期処理はasync/awaitでいいんじゃないかなぁと思ったでは"関数の途中で中断したり再開できるやつ"くらいにしか説明してなくて、さらにその辺は別に便利に使えるんだから気にしなくてよくないくらいの気分でいたんですが、しかしそれはそれとしてちゃんと調べるべきだよな〜と思ってとりあえずWikipediaなんかを見つつ、メルビンコンウェイの論文が初出らしいってことで論文読もうかとおもって論文を読んだ。

Design of a Separable Transition-Diagram Compiler

発表にもある通りCOBOLコンパイラの話で、コルーチンを使っていい感じにCOBOLコンパイラを記述できるぜ!がメインの話なので、コルーチンそのものは現在の説明からはかなり遠い記述になっていた。この論文では字句解析と意味解析を別モジュールで実装することで分離したプログラムがそれぞれ協調して動くということを実現しているらしい。

その後コルーチンに関する説明を調べると「協調的マルチタスク」と「プリエンプティブマルチタスク」という用語によって両者を比較する文脈があらわれるのだけど、これはコルーチンがスレッドどころかプロセスすらない時代に生まれたマルチタスクの概念で、コルーチンが論文に登場したのと同時期に「タイムシェアリング」についての研究も盛んになっていて、結果的にタイムシェアリング勢によるプリエンプティブマルチタスクとかスレッドとかが主流になってコルーチンは廃れたみたいな流れがあってそれはそれで面白いんだけどそれ道具としてのコルーチン関係なくない?みたいになってどう触れるか迷いが生じたりした。

協調的マルチタスクというのがコルーチンの重要なコアの概念なんだけどいかんせん一番シンプルな例でもproducer consumerパターンでややこしく、async/awaitで今まさに価値が見出されつつあるコルーチンの説明の頭にもってくるのしんどくないってなってそこも却下になった。どっちかっていうとKotlinコルーチンにおけるproduceコルーチンビルダー関数やChannelがまさに本来のコルーチンって感じだけど実際利用するケースってかなり少ないので、コルーチンを使っていこうなと言うにはニッチすぎて厳しいと考えて協調的マルチタスクというワードは出さないようにすることにした。もうひとつややこしいのは、実際のKotlinのコルーチンはスレッドプールで動くという点があってそうすると協調的マルチタスクプリエンプティブマルチタスクの対比がふんわりしてしまって簡潔に説明できないよなというのも悩ましい点だった。その辺の観点からFiber、グリーンスレッド、軽量スレッドとかにも触れるのはやめた。

2004年の論文にRevisiting Coroutinesというのがあって、ここで「昨今はマルチスレッドプログラミングが盛んになってコルーチンをnativeサポートする言語が減ってきてけしからん。コルーチンはいいぞ」って書いてあって元気だなって思って読んでみると、現代に通じるコルーチンの分類をしているぽくて我が意を得たりと思ったのだけど内容が難しくて、完全非対称コルーチンが多分async/awaitだよなーと思いつつでも言明はされてないしワンショット継続とかのワードもよくわからず(限定継続のこと??)、これをもって現代のコルーチン実装が整理されたとは言えず参照を断念した。

英語のWikipediaコルーチンの説明が一番端的で正しいのだけど、

コルーチンは、サブルーチンを一般化するコンピュータプログラムコンポーネントです。 特定の場所で実行を一時停止および再開するための複数のエントリポイントを許可することによって、非プリエンプティブマルチタスクを実現します。

みたいな文章が初っ端にあって、確かにいろいろ調べた今となってはこれでわかるんだけどさーこれ参照した上で説明すると終わらねーだろ〜ってなって、その後の例やサブルーチンやスレッドとの比較は良かったので取り入れたものの実際に書いてる事よりかなり平易に説明した結果厳密ではなくなってそこはそれで胃が痛い気持ちだったりした。サブルーチンを一般化するというのは同じスレッドで動く子コルーチンが中断しない場合サブルーチンと同じ動きやで、みたいなことでコルーチンですべて表現できるよねということなんだけどそこ説明するのはその後の話とは関係ないからしんどいなどなどしんどかった。

そこで55年飛ばすことにした。

最終的にはコルーチンを端的に表す文言としてCoroutines for Kotlin (Revision 3.2)での説明と日本語版Wikipediaの利用用途についてを参照することになった。公式リファレンスの説明も検討したがこちらは道具としてのコルーチンの話が厚めだったのでやめた。この話のあとにする話と関連していてかつ破綻がない情報を抜き出すのはかなり骨が折れた。今回の取り出し方は本当にギリギリだったなぁと思う。

この辺は本番2日前辺りでようやくfixした。

Kotlinはどのようにコルーチンを実現しているのか

ここについてはすでに大体調べていたのでそこまで迷いはなかった。 昨年のKotlin Confの発表を見返しつつ、CPS Transformとかステートマシンについて再確認して構成を落とし込んでいった。

時間的な問題やあるいは後半の使い方に直接関連しない点で削いだ部分が結構あってそれはそれで惜しい気はしている。実際にバイトコードを読みながら、ステートマシンとして生成されたクラスがCoroutineImplを継承していたりLambdaを実装していたりlabelとswitchで状態を分解している様子を眺めたり、except宣言された(suspend R.() -> T).createCoroutineUnchecked関数の実装と継続インターセプターが使われる様などを眺めたりしたがったが、収拾がつかない気がしたのでやめた。

suspend修飾子、継続インタフェース、CPS、コルーチンビルダー、継続インターセプターの説明は最初から入れていたが、前半のコルーチンとはなにかの説明で出たコルーチンの要素と整合する形で落とせたと思うのでよかった。が、コルーチンビルダー、継続インターセプターは完全にライブラリ実装に近い話なので基本的な使い方の文脈で説明してもよかったかもと思った。

Kotlinコルーチンの基本的な使い方

前半に力を持っていかれ、本当に基本的な部分しか触れられなかったのと練習不足でわりとグダグダだったな〜と反省するなど。ただ前半の説明を踏まえておけば最低限でも自分で進めていく力を得られると思って使い方部分はかなりあっさりにした。Guide to kotlinx.coroutines by exampleの内容を踏襲したほうがいいんじゃないかと思った瞬間もあったがrunBlockingを混乱なく説明できない気がしてやめた。

コルーチンの前提知識を得た状態とはいえストーリーとしてもっとライブラリ実装側の話とか提供されている機能群を厚めにしないとふわっとしないかと思いつつ基本形を作ってasync/awaitのバリエーションという形となった(手が回らず)。ジェネレータ、Channelやアクターの話、テストに関する話なども入れられたらなぁと思いつつ、リハしたら時間オーバーしたのでそこは手はつけなかった。

結構ギリギリで、最初はlanch関数の引数を上から順に説明したりしていたが当日スライドを見返しながら調整したりした。Jobの説明とか入ってなかったり。

とか言っていたが、この章のスライドは発表の2時間前までいじっていた。終盤のRetrofitのDeferredや、EventBus、android-coroutinesの話は全然深掘りできなかったのでちょっと残念だけどおもしろ感を出したかったので割り切り。

前日自宅でリハしたあと奥さんに「(血の気が引いて)顔が緑だよ」って言われて「グリーンスレッドだけにね」って言ったかどうかは定かではない。

当日の様子

ランチ難民をしていたがひつじさんがコーディネートしてくれて、元同僚と初対面の方との3人で行ったのだが、 初対面で知らない人と思っていたらなんとAndroid アプリ設計パターン入門で僕が抜けた穴を塞ぐべく参加して下さった吉岡さんだとわかり「その節はどうも」みたいな感じになった。お礼を言えてよかった。

寿司の様子。というかこの1枚しかこの日は撮ってなかった。 f:id:sys1yagi:20180827231351p:plain

スピーカー控室はめっちゃでかくてスピーカーが10人掛けテーブルを1人で専有しポツポツ座ってるみたいな感じで快適だった。 プロジェクターがありスライド映して試せるのかと思ったらA会場のライブが始まりビビったが面白かった。

会場ウロウロしたり控室戻ったりスライドいじったりコーヒー飲んだり自家製プディング食べたりして過ごした。 いつもは緊張でほぼ他の発表見られないのだけど控室にライブが流れるのでよかった。

本番後はAsk the Speakerで幸いにも行列ができいろいろ会話した。 RoomにDeferredくるか!?

Twitterの感想も好評のようでよかった。 懇親会ではAndroid老人会が発生して面白かった。

出し殻のようになって翌日はオクトパストラベラーをプレイし続ける一日となった。

良いもの残せたのではないかなと思うし運営も会場も最高だったのでめっちゃ良かったと思います(小並感)。参加して下さった方々ありがとうございました。

facebook/Sonarで大体Stethoを置き換える

Stetho便利ですよね〜。 最近Stethoを置き換えるfacebook/Sonarというライブラリが登場しました。 メトリクスツールのSonarとかDAWCakewalk SONARとかとかぶってて名前紛らわしいっすね〜

facebook/Sonarでできること

StethoはAndroid向けのライブラリであったのに対し、SonarAndroidiOSの両方の環境をサポートしています。 また独立したElectronアプリを提供していて、Chrome Dev Toolsをポチポチする必要がなくなりました。やったね。

f:id:sys1yagi:20180718112432p:plain

SonarにはBuilt-inのプラグインがいくつかあります。とりあえず現状あるやつを紹介しときます。

Logcat

Logs · Sonar

SonarのElectronアプリを起動するととりあえずLogcatが見れます。アプリ側で特に対応とか入れなくても適当につなぐみたいです。 あとなんか画面キャプチャとか動画撮影もやれるみたい。adb~

Layout Inspector

Layout Inspector · Sonar

Layoutの樹海に潜っていじれるやつです。

f:id:sys1yagi:20180718113315p:plain f:id:sys1yagi:20180718113318p:plain

Stethoでも出来た気がするな。どうだったかな。

Network Inspector

Network · Sonar

こちらもStethoで出来たやつ。概ねできることは同じはず。後ほど書くけどOkHttp3しかサポートしてないので、まだOkHttpを使ってる場合は使えないので注意。

f:id:sys1yagi:20180718113546p:plain

Shared Preference Viewer

Shared Preferences · Sonar

Shared Preferenceの中身を見たり編集したり。 ただ、特定のShared Preferenceを指定する必要があるので、Stethoよりpoorになった印象。

https://fbsonar.com/docs/assets/shared-preferences.png

Sandbox

Sandbox · Sonar

よくわかってないけど、key-valueを設定しておくと、Sonarアプリ側からいじれるようになる感じっぽい。 アプリの環境変数を動的にいじれるぜ的なsomethingという理解でよさそう。

facebook/Sonarでまだできないこと

できないことというか、plug-inがまだないというか..

  • SQLite database viewer
    • いずれBuilt-inでサポートされるとは思うけどまだない
  • Realm database viewer
    • 欲しい
  • no-op dependenciesがない
    • get startedではdebugImplementationで書けといいつつリリースビルド時に死にがち (プラグイン使うとガッツリコードで依存する。build-typeで分離はできる範囲だとは思う)

ちょ〜っと厳しいよねまだ..

導入手順

まあGetting Startedに書いてあるんですが、 dependenciesを追加して...

repositories {
  jcenter()
}

dependencies {
  debugImplementation 'com.facebook.sonar:sonar:0.6.11'
}

Applicationなどで初期化します。

fun initSonar() {
  SoLoader.init(this, false)
  if (BuildConfig.DEBUG && SonarUtils.shouldEnableSonar(this)) {
    AndroidSonarClient.getInstance(this).start()
  }
}

pluginを導入する

さてそのまま実行しても特になにも起こりません。pluginを入れないと。 とりあえずLayout InspectorとShared Preference Viewerは次のように設定します。

fun initSonar() {
  SoLoader.init(this, false)
  if (BuildConfig.DEBUG && SonarUtils.shouldEnableSonar(this)) {
    AndroidSonarClient.getInstance(this).apply {
      // layout inspector
      addPlugin(InspectorSonarPlugin(this@Application, DescriptorMapping.withDefaults()))

      // shared preference
      // 第二引数にpreference名を指定できる
      // 引数渡さない場合はデフォルトのpreferenceを参照する
      addPlugin(SharedPreferencesSonarPlugin(this@Application)) 
    }.start()
  }
}

Network Inspectorについてはもうちょい複雑で、pluginの初期化のほかにOkHttpClientのNetworkInterceptorにもpluginインスタンスをセットしないといけないのでちょっと大変。

val networkSonarPlugin = NetworkSonarPlugin()

fun initSonar() {
  SoLoader.init(this, false)
  if (BuildConfig.DEBUG && SonarUtils.shouldEnableSonar(this)) {
    AndroidSonarClient.getInstance(this).apply {
      addPlugin(networkSonarPlugin)
    }.start()
  }
}

OkHttpClientを作る時にNetworkSonarPluginインスタンスをどっから引っ張ってくるか..

@Provides
@Singleton
fun provideOkHttp3(): OkHttpClient {
  return OkHttpClient.Builder().apply {
    // initSonar()の時と同じインスタンスが必要
    addNetworkInterceptor(SonarOkhttpInterceptor(Application.networkSonarPlugin))
  }.build()
}

Daggerでinjectすんのがいいだろな〜。ちょっとめんどくさい。 SonarOkhttpInterceptorはOkHttp3向けにしか存在しないぽいので注意してください。

ここがいいよねSonar

アプリ起動したら自動的にNetwork Inspectorがキャプチャ開始してくれるので、 Chrome Dev Toolsで毎度立ち上げ直していた手間がなくなってその点はめっちゃ良い。 今の所それくらいかな...

hyperionの様子

SQLite database viewerが無いのはかなり厳しい気がしているので、せめて代替えなんかできないかということで、 Hyperion Androidhyperion-sqliteあったなーって思ったら、 not yet released だった hyperion-sqlite not yet released? · Issue #137 · willowtreeapps/Hyperion-Android · GitHub 諦め。

おわりに

自分は導入してしまったけど、まだ様子見な気がする。絶賛開発中なので導入よりいろいろcontributeを考えるほうがいいのかもなと思うなどした。 SQLite database viewerはちょっと試しに作りたい。

Android Studio自体のヒープサイズを変更する

Android Studioでしばらく開発していると、一文字打ったり、行移動するだけで一瞬固まるといった現象に見舞われる。CPUが定期的にスパイクしていて、待てど暮らせど改善しない。再起動すると直るがしばらく触っているとまた遅くなる。

どうもメモリが足りなくなってGCしまくっているため起こるらしい。

どうにかならんものかと調べたら公式に設定方法があったのでメモ

Android Studio の設定 | Android Studio

[Help] > [Edit Custom VM Options] で studio.vmoptions ファイルを開き( or 作り )、 -Xmx4gとか書いて再起動するといける。

やったね。