RecyclerViewでのAndroidデータバインディング





Google IO 2015で、彼らは新しいデータバインディングライブラリを発表しました。 その主なタスクは、モデルとビューの相互作用をxmlファイルに取り込むことです。 これにより、コードの記述が大幅に簡素化され、findByViewId()メソッドを使用したり、アクティビティ/フラグメント内のビュー要素へのリンクを追加したりする必要がなくなります。 また、カスタム属性を静的メソッドにバインドすることにより、カスタム属性を使用できます。 データバインディングに関する記事だけで既に十分ですが、RecycleViewでの使用とは関係ないため、このギャップを埋めます。



カスタマイズ


まず、プロジェクトのルートディレクトリにあるbuild.gradleファイルに移動します。 ブロックの依存関係で設定したもの:



buildscript { repositories { jcenter() } dependencies { classpath "com.android.tools.build:gradle:1.3.0" classpath "com.android.databinding:dataBinder:1.0-rc1" } } allprojects { repositories { jcenter() } }
      
      







次に、データバインディングプラグインをプロジェクトに接続します。 これを行うには、build.gradleにプラグインを含む行を追加します。 compileSdkVersionが23であることも確認してください。



 apply plugin: 'com.android.application' apply plugin: 'com.android.databinding'
      
      







バインディング


xmlファイルの作成に移りましょう。 通常、res / layoytパッケージで作成されます。 ルートタグとしてレイアウトを使用します。 Android Studioは、赤で強調表示したり、幅と高さの設定を提案することがありますが、無視します。



 <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> </data> <!--    layout --> </layout>
      
      







モデルをビューにバインドするバインダークラスを作成するには、xmlをモデルにバインドする必要があります。 これを行うには、タグ内でモデルの名前とパスを指定します。 例として映画のリストが表示されます。



 public class Movie { public boolean isWatched; public String image; public String description; public String title; public Movie(boolean isWatched, String image, String description, String title) { this.isWatched = isWatched; this.image = image; this.description = description; this.title = title; } }
      
      







 <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="movie" type="com.example.databinding.Movie" /> </data> <!--    layout --> </layout>
      
      







レイアウトを追加してモデルをそれにバインドすることは残ります。 各映画に写真、タイトル、短い説明を付けましょう。 フィールドがモデルから読み取られることを示すには、「@ {*モデルから使用するフィールド*}」を使用します。



 <?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"> <data> <variable name="movie" type="com.example.databinding.Movie" /> </data> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="8dp"> <RelativeLayout android:id="@+id/relativeLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imageView" ... app:imageUrl="@{movie.image}"/> <TextView android:id="@+id/textView" ... android:text="@{movie.title}" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/textView2" ... android:text="@{movie.description}" android:textAppearance="?android:attr/textAppearanceSmall" /> </RelativeLayout> </android.support.v7.widget.CardView> </layout>
      
      







android:text = "@ {movie.title}" and android:text = "@ {movie.description}"を使用すると、すべてが明確になります-対応するフィールドのみがテキストとして表示されますが、app:imageUrl = "@ {movie .image} "? これが、データバインディングの本当の魔法の始まりです。 任意の数のカスタム属性を追加でき、atts.xmlに書き込むことさえできません。@ BindingAdapter()アノテーションは、それらの処理に役立ちます。 以下は、そのような注釈を処理する方法を示します。



アダプターに移りましょう。 簡単なRecyclerView.Adapterを作成しましょう。 ViewHolderから始めましょう。 彼が以前どのように見えたか:



 public static class MovieItemViewHolder extends RecyclerView.ViewHolder { private TextView title, description; private ImageView image; public ViewHolder(View v) { super(v); title = (TextView) v.findViewById(R.id.textView); description = (TextView) v.findViewById(R.id.textView2); image = (ImageView) v.findViewById(R.id.imageView); } }
      
      







バターナイフの後の彼の様子:



 public static class MovieItemViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.textView) TextView title; @Bind(R.id.textView2) TextView description; @Bind(R.id.imageView) ImageView image; public ViewHolder(View v) { super(v); ButterKnife.bind(v); } }
      
      







DataBinding後の外観:



 public class MovieItemViewHolder extends RecyclerView.ViewHolder { MovieItemBinding binding; public MovieItemViewHolder(View v) { super(v); binding = DataBindingUtil.bind(v); } }
      
      







次に、2つの主要なアダプタメソッドonCreateViewHolderとonBindViewHolderに注目します。 MovieItemBindingは、作成とバインドを行います。 上で書いたxmlという名前で生成されます。 この場合、xmlファイルはmovie_item.xmlと呼ばれていました。



 @Override public MovieItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); MovieItemBinding binding = MovieItemBinding.inflate(inflater, parent, false); return new MovieItemViewHolder(binding.getRoot()); }
      
      







それでは、前のようにonBindViewHolderに進みましょう。



 @Override public void onBindViewHolder(MovieItemViewHolder holder, int position) { Movie movie = Movie.ITEMS[position]; holder.title.setText(movie.title); holder.description.setText(movie.description); Picasso.with(holder.image.getContext()).load(movie.image).into(holder.image); }
      
      







今の様子:



 @Override public void onBindViewHolder(MovieItemViewHolder holder, int position) { Movie movie = Movie.ITEMS[position]; holder.binding.setMovie(movie); }
      
      







しかし、それだけではありません。カスタムアプリはどうですか:imageUrl = "@ {movie.image}"?..繰り返しますが、すべてがシンプルです。アダプター内で、アノテーション@BindingAdapterを使用して静的メソッドを作成します。 アノテーション内で、属性を渡します。 結果として、



 @BindingAdapter("bind:imageUrl") public static void loadImage(ImageView imageView, String v) { Picasso.with(imageView.getContext()).load(v).into(imageView); }
      
      







imageViewは入力を入力し、モデルを画像として渡します。 これですべてが機能します。



残りのユーティリティ


MovieモデルにはisWatched変数がありました。 見た映画と新しい映画に異なるクリックハンドラを持たせたいとします。 DataBindingを使用すると、これが今までになく簡単になりました。 ムービーのクリックハンドラを作成します。



 public interface MovieClickHandler{ void onNewClick(View view); void onWatchedClick(View view); }
      
      







データタグのxmlファイルに追加します。



 ... <data> ... <variable name="click" type="com.example.databinding.MovieClickHandler" /> </data> ... <ImageView ... android:onClick="@{movie.isWatched ? click.onWatchedClick : click.onNewClick}"/> ...
      
      







これで、onBindViewHolderアダプターメソッドで、ライサーにデータを入力できます。 バインダーの場合と同様に、メソッド名はxmlファイル内の対応する変数名によって生成されます。



 public void onBindViewHolder(MovieItemViewHolder holder, int position) { Movie movie = Movie.ITEMS[position]; holder.binding.setMovie(movie); holder.binding.setClick(new MovieClickHandler() { @Override public void onWatchedClick(View view) { } @Override public void onOldClick(View view) { } }); }
      
      







見た映画の写真を白黒でロードしてみましょう。 画像を変換するには、新しい属性を追加します。



 <ImageView ... app:filter='@{movie.isWatched ? "grey" : null}' .../>
      
      







アダプターで、@ BindingAdapterを介して処理を実装します



 @BindingAdapter("bind:filter") public static void applyFilter(ImageView imageView, String v) { imageView.setColorFilter(null); if("grey".equals(v)){ ColorMatrix matrix = new ColorMatrix(); matrix.setSaturation(0); ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); imageView.setColorFilter(cf); } }
      
      







フィールドの1つが空の場合、スタブ値を使用することも非常に便利です。



 <TextView ... android:text='@{movie.title ?? "unknown"}' ... />
      
      







MovieItemBinding内には、xmlファイルにIDを持つすべてのビューへのリンクが含まれていることにも注意してください。







まとめ


このライブラリにより、RecycleViewの操作が大幅に簡素化されます。書き込み時のコード量は、コールバックとデータのif / elseを使用せずに、数倍削減されました。 JavaRXを使用すると、データの更新をさらに簡素化できますが、実際には一方向にのみ機能します。データを変更すると、UIは更新されますが、その逆はできません。



便利なリンク



テストプロジェクト。

公式ドキュメント。

Androidのクイックスタートデータバインディング。



All Articles