パルカワ2

最近はFlutterをやっています

最近単行本で読み始めた漫画

君に触れるなら、死んでもいいよ。これがわたしの愛なんだ。アフタヌーン公式サイト「モアイ」掲載の1話が300000PV突破!話題の「青野くん」がついに単行本化!天然少女・優里ちゃんと、その彼氏・青野くん。ごく普通のお付き合いをしていたふたりだが、ある日突然、青野くんが「いなくなって」しまう……。絶対に結ばれないし、触れ合えないふたりの、でたらめで切実すぎるラブ・ストーリー

ツイッターで見かけたから買った。
イチャイチャ漫画はあんま読まないけど違うっぽかったので買ってみたら面白かった。

クリスマスを一人むなしくコンビニバイトに費やした日野三春は、その夜、黒いサンタ服の男に遭遇する。「悪い子の所には、黒いサンタがやって来る」そう語る男に「悪い子」だと告げられた三春は、突如、サンタの袋に“捕食"され…!?
気づけばそこは、世にも奇妙なサンタの会社!! 悪い子は、サンタのために強制就労!? 手厚い待遇で可愛い同僚もいるけれど、この仕事夢か悪夢か!!?

マンガボックスで読んだら面白かったので買った。

『不死身の杉元』日露戦争での鬼神の如き武功から、そう謳われた兵士は、ある目的の為に大金を欲し、かつてゴールドラッシュに沸いた北海道へ足を踏み入れる。そこにはアイヌが隠した莫大な埋蔵金への手掛かりが!? 立ち塞がる圧倒的な大自然と凶悪な死刑囚。そして、アイヌの少女、エゾ狼との出逢い。『黄金を巡る生存競争』開幕ッ!!!!

ジャンププラスで読んだら面白かったので買った。
リスの脳みそとかご飯食べるシーンが面白い。

見た目ヤンキー、ハートはシャイ、手先は器用で女子力高め。そんな手作り大好き男子の中村くんが、クールな黒髪優等生少女・林さんに恋をした!? 溢れる想いをお菓子作りやぬいぐるみ制作にぶつける中村くんの、ギャップがキュートな恋(未満)物語!

ツイッターで見かけたから買ってみた

人が異形の獣と化す病、害獣病が蔓延する世界。性格に難ありな害獣駆除兵のアキミア・ツキヒコは害獣を追って入った森の中で衛生兵の美女、ホシ・ソウと出会う。行方不明の弟を捜しているというソウに対し、アキミアは驚くべき提案をもちかける。その提案とは――『弟を助けてほしければ私と結婚して下さい』という、あまりにも不条理なモノだった。人と獣の魂の慟哭を描く異色ダークファンタジー、開幕。

ツイッターで見かけたから買ってみた

所感

ツイッターで見かけるかアプリで見かけるかして面白いな(面白そうだな)と思うと買ってる。

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

参考