How to Build a Book Library App using Google Books API in Android? (original) (raw)

Last Updated : 23 Jul, 2025

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.

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 `

<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

<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

`

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, 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, 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

<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>

`

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: