2015年8月30日日曜日

Android Volleyで画像URLから画像を表示する

  • 公開日:2015年08月30日

記事概要


AndroidでVolleyを使用して画像URLから画像を表示する方法の記事です

環境


  • Android Studio 1.3.0
  • OS X Yosemite
  • android sdk 23(Android 6.0 Marshmallow(マシュマロ))
  • com.android.support:recyclerview-v7:23.0.0
  • compile 'com.mcxiaoke.volley:library:1.0.18'

Volley


Androidでネットワーク接続の処理をおこなうときに便利なフレームワークです。
データの習得は得意ですが、画像のアップロード、更新、登録処理には向きません。
データ習得以外には利用しないほうがよいと思います。

gradleの設定


volleyをアプリで利用できるよう、以下のように設定します。


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:23.0.0'
    compile 'com.mcxiaoke.volley:library:1.0.18'
    compile 'com.google.code.gson:gson:2.3.1'
}

volleyを使う場合、gsonを利用可能にしておくと便利です。

今回利用する画面


上記は、openWeatherMapの一覧リストの画面です。この画面の天気アイコン画像をvolleyで非同期表示実装をおこないます。
また、このリスト表示はRecyclerViewで作成しています。詳しい実装方法が知りたい場合はこの記事を参考にしてください。

画像Viewの設定


まずは、com.android.volley.toolbox.NetworkImageViewをレイアウトxmlに設定します。


    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/weather_image"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_toRightOf="@id/time_value"
        android:layout_marginLeft="5dp"
        android:scaleType="centerCrop"/>

layout_widthとlayout_heightはサイズを指定しておきましょう。 そうしないと表示が小さくなりすぎてしまいます。

BitmapCacheの実装


画像をキャッシュするBitmapCacheを実装します。この実装はなくても特に問題ないのですが、メモリを効率的に扱うために実装します。
サイズの大きい画像を扱うアプリのときには、必ず実装しましょう。


public class BitmapCache implements ImageLoader.ImageCache{

    private LruCache<String, Bitmap> mMemoryCache;

    /**
     * create BitmapCache instance
     * @return
     */
    public static BitmapCache getInstance() {
        BitmapCache bitmapCache = null;

        if (bitmapCache == null) {
            bitmapCache = new BitmapCache(getDefaultLruCacheSize());
        }
        return bitmapCache;
    }

    /**
     * Don't instantiate this class directly, use
     * @param memCacheSize Memory cache size in KB.
     */
    private BitmapCache(int memCacheSize) {
        init(memCacheSize);
    }

    /**
     * Initialize the cache.
     */
    private void init(int memCacheSize) {
        // Set up memory cache
        mMemoryCache = new LruCache<String, Bitmap>(memCacheSize) {
            /**
             * Measure item size in kilobytes rather than units which is more practical
             * for a bitmap cache
             */
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                final int bitmapSize = getBitmapSize(bitmap) / 1024;
                return bitmapSize == 0 ? 1 : bitmapSize;
            }
        };
    }

    /**
     * Get the size in bytes of a bitmap.
     */
    public static int getBitmapSize(Bitmap bitmap) {
        return bitmap.getByteCount();
    }

    @Override
    public Bitmap getBitmap(String key) {
        return getBitmapFromMemCache(key);
    }

    @Override
    public void putBitmap(String key, Bitmap bitmap) {
        addBitmapToCache(key, bitmap);
    }

    /**
     * Adds a bitmap to both memory and disk cache.
     * @param data Unique identifier for the bitmap to store
     * @param bitmap The bitmap to store
     */
    public void addBitmapToCache(String data, Bitmap bitmap) {
        if (data == null || bitmap == null) {
            return;
        }

        synchronized (mMemoryCache) {
            // Add to memory cache
            if (mMemoryCache.get(data) == null) {
                mMemoryCache.put(data, bitmap);
            }
        }
    }

    /**
     * Get from memory cache.
     *
     * @param data Unique identifier for which item to get
     * @return The bitmap if found in cache, null otherwise
     */
    public Bitmap getBitmapFromMemCache(String data) {
        if (data != null) {
            synchronized (mMemoryCache) {
                final Bitmap memBitmap = mMemoryCache.get(data);
                if (memBitmap != null) {
                    return memBitmap;
                }
            }
        }
        return null;
    }

    /**
     * Clears the memory cache.
     */
    public void clearCache() {
        if (mMemoryCache != null) {
            mMemoryCache.evictAll();
        }
    }

    public static int getDefaultLruCacheSize() {
        final int maxMemory =
                (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }
}

BitmapCacheのインスタンス作成をsingletonで行っていますが、newでオブジェクト生成しても同じです

Adapterの実装


上記で作成したBitmapCacheクラスとVolleyのImageLoaderクラスを使ってAdapterを実装します。


    private ImageLoader mImageLoader;

    /**
     * Initialize the dataset of the Adapter.
     *
     * @param dataSet String[] containing the data to populate views to be used by RecyclerView.
     */
    public WeatherAdapter(Context context, List<WeatherItem> dataSet) {
        mDataSet = dataSet;
        ImageLoader.ImageCache imageCache = BitmapCache.getInstance();
        mImageLoader = new ImageLoader(Volley.newRequestQueue(context), imageCache);
    }


    viewHolder.getWeatherView().setImageUrl (weatherItem.getDisplayImageURL(), mImageLoader);

Adapterを作成するときに、ImageLoaderを生成して変数として保持してしまいます。
あとは、データ生成をしているviewHolderのsetImageUrlに画像urlとImageLoaderオブジェクトを引数に設定すれば終了です。

さて、ビルドして表示を確認してみましょう。

綺麗に表示されています。

まとめ


volleyは優秀なネットワークフレームワークなのですが、学習コストが少し高いです。
私も初めてプロジェクトで利用した時は、結構痛い目に会いました。
フレームワークは問題を解決するための手段に過ぎません。
プロジェクトの状況(メンバーの力量やアプリの仕様)に合わせて適切なフレームワークを使ってください。
また、時には仕様をフレームワークに合わせてみることもお薦めします。アプリとして無駄なことをやっていることが見えてくるかもしれません。

以上

Androidアプリ開発にオススメの本


開発にあると便利なオススメ製品


関連記事 参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...