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

Android:文本变化时Retrofit API调用的性能优化方案

Hey there! Let's tackle your two main pain points—excessive API calls and slow list loading—plus dive into how Retrofit caching can help, along with other practical optimizations.

1. Cut Down on Unnecessary API Requests

The biggest issue here is firing a request on every keystroke. We can fix this with two key techniques:

Debouncing

Add a small delay (like 300-500ms) before triggering the API call. If the user keeps typing within that window, we cancel the pending request and wait for them to stop inputting. This way, we only send one request per completed input sequence.

If you're using Kotlin Coroutines, you can implement this with Flow:

searchView.editText?.textChanges()
    .debounce(300L) // Wait 300ms after last keystroke
    .filter { it.length >= 3 } // Only trigger after 3+ characters
    .onEach { query ->
        // Trigger your Retrofit API call here
    }
    .launchIn(viewModelScope)

For RxJava users, use the debounce operator similarly:

RxTextView.textChanges(searchView)
    .debounce(300, TimeUnit.MILLISECONDS)
    .filter(text -> text.length() >= 3)
    .subscribe(query -> {
        // Execute Retrofit request
    });

Cancel In-Flight Requests

If a previous request is still loading when the user types a new query, cancel it immediately. This prevents outdated responses from overwriting fresh data and saves bandwidth.

With Coroutines, track the active request job:

private var searchJob: Job? = null

fun performSearch(query: String) {
    searchJob?.cancel() // Cancel previous request
    searchJob = viewModelScope.launch {
        val response = apiService.search(query)
        // Handle response
    }
}

With Retrofit's Call object:

private Call<List<Data>> currentCall;

void performSearch(String query) {
    if (currentCall != null) currentCall.cancel();
    currentCall = apiService.search(query);
    currentCall.enqueue(new Callback<List<Data>>() {
        // Handle response
    });
}
2. Speed Up Large List Loading

50k+ items loaded all at once will always be slow—let's fix this with pagination and RecyclerView optimizations.

Server-Side Pagination (Best Practice)

Work with your backend team to implement pagination. Instead of fetching all 50k items at once, request small chunks (e.g., 20-50 items per page) as the user scrolls.

Use Android's Paging 3 library to handle this seamlessly with Retrofit. Here's a quick outline:

  1. Define a Retrofit endpoint that accepts page and limit parameters:
interface ApiService {
    @GET("search")
    suspend fun search(
        @Query("query") query: String,
        @Query("page") page: Int,
        @Query("limit") limit: Int = 20
    ): Response<SearchResponse>
}
  1. Create a PagingSource to fetch pages incrementally:
class SearchPagingSource(
    private val apiService: ApiService,
    private val query: String
) : PagingSource<Int, Data>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Data> {
        val currentPage = params.key ?: 1
        return try {
            val response = apiService.search(query, currentPage, params.loadSize)
            val data = response.body()?.data ?: emptyList()
            LoadResult.Page(
                data = data,
                prevKey = if (currentPage == 1) null else currentPage - 1,
                nextKey = if (data.isEmpty()) null else currentPage + 1
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}
  1. Connect this to your RecyclerView with a Pager and PagingDataAdapter.

RecyclerView Performance Tweaks

Even with pagination, optimize your list to scroll smoothly:

  • Use DiffUtil to only update changed items instead of reloading the entire list
  • Set recyclerView.setHasFixedSize(true) if your list's size doesn't change dynamically
  • Reuse ViewHolders efficiently (avoid creating new ones in onBindViewHolder)
  • Offload heavy tasks like image loading to libraries like Glide/Picasso (with memory/disk caching)
  • Enable setItemViewCacheSize to keep more views in memory for faster reuse
3. Retrofit Caching (via OkHttp)

Retrofit itself doesn't handle caching—it relies on OkHttp under the hood. Here's how to set up caching to avoid re-requesting identical queries:

  1. Configure OkHttp Cache:
val cacheDir = File(context.cacheDir, "retrofit_cache")
val cache = Cache(cacheDir, 100 * 1024 * 1024) // 100MB cache size
  1. Add a Cache Interceptor:
    This interceptor sets cache rules for your requests. For example, cache GET requests for 1 minute:
val cacheInterceptor = Interceptor { chain ->
    val originalRequest = chain.request()
    val response = chain.proceed(originalRequest)
    
    // Cache GET requests for 1 minute
    val cacheControl = if (originalRequest.method == "GET") {
        CacheControl.Builder()
            .maxAge(1, TimeUnit.MINUTES)
            .build()
    } else {
        CacheControl.Builder().noCache().build()
    }
    
    response.newBuilder()
        .header("Cache-Control", cacheControl.toString())
        .build()
}
  1. Attach Cache and Interceptor to OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
    .cache(cache)
    .addNetworkInterceptor(cacheInterceptor)
    .build()
  1. Use This Client in Retrofit:
val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

Note: Caching only works for GET requests, and make sure your backend doesn't return no-cache or no-store headers that override your settings.

4. Bonus Optimizations
  • Local Database Caching: Use Room to store past search results. When the user searches again, first show cached data, then update with fresh server data if available.
  • Trim Request Payloads: Work with your backend to return only the fields your list needs (e.g., skip large images or unused metadata) to reduce JSON size and parsing time.
  • Optimize JSON Parsing: Use Moshi (instead of Gson) for faster Kotlin-friendly parsing, or enable Gson's optimizations like @JsonClass(generateAdapter = true) for data classes.

内容的提问来源于stack exchange,提问作者Pratik Butani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 09:52:52