Glide
Glide は Android 用の画像読み込み & キャッシュライブラリです.
https://github.com/bumptech/glide
Gradle であれば以下のようにして導入できます.
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}
準備
独自モデル
GCS 上に存在するファイルを Bucket と PATH で指定する GcsImage
というクラスを定義します.
public class GcsImage {
private final String mBucket;
private final String mFilename;
public GcsImage(@NonNull String bucket, @NonNull String filename) {
mBucket = bucket;
mFilename = filename;
}
public String getBucket() { return mBucket; }
public String getFilename() { return mFilename; }
}
Glide Module
下記リンクに従って,先ほどの GcsImage
を読み込むための ModelLoader
を定義します.
Writing a custom ModelLoader
The first step is to implement the ModelLoader interface. Before we do so, we need to make two decisions:
- What type of Model should we handle?
- What type of Data should we produce for that Model?
とあるように,ModelLoader
では,扱う Model と Data 型を指定します.
Model は String
等でも良いのですが,今回は独自の GcsImage
を使用します.
Data 型としては,標準で InputStream
と ByteBuffer
のデコーダが用意されています.
public class GcsImageLoader implements ModelLoader<GcsImage, InputStream> {
private Context mContext;
public GcsImageLoader(Context context) {
mContext = context;
}
@Nullable
@Override
public LoadData<InputStream> buildLoadData(@NonNull GcsImage gcsImage, int width, int height, @NonNull Options options) {
// バケット名とファイル名が同じであればキャッシュデータを利用するようにします.
return new LoadData<>(new ObjectKey(gcsImage.getBucket() + '/' + gcsImage.getFilename()), new GcsImageFetcher(gcsImage));
}
@Override
public boolean handles(@NonNull GcsImage gcsImage) {
return true;
}
private class GcsImageFetcher implements DataFetcher<InputStream> {
private GcsImage gcsImage;
GcsImageFetcher(GcsImage gcsImage) {
this.gcsImage = gcsImage;
}
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
try {
// 実際の読み込み処理を記述します. ここでは独自のクラスを実装しました.
InputStream stream = CloudStorageUtils.downloadToStream(mContext, gcsImage.getBucket(), gcsImage.getFilename());
callback.onDataReady(stream);
} catch (IOException e) {
callback.onLoadFailed(e);
}
}
@Override
public void cleanup() {}
@Override
public void cancel() {}
@NonNull
@Override
public Class<InputStream> getDataClass() {
return InputStream.class;
}
@NonNull
@Override
public DataSource getDataSource() {
return DataSource.REMOTE;
}
}
public static class GcsImageLoaderFactory implements ModelLoaderFactory<GcsImage, InputStream> {
private Context context;
public GcsImageLoaderFactory(Context context) {
this.context = context;
}
@NonNull
@Override
public ModelLoader<GcsImage, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
return new GcsImageLoader(context);
}
@Override
public void teardown() {}
}
}
CloudStorageUtils.downloadToStream()
というメソッドも独自に作成したもので,以下のようなクラスに定義しました.
public class CloudStorageUtils {
@WorkerThread
public static InputStream downloadToStream(@NonNull Context context, @NonNull String bucket,
@NonNull String name) throws IOException {
Storage storage = getStorageService(context);
Storage.Objects.Get get = storage.objects().get(bucket, name);
return get.executeMediaAsInputStream();
}
@WorkerThread
@NonNull
public static Storage getStorageService(@NonNull Context context) throws IOException {
HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// 認証情報の取得部分も別クラスで定義しています.
Credential credential = GoogleApiCredentialFactory.getCredential(context);
return new Storage(transport, jsonFactory, credential);
}
}
public class GoogleApiCredentialFactory {
private static Credential sCredential;
public static synchronized Credential getCredential(@NonNull Context context) {
if (sCredential == null) {
// JSON ファイルを Stream で読み込み, Credential を取得します.
try (InputStream is = context.getAssets().open(BuildConfig.GCP_CREDENTIAL)) {
List<String> scopes = new ArrayList<>();
scopes.add(StorageScopes.DEVSTORAGE_FULL_CONTROL);
GoogleCredential credential = GoogleCredential.fromStream(is);
sCredential = credential.createScoped(scopes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return sCredential;
}
}
BuildConfig.GCP_CREDENTIAL
には,GCP のサービスアカウントキーが記載された JSON ファイルへのパスを指定します.
では,作成した GcsImageLoader
を追加しましょう.
@GlideModule
public class GcsImageGlideModule extends AppGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
registry.prepend(GcsImage.class, InputStream.class, new GcsImageLoader.GcsImageLoaderFactory(context));
}
}
@GlideModule
というアノテーションをつけることにより,Glide は AppGlideModule
を継承した GcsImageGlideModule
を認識してくれます.
前述の通り,build.gradle
には Annotation Processor の記述が必要です.
参照: Module classes and annotations.
実装
自作した GlideModule を使って GCS 上の画像を読み込むプログラムは以下の通りです.
ここでは mImageView
という ImageView
に画像を表示させています.
Glide.with(this).load(new GcsImage(bucket, filename)).into(mImageView);
以上で,無事画像を表示することができました.