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

Android Activity发送请求时如何正确显示加载布局

为什么你的写法不生效

核心原因是Android的UI渲染全在主线程跑,你写的三段代码全是同步顺序在主线程执行的:

  • 第一次调用setContentView(R.layout.loading)只是把loading布局的视图层级挂到了Window上,根本没等系统走完测量、布局、绘制的渲染流程,就立刻执行了sendRequests()
  • 如果sendRequests()是同步网络请求,会直接把主线程堵死,UI渲染完全停摆,loading界面根本没机会画到屏幕上
  • 等请求跑完,你直接调用setContentView(R.layout.main)切到主布局,用户从始至终都看不到loading状态,只会看到最终加载完的主界面。

另外提一句,从Android 3.0开始,主线程执行同步网络请求会直接抛NetworkOnMainThreadException,就算你不管loading的问题,这么写本身也会触发崩溃或者ANR。

正确实现方式

别用两次setContentView的思路,选下面任意一种稳妥方案就行:

  • 主布局内置双状态容器
    主布局里同时放loading布局和业务内容布局,默认只显示loading、隐藏内容,等请求全部返回后再切状态,这是最通用、性能最好的写法:
    <!-- R.layout.main 示例结构 -->
    <FrameLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!-- 业务内容区,默认隐藏 -->
        <LinearLayout
            android:id="@+id/content_wrap"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone">
            <!-- 你的主界面所有控件放这 -->
        </LinearLayout>
    
        <!-- 加载态布局,默认显示 -->
        <LinearLayout
            android:id="@+id/loading_wrap"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center">
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
    </FrameLayout>
    
    对应Activity逻辑:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        View contentWrap = findViewById(R.id.content_wrap);
        View loadingWrap = findViewById(R.id.loading_wrap);
    
        // 网络请求必须扔到子线程跑,别堵主线程
        new Thread(() -> {
            Object requestResult = sendRequests();
            // 切回主线程更新UI
            runOnUiThread(() -> {
                // 先把请求的数据绑定到内容区的控件上
                bindDataToViews(requestResult);
                // 切换显示状态
                loadingWrap.setVisibility(View.GONE);
                contentWrap.setVisibility(View.VISIBLE);
            });
        }).start();
    }
    
  • 全屏加载弹窗方案
    进入页面先弹一个不可取消的全屏loading弹窗,等所有请求完成后关闭弹窗,再给主界面控件绑定数据。这个方案改动量小,适合不想改现有主布局结构的场景。
  • ViewStub懒加载方案
    如果主布局本身inflate就很重,可以一开始只setContentView放loading的简单布局,等请求跑完后,再通过ViewStub把主布局inflate进来替换掉loading,核心还是要保证请求在子线程执行,给主线程留出渲染loading的时间。

注意:不管选哪种方案,都绝对不要在主线程执行耗时的网络请求、IO操作,否则不光加载态显示不出来,应用还会出现卡顿、无响应甚至崩溃的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:06:25