パルカワ2

最近はFlutterをやっています

Picassoはnullを渡すとplaceholderが表示される

こんな感じでnullを渡すとerrorではなくplaceholderが表示される。

String url = null;
Picasso.with(getContext())
        .load(url)
        .placeholder(R.color.placeholer)
        .error(R.drawable.no_image)
        .into(imageView);

最近Glideへの乗り換えをやっているのでGlideではどうなっているのかというと nullの場合は、 fallback -> error -> placeholder と順に見てあるものを表示してくれるらしい。
なので以下はerrorが表示される

String url = null;
GlideApp.with(getContext())
        .load(url)
        .placeholder(R.color.placeholer)
        .error(R.drawable.no_image)
        .into(imageView);

29歳になった

28歳は、チーフテクニカルリードとしてチームをどう機能させるか?などを色々考えたり、技術的挑戦をやっていくぞ!と言ったりみんなと色々やってきた。28歳になった時は、稟議をはじめて出したりしてたようだ。稟議はまだ慣れていないけど、とりあえず出来るようにはなった。

ここ数年ずっと言っている変化に強い力は、いろいろやってきた結果それなりに身についたと思っているので、次はそれをどう活かすかが重要になってくると感じている。

2018年にあえて、手紙を送り合うのはどうか

年末に突如「お気持ち表明し合いたいな」と思ったので、それを促すお手紙botを作りました。ruboty-otegami みたいに切り出そうと思ったけど、飽きてきたので公開します。

github.com

ruboty-cronと併用するといいんじゃないでしょうか。

  • 月初めに Slack上にてbotが「この人にお手紙をください」と言ってくる
  • botにDMでお手紙を書く
  • 月末に一斉にお手紙が公開され、Slack上でbotによる報告がなされる

こういう感じでGithub(またはGHE)に公開されます。 f:id:hisaichi5518:20180107180245p:plain

なんで指名されるの?

知らない人を知るきっかけを作るためです。

minneは、働く人が多くなってきていて、仕事で関わらない人も多くなってきていますが、その一方でペパボの大切にしてほしいことには「みんなと仲良くする」があり、この仲良くするを実現するためにはまずは知ることから始めるのが重要だと考えています。

しかし、まずは知ると言ってもきっかけがないとなかなか難しく、なんのきっかけがないのに何も知らない人に「ご飯行きましょう!」と声をかけるのはなんだか恥ずかしい。なので、「お手紙botで指名されたのでご飯行きましょう!」のようにきっかけとして利用出来るといいなと思います。

なんで公開されるの?

人が褒めらているのを見るとなんだかこっちも嬉しくなると思っていて、さらには普段人をそんなに褒めないような人が誰かを褒めてるのとか自然とニコニコしちゃうじゃないですか。だから、内容はもちろん書いた人も書かれた人も全部公開します。

また全部公開して全部残すので、全く知らない人のことも誰かが書いたお手紙を読むことで少し知ることができますね。

ひさいちからのお手紙

お手紙botは、普段のやり取りや絵文字だけでは伝わらないお気持ちを表明(言語化/アウトプット)する必要があります。これはペパボがアウトプットを大切にしているからだけではなく、あえて手軽さのない言葉で気持ちを伝えるからこそ伝わる何かに価値があると考えるからです。

このbotが実現するのは、あくまできっかけづくりです。実際に仲良くするのはbotではなく人であるけど、このbotが作るきっかけでよりみんなと仲良くできるんじゃないかとワクワクしますね。ちなみに、このbotは一切運用されていません。

元ネタ:スマイル給公開 | 面白法人カヤック

Android の DataBinding の構文内でContextにアクセスしたい

忘れそうなので書いておく。

ContextをXML内で利用したい

@{context.getString(errorRes)}

こういう感じでcontextを渡してあげるとよい。contextは、variableで定義する必要もないし、setContext()する必要もない。よしなにセットされる。
上の例の実際の呼び出しはこういう感じになる。

getRoot().getContext().getString(errorRes);

Using resource IDs in data binding layouts

その他

EpoxyとDataBindingをやろうとしたらTypeCastExceptionが起きた

エラー: Epoxy Processor Exception:  Caused by TypeCastException: null cannot be cast to non-null type javax.lang.model.element.TypeElement

Stacktrace:
com.airbnb.epoxy.DataBindingModelInfo.<init>(DataBindingModelInfo.kt:25)
com.airbnb.epoxy.DataBindingModelInfo.<init>(DataBindingModelInfo.kt:14)
com.airbnb.epoxy.DataBindingProcessor.process(DataBindingProcessor.kt:33)
com.airbnb.epoxy.EpoxyProcessor.processRound(EpoxyProcessor.java:189)
com.airbnb.epoxy.EpoxyProcessor.process(EpoxyProcessor.java:165)

こういうエラーが出る。このあたりでエラーになってる。

https://github.com/airbnb/epoxy/blob/a9aee295ac7299af849e8d30b598d348d8ed5fc5/epoxy-processor/src/main/java/com/airbnb/epoxy/DataBindingModelInfo.kt#L25

EPOXY_DATA_BINDING_MODELを見るとDataBindingEpoxyModelというクラスのTypeElementを取ろうとしてるメソッドがnullを返してるらしい。

https://github.com/airbnb/epoxy/blob/12e27f98cc4e93f7b18a17b6fdb527ec1f6b4179/epoxy-processor/src/main/java/com/airbnb/epoxy/ClassNames.java#L38-L38

DataBindingEpoxyModelはどこにあるのか調べたら、epoxy-databinding以下にある。アレ!実はepoxyを指定するだけではダメなのでは?!と思って調べたらそうだった。

Data Binding Support · airbnb/epoxy Wiki · GitHub

    def epoxy_version = "2.7.3"
    compile "com.airbnb.android:epoxy:${epoxy_version}"
    compile "com.airbnb.android:epoxy-databinding:${epoxy_version}"
    annotationProcessor "com.airbnb.android:epoxy-processor:${epoxy_version}"

これで動いた。

RecyclerViewで複雑な画面を作るためのライブラリ Epoxy

この記事は、 Android Advent Calendar 2017 - Qiita 11日目の記事です。


RecyclerViewで複雑な画面を作りたい!そんな欲求を持っている人が多いと思います。僕もそうです。でも、1個や2個のViewTypeならまだしもたくさんのViewTypeがある場合、getItemViewTypeとかで頑張った結果つらいコードになる未来が見えます。というか見てきました。

Epoxy というアプローチ

Airbnbが作ったRecyclerViewで複雑な画面を作るためのライブラリです。

github.com

ModelをCustomViewやDataBinding等から自動生成し、それらを操作するControllerを書き、そのControllerをEpoxyRecyclerViewというクラスにセットする感じです。

具体的に出来ることは、READMEに書かれてある通りなのですが、こういう事が出来ます。

This abstracts the boilerplate of view holders, diffing items and binding payload changes, item types, item ids, span counts, and more, in order to simplify building screens with multiple view types. Additionally, Epoxy adds support for saving view state and automatic diffing of item changes.

ワオ!便利!

使ってみる

サンプルアプリがあったので、それのコードを読んでいきたいと思います。

epoxy/epoxy-sample at master · airbnb/epoxy · GitHub

こういう動きをするアプリです。

f:id:hisaichi5518:20171211183913g:plain

これら全ての動作を全部追いかけると大変なので、今回は、DataBindingを利用しているAdd, Clearなどのボタンにフォーカスを当てたいと思います。 このような動きをする部分です。

f:id:hisaichi5518:20171211184004g:plain

Modelを作る

今回のサンプルアプリでDataBindingは、 button.xml で利用されています。このbutton.xmlは、リスト上にあるAdd, Clearなどを行うボタンを指しています。

epoxy/button.xml at d2e298902e64a5b634e9932ee2f16f56abfa52bd · airbnb/epoxy · GitHub

DataBindingを利用してるViewのModelを自動生成する場合は、package-info.java@EpoxyDataBindingLayoutsを利用して、Modelを自動生成することを宣言する必要があります。

epoxy/package-info.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub

@EpoxyDataBindingLayouts(R.layout.button)
@PackageModelViewConfig(rClass = R.class)
package com.airbnb.epoxy.sample;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;
import com.airbnb.epoxy.PackageModelViewConfig;

これで、Modelの生成が行われ、ButtonBindingModel_ という名前のクラスが生成されます。

Controller を作る

ButtonBindingModel_SampleControllerというクラスで利用されています。コードを見ると案外シンプルです。

epoxy/SampleController.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub

今回のコードを読むにあたって、僕が重要だなと感じたのは、protected void buildModels(List<CarouselData> carousels)です。

epoxy/SampleController.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub

buildModels(List carousels)

このメソッドは、リストのデータが更新されるたびに実行されます。

buildModelsの中では、このようなコードがあり、何を表示するのか?やそのViewを表示するのか?などの操作が行われていることがわかります。

    // 表示文言の指定
    // Clickしたら、onAddCarouselClicked callbackを実行する
    addButton
        .textRes(R.string.button_add)
        .clickListener((model, parentView, clickedView, position) -> {
          callbacks.onAddCarouselClicked();
        });

    clearButton
        .textRes(R.string.button_clear)
        .clickListener(v -> callbacks.onClearCarouselsClicked())
        .addIf(carousels.size() > 0, this); // データの条件があえばViewを表示する

SampleControllerをEpoxyRecyclerViewにセットする

作成したControllerは、EpoxyRecyclerViewにセットしています。

ここは、RecyclerViewにセットも出来るようですが、EpoxyRecyclerViewを使うことで、シンプルになり更にパフォーマンスのアレコレもやってくれるそうです。

EpoxyRecyclerView · airbnb/epoxy Wiki · GitHub

    recyclerView.setController(controller);

セットしているのはこの部分

epoxy/MainActivity.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub

あとはデータの更新を行いたい時にcontroller.setData(...)を呼び出すだけです。

  private void updateController() {
    controller.setData(carousels);
  }

所感

コード読んだ部分が簡単過ぎた。

データの更新が行われるたびにループがデータ分実行されるのが気になりました。データが大きくなるとつらそう。 RecyclerViewのAdapterにあるnotifyItemInsertedのようにどこが変わったのか通知する形の方が早そうな印象は受けましたが、実際どうなのかは調べてないです。

その他のアプローチ

Githubを検索すると色々あるんですが、どれがいいのかというのは正直よくわかりませんでした。それらと比較して自分がメンテナンスするアプリへの導入を検討するといいと思います。

まとめ

RecyclerViewを利用して複雑な画面を作るためのライブラリであるEpoxyのサンプルアプリのコードを読んでみました。

複雑な画面はなるべく作りたくないですが、Epoxyには様々な機能があり、複雑な画面を作るのにとても有効だと感じました。次は、実際に開発しているアプリで試してみようと思います。

参考

デスクライト買った

コード書いてる時とか集中してるときは暗い方が集中出来るので、部屋では灯りをつけずに暗くしてる。けど、そのまま夜になったりすると真っ暗の中にモニタの明かりが自分を照らしていて、ツイッターとか見てニヤニヤしてると漫画とかに出てくる引きこもり感がすごいので部屋の電気を付けに歩いていた。だるすぎる。なので机用の灯りでも買うかという感じで買った。

光をこっちに向けると眩しいし目が潰れるので壁のほうに向けてる。想像よりでかかったけど、安いしちょうどいい感じの明るさで便利。


奥に展示されてるのはNature Remoなので、部屋の電気もNature Remoでやれよって話なんだけど、リモコンを捨てたので出来ない。
勧められたシーリングライトあるけどまだ買ってません