hizi memo

びぼうろく📝

DroidKaigi 2019 を振り返る

2019年2月7日(木)と8日(金)の2日間, DroidKaigi 2019 に初めてスピーカーとして参加してきました. DroidKaigi 自体には2016年から参加していて, 「登壇とかすごいな〜」程度の感覚でした. それが今回, 自分が登壇することになったというか実際にしてきたというのが未だに驚きです. 今回のDroidKaigiを除けば, 勉強会で登壇したのは去年の夏が初めてでした. しかも5分です. あの時と比べると規模が大きすぎました.

2日目の16:50から「Navigation Architecture Component によるアプリ内遷移の管理」というタイトルで登壇させて頂きました. 「人来なかったらどうしよう😇」とか「マサカリがこわい😇」とか考えているうちに時間が近づいて, セッションの部屋に入ってみると立ち見の方が数名いるなど, ほぼ満員になっていて驚きました. ありがとうございます. もちろん, Day 1 に予定されていた同じテーマのセッションが急遽キャンセルになってしまったことや, そもそも今熱いトピックだということもありますが, それでも嬉しかったです.


振り返れば, 先輩に圧力をかけられてセッションの応募をし, あれやこれやで採択されてから今日まで, Navigation のことをひたすら調べていました. 英語力が無いので, 公式のドキュメントやリリースノートを全て日本語に自力で翻訳して資料として残し, Webにある記事をひたすら読み漁り, Twitter で関連するツイートをしている方を監視し, AOSP のコミットメッセージを読んで開発者の考えを理解し, Issue Tracker を漁り, …とにかく色々なことをやってきました.

1月中旬になって, ようやく資料作成に取り掛かりました. これは非常にまずいです. スライドは無限に拘るポイントがあるので, 完璧主義な自分にとっては苦行です. ゴールがないものは難しいです. 結局, 当日までスライドを手直ししていました. 時間切れが自分にとってのゴールです.

実際のところ, 発表はNavigationの概念や原則, 基本的な使い方とマルチモジュールでの利用例を紹介する程度になりましたが, 上に挙げた調査で得た知識は発表する際に自信となって自分を助けてくれました. 発表の練習に付き合っていただいた社内の方々もありがとうございました. 頂いたフィードバック全てを反映することは出来ませんでしたが, より良いものに仕上げられたと思います. 発表練習によって緊張しがちな自分でも, 比較的スムーズに話せた気がします.

Twitter でもポジティブなコメントを頂きありがとうございました. 登壇を終えてから皆さんのツイートを見て安心しました. 説明不足なところがあったのは私自身も理解しています. 改善に繋がるツイートが自分の成長の糧となります. 今回, DroidKaigi という大きなイベントに登壇者として参加できて, 去年までよりずっと楽しかったと思います. ひたすらインプットする2日間より, 他の発表者のスライドを見て「自分のスライドもこうした方がいいな」とか, 「こういう内容あると面白いな」とか, また少し違った視点で参加することができました. インプットに集中した方がいいのは勿論ですが, 自分はこんなことを考えてしまうんだな, という発見になりました.

最後に, このような大きなイベントを開催して頂いた主催の皆様ありがとうございました. そして, セッションを採択して頂いてありがとうございました. 素晴らしい体験をさせて頂きました.

f:id:hizi_tkc:20190208233830j:plain 良い景色☺️

CoroutineExceptionHandler を用いて Coroutines のエラー処理を行う

この記事は Kotlin Advent Calendar 2018 の9日目の記事です. Kotlin の Coroutines を使う際、エラーハンドリングをいい感じにできないか調べてたのでメモ.

try-catch によるエラーハンドリング

Coroutines におけるエラーハンドリングといえば, 次のようなtry-catchを使用したサンプルが多くみられた.

GlobalScope.launch {
    try {
        // do something
    } catch (e: Exception) {
        // do something
    }
}

このやり方でももちろん正しく動作するが, Coroutinesを多用し, なおかつ, それぞれエラーハンドリングを適切に行う必要がある場面において try-catch が全体における可読性を下げてしまい, また, 毎回 try-catch を書くのが手間になってくると感じた.

CoroutineExceptionHandler によるエラーハンドリング

このようなケースにおいて, CoroutineExceptionHandlerは有効な解決策であると考えた. try-catch を書く代わりに, GlobalScope.launchの引数coroutineContextに渡してやるだけで, エラーハンドリングを丸投げすることができる. あとは, この CoroutineExceptionHandlerを使い回すだけで良い.

val errorHandler = CoroutineExceptionHandler { _, exception ->
    // do something...
    // ex. Timber.e(exception)
}

GlobalScope.launch(errorHandler) {
    throw RuntimeException() // crashすることなく, errorHandler に処理が移行する
}

try-catch を書く必要がなくなり, 非常にスッキリした. 実際, どのような状況で使用したかというと, RxJava を用いた Flux Architecture において, Action が持つ関数内で, Repositoryが返すエラーをDispatcherに伝播する部分で使用した. エラーがおおよそ3パターンくらい(IO, HTTP, その他)になるので, 共通の CoroutineExceptionHandlerで問題なかった. もし, エラーハンドリングがより複雑であれば共通で使用すると複雑化する可能性があるので注意.

雑感

try-catch 使うより CoroutineExceptionHandler のほうが良いなと思って書いた. RxJava脳なので, RxJavaのように 正常系と異常系が分離されているのが綺麗だと思い込んでいる. これが一般的に良いかどうか判断つかないが, 個人的にはtry-catchを毎回書く手間が気になっていたので解消されてよかった.

参考

技術書典5にサークルとして初参加してきました

2018年10月8日(月・祝)に池袋で開催された技術書典5に、サークルとして初参加してきました。今回は、執筆開始から当日まで、進捗や反省点などを振り返ります。 技術書典は今回で5回目となる, 技術書オンリーの同人誌即売会です。今回は以下の通り、1万人を超える方々が来場していたようです。すごい。

続きを読む

ViewOutlineProvider で Extended FAB をつくる

Androidアプリにおいて, ViewOutlineProvider を用いて Material Design 2 にて追加された Extended FAB(Floating Action Button) を作成する方法を紹介します.

tl; dr

  • Extended FAB は, Material Design 2 で追加された新しいコンポーネント
  • ViewOutlineProvider は, View の Outline を制御するためのもので, これによってelevation でつく影の形を変えられる.
  • 一番簡単にやるなら, rounded corner な drawable を作成し, Button の background にそれを設定しつつ, android:outlineProvider="background" を設定するだけ.
  • ただし, corner の radius を十分に大きい適当な値を入れるなど, 不安定な方法なので, 自分で ViewOutlineProvider を継承したものを実装し, それを適用するほうが綺麗.

Extended FAB

Material Design の公式ページでも紹介されている通り, Extended FAB とは より幅が広く, テキストを含んだFAB と紹介されています.

テキストは必須ですが, アイコンは Optional となっています. テキストがない場合は, Extended FAB ではなく FAB を使用すればよい話だからです. アイコンを置く場合は, テキストの左側でなければなりませんが, RTLな言語の場合はその限りではありません.

以下の画像のものが, 今回実装したものになります.

ViewOutlineProvider

今回の実装では表題の通り, ViewOutlineProvider を使用します. これは API Level 21 から追加されたクラスで, View の Outline を設定するためのクラスです. Extended FAB の両端が丸くなっており, その形通りにelevationなどのshadowを表示するために活用します.

実装パターン1

もっとも単純な実装方法は, 十分な Corner Radius をもった Drawable を Background に設定し, xmlにおいて対象のViewに対して android:outlineProvider="background" をセットしてあげる方法です. これは, background の形と同じように outline を切り取るという設定になります. その他の設定として, padding を考慮した paddedBounds, paddingを考慮しない bounds, outline を指定しない none が設定できます.

以下が Background に設定する Shape Drawable です. Button の minHeight は48dpと仮定して, Radius は 24dp に設定します.

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="24dp"/>
    <gradient
        android:angle="135"
        android:endColor="#00a8ff"
        android:startColor="#0097e6"/>
</shape>

そして, 作成したDrawable を android:background に設定し, android:outlineProvider="background" を設定します.

  <Button
      android:id="@+id/addToCardButton"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@drawable/background_extended_fab" <!-- 作成したDrawable -->
      android:outlineProvider="background"/>

しかし, この方法だと端末の文字サイズを通常より大きくした状態だと minHeight を超えたサイズになる可能性があり, 結果として Radius が足りずデザインが崩れてしまうことになります. そのため, この方法はあまりオススメできません.

実装パターン2

より安全な方法として, ViewOutlineProvider を継承した独自クラスを実装する方法です. どのような形で View を切り取るかを, いくつかの制約のもとで独自に設定できます.

実装は非常に単純で, 本質的なコードはたった1行のみになります.

class ExtendedFabOutlineProvider : ViewOutlineProvider() {

    override fun getOutline(view: View, outline: Outline) {
        outline.setRoundRect(0, 0, view.width, view.height, view.height / 2f)
    }
}

次に, 対象となる View に対して, 作成した ViewOutlineProvider を設定し, clipToOutlinetrue をセットします.

view.outlineProvider = ExtendedFabOutlineProvider()
view.clipToOutline = true

また, この方法ではコードから角丸を実現しているため, 対象となる View の Background は, 角丸のDrawableを作成する必要はなく, 単純に color を設定してあげるだけで問題ありません.

この方法が, パターン1より優れているのは, 実際のViewの高さをもとにradiusを決定している点です. これにより, 前述のデザイン崩れが起きる心配はありません. 基本的には, こちらの実装方法を用いることをオススメします.

その他

  • ViewOutlineProvider は, 角丸くらいしか作れない
  • setRoundRect 以外にも, setOval も使えるらしい
  • setConventPath というものも使えるが, 動かなかった 🤔
    • この辺り解決している方がいたら教えて欲しい...

個人でアプリを運用して気づいたことまとめ

いざ技術記事書くぞ!ってなるとネタが思いつかない. 業務で手に入れた tips を雑に投下していくだけでもいい気がしてる. それくらいなら少しはあるかも. kotlin の class delegation とか知らなかったし, instant apps 対応とか最近やってるのでなんとなくの知見はあるかもしれない...

概要

1月2日にリリースしてから現在まで, アプリを運用してみて気づいたことをざっくりまとめてみる. 運用といえば聞こえはいいが, 初期設定して放置して数値を眺めていただけである. けど, わりと面白かった.

続きを読む