[Android] [Java] Télécharger des images sur GCS (Google Cloud Storage) avec Stream à l'aide de Glide

Glide Glide est une bibliothèque de chargement et de mise en cache d'images pour Android. https://github.com/bumptech/glide

Avec Gradle, vous pouvez l'installer comme suit.

build.gradle


repositories {
    mavenCentral()
    google()
}

dependencies {
    implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}

Préparation

Modèle original

Définissez une classe appelée GcsImage qui spécifie les fichiers qui existent sur GCS avec Bucket et PATH.

GcsImage.java


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 Suivez le lien ci-dessous pour définir un ModelLoader pour charger la GcsImage. Writing a custom ModelLoader

The first step is to implement the ModelLoader interface. Before we do so, we need to make two decisions:

  1. What type of Model should we handle?
  2. What type of Data should we produce for that Model?

Comme vous pouvez le voir, ModelLoader spécifie le modèle et le type de données à gérer.

Le modèle peut être String, etc., mais cette fois, nous utiliserons notre propre GcsImage. En tant que type de données, les décodeurs ʻInputStream et ByteBuffer` sont fournis en standard.

GcsImageLoader.java


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) {
        //Si le nom du compartiment et le nom du fichier sont identiques, les données du cache seront utilisées.
        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 {
                //Décrit le processus de lecture réel. Ici, nous avons implémenté notre propre classe.
                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() {}
    }
}

J'ai également créé une méthode appelée CloudStorageUtils.downloadToStream () et je l'ai définie dans la classe suivante.

CloudStorageUtils.java


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();
        //La partie d'acquisition des informations d'authentification est également définie dans une autre classe.
        Credential credential = GoogleApiCredentialFactory.getCredential(context);
        return new Storage(transport, jsonFactory, credential);
    }
}

GoogleApiCredentialFactory.java


public class GoogleApiCredentialFactory {

    private static Credential sCredential;

    public static synchronized Credential getCredential(@NonNull Context context) {
        if (sCredential == null) {
            //Lisez le fichier JSON avec Stream et obtenez les informations d'identification.
            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;
    }
}

Pour BuildConfig.GCP_CREDENTIAL, spécifiez le chemin d'accès au fichier JSON qui contient la clé de compte de service GCP.

Maintenant, ajoutons le GcsImageLoader créé.

GcsImageGlideModule.java


@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));
    }
}

En annotant @ GlideModule, Glide reconnaîtra GcsImageGlideModule, qui hérite de ʻAppGlideModule`.

Comme mentionné ci-dessus, build.gradle doit décrire le processeur d'annotation.

Voir: Classes de module et annotations.

la mise en oeuvre

Le programme qui lit l'image sur GCS à l'aide du GlideModule que j'ai créé est le suivant. Ici, l'image est affichée dans ʻImageView appelée mImageView`.

Glide.with(this).load(new GcsImage(bucket, filename)).into(mImageView);

Avec ce qui précède, l'image peut être affichée en toute sécurité.

Recommended Posts

[Android] [Java] Télécharger des images sur GCS (Google Cloud Storage) avec Stream à l'aide de Glide
Essayez d'utiliser Firebase Cloud Functions sur Android (Java)
Utiliser Java 11 avec Google Cloud Functions
Utilisation de JupyterLab + Java avec WSL sous Windows 10
Filtre Sobel utilisant OpenCV sur Android (Java)
Problème de lenteur de traitement lors de l'utilisation d'Active Storage avec le stockage cloud (GCS, S3, etc.)
[Java] Obtenez des images avec l'API Google Custom Search
Essayez la communication en utilisant gRPC sur un serveur Android + Java
Utilisation de Java 8 avec Bluemix (sur Liberty Runtime & DevOps Service)
Créez un référentiel interne Maven sur Google Cloud Storage
Essayez la classification d'image à l'aide de TensorFlow Lite sur Android (JAVA)
Téléchargement confortable avec JAVA
Téléchargement Java avec Ansible
Utilisation de plusieurs versions de Java avec Brew sur Mac + jEnv
J'ai essayé d'utiliser la bibliothèque CameraX avec Android Java Fragment
Télécharger des fichiers sur Aspera fournis avec IBM Cloud Object Storage (ICOS) à l'aide du SDK (version Java)