You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中添加EditText搜索框并实现交互?Android Studio书籍API结果展示

Hey there! Glad you're diving into Android app development with the Google Books API—this is such a fun project to learn with. Let's break down exactly how to get your search results showing up after typing in an EditText, step by step.

1. Add Required Permissions & Dependencies

First, your app needs permission to access the internet. Open your AndroidManifest.xml and add this line right above the <application> tag:

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

If you're targeting Android 9 (API 28) or higher, you'll also need to allow cleartext traffic for the Google Books API. Add this inside your <application> tag:

android:usesCleartextTraffic="true"

Next, let's add dependencies for network calls and JSON parsing. Open your module-level build.gradle (the one inside the app folder) and add these lines to the dependencies block:

// Retrofit for simplified network requests
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Gson converter to map JSON responses to Kotlin objects
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// RecyclerView for displaying book lists
implementation 'androidx.recyclerview:recyclerview:1.3.2'

Don't forget to sync your project after adding these!

2. Create Data Classes to Parse API Responses

The Google Books API returns a JSON object with a list of "volumes" (books). We need data classes to map this JSON into usable Kotlin objects. Create these three Kotlin files:

First, BookResponse.kt:

data class BookResponse(
    val items: List<BookItem>?
)

Then BookItem.kt:

data class BookItem(
    val volumeInfo: VolumeInfo
)

And VolumeInfo.kt (holds the core book details we want to display):

data class VolumeInfo(
    val title: String,
    val authors: List<String>?,
    val imageLinks: ImageLinks?
)

data class ImageLinks(
    val thumbnail: String?
)

You can add more fields later (like publisher or description) if you want to expand the details shown.

3. Build the Retrofit API Service

Retrofit makes defining API endpoints straightforward. Create an interface called BooksApiService.kt:

import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

interface BooksApiService {
    // Replace YOUR_API_KEY with your actual key from Google Cloud Console
    @GET("volumes")
    fun searchBooks(
        @Query("q") query: String,
        @Query("key") apiKey: String = "YOUR_API_KEY"
    ): Call<BookResponse>
}

Important: You'll need to get an API key from the Google Cloud Console (search for "Google Books API", enable it, and generate a key). For learning purposes, hardcoding it works, but avoid this in production apps.

4. Connect EditText to API Calls

Let's link your search input to the API. Suppose you have an EditText (searchEditText) and a Button (searchButton) in your layout. In your Activity:

First, initialize Retrofit and the API service:

private lateinit var booksApiService: BooksApiService

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

    // Set up Retrofit
    val retrofit = Retrofit.Builder()
        .baseUrl("https://www.googleapis.com/books/v1/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    booksApiService = retrofit.create(BooksApiService::class.java)

    // Connect search button to input
    val searchButton = findViewById<Button>(R.id.searchButton)
    val searchEditText = findViewById<EditText>(R.id.searchEditText)

    searchButton.setOnClickListener {
        val query = searchEditText.text.toString().trim()
        if (query.isNotEmpty()) {
            fetchBooks(query)
        } else {
            Toast.makeText(this, "Please enter a search term", Toast.LENGTH_SHORT).show()
        }
    }
}

Then create the fetchBooks function to make the API call. Here's the callback-based version (great for beginners):

private fun fetchBooks(query: String) {
    booksApiService.searchBooks(query).enqueue(object : Callback<BookResponse> {
        override fun onResponse(call: Call<BookResponse>, response: Response<BookResponse>) {
            if (response.isSuccessful) {
                val books = response.body()?.items
                // Pass results to display function
                books?.let { displayBooks(it) } ?: run {
                    Toast.makeText(this@MainActivity, "No books found", Toast.LENGTH_SHORT).show()
                }
            } else {
                Toast.makeText(this@MainActivity, "Error fetching books", Toast.LENGTH_SHORT).show()
            }
        }

        override fun onFailure(call: Call<BookResponse>, t: Throwable) {
            Toast.makeText(this@MainActivity, "Network error: ${t.message}", Toast.LENGTH_SHORT).show()
        }
    })
}

If you prefer modern Kotlin Coroutines, replace the above with this:

private fun fetchBooks(query: String) {
    CoroutineScope(Dispatchers.IO).launch {
        try {
            val response = booksApiService.searchBooks(query).execute()
            if (response.isSuccessful) {
                val books = response.body()?.items
                runOnUiThread {
                    books?.let { displayBooks(it) } ?: run {
                        Toast.makeText(this@MainActivity, "No books found", Toast.LENGTH_SHORT).show()
                    }
                }
            } else {
                runOnUiThread {
                    Toast.makeText(this@MainActivity, "Error fetching books", Toast.LENGTH_SHORT).show()
                }
            }
        } catch (e: Exception) {
            runOnUiThread {
                Toast.makeText(this@MainActivity, "Network error: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
5. Display Results with RecyclerView

Finally, let's set up the RecyclerView to show the books. First, create a list item layout (item_book.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/bookThumbnail"
        android:layout_width="80dp"
        android:layout_height="120dp"
        android:scaleType="centerCrop"/>

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

        <TextView
            android:id="@+id/bookTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold"/>

        <TextView
            android:id="@+id/bookAuthors"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="@android:color/darker_gray"/>

    </LinearLayout>

</LinearLayout>

Next, create the RecyclerView Adapter (BookAdapter.kt):

class BookAdapter(private val books: List<BookItem>) : RecyclerView.Adapter<BookAdapter.BookViewHolder>() {

    inner class BookViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val title: TextView = itemView.findViewById(R.id.bookTitle)
        val authors: TextView = itemView.findViewById(R.id.bookAuthors)
        val thumbnail: ImageView = itemView.findViewById(R.id.bookThumbnail)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_book, parent, false)
        return BookViewHolder(view)
    }

    override fun onBindViewHolder(holder: BookViewHolder, position: Int) {
        val book = books[position].volumeInfo
        holder.title.text = book.title
        holder.authors.text = book.authors?.joinToString(", ") ?: "Unknown Author"

        // Load thumbnail (use Glide/Picasso for production apps)
        book.imageLinks?.thumbnail?.let { url ->
            holder.thumbnail.setImageBitmap(getBitmapFromUrl(url))
        } ?: run {
            holder.thumbnail.setImageResource(R.drawable.ic_book_placeholder) // Add a placeholder drawable
        }
    }

    override fun getItemCount(): Int = books.size

    // Basic image loading (replace with Glide/Picasso for better performance)
    private fun getBitmapFromUrl(url: String): Bitmap? {
        return try {
            val connection = URL(url).openConnection()
            connection.doInput = true
            connection.connect()
            val input = connection.getInputStream()
            BitmapFactory.decodeStream(input)
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }
}

Back in your Activity, initialize the RecyclerView and create the displayBooks function:

private lateinit var recyclerView: RecyclerView

override fun onCreate(savedInstanceState: Bundle?) {
    // ... existing code ...
    recyclerView = findViewById(R.id.recyclerView)
    recyclerView.layoutManager = LinearLayoutManager(this)
}

private fun displayBooks(books: List<BookItem>) {
    val adapter = BookAdapter(books)
    recyclerView.adapter = adapter
}

Don't forget to add the RecyclerView to your main layout (activity_main.xml):

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/searchLayout"/>
6. Bonus: Polish with Loading & Error States

To make the app feel more polished, add a ProgressBar for loading and an empty state message:

<ProgressBar
    android:id="@+id/loadingProgress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:visibility="gone"/>

<TextView
    android:id="@+id/emptyState"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="No books found"
    android:visibility="gone"/>

Update the fetchBooks function to show/hide these views as needed.

That's it! Plug in your API key, run the app, and you'll see book results pop up after searching.

内容的提问来源于stack exchange,提问作者Kadi Simpson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:32:40