読者です 読者をやめる 読者になる 読者になる

今更遅れてDataBinding事始め(3.5)

android data_binding RecyclerView

後で加筆予定


前回のお話


エントリ内容のキッカケ

一応双方向の話とかはローカルで試しているんですが、イマイチしっくり来ないので

それ以前の使い勝手的なところに関してメモしておこうかと

AS 2.2.2 にして困っていること

  • data-binding用のlayoutにすると高確率でlayout editorのプレビューでエラーが出る
    • 酷いときにはrendering timeout というExceptionが発生*1

何がマズイのか

通常状態の最近の layoutプレビュー

  • AS 2.2 あたりからapplicationのデフォルトthemeの記述をみなくなった*2

  • app/AndroidManifest.xml

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" /> //★ココ

で、テンプレートのレイアウトが作成される時

  • app/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:content=".MainActivity" />//★ココ

</android.support.v4.widget.DrawerLayout>

の tools:content を指定しないと、themeを探してくれなくなったわけで

一時期 target-sdk を下げればという話もあったけど

  • target-21とかにして v21とかフォルダを掘って、マッチングする style.xmlを設置すれば、出る?
  • values/style.xml のままだと探してくれない?

状況のようで、使いづらくなったな~というのが感想。

data-bindingでの layoutプレビュー

で、上記の app/activity_main.xml を下記のように修正すると、プレビューが失敗しやすくなる

これってbinding情報を除いた変換済みのxmlを参照しているわけじゃないからだろうなーというのが推察される動作。

現在のレイアウトを解析してプレビュー作ろうとして失敗してるんじゃないだろうか?

  • かなりNGなパターン
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    
<android.support.v4.widget.DrawerLayout 
    tools:content=".MainActivity" />//★ココ
    
</android.support.v4.widget.DrawerLayout>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout>
    
<android.support.v4.widget.DrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:content=".MainActivity" />//★ココ
    
</android.support.v4.widget.DrawerLayout>

</layout>

これ今後に期待系なのでしょうかね。。

ちなみにfragmentに関しても

AS 2.2.2でレイアウトプレビュー時のlintチェックが厳しくなったようで、theme参照エラーが出るわけですが

StackOverFlowに載ってる tools:content指定だと解決しないんですよね・・*3

<fragment
        android:id="@+id/map"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:content=".MainActivity" />//★ココ

tools:layoutを指定しろ

って奴らしいんですけど、そんなのカスタムFragmentでない限り解らんわ~

と言いたい。

他者ライブラリとか入れた場合はどうなの?

カスタムattitudeがあるサードパーティーUI libraryで

attitude参照エラーが出まくりでポイズン。

aar形式で同梱されてるはずなんですけどね~(^^;) 正直訳わからない。

yahooの人が、極力標準library使うのが安心

とかいう話聞くのよくわかるわ~

tools属性の利用について

qiita.com

らへんの話の他に

data-bindingを使うと

  • android:text 辺りの箇所が全部潰れるわけです。

これだと AS 2.2 新機能とか言われている layout画面保存機能とか意味なくない?

の状態なので、下記のattribute が追加されています

  • Designtime Layout Attributes
    • android:XXX の一部の属性を tools:XXX で置き換える
      • 勿論 app:XXX は駄目なので Toolbarの app:titile とかには使えない
    • 現状だと下記数個くらい?
    • ListViewとかSpinner の初期値とかは表示できない

というのが追加されている状態です

         <TextView 
            android:text="Name:"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <EditText 
            tools:text="John Doe"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <ImageView 
            tools:src="@drawable/bird"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

      <ImageView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:visibility="gone"
          tools:visibility="visible"/>

<android.support.v7.widget.RecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    app:layoutManager="LinearLayoutManager"
    tools:listitem="@layout/fragment_book_list_item"
    />

<!--G様が用意しているlistitem定義-->
    tools:listitem="@android:layout/simple_list_item_2"

    tools:listheader
    tools:listfooter.
は RecyclerView には元々対応プロパティが存在しないので意味がない
(ListViewには存在するが・・)

まあ気休め程度なのかな・・。

  • あんまり意味があると思えない属性
<!-- includeタグで呼ばれるレイアウトの方で、親レイアウトを指定 -->
tools:showIn="@layout/activity_main"   

tools:layout_height="match_parent"
tools:targetApi="M"
tools:locale="es"

tools:background  ・・背景変更だけど、これあんまり使わない気がする・・

因みに、勿論Data-bindingを書いているレイアウトだと

tools:XXXを書き換える度にビルドが走るわけで

瞬間的にカクカクしますね・・*4

appcompatとかsupport-library系の表示チェックが

未だに実機で動かさないとわからないのは正直死んでると思うんですけどね。。(汗


data-bindingのクラス名の変更について

これ現在動きません。コマンドラインでは動くようなのですが

補完関係が全滅・・ たぶんlayoutのファイル名でindex作っちゃってるからだろうな。。という感じ

パーサーとかのチェックではなく、高速化のためにテキストベースでチェックなんだろうな・・というのが感想

<data class="MainActivityViewHolder">
    ...
</data>

因みに前動いていたらしい、下記の記述はコマンドラインでもだめ・・・

<data class="MainActivityViewHolder"/>

bindする式記述に関して

触ってみたところ、下記の記述あたりはNGでした

  • @{ }あたりをシングルクオーテーションで囲む *5
    • “◎◎” を抽出条件にしている?感じかな
  • 二項演算子を更に重ねるような式を書く
    • 複雑な式の展開は難しいよう。

NGなパターン

<TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text='@{String.format("%.1f", user.money)}'/>

OKなパターン(AS.2.2.2ではNGになった)

<TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{String.format('%.1f', user.money)}"/>

まあ

  • activity_main.xml
<TextView
    android:id="@+id/text_view2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{person.getName() + ` (` + person.getAge() + `)`}"/>

と記載すると

  • ActivityMainBinding.java
String name = person.getName();
int age = person.getAge();

textView2.setText(name + " (" + age + ")");

と展開される仕様のようなのでそういう物なんでしょうね。。*6

AS2.2.2で完全OKなパターン

上記の設定ですが、現在は動かないようです。AS 2.2.1 までは動いていたようなのですが。。

  • [`]が変換式の中に入っていると、一律変換前 lintチェックでエラー

対処法として下記が現在は正解のようです。

  • string.xml にフォーマット書式を定義して参照する

  • string.xml

<string name="money_str">%.1f</string>
<string name="age_str">%s(%s)</string>
    android:text="@{ @string/money_str(user.money) }"/>


    android:text="@{ @string/age_str(person.getName(),person.getAge()) }"/>

公式のサイトだと、どれでも書ける風な記述が有るのですが・・・(汗


関数のbindingに関して

  • app/activity_main.xml
<TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:onClick="@{activity.onClick}"/>

って書き方が例題によく載ってますが、これって

<TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:onClick="onClick"/>

な書き方が元からできますし、Cmd+Bで呼べるのは下の方なんで

この書き方できて何が嬉しいの? というお話になるわけですけど。

まあ onClickの実装コードを見たことが有りますが、

  • Contextの参照をActivityの時のみマッピングする
    • 参照Contextを instance of Activity でわざわざ判定している
    • その為、FragmentのGUI部品のところで onClickListenrを実装せよ みたいな糞実装がまかり通る。。
  • したがってFragmentで android:onClick を実行できない
    • 何のためのFragmentか!*7
    • ActivityをFatにしないためのやつじゃないの?

で、data-bindingでFragment上の関数を呼べるかどうか? で試してみました

結論としては

  • activityの参照は一律OK
  • fragmentの参照ができるものとできないものが有る
    • 参照不可=>生成エラーにして弾いているような挙動?
    • variable でFragmentは指定できません的なエラーが出る
  <data>
        <variable name="activity" type="hoge.fuga.mainActivity"/>
        <variable name="fragment" type="hoge.fuga.hogeFragment"/>
  </data>



<TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:onClick="@{fragment.onHogeClick}"/>
  • OKなパターン

    • DataBindingUtil.setContentView;
      • activityでの例で書かれているやつ
    • XXXBinding.bind(view);
      • fragmentでの例で書かれているやつ
  • NGなパターン

    • DataBindingUtil.inflate
    • DataBindingUtil.getBinding
      • adapterとかカスタムViewとか

*1:出るまでの間CPUが、limit付けない状態だと400%とか振り切る

*2:自分は正直これデグレだと思ってる

*3:昔はこちらで解決していたらしいのですが。。

*4:早くちゃんと変更したファイルだけビルドしてくれるようにならないのかな〜

*5:昔は動いていたらしく、未だにココらへんの記述津がググって引っかかるので混乱しやすい。。

*6:内部の置換ロジック的にNG

*7:これ調べたら、UI無しのFragmentが定義できるから、android:onClick をあえて必須にしなかったらしい