南の島で読んだ本たち
先日ふらっと南の島(タイのサムイ島)に行ってきた。日常から頭を切り離すことが目的でとにかくぼんやりしてみたくなったのだ。 ぼんやりするにも時間は潰したいので本を持って行くことにしたのだか、日常を想起させる技術書・ビジネス書はNGという縛りで何冊かピックアップ+Twitterでオススメしてもらった本を持って行った。その備忘ログ。
1冊目:走ることについて語るときに僕の語ること(村上春樹)
- 作者: 村上春樹
- 出版社/メーカー: 文藝春秋
- 発売日: 2010/06/10
- メディア: ペーパーバック
- 購入: 25人 クリック: 137回
- この商品を含むブログ (182件) を見る
村上春樹によるエッセイ。村上春樹の書籍は「村上さんのところ」くらいしか読んだことがなかったが、私もサボりがちながらも走ったりするので以前から興味があり購入。走ることだけじゃなくて、著者の考え方だったり作家という職業だったり、ほんの少し知らない世界が覗き見れた気がして楽しかった。
2冊目:美味礼讃(ブリア=サヴァラン)
- 作者: ブリア=サヴァラン,Jean Anthelme Brillat‐Savarin,玉村豊男
- 出版社/メーカー: 新潮社
- 発売日: 2017/04/27
- メディア: 単行本
- この商品を含むブログを見る
19世紀のフランスでベストセラーになった書籍の玉村豊男の新訳の方。新訳じゃなかったら絶対に途中で心折れてただろうなってくらい訳が秀逸。訳だけじゃなくて、2,3ページに毎くらいに解説(ツッコミ?)が入っているのが楽しくてどんどん読める。食(美味学)というのが本書のテーマだが、食だけじゃなくて恋愛とそれに関わる一連の行動について謎の圧で語られていて笑える。
3冊目:サイコパス(中野 信子)
- 作者: 中野信子
- 出版社/メーカー: 文藝春秋
- 発売日: 2016/11/18
- メディア: 新書
- この商品を含むブログ (11件) を見る
新宿紀伊国屋の精神医学や犯罪心理学の棚で見つけた一冊。これはかなり当たりだった!!本書はサイコパスを脳科学の観点から解き明かして行く。目次をみただけでも「サイコパスと恋愛はできるか」、「サイコパスかもしれないあなたへ」、「サイコパス向けの仕事を探そう」という具合にパワーワードが並ぶ。身の回りの誰かの顔を思い浮かべながら読むと楽しい。
ここまでの3冊は自分で選んで買ったもの。以降はTwitterでオススメしてもらったものたち。
4冊目:世界の終わりとハードボイルド・ワンダーランド(村上春樹)
- 作者: 村上春樹
- 出版社/メーカー: 新潮社
- 発売日: 2005/09/15
- メディア: 単行本
- 購入: 7人 クリック: 288回
- この商品を含むブログ (93件) を見る
またまた村上春樹。こちらはshiroyamaさんのオススメの一冊。
世界の終わりとハードボイルドワンダーランド
— 父 (@fushiroyama) 2018年2月12日
村上春樹の小説初めて読んだけど、ミステリー調で想像していたものより100倍読みやすかった!食べ物とお酒とファッションと音楽と女の子が魅力的に語られるシャレオツ小説でした。世界の終わりの影が好きでした。ハードボイルド・ワンダーランドの方だと博士と図書館の女性が好き。あと、よく「やれやれ」っていうと村上春樹っぽいってインターネッツでネタにされてるのがようやく理解できた。本当にたくさん「やれやれ」って言ってた。
5冊目:EAT&RUN(スコット・ジュレク)
- 作者: スコット・ジュレク,スティーヴ・フリードマン,小原久典,北村ポーリン
- 出版社/メーカー: NHK出版
- 発売日: 2013/02/21
- メディア: 単行本(ソフトカバー)
- クリック: 1回
- この商品を含むブログ (7件) を見る
こちらはimaiさんのオススメ。ヴィーガンでウルトラマラソン走っちゃうとんでもない人の自伝。
— Tomoaki Imai (@tomoaki_imai) 2018年2月13日
「とにかくいいからやるんだ」期と「どうやったら勝てるか?」を考える期、どちらが適切か受け入れる姿勢は取り入れていきたい。そんな難しいことを考えながら読んで勉強になったけど、最後にはシンプルに「あぁ、走りたいなぁ」と思えるいい本だった。
6冊目:仁義なきキリスト教史(架神恭介)
- 作者: 架神恭介
- 出版社/メーカー: 筑摩書房
- 発売日: 2016/12/07
- メディア: 文庫
- この商品を含むブログ (9件) を見る
こちら、オススメしていただいた時の元tweetが消されているため、本当はオススメじゃなかった説あるけど気になったので読んだ。色々ぶっ飛んでて楽しかった!セリフが全部広島弁の極道。多少なりともキリスト教の知識があったほうが笑えると思う。これ読んで日本帰ったらポプテピピック8話が同じく広島弁極道ネタだったのでまた笑えた。
以下、持っていけなかったけどオススメしてもらったのでいつか読みたい本たち。
おまけ1:野火(大岡昇平)
- 作者: 大岡昇平
- 出版社/メーカー: 新潮社
- 発売日: 1954/05/12
- メディア: 文庫
- 購入: 9人 クリック: 520回
- この商品を含むブログ (95件) を見る
こちらはkurokawaさんオススメ。あらすじ読んで怖くなったのでいつかメンタルが強くなったら読みたい。
なにも思い付かなかったのですが、大岡昇平さんの「野火」はどうでしょう。太平洋戦争中の南の島の話です。
— Hiroshi Kurokawa (@hydrakecat) 2018年2月13日
おまけ2:孤島の冒険(N. ヴヌーコフ)
- 作者: N.ヴヌーコフ,ジマイロフ,Nikolai Andreevich Vnukov,島原落穂
- 出版社/メーカー: 童心社
- 発売日: 1998/06
- メディア: 文庫
- 購入: 2人 クリック: 2回
- この商品を含むブログ (1件) を見る
こちらはmitsuyoshiのオススメ。児童書なのかな?絶版っぽいので今度会った時に貸してもらう。
「孤島の冒険」
— みつよし (@vespid) 2018年2月13日
おまけ3:蜜蜂と遠雷(恩田陸)
こちらは鍵付きアカウントからのオススメ。恩田陸は高校生の頃めちゃめちゃ読んでたなぁ。
- 作者: 恩田陸
- 出版社/メーカー: 幻冬舎
- 発売日: 2016/09/21
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
おまけ4:グラゼニ(原作 森高夕次 漫画 アダチケイジ)
こちらはnakagawaさんのオススメ。Webコミックなのかな?
野球のことは全くわからないけどせっかくオススメされたので読んでみたい。
グラゼニ(漫画)
— Shinichi Nakagawa (@shinyorke) 2018年2月13日
こうやってみると仕事以外だと食べることと走ることに興味があるんだなー。
DroidKaigi公式アプリにRTL周りのPull Request出した時にやったことまとめ
DroidKaigiお疲れ様でした!公式アプリでRTL周りのPull Requestを出したので何をしたのか備忘録のメモを残しておきます。
Issue
Pull Request
やったこと
Left / Right をgrepして適切なものに置き換え
ConstraintLayout周りとかLintで指摘してくれないものがあるのでleft
/ right
でgrepした方がいいと思います。
grepした結果を機械的に置き換えれば良いというわけではなく、例えば情報としてはひとまとまりなんだけどviewとしては別れているみたいなケースがあります。
例えば、下記の画像の場合、
What is "
が一つのTextView, DroidKaigi
が一つのImageVIew, " ?
が一つのTextViewで構成されています。
RTL表示の場合でも英字はLTRの方向で表示するため、単純にleft / right をstart / end に置き換えてしまうと表示がおかしくなってしまいます。
RTL対応、今までParent ViewGroup作って対応していたところがConstraintLayoutでどうやるか悩む… A B C Dみたいなviewを4つ並べるデザインで、B Cが意味のひとかたまりだと、D B C A みたいな表示にしたいけど、各Viewに制約つけるとうまくいかないし、ConstraintLayoutで子の階層深くするのは悔しい
— むーむー (@muumuumuumuu) 2018年2月5日
ConstraintLayoutの中に置いたRelativeLayoutのwidthをwrap_contentにしているのだけど、RTLの時だけなぜかmatch_parentとして振る舞うようになってしまって泣いてる
— むーむー (@muumuumuumuu) 2018年2月5日
RelativeLayoutに `android:layoutDirection="ltr"` つけるのも考えたけど、RelativeLayout自体のgravityをrtlにしたいので却下。さてどうすればいいんだ…
— むーむー (@muumuumuumuu) 2018年2月5日
上記のように色々試行錯誤した結果たどり着いたのがこちら。
真ん中のViewに余白大きめにとってそこを起点に制約をつけていくというハックを覚えた
— むーむー (@muumuumuumuu) 2018年2月5日
具体的に書くと、DroidKaigi
のImageViewの(画像自体に)左右に余白を取って、そこを起点に左右のViewに制約をつける方法で回避しました。
今気がついたんだけど、なぜか" ?
の方だけRTL設定の時に? "
になっちゃってますね。
What is "
の方は大丈夫なんだけど。
" ?
の方のTextViewにandroid:textDirection="ltr"
を指定してLocaleに関係なく文字方向を固定することで回避できます。
Localeに関わらずTextViewにRTLを強制する場合は android:textAlignment を設定
例えばこのような条件の場合、
2で設定したリソースは右から表示されます。
今回のDroidKaigiの公式アプリはアラビア語リソースは用意されていないので、「開発者向けオプション」> 「RTLレウアウト方向を使用」にチェックを入れて表示確認をして行きます。この場合だと英語リソースのままレイアウト方向はRTLになりますが、逆にいうとレイアウト方向しかRTLにならないのでmatch_parentなTextViewのtextは左から表示されます。
こんな感じ。
そこでandroid:textAlignment="viewStart"
を設定することでレイアウト方向とテキスト方向が連動するようになります。
directional symbolは反転させる
directional symbolって日本語でなんていうのがポピュラーなのかわかっていませんが、矢印のように方向性を持ったシンボル(そのまんまや…)のことです。Droidkaigi公式アプリではほとんどvector drawableでアイコンが作られていたので<vector>
tagのなかにandroid:autoMirrored="true"
を指定してやればRTL表示時に反転します。
stringsのplaceholderは(必要があれば)RTL用のものを作る
そのまんま。必要があればこんな感じでRTL用のplaceholderを作ります。
<string name="room_format" translatable="false">%1$s%2$s</string> <string name="room_format_rtl" translatable="false">%2$s%1$s</string>
アラビア語のリソースを用意するのであれば不要かもしれません。ケースバイケース。
上で書いたように今回は同じ言語リソース(英語と日本語)でRTLの場合とそうでない場合に対応するのでコードで、動的にどちらを読むか判断しています。
どちらを読むかについては下記の拡張関数を作ってレイアウト方向をチェックして判断するようにしました。
fun View.isLayoutDirectionRtl() =
resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
コードからPadding設定するとき用に拡張関数作る
View#setPadding()
メソッドは引数を4つ持ちますが、そのうち第1引数は(startではなく)left固定、第3引数も同様にright固定となります。そのため、RTL表示の場合はleftとrightを入れ替える拡張関数を作りました。
fun View.setPaddingWithLayoutDirction(start: Int, top: Int, end: Int, bottom: Int) = if (isLayoutDirectionRtl()) { setPadding(end, top, start, bottom) } else { setPadding(start, top, end, bottom) }
おまけ
全く気がつかなかったのですが自分のPull Requestにtypoがあって気がついた方に直してもらいました…
今まで出したPR見たら29個できりが悪かった感じしたので30個目のPR出した(Typo修正)https://t.co/VIxwSR8fCo
— Rui Kowase (@rkowase) 2018年2月11日
圧倒的申し訳なさ…!
アアアアtypo気づかなかった本当に申し訳ないありがとうございます🙏🙏🙏🙏🙏
— むーむー (@muumuumuumuu) 2018年2月11日
AndroidのMVIについて勉強した時のメモ
AndroidのMVIについて勉強した時のメモです。自分用のメモなので雑です。
MVIとは
「MVCを元にして、jsのreduxやreactの思想を取り入れた何か」のようなもの。リアクティブで関数型プログラミングを採用している。
MVCだとViewを操作するのがControllerかもしれないし、Modelかもしれないが、MVIはreduxのようにデータの流れが単一方向。また、Reduxのようにいろんな部分を純粋関数で記述するのでテストも書きやすい。
詳しくは
この辺のリンクに目を通したらだいたいわかった気になれる。
雑感
Reduxと違うところ
すでにReduxが何か理解している人向けに書くと、Reduxと比べてこの辺が良さそう。
- 非同期処理というかデータの取得と整形をProcessorでやると定まっている
- Reduxだとこの辺がふわふわしている印象
- ほとんどの人はCreatorProducerがやるんだろうけど
- 初めての人でも迷わなさそう
- Reduxだとこの辺がふわふわしている印象
- ActionとIntentが別れているのが良い
- ReduxだとViewがCreatorProducer経由でAction発行するの、わかるんだけど、User観点で何をしたいのか?と実際にデータをどうするか?を分けて記述できるのがわかりやすい
- ActionとResultが別れているのが良い
- ReduxだとActionに変更したいstateのデータを詰める感じだと思うけど、それをResultという別のものとして扱うのが直感的
- ユーザの入力によって何をするべきかというのがコードで表現される
- あまり仕様を書かない文化のチームだと助かる場面があるかも
一方、Reduxと比べてこの辺つらみありそうというところもあって、
- SingleなStoreの概念がないので、一箇所で集中管理する感じではない
- ViewModel層がいかつい
- 細かく切ってる分ボイラープレート増える
- IntentとAction増えてくるとここまでする必要あるのかな〜って気分になってきそう
- 細かく切ってる分ボイラープレート増える
- まだそんなに流行ってないので知見がweb上で見つかりにくい
で、どうなの
自分の中では結局「どういうプロダクトかによる」という普通かよ〜〜〜みたいな結論になった。ユーザの入力というかIntentの種類がたくさんあって、かつ結びつけるActionがバラバラだったりすると、ActionをIntentを分ける恩恵はありそう。今Reduxを採用しているAndroidアプリの中からMVIに移行するケースがあれば話を聞いてみたい。でもStoreがないのでAndroidで採用するほどのモチベーションがありそうなケース、そんなになさそうかも?
今年のDroidKaigiでMVIのセッションがあるので今から楽しみにしている。
完全に余談になるが、AndroidでIntentというとおそらく大多数の人がandroid.content.Intent
だと思うし、Processorもio.reactivex.processors
を連想する人が多いと思う。名前の衝突が発生して、今どちらについて話しているのか?の認識合わせをしながらコミュニケーションとって行く必要があるので地味にストレス溜まるかもしれないなーと思った。チーム開発で取り入れてみないと何も言えないけれど。
おまけ:本家Circle.js
Twitterで釘宮さんに圧倒的知見をいただいた。感謝!
MVIってcycle.jsからきてるので、オリジナルのものも見てみるといいかも ( https://t.co/RtmPJx1SxG ) 。1hくらいの動画もあって手軽に学べますよ
— 有象無象 (@kgmyshin) 2018年1月25日
で、オリジナルだとReducerとかって言葉は出てこなかったはずなので、Android用に変えてるのか、ちょっとRedux混ぜてるかもですね (悪いとかではなく)
本家Cycle.jsだとかなりシンプルな構成で、DOM source(入力)とDOM sink (出力)を繋ぐのは、intentとmodelとviewだけ。面白いのはintentとか含めだいたいstreamとして扱われるところ。reactだからかな。
こんなにスッキリかけるのは羨ましい。
function main(sources) { return {DOM: view(model(intent(sources.DOM)))}; }
また、Eggheadのvideoコースもわかりやすいので、jsと英語にアレルギーがなかったらみてみると良いと思う。
[海外対応] AndroidのLocale周りまとめ [多言語対応]
はじめに
複数の国や地域、あるいは言語に対応する場合に避けられないMulti Locale対応ですが、Android Frameworkのバージョンによってできること・しなくてはならないことが変わって来ます。 各APIでの大きな変化を時系列でまとめてご紹介します。 また、実際にMulti Localeに対応して来た中で遭遇したハマり所とその対策方法・tipsなども共有していきます。
ってDroidKaigi2018のCfPに応募したけどRejectされたのでブログにまとめます😇 「急にグローバル対応しなきゃいけなくなったけど何していいかわかんない!」みたいな人にざっと見ていただきたいような内容です。
それでは各APIで何が対応されたのかまとめます。ハマり所とその対策方法とかは別のエントリで書けたらいいな。
Locale周りの変遷
API Level 1 : Localeの基礎
LocaleクラスはAPI Level 1の時代から存在している。というかAndroidで独自に定義したものではなく、java.util.Locale
を使っている。そもそもLocaleってなに?という話をすると、ドキュメントには
A Locale object represents a specific geographical, political, or cultural region.
と定義されている。単に国というわけではなく、地理的・政治的・文化的な特定の地域をさすものである。例を挙げると、日本だとja-JP
になる。これはlanguageとcountry(region)を合わせたものだ。この頃はlanguage codeについてはISO 639-1、region codeについてはISO 3166-1で定義されているものが使える。後述するが、API Level 24以降ではIETF BCP 47をサポートする。
「地理的・政治的・文化的」という部分について補足すると、languageにおいて同じ中国語でも簡体字と繁体字が別のものとして扱われていたり、regionの方も中国(本土)と香港と台湾が別のコードが割り当てられている例がわかりやすいかもしれない。
さて、話をAndroidに戻そう。LocaleオブジェクトはContextからgetResources()
、getConfiguration()
と経由して、Configurationのpublicなメンバであるlocaleにアクセスすることができる。アプリやActivity独自でLocaleの設定を持ちたい場合は、ApplicationやActivityのContextのlocale
を書き換えることで言語切り替えを行うことができる。具体的にはいい感じにLocaleを書き換えたConfigurationオブジェクトを使って Resources#updateConfiguration()
を呼んでやるとできる。(端末の言語設定に従う場合は端末で設定したLocaleがここに入ってくるので特に個別のアプリで対応する必要はない。)端末の言語設定で何が選択されているか知りたい時にはLocale#getDefault()
が使える。
では各Localeごとのリソースをどう定義するか。ドキュメントはこの辺りを参照してほしいが、ざっくりいうとres/
配下のディレクトリにconfig_qualifier
を付与することでLocaleごとのリソースを定義することができる。ディレクトリ名のルールはこのようにハイフンつなぎ。
<resources_name>-<config_qualifier>
例を挙げると、 アメリカ・英語用の言語リソースは下記のように定義できる。values
がresources_name
でen
とrUS
がconfig_qualifier
だ。
values-en-rUS/strings.xml
上記の例のように、qualifierはハイフンで複数繋げることができる。Localeクラス同様languageは ISO 639-1、regionは ISO 3166-1で定義されたものが使える。ただし、regionの方は頭にr
をつけなければならない。なぜかというとcase sensitiveではないので、ハイフンでqualifierを繋げた場合にregionを明示的に示すために必要なのだ。また、regionを指定する場合は必ずlanguageとセットで指定しなければならない。(region単体では使えない。)
例ではvalues/
を示したが、values以外にももちろん使える。例えばdrawable/
でも文字埋め込み画像の出し分けをするのに必要だし、xml/
やmenu/
でLocaleによって機能の出し分けをするのに使うことができる。
API Level 17 : RTL対応
ここからConfiguration
クラスにsetLocale()
メソッドが追加された。とは言え、このクラスのメンバであるlocale
はpublicのままだ。では直接locale
の値を書き換えるのとsetLocale()
メソッドでやっていることは何が違うかコード見てみよう。
/** * Set the locale. This is the preferred way for setting up the locale (instead of using the * direct accessor). This will also set the userLocale and layout direction according to * the locale. * * @param loc The locale. Can be null. */ public void setLocale(Locale loc) { locale = loc; userSetLocale = true; setLayoutDirection(locale); }
まずはlocale
の更新を行なっている。これは予想通りだろう。次にuserSetLocale
フラグをtrueにしている。このフラグはpublicだがhideアノテーションが付いている。これはActivityManagerServiceがsystem propertyにlocale情報を書き込む時に使われる。
そして最後のsetLayoutDirection()
メソッド。これもAPI Level 17から追加されたAPIだ。何をしているかと言うと、どちらからどちらの方向にレイアウトするをLocaleから判断している。
「どちらからどちらにレイアウトするか」と聞いてピンと来ない人がいるかもしれない。我々が普段目にする文字は(横書きの)日本語であれば左から右方向に流れる。よく目にする英語もそうだ。しかしアラビア語やヘブライ語など一部の言語では横書きでも右から左に文字を記述する。右から左、なのでRight to Left, 頭文字をとってRTL言語と言われる。文字だけでなく、ボタンの位置などもRTL方向に配置する必要があるが、言語によってレイアウトを複数分けて用意する必要はない。例えばRelative Layoutの子要素として、TextViewとその右にButtonを置きたいと思ったらandroid:layout_toRightOf
ではなくandroid:layout_toEndOf
を使おう。これもAPI Level 17から追加されたattributeだ。このattributeを使っているとsetLocale()
を使ってLocaleを更新した際に画面の再描画が走って適切なLayout Directionで表示されるようになる。
API Level 24 : Multi Locale
このAPIバージョンから java.util.Locale
が変わってIETF BCP 47をサポートするようになった。これによりサポートされる言語が大幅に増えた。
また、Multi LocaleをサポートするようになったのもAPI Level 24からだ。
Multi Localeについては以前ブログにまとめた。
詳細は上記を読んでもらうとして、ざっくり概要を書くと「これまではユーザは言語を一つしか設定できなかったが、このバージョンからは複数の言語とその優先順位を設定でき、かつシステム側もいくつかLocaleを準備しておくことによってより良いマッチングを行うことができる」ものである。
いくつかの言語をユーザが設定できるという部分だが、これに伴いConfigurationクラスのAPIにいくつか変更が入った。具体的には単一のLocaleを引数に取る setLocale()
、またpublicメンバのlocale
がdeperecatedになった。代わりに使用が推奨されるのがLocaleList
クラスを引数に取るsetLocales()
だ。
public void setLocales(@Nullable LocaleList locales) { mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; locale = mLocaleList.get(0); setLayoutDirection(locale); }
3行のシンプルなメソッドだ。Localeのリストを更新して、その優先順位トップのものを現在のLocaleとして設定、最後に現在のLocaleに応じたLayout Directionを設定する。
ちなみにLocaleList
クラスがマッチングをやってくれる。ロジックはこの辺。以前blogにもちょっと書いた。
API Level 25 : Configurationの設定方法が変わった
Resources#updateConfiguration()
がdeprecatedになった。代わりに何を使うのが推奨されているかというと、Context#createConfigurationContext()
だ。(このAPIが追加されたのはAPI Level 17。)ただし、これは引数で指定したConfigurationが設定された新しいContextオブジェクトを返してくれるだけだ。ここで生成したContextをActivity#attachBaseContext()
に渡してやると新しいConfiguration(と、これが持っているLocale)が設定される。
(Twitterで教えてもらいました。感謝!)
以前、下のやり方を参考に言語設定を変えてました。参考になれば…https://t.co/mmYczmIgfe
— tsuyoshi uehara@転職活動中 (@uecchi) 2017年8月23日
API Level 26: Configurationの共有範囲が変わった
API Level 25でdeprecatedになったResources#updateConfiguration()
だが、25までは一度コールするとその設定がapplication内で共有されていたが、API Level 26からは各activity/applicationで別の設定になった。
このあたりの記事が参考になった。
最後に
以上でざっとLocale周りの変遷を書いた。最後の方とかLocaleともはや直接関係ないんじゃ…という気がしなくもないが、多言語、海外対応する際に必要になるケースも多いのではないかと思うので消さずに残しておく。
それにしてもAPI Level が上がれば上がるほどアプリ内で独自の言語設定させていかないぞ♡というGoogle先生のお気持ちが強まっているのかなと思わずにはいられない😇 😇 😇
Kotlin 1.1以降をAndroidで安全に使いたかった話
はじめに
この記事は「Kotlin 1.1以降をAndroidで安全に使いたかった話」です。本当は会社のAdvent Calendar向けに書くはずだったのですが、色々あってお蔵入りになったのでこちらで供養。 ちなみにこれはボツネタ第2弾で、第1弾はこちら。 muumuutech.hatenablog.com
Kotlin 1.1 とJava 8
Kotlin 1.1がリリースされて久しいが、1.1.系からJava 8 に依存したAPIがいくつか追加された。AndroidはAPI Level 24からJava 8 に対応しているので、23以下の端末でうっかり該当APIが実行されるとCrashしてしまう。
Java 8 に依存したAPIは@PlatformDependent
アノテーションが付与されている。今の所このアノテーションが付与されているのは、Map
インターフェイスのgetOrDefault() とMutableMap
インターフェイスのremove()の二つ。
これらのAPIを安全に扱うためにCustom Lintの導入を試みた。1
Custom Lintを作ろう
Android LintもしくはJava Lintに使えそうなものがないか確認したところ2なさそうなので作っていく。gradleの設定をして、Detector, Issue, Registryの順に作っていく。
最初にGradleでビルドするプロジェクトを作る。言語は今回Kotlinにした。
Gradle
プロジェクトができたらGradleを書いて行く。
lint-api
とlint-checks
を追加する。(kotlinを使う場合はkotlin用の依存も追加)
dependencies { def lintVersion = "25.3.0" compile "com.android.tools.lint:lint-api:$lintVersion" compile "com.android.tools.lint:lint-checks:$lintVersion" }
そしてここがポイントなのだが、Lint-Registry-v2 でRegistoryを定義する。色々ググったらLint-Registry
で定義している情報が出てくるが、2017年末時点ではLint-Registry-v2
で定義しないとLintがうまく動かなかった。(これに気がつかず何時間も無駄にしてしまった…)
jar { manifest { attributes("Lint-Registry-v2": "com.your.package.CustomLintRegistry") } }
Detector
今回やりたいことは「特定のアノテーション(@PlatformDependent
)が付与されたAPIを使用した際にwarningをだす」である。本来であればJavaPsiScanner
を使ってASTに解析されたノードを探索して行って…みたいなことをするべきなんだろうけど、Advent Calendar向けにはヘビィだったので妥協案でいくことにする。
該当APIが付与されたAPIはたったの2個なので、「それらが使われた時にwarningをだす」でとりあえずお茶を濁すことにする。特定のコードが記述されているか検知したいので(まずはよく使うgetOrDefault()
でlintチェックが出るか試す)、 ClassScanner
インターフェイスを使い、必要なメソッドをoverrideしていく。
getApplicableCallNames()
detectorが検知したいメソッド名のリストを返すメソッド。今回は特定のメソッドがコールされたことを検知したいので、そのメソッド名をstringのmutable listにして返してやる。
override fun getApplicableCallNames(): MutableList<String> = mutableListOf("getOrDefault")
checkCall()
detectorが上記のgetApplicableCallNames()
で定義したメソッドを検知すると呼ばれるメソッド。本当はpackageのチェックとかやらなきゃいけないがとりあえずノーチェックで通す。
override fun checkCall(context: ClassContext?, classNode: ClassNode?, method: MethodNode?, call: MethodInsnNode?) { context?.report(ISSUE, method, call, context.getLocation(call), "Don't use Java 8 dependency API") }
Issue
DetectorクラスのstaticなオブジェクトとしてIssue.create()
メソッドを使って作成する。
適当に各パラメータを設定しよう。Implementation
の第1引数には上記で作成したDetectorのクラスオブジェクトを渡す。
class CustomLintDetector : Detector(), Detector.ClassScanner { companion object { val ISSUE: Issue = Issue.create( "Java8Api", "Java 8 API is used", "Java 8 API is used. This causes crash with Android OS level under 23.", Category.CORRECTNESS, 6, Severity.WARNING, Implementation(CustomLintDetector::class.java, Scope.CLASS_FILE_SCOPE)) }
Custom Lintを実行する
ここまでで作ったプロジェクトをbuildして作成されたjarファイルを.android/lint/
配下に格納し、./gradlew lint
コマンドを叩けばlintが動く。
ここからが本当にわけがわからないのだが、fat jarにしないとうまく動いたり動かなかったりする。(自分で書いていて「そんなことある?」って今思ってます…)
jarファイルを作る環境のJavaのバージョンだったり、gradleのバージョンだったりをいくつか試してみたが、どういう時に動いてどういう時に動かなかったか全然切り分けができなかった。Gradleのcacheを疑ったがこれもダメ。
そう行ったわけでQiitaで書いているAdvent Calendarに載せるわけには行かなかったのでこちらで供養。なんだかモヤモヤしたままだが、とりあえずfat jarにしておけばこんな感じでCustom Lintを作ることはできた。
感想
Custom ListをよりによってKotlinで作ろうとして一番大変だったのは、とにかくドキュメントがないこと。公式もそうだが、全体的に情報が少ない。ヒットしても数年前のものだったりして現状で動かなくなったりして困った。無駄にCustom Listの中のコードを読んでちょっと詳しくなってしまった気がする…
もしもどこかに体系化された素晴らしいドキュメントがあれば教えてください(´;ω;`)
Links
実装にあたりこれらの記事を参考にした。
Help developers with custom Lint rules · Jeremie Martinez
www.slideshare.net
-
Jet Brains 公式ドキュメントでは
kotlin-stdlib-jre7
とkotlin-stdlib-jre8
を使えと書いている。kotlin-stdlib-jre7
だけを指定するとJava 8 に依存した機能を使った時にコンパイルエラー出してくれるかな?と期待したが、残念ながらエラーは出なかった。kotlin-stdlib-jre8
を指定しようと思ったらAndroidではJack and Jill
へ依存を持っているようでgradleのsyncすらできなかった。(Jack and Jill
はdeprecatedになりましたね…)↩ -
むしろデフォルトでチェックがついているJava 8 migration aidsの
Replace with single Map method
でMap.getOrDefault()を使うように推奨してきます😇↩
2017年を振り返る
はじめに
2017年に自分が何をしていたか後から振り返られるようにメモを残しておく。 shirajiさんのエゴサで振り返るというアイディアがとても素敵だったので彼に倣ってtweetをペタペタしていこう。
1月
🌏❤🍻㊗️🌏㊗️🍻❤🌏
— むーむー (@muumuumuumuu) 2017年1月19日
自分が業務でやっているサービスのAndroid Appが初の海外対応をリリースして浮かれていた。この時に割と多言語・他地域対応の知見が溜まったのでよかった。
ここでちょっと業務が落ち着いたので以降はDroidKaigiの準備に追われていたように思う。
2月
android-jpのslack channelにjoinしてみた。知っている顔がちらほらあって安心する。
— むーむー (@muumuumuumuu) 2017年2月3日
今まで怖くて入れなかったandroid-jpのslack channelに入ってみた。最近は #generalより #english の方が活発な不思議なコミュニティだった。
けものフレンズ、twitterでよくわからないけど流行ってるなーくらいの認識だったけど、4話で豹変すると聞いてうっかり手を出してしまった。あれは我々の倫理観を揺さぶるやばいやつだぞ…
— むーむー (@muumuumuumuu) 2017年2月13日
そうか、けもふれは今年の2月か…
皇居ランデビューして10km女子の部で2位になったので副賞にお米貰った。重い。嬉しいけど、重い。
— むーむー (@muumuumuumuu) 2017年2月19日
この頃からランニングを再開していたようだ
3月
DroidKaigi最高に楽しかった!いろんな人から直接セッションのフィードバックもらえたし、本当に貴重な体験でした!来年も出来ればスピーカーで出たい! #droidkaigi
— むーむー (@muumuumuumuu) 2017年3月10日
DroidKaigiにスピーカーとして参加した。最高に楽しかったけど、今年はrejectされたので聞く側で楽しんできます :p この頃はずっとねこ、えさ、ねこ、って言ってたきがする
DroidKaigi2017で登壇した時のvideoが公開されました!🎉🎉🎉🎉
— むーむー (@muumuumuumuu) 2017年8月15日
https://t.co/btQdU1c2Um
- 作者: スティーブ・マクラッチー,花塚恵
- 出版社/メーカー: ダイヤモンド社
- 発売日: 2015/04/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
4月
この頃からPodcastを大量に聴き始める。そういう意味で今年はインプットの方法が大きく変わった。通勤中とかもうほとんど音楽聞かずにPodcastばかり聴いている。最近たまたま見つけた @engineermeeting のpodcastがすごく面白い。ちょっと自分より上の年代の人たちが話しているんだけど気づきが多い気がする。話がぽんぽん飛んでいくのが新鮮で良い🙂
— むーむー (@muumuumuumuu) 2017年4月4日
Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)
- 作者: 有野和真
- 出版社/メーカー: 技術評論社
- 発売日: 2017/02/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
5月
ビッグウェーブに乗って書いた٩( 'ω' )و We ♡ Kotlin!
— むーむー (@muumuumuumuu) 2017年5月18日
RettyとKotlinの歩み〜アプリからサーバサイドまで - rettydev’s blog https://t.co/tYvMQkMadq
KotlinがAndroid公式サポートされた。便乗して会社のTech Blogを書いていた。
引っ越し完了祝いに最高に美味しい赤身肉と最高に美味しいクラフトビールのお店に行ってきた。日曜だからか空いててかなり穴場だったのでマジでおすすめ!最高に美味しいお肉の脂は官能的だってみんなに知って欲しい…!https://t.co/HKIna8jyOI pic.twitter.com/1Vgmr38ub3
— むーむー (@muumuumuumuu) 2017年5月28日
自宅の引越しを行ったのもこの時期。都民デビュー。
6月
五反田最終日。お世話になりました。
— むーむー (@muumuumuumuu) 2017年6月23日
麻布十番オフィス初出勤
— むーむー (@muumuumuumuu) 2017年6月26日
今度は自宅ではなくオフィスも引越した。
とだか貸切最高〜〜〜 pic.twitter.com/HNwU0p0jFV
— むーむー (@muumuumuumuu) 2017年6月14日
引越し直前にオフィス近くの人気店とだかを貸し切って美味しい食事をしていた。
今日は代休。諸々所用が終わって夕方から一部のAndroidエンジニア大人気で気になっていたSHIROBAKOをamazon primeでみている。まだ2話しか見ていないけどこれはPMの話だ…納期とクオリティとプロジェクト進行。
— むーむー (@muumuumuumuu) 2017年6月29日
SHIROBAKOに手を出し始めたのもこの頃。
7月
Swiftに手を出し始めたようだ。Swift入門するはずが築地デート満喫していた
— むーむー (@muumuumuumuu) 2017年7月29日
アラサーにして初めてまともにドラクエをみた。夫がPS4版ドラクエ11をやってるのをところどころチラ見していたけど衝撃のストーリー展開にびっくりしすぎて自分でもやり始めた。セーニャちゃんと結婚したかった…ドラクエやってる夫「魔物が出てきた時点で村長に報告に行くべきだよね。魔物出てきたんですけど先進んじゃって本当に大丈夫ですかーって。」
— むーむー (@muumuumuumuu) 2017年7月29日
8月
Lisp本を読み切った。なんだかんだネタ枠と言いつつ意外とよかった…ネタです。みんなで関数型プログラミングやろうぜ〜〜〜 /
— むーむー (@muumuumuumuu) 2017年8月1日
Kotlin初心者から抜け出したい?それなら、 - 言いたいことはそれだけかhttps://t.co/wrnnWsZvkQ pic.twitter.com/bgpz2856Hn
会社でやっているもくもく会が20回を突破。 もくもく会については最近ポエムも書いた。[リンク修正しました] 第20回 Androidもくもく勉強会@ Rettyオフィス を公開しました! 8/23(水) 開催です。ついに20回突破! #AndroidMokuMokuRettyhttps://t.co/c5QBRMSroM
— むーむー (@muumuumuumuu) 2017年8月8日
Swift入門枠で登壇もやった。今日の発表のスライドあげました。「KotlinエンジニアがSwiftに入門したらちょっと戸惑った話」です。https://t.co/aTaoEVQmsG #swift_kotlin_jp
— むーむー (@muumuumuumuu) 2017年8月9日
Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン
- 作者: Mary Lynn Manns,Linda Rising,川口恭伸,木村卓央,高江洲睦,高橋一貴,中込大祐,安井力,山口鉄平,角征典
- 出版社/メーカー: 丸善出版
- 発売日: 2014/01/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (16件) を見る
9月
今からこの話します! https://t.co/5Q5d7DALRK #Retty_tech_cafe
— むーむー (@muumuumuumuu) 2017年9月1日
KotlinとReduxの話を自社イベントでしてきた。
Android エンジニアTシャツ、この日以降まだ出番はない。
Androidエンジニアです!!!! #Retty_tech_cafe pic.twitter.com/9aGhz0FW65
— むーむー (@muumuumuumuu) 2017年9月1日
着替えるの面倒だったのでAndroidエンジニアTシャツ着たまま電車乗って帰宅したけれど、誰からも何も言われないし特に視線も感じなかったのは華金だからなのか
— むーむー (@muumuumuumuu) 2017年9月1日
10月
この頃からTwitterをはじめ色々なwebサービスで設定しているアイコンを自分の顔写真にした。ちょっと前にアイコン変えたけど、私だって認識されてない気がしてきた。
— むーむー (@muumuumuumuu) 2017年10月23日
11月
DroidKaigi不採択だった〜〜〜😇😇😇😇
— むーむー (@muumuumuumuu) 2017年11月6日
DroidKaigi 2018のCfPが不採択でショックを受けるなか、その日は外部の勉強会でKotlinとサービスについて話してきた。今からこの話します! https://t.co/oG2Fs5uxdp #yjbonfire
— むーむー (@muumuumuumuu) 2017年11月6日
ハーフマラソンを走った。20km以上走るのは7年前のフルマラソン以来だったので不安だったが無事完走。ハーフ完走したぞ!イェーイ!!🎉🎉
— むーむー (@muumuumuumuu) 2017年11月12日
ずっとファンだったPodcastにゲストとして呼んでもらった。感動した。念願の @dexfmpodcast デビュー🎉 @shiraj_i さんのエピソード期待してた人達ごめんなさい 🙏 (実はその前に収録してました) https://t.co/ueKFSeUt5d
— むーむー (@muumuumuumuu) 2017年11月27日
12月
社内のエンジニア向けに「Androidではじめの方に知っておきたかったこと講習会」みたいなことをやり始めた。これは機会があれば資料を綺麗に作り直してどこかに出したい。今日社内でAndroid興味あるエンジニア向けに簡単なAndroid講習会やったんだけど、ActivityとContextとIntent周りを軽く話したら「Androidつらそう…」と言われてしまったので次回は楽しい話をしよう。
— むーむー (@muumuumuumuu) 2017年12月19日
仲間内でクローズドなPodcastごっこを始めた。最近仲間内のエンジニアでPodcastごっこをしているのだけど、private sharingできるaudio serviceないのかなー。Show note とかも合わせて表示できる感じの。
— むーむー (@muumuumuumuu) 2017年12月25日
来年
DroidKaigi 2018のセッションの解説をする。プレミアムフライデーって本当に実在するのか…。解説陣がgfxさんshirajiさんと(私はともかく)豪華なので楽しいと思うのでぜひご参加ください。 connpass.com私はDroidKaigiリジェクトされた勢ですがセッションの解説にお招きいただいたので、リジェクトされた人もそもそもCfP出してない人もお気軽にどうぞ♥ https://t.co/pMFVcVU2V2
— むーむー (@muumuumuumuu) 2017年12月5日
おまけ
夫が可愛いシリーズ
夫「K(かっこいい)P(パパ)T(強い)」
— むーむー (@muumuumuumuu) 2017年1月24日
夫「Android Oって何になるの?…おかし?」
— むーむー (@muumuumuumuu) 2017年3月21日
かわいい
夫の夕飯リクエストがピカタだったので準備してたら、本当に食べたかったのはミラノ風カツレツだということがお肉を焼いている段階で判明してしまった。なぜピカタというワードが夫の口から出てきたかは不明。それでも美味しいって言って食べてくれるから天使なのかもしれない😇
— むーむー (@muumuumuumuu) 2017年4月1日
ランニングから帰ってきたら旦那さんが「今日は6km?」という感じで距離を当ててくるようになった。これがかなりの精度で当たる。走ってきた時間とか私の疲れ具合とか気温とか天気とかの変数で予測するらしい。好きな人じゃなかったら怖いぞってレベルで当たる。
— むーむー (@muumuumuumuu) 2017年4月16日
今日は天気もいいし風も気持ちいいので、窓を開けてビールを飲みながら旦那さんと家庭内もくもく会してる。ビールはGRAND KIRIN DIP HOP WEIZEN BOCK! 🍺
— むーむー (@muumuumuumuu) 2017年4月16日
ハーフマラソン申し込んだ!完走賞でチョコレート貰える話を夫にしたら「そんなに頑張らなくてもチョコレートは手に入るんだよ?」と圧倒的正論を頂きました😇😇😇 https://t.co/U3DJ5gj5mN
— むーむー (@muumuumuumuu) 2017年9月2日
これは惚気なんですけど、今朝出社途中に深夜作業から帰宅する夫とばったり出会って、「好きな人と道端で偶然出会う」というシチュエーションをめちゃめちゃ久しぶりに体験してテンション上がった✌️
— むーむー (@muumuumuumuu) 2017年9月15日
KotlinJSでReact Nativeを書いてみたかった話
はじめに
この記事は「KotlinJSでReact Nativeを書いてみたかった話」です。つまりできなかった話 であることをあらかじめご了承ください。
では本題。
年末になり会社のAdvent Calendarのネタ探しをしている最中に電波が降りて来た。
KotlinでReact Nativeっていけるのかな。Kotlin 1.1 からJavaScriptサポートしてるからいける気もする。可能ならiOS Appも部分的にKotlinで開発できるのでは?
— むーむー (@muumuumuumuu) 2017年10月25日
当時Kotlinが好きすぎてちょっとおかしくなっていたのか、「SwiftではなくKotlinでiOSかけたら最高では?😇 」「でもKotlin/Native で書くのはちょっとまだ早すぎるよな〜〜😓」「あれ?KotlinJSでReactNativeいける!?!?」
ネタとしてもちょっとおもしろいかなと思いやってみることに。
ちなみにKotlin/Nativeまだ実務ではつらいよねって話は同僚がまとめてくれた記事が良いので興味ある人はぜひ読んでほしい。せめて補完が効くようになったら起こしてください( ˘ω˘ ) スヤァ…
React NativeとKotlinについて
React NativeはJavascriptで記述する。その名の通りReactベースなのだが、コンポーネント部分をそれぞれのプラットフォームのブリッジでごにょごにょしてくれるのでnativeとして動く。つまり、AndroidであればJavaに1、iOSであればSwiftのコードになる。2
一方Kotlinは1.1よりJavascriptへのコンパイルをサポートした。どういうことかというと、Kotlinで書いたコードがJavascriptにconvertされるということ。
これらを組み合わせて、
- React NativeでJavascript部分をまずはKotlinで書いて、
- それをJavascriptに変換し、
- さらにブリッジを経由してJavascriptが対応するSwiftもしくはJavaのコードとして動作
これにより実質KotlinでReactNativeでは?というのがやりたいことになる。
やってみた
まずはReact Nativeのプロジェクトを用意する
このへんをみて適当にプロジェクトを作る。まずはデフォルトで生成されるJavascriptがちゃんとアプリで表示されることを確認。デフォルトの画面が表示されえたのでOK。
JSのコードをKotlinに置き換えたかった
Kotlin JS がサポートしているビルド方法は下記4種類。
- Getting Started with Gradle
- Getting Started with IntelliJ IDEA
- Getting Started with Maven
- Getting Started with the Command Line
それぞれCompile後にjsファイルが吐き出される。
React NativeはReactで動いているので、まずはReactをimportする。 Kotlinを開発しているJetBrains社がWrapperを用意してくれているのでこいつをinstallする。
npm i @jetbrains/kotlin-react
次にReactNativeのコンポーネント部分をimportしよう、と思ったところでそんなものは世の中に存在しないことに気がついてしまった。
Kotlin JS でReact Nativeのcomponentが使えないことに気がついてしまった😇 Bridge使うのもやりたいことと違うんだよな… #AndroidMokuMokuRetty
— むーむー (@muumuumuumuu) 2017年11月30日
自分で書くにはJS力足りないし、何よりもはやAdvent Calendarのネタとしては重すぎるよな〜〜というわけでお蔵入りになりました :p
というわけでボツネタ供養でした :pray: