Open In App

How to Build a Book Library App using Google Books API in Android?

Last Updated : 02 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

If you are looking for building a book library app and you want to load a huge data of books then for adding this feature, you have to use a simple API which is provided by Google, and of course, it’s free. In this article, we will take a look at the implementation of this API in our Android App. 

What we are going to build in this article? 

We will be building a simple application in which we will be searching different types of books and we will get to see the list of books related to that topic in our RecyclerView. For searching these books we will be using a free API provided by Google which holds a huge collection of books. A sample video is given below to get an idea about what we are going to do in this article.

Note that we are going to implement this project using the Java language. 

Step by Step Implementation

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.

Step 2: Add the dependency for Volley in your Gradle files

Navigate to the app > Gradle Scripts > build.gradle.kts (Module :app) file and add below dependency in the dependencies section. 

dependencies {
    ...
    implementation("com.android.volley:volley:1.2.1")
    implementation("com.github.bumptech.glide:glide:4.16.0")
}

After adding the below dependencies in your gradle file now sync your project. As we will be using volley to fetch data from our API and Glide image loading library to load images from URL.

Step 3: Adding permissions for the Internet 

Navigate to the app > manifests > AndroidManifest.xml and add the below permissions to it. 

<uses-permission android:name="android.permission.INTERNET" />

As we will be loading the books from API so we have to request Internet permissions from the user. For that add the permissions for the internet in AndroidManifest.xml


Step 4: Working with the activity_main.xml and its sub layout

Go to the activity_main.xml file and refer to the following code. Now, create a new layout for each item of the recyclerview and name it book_rv_item.xml. Remember to add a drawable for the search button.

The xml code is given below.

activity_main.xml
<?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"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/searchLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="32dp"
        android:orientation="horizontal"
        android:weightSum="5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <!-- search bar -->
        <EditText
            android:id="@+id/searchEditText"
            style="@style/Widget.Material3.Button.OutlinedButton"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="4"
            android:gravity="start|center_vertical"
            android:hint="Search books..."
            android:textColor="@color/black" />

        <!--search button -->
        <ImageButton
            android:id="@+id/searchButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_weight="1"
            android:background="@color/colorPrimary"
            android:padding="16dp"
            android:src="@drawable/ic_search"
            app:tint="@color/white" />

    </LinearLayout>

    <!--recycler view for displaying our list of books-->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/searchLayout"
        tools:listitem="@layout/book_rv_item" />

    <!--progressbar for displaying our loading indicator-->
    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
book_rv_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="@color/white"
    android:layout_margin="4dp"
    app:cardCornerRadius="24dp"
    app:strokeWidth="2dp"
    app:cardElevation="0dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/bookImage"
            android:layout_width="130dp"
            android:layout_height="160dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"
            android:src="@drawable/background"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/bookTitle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:padding="3dp"
            android:text="Book Title"
            android:textColor="@color/black"
            android:layout_marginEnd="16dp"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toTopOf="@+id/publisher"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toEndOf="@+id/bookImage"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed" />

        <TextView
            android:id="@+id/publisher"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="3dp"
            android:text="Publisher"
            android:textColor="@color/black"
            android:textSize="12sp"
            android:textStyle="italic"
            app:layout_constraintBottom_toTopOf="@+id/pageCount"
            app:layout_constraintStart_toEndOf="@+id/bookImage"
            app:layout_constraintTop_toBottomOf="@+id/bookTitle" />


        <TextView
            android:id="@+id/pageCount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/publisher"
            android:layout_toEndOf="@id/bookImage"
            android:padding="3dp"
            android:text="Page count"
            android:textColor="@color/black"
            android:textSize="12sp"
            app:layout_constraintBottom_toTopOf="@+id/date"
            app:layout_constraintStart_toEndOf="@+id/bookImage"
            app:layout_constraintTop_toBottomOf="@+id/publisher" />


        <TextView
            android:id="@+id/date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/pageCount"
            android:layout_alignParentEnd="true"
            android:padding="3dp"
            android:text="date"
            android:textColor="@color/black"
            android:textSize="12sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/bookImage"
            app:layout_constraintTop_toBottomOf="@+id/pageCount" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</com.google.android.material.card.MaterialCardView>
ic_search.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?attr/colorControlNormal">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>


Step 5: Creating a Modal Class for storing our data from the API. 

For creating a new Modal class. Navigate to the app > java > {package-name}, Right-click on it and Click on, New > Java/Kotlin class and give a name to our file as BookInfo and add below code to it. Comments are added in the code to get to know in more detail.

BookInfo.java
package org.geeksforgeeks.demo;

import java.util.ArrayList;

public class BookInfo {

    // creating string, int and array list
    // variables for our book details
    private String title;
    private String subtitle;
    private ArrayList<String> authors;
    private String publisher;
    private String publishedDate;
    private String description;
    private int pageCount;
    private String thumbnail;
    private String previewLink;
    private String infoLink;
    private String buyLink;

    // creating getter and setter methods
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSubtitle() {
        return subtitle;
    }

    public void setSubtitle(String subtitle) {
        this.subtitle = subtitle;
    }

    public ArrayList<String> getAuthors() {
        return authors;
    }

    public void setAuthors(ArrayList<String> authors) {
        this.authors = authors;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public String getPublishedDate() {
        return publishedDate;
    }

    public void setPublishedDate(String publishedDate) {
        this.publishedDate = publishedDate;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getPageCount() {
        return pageCount;
    }

    public void setPageCount(int pageCount) {
        this.pageCount = pageCount;
    }

    public String getThumbnail() {
        return thumbnail;
    }

    public void setThumbnail(String thumbnail) {
        this.thumbnail = thumbnail;
    }

    public String getPreviewLink() {
        return previewLink;
    }

    public void setPreviewLink(String previewLink) {
        this.previewLink = previewLink;
    }

    public String getInfoLink() {
        return infoLink;
    }

    public void setInfoLink(String infoLink) {
        this.infoLink = infoLink;
    }

    public String getBuyLink() {
        return buyLink;
    }

    public void setBuyLink(String buyLink) {
        this.buyLink = buyLink;
    }

    // creating a constructor class for our BookInfo
    public BookInfo(String title, String subtitle, ArrayList<String> authors, String publisher,
                    String publishedDate, String description, int pageCount, String thumbnail,
                    String previewLink, String infoLink, String buyLink) {
        this.title = title;
        this.subtitle = subtitle;
        this.authors = authors;
        this.publisher = publisher;
        this.publishedDate = publishedDate;
        this.description = description;
        this.pageCount = pageCount;
        this.thumbnail = thumbnail;
        this.previewLink = previewLink;
        this.infoLink = infoLink;
        this.buyLink = buyLink;
    }
}
BookInfo.kt
package org.geeksforgeeks.demo

data class BookInfo (
    // creating string, int and array list 
    // variables for our book details
    var title: String,
    var subtitle: String,
    var authors: ArrayList<String>,
    var publisher: String,
    var publishedDate: String,
    var description: String,
    var pageCount: Int,
    var thumbnail: String,
    var previewLink: String,
    var infoLink: String,
    var buyLink: String
)


Step 7: Creating an Adapter class for setting our data to the item of RecyclerView

Navigate to the app > java > {package-name}, Right-click on it and Click on, New > Java/Kotlin class and name it as BookAdapter and add below code to it. Comments are added in the code to get to know in more detail. 

BookAdapter.java
package org.geeksforgeeks.demo;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;

public class BookAdapter extends RecyclerView.Adapter<BookAdapter.BookViewHolder> {

    private final ArrayList<BookInfo> bookInfoArrayList;
    private final Context context;

    // Constructor to initialize adapter with data
    public BookAdapter(ArrayList<BookInfo> bookInfoArrayList, Context context) {
        this.bookInfoArrayList = bookInfoArrayList;
        this.context = context;
    }

    @NonNull
    @Override
    public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Inflate layout for each RecyclerView item
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.book_rv_item, parent, false);
        return new BookViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull BookViewHolder holder, int position) {
        // Get current book info
        BookInfo bookInfo = bookInfoArrayList.get(position);

        // Set data to UI components
        holder.nameTV.setText(bookInfo.getTitle());
        holder.publisherTV.setText(bookInfo.getPublisher());
        holder.pageCountTV.setText("Pages : " + bookInfo.getPageCount());
        holder.dateTV.setText("Published On : " + bookInfo.getPublishedDate());

        // Load image from URL using Glide
        Glide.with(context).load(bookInfo.getThumbnail()).into(holder.bookIV);

        // Set click listener to open BookDetails activity with data
        holder.itemView.setOnClickListener(v -> {
            Intent intent = new Intent(context, BookDetails.class);
            intent.putExtra("title", bookInfo.getTitle());
            intent.putExtra("subtitle", bookInfo.getSubtitle());
            intent.putExtra("authors", bookInfo.getAuthors());
            intent.putExtra("publisher", bookInfo.getPublisher());
            intent.putExtra("publishedDate", bookInfo.getPublishedDate());
            intent.putExtra("description", bookInfo.getDescription());
            intent.putExtra("pageCount", bookInfo.getPageCount());
            intent.putExtra("thumbnail", bookInfo.getThumbnail());
            intent.putExtra("previewLink", bookInfo.getPreviewLink());
            intent.putExtra("infoLink", bookInfo.getInfoLink());
            intent.putExtra("buyLink", bookInfo.getBuyLink());

            // Start new activity with intent
            context.startActivity(intent);
        });
    }

    @Override
    public int getItemCount() {
        return bookInfoArrayList.size();
    }

    // ViewHolder class to hold UI elements for each item
    public static class BookViewHolder extends RecyclerView.ViewHolder {
        TextView nameTV, publisherTV, pageCountTV, dateTV;
        ImageView bookIV;

        public BookViewHolder(@NonNull View itemView) {
            super(itemView);
            // Initialize UI components
            nameTV = itemView.findViewById(R.id.bookTitle);
            publisherTV = itemView.findViewById(R.id.publisher);
            pageCountTV = itemView.findViewById(R.id.pageCount);
            dateTV = itemView.findViewById(R.id.date);
            bookIV = itemView.findViewById(R.id.bookImage);
        }
    }
}
BookAdapter.kt
package org.geeksforgeeks.demo

import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

class BookAdapter(
    private val bookInfoArrayList: ArrayList<BookInfo>,
    private val context: Context
) :
    RecyclerView.Adapter<BookAdapter.BookViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookViewHolder {
        // inflating layout for item of recycler view
        val view: View =
            LayoutInflater.from(parent.context).inflate(R.layout.book_rv_item, parent, false)
        return BookViewHolder(view)
    }

    override fun onBindViewHolder(holder: BookViewHolder, position: Int) {
        // setup data to each UI component
        val bookInfo = bookInfoArrayList[position]
        holder.nameTV.text = bookInfo.title
        holder.publisherTV.text = bookInfo.publisher
        holder.pageCountTV.text = "Pages : " + bookInfo.pageCount
        holder.dateTV.text = "Published On : " + bookInfo.publishedDate
        // set image from URL in our image view.
        Glide.with(context).load(bookInfo.thumbnail).into(holder.bookIV)

        // add on click listener on the card
        holder.itemView.setOnClickListener {
            // call a new activity and passing all the data of that item in next intent
            val intent = Intent(context, BookDetails::class.java)
            intent.putExtra("title", bookInfo.title)
            intent.putExtra("subtitle", bookInfo.subtitle)
            intent.putExtra("authors", bookInfo.authors)
            intent.putExtra("publisher", bookInfo.publisher)
            intent.putExtra("publishedDate", bookInfo.publishedDate)
            intent.putExtra("description", bookInfo.description)
            intent.putExtra("pageCount", bookInfo.pageCount)
            intent.putExtra("thumbnail", bookInfo.thumbnail)
            intent.putExtra("previewLink", bookInfo.previewLink)
            intent.putExtra("infoLink", bookInfo.infoLink)
            intent.putExtra("buyLink", bookInfo.buyLink)
            
            // after passing that data we are start new  intent
            context.startActivity(intent)
        }
    }

    override fun getItemCount(): Int = bookInfoArrayList.size

    inner class BookViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        
        // initialize text views and image view
        var nameTV: TextView = itemView.findViewById(R.id.bookTitle)
        var publisherTV: TextView = itemView.findViewById(R.id.publisher)
        var pageCountTV: TextView = itemView.findViewById(R.id.pageCount)
        var dateTV: TextView = itemView.findViewById(R.id.date)
        var bookIV: ImageView = itemView.findViewById(R.id.bookImage)
    }
}


Step 8: Creating a new Activity for displaying our Book Info in detail 

Navigate to the app > java > your app’s package name > Right-click on it and click on New > Activity > Select Empty Activity and name it as BookDetails. Make sure to select Empty Activity. Go to the activity_book_details.xml and BookDetails.kt/.java file and refer to the following code.

BookDetails.java
package org.geeksforgeeks.demo;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.bumptech.glide.Glide;

public class BookDetails extends AppCompatActivity {

    // Declaring variables for book details
    private String title, subtitle, publisher, publishedDate, description, thumbnail, previewLink, infoLink, buyLink;
    private int pageCount;

    // UI components
    private TextView titleTV, subtitleTV, publisherTV, descTV, pageTV, publishDateTV;
    private Button previewBtn, buyBtn;
    private ImageView bookIV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_book_details);

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        // Initializing views
        titleTV = findViewById(R.id.bookTitle);
        subtitleTV = findViewById(R.id.bookSubTitle);
        publisherTV = findViewById(R.id.publisher);
        descTV = findViewById(R.id.bookDescription);
        pageTV = findViewById(R.id.pageCount);
        publishDateTV = findViewById(R.id.publishedDate);
        previewBtn = findViewById(R.id.idBtnPreview);
        buyBtn = findViewById(R.id.idBtnBuy);
        bookIV = findViewById(R.id.bookImage);

        // Getting data passed from the adapter class
        Intent intent = getIntent();
        title = intent.getStringExtra("title");
        subtitle = intent.getStringExtra("subtitle");
        publisher = intent.getStringExtra("publisher");
        publishedDate = intent.getStringExtra("publishedDate");
        description = intent.getStringExtra("description");
        pageCount = intent.getIntExtra("pageCount", 0);
        thumbnail = intent.getStringExtra("thumbnail");
        previewLink = intent.getStringExtra("previewLink");
        infoLink = intent.getStringExtra("infoLink");
        buyLink = intent.getStringExtra("buyLink");

        // Setting data to UI components
        titleTV.setText(title);
        subtitleTV.setText(subtitle);
        publisherTV.setText(publisher);
        publishDateTV.setText("Published On : " + publishedDate);
        descTV.setText(description);
        pageTV.setText("Pages : " + pageCount);
        Glide.with(this).load(thumbnail).into(bookIV);

        // Adding click listener for preview button
        previewBtn.setOnClickListener(v -> {
            if (previewLink == null || previewLink.isEmpty()) {
                Toast.makeText(BookDetails.this, "No preview link present", Toast.LENGTH_SHORT).show();
                return;
            }
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(previewLink));
            startActivity(i);
        });

        // Adding click listener for buy button
        buyBtn.setOnClickListener(v -> {
            if (buyLink == null || buyLink.isEmpty()) {
                Toast.makeText(BookDetails.this, "No buy page present for this book", Toast.LENGTH_SHORT).show();
                return;
            }
            Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(buyLink));
            startActivity(i);
        });
    }
}
BookDetails.kt
package org.geeksforgeeks.demo

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.bumptech.glide.Glide

class BookDetails : AppCompatActivity() {
    //creating variables for strings,text view, image views and button.
    private var title: String? = null
    private var subtitle: String? = null
    private var publisher: String? = null
    private var publishedDate: String? = null
    private var description: String? = null
    private var thumbnail: String? = null
    private var previewLink: String? = null
    private var infoLink: String? = null
    private var buyLink: String? = null
    private var pageCount: Int = 0

    private lateinit var titleTV: TextView
    private lateinit var subtitleTV: TextView
    private lateinit var publisherTV: TextView
    private lateinit var descTV: TextView
    private lateinit var pageTV: TextView
    private lateinit var publishDateTV: TextView
    private lateinit var previewBtn: Button
    private lateinit var buyBtn: Button
    private lateinit var bookIV: ImageView


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_book_details)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        //initializing our views..
        titleTV = findViewById(R.id.bookTitle)
        subtitleTV = findViewById(R.id.bookSubTitle)
        publisherTV = findViewById(R.id.publisher)
        descTV = findViewById(R.id.bookDescription)
        pageTV = findViewById(R.id.pageCount)
        publishDateTV = findViewById(R.id.publishedDate)
        previewBtn = findViewById(R.id.idBtnPreview)
        buyBtn = findViewById(R.id.idBtnBuy)
        bookIV = findViewById(R.id.bookImage)

        //getting the data which we have passed from our adapter class.
        title = intent.getStringExtra("title")
        subtitle = intent.getStringExtra("subtitle")
        publisher = intent.getStringExtra("publisher")
        publishedDate = intent.getStringExtra("publishedDate")
        description = intent.getStringExtra("description")
        pageCount = intent.getIntExtra("pageCount", 0)
        thumbnail = intent.getStringExtra("thumbnail")
        previewLink = intent.getStringExtra("previewLink")
        infoLink = intent.getStringExtra("infoLink")
        buyLink = intent.getStringExtra("buyLink")

        //after getting the data we are setting that data to our text views and image view.
        titleTV.text = title
        subtitleTV.text = subtitle
        publisherTV.text = publisher
        publishDateTV.text = "Published On : $publishedDate"
        descTV.text = description
        pageTV.text = "Pages : $pageCount"
        Glide.with(this).load(thumbnail).into(bookIV)

        //adding on click listener for our preview button.
        previewBtn.setOnClickListener {
            if (previewLink!!.isEmpty()) {
                //below toast message is displayed when preview link is not present.
                Toast.makeText(this@BookDetails, "No preview Link present", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            //if the link is present we are opening that link via an intent.
            val uri = Uri.parse(previewLink)
            val i = Intent(Intent.ACTION_VIEW, uri)
            startActivity(i)
        }

        //initializing on click listener for buy button.
        buyBtn.setOnClickListener {
            if (buyLink!!.isEmpty()) {
                //below toast message is displaying when buy link is empty.
                Toast.makeText(this@BookDetails, "No buy page present for this book", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            //if the link is present we are opening the link via an intent.
            val uri = Uri.parse(buyLink)
            val i = Intent(Intent.ACTION_VIEW, uri)
            startActivity(i)
        }
    }
}
activity_book_details.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
    android:id="@+id/main"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".BookDetails">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:orientation="horizontal">

            <!--Image view for displaying our book image-->
            <ImageView
                android:id="@+id/bookImage"
                android:layout_width="130dp"
                android:layout_height="160dp"
                android:src="@drawable/background"
                android:layout_margin="18dp" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:orientation="vertical">

                <!--Text view for displaying book publisher-->
                <TextView
                    android:id="@+id/publisher"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:text="Publisher"
                    android:textStyle="italic"
                    android:textColor="@color/black"
                    android:textSize="15sp" />

                <!--text view for displaying number of pages of book-->
                <TextView
                    android:id="@+id/pageCount"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="4dp"
                    android:padding="4dp"
                    android:text="Number of Pages"
                    android:textColor="@color/black"
                    android:textSize="15sp" />

                <!--text view for displaying book publish date-->
                <TextView
                    android:id="@+id/publishedDate"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="4dp"
                    android:padding="4dp"
                    android:text="Publish Date"
                    android:textColor="@color/black"
                    android:textSize="15sp" />

            </LinearLayout>

        </LinearLayout>

        <!--text view for displaying book title-->
        <TextView
            android:id="@+id/bookTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:padding="4dp"
            android:text="title"
            android:textStyle="bold"
            android:textColor="@color/black"
            android:textSize="24sp" />

        <!--text view for displayig book subtitle-->
        <TextView
            android:id="@+id/bookSubTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:padding="4dp"
            android:textStyle="italic"
            android:text="subtitle"
            android:textColor="@color/black"
            android:textSize="12sp" />

        <!--text view for displaying book description-->

        <TextView
            android:id="@+id/bookDescription"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:padding="4dp"
            android:text="description"
            android:textColor="@color/black"
            android:textSize="12sp" />


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:orientation="horizontal"
            android:weightSum="2">

            <!--button for displaying book preview-->
            <Button
                android:id="@+id/idBtnPreview"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:layout_weight="1"
                android:text="Preview"
                android:textAllCaps="false" />

            <!--button for opening buying page of the book-->
            <Button
                android:id="@+id/idBtnBuy"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_margin="4dp"
                android:layout_weight="1"
                android:text="Buy"
                android:textAllCaps="false" />

        </LinearLayout>
    </LinearLayout>
</ScrollView>


Step 9: Working with the MainActivity file

Go to the MainActivity.java/.kt file and refer to the following code. Below is the code for the MainActivity file. Comments are added inside the code to understand the code in more detail.

MainActivity.java
package org.geeksforgeeks.demo;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;

// MainActivity handles the UI and API request
// to fetch books from Google Books API
public class MainActivity extends AppCompatActivity {

    // Variables for networking and UI components
    private RequestQueue mRequestQueue;
    private ArrayList<BookInfo> bookInfoArrayList;
    private ProgressBar progressBar;
    private EditText searchEdt;
    private ImageButton searchBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        // Initializing UI components
        progressBar = findViewById(R.id.progressBar);
        searchEdt = findViewById(R.id.searchEditText);
        searchBtn = findViewById(R.id.searchButton);

        // Setting click listener on the search button
        searchBtn.setOnClickListener(v -> {
            
            // Show progress bar while searching
            progressBar.setVisibility(View.VISIBLE); 
            String query = searchEdt.getText().toString();
            if (query.isEmpty()) {
                
                // Error if input is empty
                searchEdt.setError("Please enter search query"); 
                return;
            }
            
            // Fetch books based on the search query
            getBooksInfo(query); 
        });
    }

    // Function to fetch book data from Google Books API
    private void getBooksInfo(String query) {
        
        // Initialize the book list
        bookInfoArrayList = new ArrayList<>(); 
        mRequestQueue = Volley.newRequestQueue(this);
        
        // Clear cache before making a new request
        mRequestQueue.getCache().clear(); 

        // Construct API URL using the search query
        String url = "https://www.googleapis.com/books/v1/volumes?q=" + query;
        RequestQueue queue = Volley.newRequestQueue(this);

        // Make API request to get book data
        JsonObjectRequest booksObjRequest = new JsonObjectRequest(Request.Method.GET, url, null,
                response -> {
                    
                    // Hide progress bar after fetching data
                    progressBar.setVisibility(View.GONE); 
                    try {
                        // Get book items array
                        JSONArray itemsArray = response.getJSONArray("items"); 
                        
                        for (int i = 0; i < itemsArray.length(); i++) {
                            JSONObject itemsObj = itemsArray.getJSONObject(i);
                            JSONObject volumeObj = itemsObj.getJSONObject("volumeInfo");

                            // Extract book details with default values
                            String title = volumeObj.optString("title", "N/A");
                            String subtitle = volumeObj.optString("subtitle", "N/A");
                            JSONArray authorsArray = volumeObj.optJSONArray("authors");
                            String publisher = volumeObj.optString("publisher", "N/A");
                            String publishedDate = volumeObj.optString("publishedDate", "N/A");
                            String description = volumeObj.optString("description", "N/A");
                            int pageCount = volumeObj.optInt("pageCount", 0);

                            // Get book thumbnail if available
                            JSONObject imageLinks = volumeObj.optJSONObject("imageLinks");
                            String thumbnail = (imageLinks != null) ? imageLinks.optString("thumbnail", "") : "";

                            // Get book preview and info links
                            String previewLink = volumeObj.optString("previewLink", "");
                            String infoLink = volumeObj.optString("infoLink", "");

                            // Get buy link from sale info (if available)
                            JSONObject saleInfoObj = itemsObj.optJSONObject("saleInfo");
                            String buyLink = (saleInfoObj != null) ? saleInfoObj.optString("buyLink", "") : "";

                            // Convert authors JSONArray to ArrayList<String>
                            ArrayList<String> authorsArrayList = new ArrayList<>();
                            if (authorsArray != null) {
                                for (int j = 0; j < authorsArray.length(); j++) {
                                    authorsArrayList.add(authorsArray.optString(j, "Unknown"));
                                }
                            }

                            // Create BookInfo object with fetched details
                            BookInfo bookInfo = new BookInfo(
                                    title, subtitle, authorsArrayList, publisher, publishedDate,
                                    description, pageCount, thumbnail, previewLink, infoLink, buyLink
                            );

                            // Add book details to the list
                            bookInfoArrayList.add(bookInfo);
                        }

                        // Set up RecyclerView with BookAdapter to display the book list
                        RecyclerView recyclerView = findViewById(R.id.rv);
                        recyclerView.setLayoutManager(new LinearLayoutManager(this));
                        BookAdapter adapter = new BookAdapter(bookInfoArrayList, this);
                        recyclerView.setAdapter(adapter);

                    } catch (JSONException e) {
                        e.printStackTrace();
                        Toast.makeText(this, "No Data Found: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                },
                error -> {
                    // Handle API request error
                    Toast.makeText(this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
                });

        // Add request to the Volley queue
        queue.add(booksObjRequest);
    }
}
MainActivity.kt
package org.geeksforgeeks.demo

import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.VolleyError
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import org.json.JSONArray
import org.json.JSONException

// MainActivity handles the UI and API request
// to fetch books from Google Books API
class MainActivity : AppCompatActivity() {

    // Variables for networking and UI components
    private lateinit var mRequestQueue: RequestQueue
    private lateinit var bookInfoArrayList: ArrayList<BookInfo>
    private lateinit var progressBar: ProgressBar
    private lateinit var searchEdt: EditText
    private lateinit var searchBtn: ImageButton

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

        // Initializing UI components
        progressBar = findViewById(R.id.progressBar)
        searchEdt = findViewById(R.id.searchEditText)
        searchBtn = findViewById(R.id.searchButton)

        // Setting click listener on the search button
        searchBtn.setOnClickListener {
            
            // Show progress bar while searching
            progressBar.visibility = View.VISIBLE  
            val query = searchEdt.text.toString()
            if (query.isEmpty()) {
            
                // Error if input is empty
                searchEdt.error = "Please enter search query"  
                return@setOnClickListener
            }
            
            // Fetch books based on the search query
            getBooksInfo(query)  
        }
    }

    // Function to fetch book data from Google Books API
    private fun getBooksInfo(query: String) {
        bookInfoArrayList = ArrayList()  
        
        // Initialize the book list
        mRequestQueue = Volley.newRequestQueue(this)
        
        // Clear cache before making a new request
        mRequestQueue.cache.clear()  

        // Construct API URL using the search query
        val url = "https://www.googleapis.com/books/v1/volumes?q=$query"
        val queue = Volley.newRequestQueue(this)

        // Make API request to get book data
        val booksObjRequest = JsonObjectRequest(Request.Method.GET, url, null,
            { response ->
            
                // Hide progress bar after fetching data
                progressBar.visibility = View.GONE  
                try {
                
                    // Get book items array
                    val itemsArray = response.getJSONArray("items")  
                    for (i in 0 until itemsArray.length()) {
                        val itemsObj = itemsArray.getJSONObject(i)
                        val volumeObj = itemsObj.getJSONObject("volumeInfo")

                        // Extract book details with default values
                        val title = volumeObj.optString("title", "N/A")
                        val subtitle = volumeObj.optString("subtitle", "N/A")
                        val authorsArray = volumeObj.optJSONArray("authors") ?: JSONArray()
                        val publisher = volumeObj.optString("publisher", "N/A")
                        val publishedDate = volumeObj.optString("publishedDate", "N/A")
                        val description = volumeObj.optString("description", "N/A")
                        val pageCount = volumeObj.optInt("pageCount", 0)

                        // Get book thumbnail if available
                        val imageLinks = volumeObj.optJSONObject("imageLinks")
                        val thumbnail = imageLinks?.optString("thumbnail", "") ?: ""

                        // Get book preview and info links
                        val previewLink = volumeObj.optString("previewLink", "")
                        val infoLink = volumeObj.optString("infoLink", "")

                        // Get buy link from sale info (if available)
                        val saleInfoObj = itemsObj.optJSONObject("saleInfo")
                        val buyLink = saleInfoObj?.optString("buyLink", "") ?: ""

                        // Convert authors JSONArray to ArrayList<String>
                        val authorsArrayList = ArrayList<String>()
                        for (j in 0 until authorsArray.length()) {
                            authorsArrayList.add(authorsArray.optString(j, "Unknown"))
                        }

                        // Create BookInfo object with fetched details
                        val bookInfo = BookInfo(
                            title, subtitle, authorsArrayList, publisher, publishedDate,
                            description, pageCount, thumbnail, previewLink, infoLink, buyLink
                        )

                        // Add book details to the list
                        bookInfoArrayList.add(bookInfo)
                    }

                    // Set up RecyclerView with BookAdapter to display the book list
                    val adapter = BookAdapter(bookInfoArrayList, this)
                    val recyclerView = findViewById<RecyclerView>(R.id.rv)
                    recyclerView.layoutManager = LinearLayoutManager(this)
                    recyclerView.adapter = adapter

                } catch (e: JSONException) {
                    e.printStackTrace()
                    Toast.makeText(this, "No Data Found: ${e.message}", Toast.LENGTH_SHORT).show()
                }
            },
            { error: VolleyError ->
                // Handle API request error
                Toast.makeText(this, "Error: ${error.message}", Toast.LENGTH_SHORT).show()
            })

        // Add request to the Volley queue
        queue.add(booksObjRequest)
    }
}

Check out the project on the below link: Book-Library-App-using-Google-Books-API

Output:




Next Article

Similar Reads