techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

Data Bindingを使ってみる その6

さて、またまた今回も公式に従ってData Bindingを見ていきます。
今回はBindingAdapterアノテーションを使って、ImageViewに画像を表示する属性とSetterを追加します。

今回は例として、画像のURLをセットすると画像をロードして表示する属性をImageViewに付与してみます。 f:id:uentseit:20160415004913p:plain:w300

BindingAdapterアノテーション

BindingAdapterアノテーションを利用して、Activity側からImageViewに画像のURLをセットして表示する属性を追加します。
まずはActivityにBindingAdapterアノテーションを定義したメソッドを用意します。
[MainActivity.java]

public class MainActivity extends AppCompatActivity {

    private Hanter hanter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ActivityMainBinding binder = DataBindingUtil.setContentView(this, R.layout.activity_main);
        hanter = new Hanter("ハンタくん", "MAN");
        binder.setHanter(hanter);

        binder.btnChangeGender.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hanter.gender.set("WOMAN");
            }
        });
    }

    @BindingAdapter("loadImg")   ・・・21行目
    public static void setImage(ImageView view, String oldUrl, String newUrl) {
        if(!newUrl.equals(oldUrl)) {
            Picasso.with(view.getContext()).load(newUrl).into(view);
        }

    }

注目は21行目以降です。
BindingAdapterアノテーションに指定したloadImgが属性名となり、名前空間"app"で属性が使用できます。
レイアウトXMLにImageViewを追加し、loadImg属性を実装します。
[activity_main.xml]

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="activity" type="techium.hatenablog.com.monhaan1.MainActivity"/>
        <variable name="hanter" type="techium.hatenablog.com.monhaan1.Hanter"/>

        <variable name="imageUrl" type="String"/>   ・・・7行目
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin">

        <TextView
            android:id="@+id/txt_hello"
            android:text="hello, Hanter!"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

         (・・・略・・・)

        <ImageView
            android:id="@+id/img_sample"
            android:layout_width="40dp"
            android:layout_height="40dp"
            app:loadImg="@{imageUrl}"      ・・・33行目
            android:layout_below="@id/txt_gender"/>

        <Button
            android:id="@+id/btn_change_gender"
            android:text="change gender"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/img_sample"/>

    </RelativeLayout>
</layout>

8行目でURLをバインドするためのString型変数"imageUrl"を定義しています。
34行目にloadImg属性を実装し、8行目で定義したString型の変数をセットしています。
これで、自動生成されたsetImageUrlメソッドをActivity側から呼ぶことで、loadImg属性にURLをバインドする準備ができました。

では実際に画像のURLバインドしてみます。
[MainActivity.java]

public class MainActivity extends AppCompatActivity {

    private Hanter hanter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ActivityMainBinding binder = DataBindingUtil.setContentView(this, R.layout.activity_main);
        hanter = new Hanter("ハンタくん", "MAN");
        binder.setHanter(hanter);
        binder.setImageUrl("http://hogefuga.com/icon.png");   ・・・12行目

        binder.btnChangeGender.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hanter.gender.set("WOMAN");
            }
        });
    }

    @BindingAdapter("loadImg")   
    public static void setImage(ImageView view, String url) {
            Picasso.with(view.getContext()).load(url).into(view);
    }

12行目でURLをバインドする処理を追加しました。
これでloadImgにURLがバインドされると同時にsetImageメソッドが呼び出され、Picassoで画像を取得する処理が実行されます。

[f:id:uentseit:20160415004913p:plain:w300"]

BindingAdapterアノテーションによるメソッドの定義はアプリ全体に影響を及ぼします。
BindingAdapterアノテーションを定義する専用のクラスを用意するなどすると良いかもしれません。

public class BindingUtils {

    @BindingAdapter({"loadImg"})
    public static void setImage(ImageView view, String url) {
            Picasso.with(view.getContext()).load(url).into(view);
    }
}

おまけ Picasso

今回、画像を取得するために使用したPicassoは、URLやリソースフォルダなどから画像を取得してImageViewにセットするまでをたった1行で記述することができる便利なOSSライブラリ(Apache License 2.0)です。

 Picasso.with(view.getContext()).load(url).into(view);

以下のようにすれば、ネットワークの問題などで画像が取得できなかった場合に、リソースフォルダからアイコン(ここではR.drawable.gohan)を取得して表示させることもできます。

Picasso.with(view.getContext()).load(newUrl).error(R.drawable.gohan).into(view);

今日はここまでにします。