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

Android Studio中API请求时如何显示圆形加载进度条

问题根源分析

你的ProgressBar无法正常显示,核心问题出在thread.join()这行代码:
当你在主线程中调用thread.join()时,主线程会被阻塞,直到子线程的网络请求完全执行完毕才会继续向下执行。这就导致:

  1. 你调用的第一个runOnUiThread虽然提交了"显示进度条"的任务,但主线程被阻塞,无法及时处理这个UI更新操作
  2. 等子线程执行完成后,主线程才恢复运行,先执行"显示进度条",紧接着又执行"隐藏进度条"的操作,所以你完全看不到进度条的加载状态

修复方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:04:58