Android Studio中API请求时如何显示圆形加载进度条
问题根源分析
你的ProgressBar无法正常显示,核心问题出在thread.join()这行代码:
当你在主线程中调用thread.join()时,主线程会被阻塞,直到子线程的网络请求完全执行完毕才会继续向下执行。这就导致:
- 你调用的第一个
runOnUiThread虽然提交了"显示进度条"的任务,但主线程被阻塞,无法及时处理这个UI更新操作 - 等子线程执行完成后,主线程才恢复运行,先执行"显示进度条",紧接着又执行"隐藏进度条"的操作,所以你完全看不到进度条的加载状态
修复方案
方案1:移除thread.join(),改用回调返回结果
不要用join阻塞主线程,通过回调接口在子线程完成后通知主线程更新UI并处理结果:
第一步:定义回调接口
public interface OnIngredientSearchListener { void onSearchSuccess(List<FoodHint> hints); void onSearchFailed(String errorMsg); }
第二步:修改搜索方法
private void searchIngredient(String ingredient, OnIngredientSearchListener listener) { Gson gson = new Gson(); // 直接在主线程设置进度条可见(无需额外runOnUiThread,因为当前方法就在主线程调用) progressBar.setVisibility(View.VISIBLE); Runnable runnable = new Runnable() { @Override public void run() { FoodSearchResults searchResults = null; try { StringBuilder result = new StringBuilder(); URL url = new URL("www.exampleurl.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.connect(); int responseCode = connection.getResponseCode(); if (responseCode == 200) { Scanner scanner = new Scanner(url.openStream()); while (scanner.hasNext()) { result.append(scanner.nextLine()); } scanner.close(); searchResults = gson.fromJson(result.toString(), FoodSearchResults.class); } else { Log.d("debug-error", "Response Code: " + responseCode); } } catch (MalformedURLException e) { e.printStackTrace(); // 异常时回到主线程通知失败 runOnUiThread(() -> listener.onSearchFailed(e.getMessage())); return; } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> listener.onSearchFailed(e.getMessage())); return; } // 子线程完成后,回到主线程更新UI并返回结果 runOnUiThread(() -> { progressBar.setVisibility(View.GONE); if (searchResults != null) { listener.onSearchSuccess(searchResults.getHints()); } else { listener.onSearchFailed("搜索结果为空"); } }); } }; new Thread(runnable).start(); }
第三步:调用方法
searchIngredient("番茄", new OnIngredientSearchListener() { @Override public void onSearchSuccess(List<FoodHint> hints) { // 在这里处理搜索到的食材列表 } @Override public void onSearchFailed(String errorMsg) { // 在这里处理搜索失败的情况,比如提示用户 } });
方案2:使用Android推荐的协程(Kotlin项目优先)
如果你的项目是Kotlin编写,用协程可以更简洁地处理线程切换,无需手动管理线程:
第一步:确保依赖(build.gradle)
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" }
第二步:实现搜索方法
private fun searchIngredient(ingredient: String) = lifecycleScope.launch { // 主线程显示进度条 progressBar.visibility = View.VISIBLE try { // 切换到IO线程执行网络请求 val searchResults = withContext(Dispatchers.IO) { val gson = Gson() val result = StringBuilder() val url = URL("www.exampleurl.com") val connection = url.openConnection() as HttpURLConnection connection.requestMethod = "GET" connection.connect() if (connection.responseCode == 200) { val scanner = Scanner(url.openStream()) while (scanner.hasNext()) { result.append(scanner.nextLine()) } scanner.close() gson.fromJson(result.toString(), FoodSearchResults::class.java) } else { Log.d("debug-error", "Response Code: ${connection.responseCode}") null } } // 主线程处理结果 searchResults?.let { // 处理食材列表 } ?: run { // 处理结果为空的情况 } } catch (e: Exception) { e.printStackTrace() // 处理异常 } finally { // 无论成功失败,都隐藏进度条 progressBar.visibility = View.GONE } }
额外注意事项
- 确保布局中ProgressBar的初始状态为
android:visibility="gone" - 网络请求必须在子线程执行,你的代码这部分是正确的,不要改动
- 如果是Java项目,除了方案1,也可以使用
AsyncTask(虽已废弃,但简单场景仍可用),但更推荐回调方案
内容的提问来源于stack exchange,提问作者CladCobra
相关产品推荐
相关产品推荐

