How to Build a Book Library App using Google Books API in Android?
Last Updated :
02 Apr, 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.
<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:
Similar Reads
AVL Tree Data Structure
An AVL tree defined as a self-balancing Binary Search Tree (BST) where the difference between heights of left and right subtrees for any node cannot be more than one. The absolute difference between the heights of the left subtree and the right subtree for any node is known as the balance factor of
4 min read
Sliding Window Technique
Sliding Window problems involve moving a fixed or variable-size window through a data structure, typically an array or string, to solve problems efficiently based on continuous subsets of elements. This technique is used when we need to find subarrays or substrings according to a given set of condit
15+ min read
Decorators in Python
In Python, decorators are a powerful and flexible way to modify or extend the behavior of functions or methods, without changing their actual code. A decorator is essentially a function that takes another function as an argument and returns a new function with enhanced functionality. Decorators are
10 min read
What is a Neural Network?
Neural networks are machine learning models that mimic the complex functions of the human brain. These models consist of interconnected nodes or neurons that process data, learn patterns, and enable tasks such as pattern recognition and decision-making. In this article, we will explore the fundament
14 min read
Read JSON file using Python
The full form of JSON is JavaScript Object Notation. It means that a script (executable) file which is made of text in a programming language, is used to store and transfer the data. Python supports JSON through a built-in package called JSON. To use this feature, we import the JSON package in Pytho
4 min read
Multithreading in Python
This article covers the basics of multithreading in Python programming language. Just like multiprocessing , multithreading is a way of achieving multitasking. In multithreading, the concept of threads is used. Let us first understand the concept of thread in computer architecture. What is a Process
8 min read
ArrayList in Java
Java ArrayList is a part of the collections framework and it is a class of java.util package. It provides us with dynamic-sized arrays in Java. The main advantage of ArrayList is that, unlike normal arrays, we don't need to mention the size when creating ArrayList. It automatically adjusts its capac
10 min read
What is an API (Application Programming Interface)
In the tech world, APIs (Application Programming Interfaces) are crucial. If you're interested in becoming a web developer or want to understand how websites work, you'll need to familiarize yourself with APIs. Let's break down the concept of an API in simple terms. What is an API?An API is a set of
10 min read
Adding New Column to Existing DataFrame in Pandas
Adding a new column to a DataFrame in Pandas is a simple and common operation when working with data in Python. You can quickly create new columns by directly assigning values to them. Let's discuss how to add new columns to the existing DataFrame in Pandas. There can be multiple methods, based on d
6 min read
Android Architecture
Android architecture contains a different number of components to support any Android device's needs. Android software contains an open-source Linux Kernel having a collection of a number of C/C++ libraries which are exposed through application framework services. Among all the components Linux Kern
5 min read