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

Retrofit call.enqueue在Fragment与BottomNavigationView的onNavigationItemSelected中无响应

问题分析与解决方案

你遇到的这个问题本质是异步操作的时序错误,加上可能的对象被GC回收的问题,导致Retrofit的回调永远不会触发,具体原因和解决方法如下:

核心原因

  1. 异步请求的时序问题
    你的userProfileDetails()是一个同步方法,但内部使用了Retrofit的call.enqueue()——这是异步执行的网络请求。当你调用userProfile = userProfileDetails()时,方法会立刻返回初始值(大概率是null),然后继续执行创建Fragment、传递参数的逻辑,而此时网络请求还在后台跑,回调完全没机会执行。

  2. Call对象被提前回收
    如果Call<UserProfile>对象只是作为userProfileDetails()方法的局部变量,当方法执行完毕后,这个对象可能被GC回收,导致网络请求的回调通道被切断,自然不会触发onResponse或onFailure。

  3. 额外细节问题
    你的onNavigationItemSelected返回了false,这会导致BottomNavigationView的菜单项不会被标记为选中状态,虽然和回调问题无关,但也是一个需要修正的细节。

解决方案

方案1:把网络请求逻辑移到UserProfileFragment内部

最合理的做法是让Fragment自己负责加载数据,这样可以避免时序问题,也符合组件的职责分离:

修改onNavigationItemSelected方法:

@Override 
public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
    Fragment fragment = null; 
    switch (item.getItemId()){ 
        case R.id.menu_landingorder: 
            fragment = new OrderFragment(); 
            break; 
        case R.id.menu_reccuringcart: 
            fragment = new RecurringCartFragment(); 
            break; 
        case R.id.menu_landingprofile: 
            fragment = new UserProfileFragment(); 
            // 不需要提前传递userProfile,让Fragment自己请求数据
            break; 
    } 
    if(fragment!=null){ 
        displayFragment(fragment); 
    } 
    // 返回true,标记当前菜单项为选中状态
    return true; 
}

然后在UserProfileFragment的onViewCreated方法里发起网络请求:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // 从SessionManager获取token(根据你的实际实现调整)
    String token = "Bearer "+ yourSessionManager.getSessionToken();
    Call<UserProfile> call = RetrofitClient.getInstance().getApi().getUserDetails(token);
    
    call.enqueue(new Callback<UserProfile>(){
        @Override 
        public void onResponse(Call<UserProfile> call, Response<UserProfile> response) { 
            if(response.isSuccessful()){ 
                UserProfile userProfile = response.body(); 
                Log.i("Response SuccessFul :: ", userProfile.getPhoneNo());
                // 拿到数据后更新Fragment的UI
                updateProfileUI(userProfile);
            }else { 
                Log.e("Response Failure :: ", "请求失败,状态码: "+response.code());
                try { 
                    if(response.errorBody() != null){
                        Log.e("错误详情", response.errorBody().string());
                    }
                } catch (IOException e) { 
                    Log.e("错误解析失败", e.getMessage());
                } 
            } 
        } 

        @Override 
        public void onFailure(Call<UserProfile> call, Throwable t) { 
            Log.e("网络请求失败 ", t.getMessage() ); 
        } 
    });
}

private void updateProfileUI(UserProfile userProfile) {
    // 这里写更新UI的逻辑,比如给TextView设置手机号、昵称等
}

方案2:在Activity中发起请求,拿到数据后再创建Fragment

如果你一定要在Activity中处理请求,可以用回调的方式,等请求完成后再创建并显示Fragment:

首先定义一个回调接口:

interface OnProfileLoadedListener {
    void onProfileLoaded(UserProfile profile);
    void onProfileLoadFailed(Throwable error);
}

修改userProfileDetails方法,接收回调:

// 把Call对象作为Activity的成员变量,避免被GC回收
private Call<UserProfile> profileCall;

private void userProfileDetails(OnProfileLoadedListener listener) { 
    String token = "Bearer "+ user.get(SessionManager.KEY_SESSION_TOKEN);
    Log.i("user :: " , token);
    profileCall = RetrofitClient.getInstance().getApi().getUserDetails(token);
    
    profileCall.enqueue(new Callback<UserProfile>(){
        @Override 
        public void onResponse(Call<UserProfile> call, Response<UserProfile> response) { 
            if(response.isSuccessful()){ 
                UserProfile userProfile = response.body(); 
                Log.i("Response SuccessFul :: ", userProfile.getPhoneNo());
                listener.onProfileLoaded(userProfile);
            }else { 
                Log.e("Response Failure :: ", "请求失败,状态码: "+response.code());
                listener.onProfileLoadFailed(new Exception("请求失败,状态码: "+response.code()));
            } 
        } 

        @Override 
        public void onFailure(Call<UserProfile> call, Throwable t) { 
            Log.e("网络请求失败 ", t.getMessage() ); 
            listener.onProfileLoadFailed(t);
        } 
    });
}

然后修改onNavigationItemSelected:

@Override 
public boolean onNavigationItemSelected(@NonNull MenuItem item) { 
    switch (item.getItemId()){ 
        case R.id.menu_landingorder: 
            displayFragment(new OrderFragment()); 
            break; 
        case R.id.menu_reccuringcart: 
            displayFragment(new RecurringCartFragment()); 
            break; 
        case R.id.menu_landingprofile: 
            // 发起请求,等回调拿到数据后再创建Fragment
            userProfileDetails(new OnProfileLoadedListener() {
                @Override
                public void onProfileLoaded(UserProfile profile) {
                    UserProfileFragment fragment = new UserProfileFragment();
                    Bundle b = new Bundle(); 
                    b.putSerializable(StringConstants.USERPROFILE, profile); 
                    fragment.setArguments(b);
                    displayFragment(fragment);
                }

                @Override
                public void onProfileLoadFailed(Throwable error) {
                    // 处理加载失败的情况,比如显示错误提示
                    Toast.makeText(LandingActivity.this, "加载个人信息失败: "+error.getMessage(), Toast.LENGTH_SHORT).show();
                    // 可以显示一个空状态的Fragment
                    displayFragment(new UserProfileFragment());
                }
            });
            break; 
    } 
    return true; 
}

同时,记得在Activity的onDestroy方法中取消请求,避免内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    if(profileCall != null && !profileCall.isCanceled()){
        profileCall.cancel();
    }
}

关键注意点

  • 永远不要在同步方法里等待异步请求的结果(比如用call.execute()同步请求,这会阻塞主线程,导致ANR)。
  • 确保Retrofit的Call对象被持有(比如作为类成员变量),避免被GC回收而导致回调丢失。
  • 组件间的数据传递尽量遵循单一职责原则,让Fragment自己管理数据加载更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:39:35