Akshay Rana I'm a self-taught, full-time programmer. I have experience working with various technologies including React, React Native, WordPress, Node.js, Express.js, Raspberry Pi, Python, REST APIs, and GraphQL. I love to explore new technologies and update my skills.

Create an Android photo app using Glide

7 min read 2223

Glide Logo Over Clouds

In this tutorial, we’ll introduce you to Glide and demonstrate how to build a simple photo app. We’ll outline the basics of Glide, including why it exists and what problems it is designed to solve. Then, we’ll examine some practical code examples to see Glide in action.

By the end of the tutorial, you will know how to implement Glide in your Android app from scratch using Kotlin. The finished app will look like this:

Example Photo App

What is Glide?

Glide is an Android image loading and caching library. It is designed to simplify the process of loading an image from the server or elsewhere on the internet. Just one line of code and, boom! Your image is loaded from the server.

Without Glide, it can be a nightmare to handle all the actions associated with loading and caching an image from the server manually. Glide enables you to focus on building a high-quality Android application for your users.

Set up a new project in Android Studio

To start building our Android photo app with Glide, we must first create a new project in Android Studio.

Launch Android Studio and create a new project. Choose Empty Activity.

New Project View

After that, choose your application name.

Empty Activity View

Also, choose your Android minimum SDK as per your need.

Add required dependencies

Now that we’ve created a new project in Android Studio, it’s time to add our dependencies.

Open your build.gradle file (module level) and add the following dependencies in your dependencies block:

implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation 'com.amitshekhar.android:android-networking:1.0.2'

The first two lines are for the Glide library and the last library is for networking. We will make the API calls using the Unsplash Image API for fetching image links.

Create a layout for images

We’ll make a grid layout to show image thumbnails. To create grid layout, we’ll use RecyclerView in our app.

To create a RecyclerView item layout file, right-click the layout folder and select New, then Layout Resource File.

After that, fill in the name of the file.



File Name Blank Field

After creating the file, we’ll create our item layout using CardView.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="10dp"
    >

    <androidx.cardview.widget.CardView
        android:layout_width="180dp"
        android:layout_height="180dp"
        app:cardCornerRadius="7dp"
        android:elevation="4dp"
        android:id="@+id/image_card">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:id="@+id/image_view"
            android:src="@drawable/logrocket"
            />
    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

LogRocket Card

Now we need to create the data class to store the image URLs. We’ll store only two URL links: one for the thumbnail URL and another for the URL of the high-resolution image. This way, we only need to store two strings.

Create a data class to store image links

Right-click on your package folder and choose New. Then, click New Kotlin Class/File.

After that, click Data Class and type your class name.

Data Class Highlighted

In the file, we’ll create a construct like below:

package com.logrocket.glidetutorial

data class ImageLinks(var thumbnailUrl: String, var fullImageUrl: String)

In the above code, we are accepting two strings: one for the thumbnail URL and another for the full image URL.

Implement RecyclerView and Adapter

Now it’s time to add RecyclerView in your main activity layout and create an Adatper class for it.

First, add RecyclerView in main activity. Open your main activity layout file and run the following code:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recycler_view"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

We have given the recycler_view id and recyclerview element.

Now, create a new Kotlin class for the Adapter class.

Right-click on the Package folder and select New, then Kotlin File / Class. Give it the name ImageAdapter.


More great articles from LogRocket:


After creating the Adapter class, we need to extend the RecyclerView.Adapter class and pass the custom view holder class as generic.

Your code should look like this:

class ImageAdapter(): RecyclerView.Adapter<ImageAdapter.ViewHolder>() {
....
}

At this point, you’ll see an error prompting you to implement the members for the adapter. So let’s implement the members.

The Adapter class has three methods:

  • onCreateViewHolder
  • onBindViewHolder
  • getItemCount

Before implementing these methods, let’s create a construct where we will get the data from our main activity.

We’ll need image links and context for the activity. We need to change our code like this:

class ImageAdapter(private var context: Context, private var imageURLList : ArrayList<ImageLinks>): RecyclerView.Adapter<ImageAdapter.ViewHolder>() {
....
} 

The first parameter accepts the context and the second accepts the array list of our data class where we will store the links data.

Now let’s implement the Adapter methods and also create a custom ViewHolder class.

class ImageAdapter(private var context: Context, private var imageURLList : ArrayList<ImageLinks>): RecyclerView.Adapter<ImageAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {

    }

    override fun getItemCount(): Int {
    }


    class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
    }
}

As you can see, in the custom ViewHolder class, we have extended the class with RecyclerViewand its constructor and passed itemView.

Our custom ViewHolder will accept a layout, which we created before as the RecyclerView item.

Now let’s complete the adapter code:

class ImageAdapter(private var context: Context, private var imageURLList : ArrayList<ImageLinks>): RecyclerView.Adapter<ImageAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.image_list_item, parent, false);
        return  ViewHolder(itemView);
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val imageUrls = imageURLList[position]
        val imageView = holder.imageView
        Glide.with(context)
            .load(imageUrls.thumbnailUrl)
            .into(imageView)
        imageView.setOnClickListener {
            run {
                val intent = Intent(context, FullScreenImage().javaClass)
                intent.putExtra("fullImageUrl", imageUrls.fullImageUrl)
                context.startActivity(intent)
            }
        }
    }

    override fun getItemCount(): Int {
        return imageURLList.size
    }

    class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
        var imageView: ImageView = itemView.findViewById(R.id.image_view)
    }
}

In the above code, the onCreateViewHolder method enables us to inflate a view to load the RecyclerView item layout and return ViewHolder.

In the ViewHolder, we’re using the itemView and finding imageView using its ID.

In the onBindViewHolder method, we are binding our data with the viewholder’s view that is imageview. This is the main logic where we are using Glide library to load the image from the url and show them in image view.

The line Glide.with(context).load(imageUrls.thumbnailUrl).into(imageView) enables us to load the image. The first function, with, takes the context of the activity, the load function takes the URL of the image, and, finally, the into function passes our image view.

Also, we have added a click listener on image view to open a new activity where we will show the image in full screen. We are passing the full screen image link with the intent using putExtra method.

After doing this, don’t forget to return the number of images in the getItemCount method.

That’s it for the RecyclerView adapter. Now we need to attach this adapter with our main activity’s RecyclerView.

Attach Adapter to RecyclerView

In the main activity, we have to do two things:

  1. Fetch the image URLs from the Unsplash API
  2. Attach Adapter to RecyclerView with our image links data

To make an API request call, we’ll use the Fast Android Networking library, which we’ll add as a dependency.

class MainActivity : AppCompatActivity() {
    private lateinit var  recyclerView: RecyclerView
    private var imageList: ArrayList<ImageLinks> = arrayListOf()
    var RANDOM_IMAGE_URL: String = "https://api.unsplash.com/photos"
    var ACCESS_ID = "UNSPLASH_ACCESS_ID"
    val context: Context = this;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        AndroidNetworking.initialize(applicationContext)

        AndroidNetworking.get(RANDOM_IMAGE_URL)
            .addHeaders("Authorization", "Client-ID $ACCESS_ID")
            .build()
            .getAsJSONArray(object : JSONArrayRequestListener{
                override fun onResponse(response: JSONArray?) {
                // handle response here
                }
                override fun onError(anError: ANError?) {
                    // handle error here
                }
            })
    }
}

In the above snippet, we first initialize the Android network library using AndroidNetworking.initialize(applicationContext). We also need to pass the application context.

After initializing, we can use get function of networking library. In the parameter, we need to pass the API URL. To add request headers, we can use addHeaders and pass whatever you want to set in the request header. In our case, we are setting authorization and pass our access ID.

Now we can call build a function to make a call to the URL and get a response using getAsJSONArray.

We need to pass an interface that overrides two methods:

  1. onResponse, which is invoked when we successfully receive a response from the server
  2. onError, which is invoked when the server returns an error

We’ll focus on the onResponse method. In this method, we will get our data and pass it to Adapter, like so:

        AndroidNetworking.get(RANDOM_IMAGE_URL)
            .addHeaders("Authorization", "Client-ID $ACCESS_ID")
            .build()
            .getAsJSONArray(object : JSONArrayRequestListener{
                override fun onResponse(response: JSONArray?) {

                    val length: Int? = response?.length()
                    for (i in 0 until length!!){
                        val jsonObject: JSONObject = response.getJSONObject(i)
                        val urlJson: JSONObject = jsonObject.getJSONObject("urls")
                        val thumbnailUrl = urlJson.getString("thumb")
                        val fullImageUrl = urlJson.getString("regular")
                        val imageLinks = ImageLinks(thumbnailUrl, fullImageUrl)
                        imageList.add(imageLinks)
                    }

                    recyclerView = findViewById(R.id.recycler_view)
                    recyclerView.layoutManager = GridLayoutManager(applicationContext, 2)
                    recyclerView.adapter = ImageAdapter(context, imageList)

                }
                override fun onError(anError: ANError?) {
                    // handle error here
                }
            })
    }
}

In the onResponse method, we are looping to the response and storing the thumbnail and full image URL from the response. This is how our response is coming from the Unsplash API:

[
    {
        ...
        "urls": {
            "regular": "https://images.unsplash.com/photo-1524758631624-e2822e304c36?crop=entropy\u0026cs=tinysrgb\u0026fit=max\u0026fm=jpg\u0026ixid=MnwyNzU1MjN8MXwxfGFsbHwxfHx8fHx8Mnx8MTYzNjg4NjU4OA\u0026ixlib=rb-1.2.1\u0026q=80\u0026w=1080",
            "thumb": "https://images.unsplash.com/photo-1524758631624-e2822e304c36?crop=entropy\u0026cs=tinysrgb\u0026fit=max\u0026fm=jpg\u0026ixid=MnwyNzU1MjN8MXwxfGFsbHwxfHx8fHx8Mnx8MTYzNjg4NjU4OA\u0026ixlib=rb-1.2.1\u0026q=80\u0026w=200"
        }
      ...        
    }
....
]

After getting the image links and storing them in an array list, the next step is to attach Adapter to RecyclerView and pass that array list of image links.

But before attaching Adapter, we need to specify which type of layout we want for our RecyclerView. We have two to choose from:

  1. Linear Layout Manager, which makes a vertical, single-column list
  2. Grid Layout Manager, which produces a gridlike system

For our application design, we need to use Grid Layout Manager to set the number of columns.

Finally, we need to attach the Adapter, set the Adapter property of RecyclerView, and set the ImageAdapter object. While calling the adapter constructor, we have to pass the required parameters — that is, the activity context and image array list.

Now if we run our app, we can see our list of images. But when clicking on any image, we need to open our full screen activity.

To do that, first we need to create a new activity in our project.

Right-click on the app folder and select New, Activity, and then Empty Activity.

After that, we need to set the activity name. We’ll set this sctivity name as “FullScreenImage.”

Fullscreenimage Activity Name

Open the layout file of this activity and add an ImageView to all over the screen, like this:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FullScreenImage">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fullImageView"
        android:scaleType="centerCrop"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

After adding the ImageView, set the clicked image in this activity.

Open the class file and add the following code:

class FullScreenImage : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_full_screen_image)

        val fullImageUrl = intent.getStringExtra("fullImageUrl")
        val fullImageView: ImageView = findViewById(R.id.fullImageView)

        Glide.with(this)
            .load(fullImageUrl)
            .into(fullImageView)

    }
}

This is very straightforward. First, we get the full image URL from the intent’s getStringExtra (remember, we are passing the full image URL).

After getting the image URL, we access our image view and use Glide to load the image from the URL and show it in image view, as we did earlier in the code for the custom adapter.

At this point, our photo application built using Glide is complete!

Conclusion

In this tutorial, we demonstrated how to use RecyclerView with CardView and more. We also showed you how to use the Glide Image Library to build an Android photo application with just a single line of code.

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

LogRocket: Instantly recreate issues in your Android apps.

LogRocket is an Android monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your Android apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your Android apps — .

.
Akshay Rana I'm a self-taught, full-time programmer. I have experience working with various technologies including React, React Native, WordPress, Node.js, Express.js, Raspberry Pi, Python, REST APIs, and GraphQL. I love to explore new technologies and update my skills.

Leave a Reply