Skip to content
Elvis Chidera

Loading Images From JSON Response — Advanced Android Glide Tips Part 2

android2 min read

You have probably been in a situation where you wanted to load some images into an ImageView but the API call to get the image returns a JSON object that contains a field specifying the actual image URL. This usually happens when you are using a third-party service and can’t modify the behavior of the API.

banner

This was a challenge I faced when I decided to use the Last.FM API for FX Music Player. One way to solve this is to create a loader or AsyncTask that makes the API call then parses the JSON response and return the image URL. But each time you want to load an image you will have to manage multiple requests yourself and this gets difficult when you have a List or RecyclerView where items get reused.

I will show you a neat trick that allows you to load images from a JSON response using the Glide library. Each time you want to load an image, it will just take a single line with no additional stress.

First, create a request class. This will be a regular java class with any fields/variables you want to add to it. Example:

JsonRequest.java
1public class JsonRequest {
2
3 // Add any field you can use to identify the request or that will hold values you will
4 // pass to the api endpoint. For example this can be an id, name, size or any other thing
5}

Next, create a class that models the API JSON response. This is also just a regular java class and you can add any field/variable to it. You can use the JSONSchema2Pojo tool to do the API response modeling. Example:

JsonResponse.java
1public class JsonResponse {
2
3 // This class should contain fields that model the response from the api call you are making
4 // You can use this site to create a proper model based on the response: http://www.jsonschema2pojo.org/
5}

Next, we will have to create a custom Glide ModelLoader. This will be the class doing most of the work here like making the network calls and parsing the JSON response.

In order to keep this post HTTP library agnostic, I didn’t include any HTTP calls in the example code below. Just follow the TODO comments in the code below and use whatever HTTP library you are already using in your project to make the HTTP requests.

JsonModelLoader.java
1import android.support.annotation.NonNull;
2import android.support.annotation.Nullable;
3
4import com.bumptech.glide.Priority;
5import com.bumptech.glide.load.data.DataFetcher;
6import com.bumptech.glide.load.model.stream.StreamModelLoader;
7
8import java.io.IOException;
9import java.io.InputStream;
10
11public class JsonModelLoader implements StreamModelLoader<JsonRequest> {
12
13 public JsonModelLoader() {}
14
15 @Override
16 public DataFetcher<InputStream> getResourceFetcher(final JsonRequest model, int width, int height) {
17 // Return a custom ImageLoader that will handle a JSON response
18 return new JsonImageLoader(model);
19 }
20
21 private static class JsonImageLoader implements DataFetcher<InputStream> {
22
23 private final JsonRequest model;
24
25 JsonImageLoader(@NonNull JsonRequest model) {
26 this.model = model;
27 }
28
29 @Override
30 public InputStream loadData(Priority priority) throws IOException {
31 JsonResponse jsonResponse = makeApiCallToGetData(model);
32
33 if (jsonResponse != null) {
34 return getInputStreamFromApiResponse(jsonResponse);
35 }
36
37 return null;
38 }
39
40 private @Nullable JsonResponse makeApiCallToGetData(@NonNull JsonRequest model) {
41 // TODO: Make the call to the API to fetch data for the given model.
42 // You can use any field you added to the model class here like ids, name, and more
43 // Feel free to use any networking library here like OkHttp, Ion or any other.
44 return null;
45 }
46
47 private @Nullable InputStream getInputStreamFromApiResponse(@NonNull JsonResponse response) {
48 // TODO: Make the actual call to fetch the image data from the url specified in the Json Response
49 // Use your favorite Http client (OkHTTP, Ion and more) and just return the input stream
50 return null;
51 }
52
53 @Override
54 public String getId() {
55 // TODO: Do not return null, rather return a value that uniquely identifies the request else caching won't work
56 // This can be any unique field in the model class
57 return null;
58 }
59
60 @Override
61 public void cancel() {
62 // You can ignore for now
63 }
64
65 @Override
66 public void cleanup() {
67 // Do any necessary cleanup
68 }
69
70 }
71
72}

You will have to create a custom ModelLoaderFactory that returns your newly created ModelLoader. Its pretty straightforward, this class just returns a new instance of the JsonModelLoader. Use the code below:

JsonModelLoaderFactory.java
1import android.content.Context;
2
3import com.bumptech.glide.load.model.GenericLoaderFactory;
4import com.bumptech.glide.load.model.ModelLoader;
5import com.bumptech.glide.load.model.ModelLoaderFactory;
6
7import java.io.InputStream;
8
9class JsonModelLoaderFactory implements ModelLoaderFactory<JsonRequest, InputStream> {
10
11 @Override
12 public ModelLoader<JsonRequest, InputStream> build(Context context, GenericLoaderFactory factories) {
13 return new JsonModelLoader();
14 }
15
16 @Override
17 public void teardown() {}
18}

Then create a GlideModule that will allow us to use the JsonRequest class we created above to make requests with Glide. All we will be doing in this class is just to register our custom component (You can have several components, all you have to do is register them here so they will work). Use the code below to register the JsonModelLoader:

MyGlideModule.java
1import android.content.Context;
2
3import com.bumptech.glide.Glide;
4import com.bumptech.glide.GlideBuilder;
5import com.bumptech.glide.load.DecodeFormat;
6import com.bumptech.glide.module.GlideModule;
7
8import java.io.InputStream;
9
10public class MyGlideModule implements GlideModule {
11
12 @Override
13 public void applyOptions(Context context, GlideBuilder builder) {}
14
15 @Override
16 public void registerComponents(Context context, Glide glide) {
17 // register ModelLoaders here.
18 glide.register(JsonRequest.class, InputStream.class, new JsonModelLoaderFactory());
19 }
20}

Finally, add the GlideModule in your AndroidManifest.xml file. This is pretty easy, just use the code below to do that (don’t forget to change your.company.package.name to your actual package name).

AndroidManifest.xml
1<manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
3 <application>
4
5 <!-- Register Glide Module -->
6 <meta-data
7 android:name="**your.company.package.name.MyGlideModule**"
8 android:value="GlideModule" />
9
10 </application>
11
12</manifest

Everything is all set now. If you want to load images, it’s really really easy. Just use do something like this:

GlideUsage.java
1JsonRequest jsonRequest = new JsonRequest();
2// Set any of the request object fields you defined
3Glide.with(this).load(jsonRequest).into(imageView);

Once you understand the concepts explained here, you will be able to create more custom loaders to handle different types of requests/responses.

© 2020 by Elvis Chidera. All rights reserved.