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

LinearLayout内双RecyclerView加载Firebase及Google Play内购数据时显示异常求助

我太懂这种随机bug的痛苦了——明明数据都能拿到,UI却时好时坏,连报错都没有,完全摸不着头脑。咱们一步步拆解你的问题,找出根源:

核心问题排查与修复步骤

1. 致命问题:后台线程更新UI

BillingClient的queryProductDetailsAsync回调是在后台线程执行的,而Android要求所有UI操作(包括setAdapter)必须在主线程完成。你直接在这个回调里调用displayPremiumData(),相当于在后台线程更新RecyclerView,这会导致UI卡住、不生效甚至隐性崩溃。

修复代码:
在querySkuDetails的回调里,强制切换到主线程再更新UI:

billingClient.queryProductDetailsAsync(
    params,
    (billingResult, productDetailsList) -> {
        if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
            System.out.printf(Locale.ENGLISH, "Unable to query sku details: %d - %s%n", billingResult.getResponseCode(), billingResult.getDebugMessage());
        } else {
            // 先清空旧数据,避免重复累加
            prodDetailsList.clear();
            for (ProductDetails details: productDetailsList) {
                prodDetailsList.add(details);
            }
            // 切换到主线程更新UI
            if (getActivity() != null) {
                getActivity().runOnUiThread(() -> displayPremiumData());
            }
        }
});

2. 数据源重复与线程安全问题

你的全局数据源(contentList、skuList、prodDetailsList)没有在每次请求前清空,导致多次调用请求时,旧数据和新数据混在一起,引发Adapter数据混乱,甚至显示异常。

修复代码:

  • 在listFilesFolders的成功回调开头,清空contentList:
.addOnSuccessListener(listResult -> {
    contentList.clear(); // 新增:清空旧数据
    for (StorageReference folder : listResult.getPrefixes()) {
        parentFolder = folder.getName();
        contentList.add(fileStorageRef.child(parentFolder));
    }
    // ... 原有代码
})
  • 在listPremium的onDataChange开头,清空所有相关列表:
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
    cProductsList.clear();
    skuList.clear(); // 新增:清空旧SKU
    productList.clear(); // 新增:清空旧查询参数
    // ... 原有代码
}

3. RecyclerView布局高度问题

如果你的RecyclerView设置了wrap_content,尤其是第一个用GridLayoutManager的列表,Android可能无法正确计算列表高度,导致显示为空或者只显示部分内容。

修复布局:
改用layout_weight分配两个RecyclerView的空间(假设父布局是垂直LinearLayout):

<LinearLayout
    android:id="@+id/mainLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/file_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/product_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
</LinearLayout>

这样两个列表会平分父布局的高度,确保都有足够空间显示内容。

4. BillingClient连接稳定性优化

当BillingService断开连接时,你的代码没有重连逻辑,导致后续无法获取商品数据。添加重连逻辑可以提升稳定性:

修复代码:

@Override
public void onBillingServiceDisconnected() {
    System.out.println("Billing service disconnected, attempting reconnect...");
    // 延迟3秒重连,避免频繁请求
    new Handler(Looper.getMainLooper()).postDelayed(() -> connectToGooglePlay(), 3000);
}

记得导入android.os.Handler和android.os.Looper。

5. Fragment生命周期适配

在onCreateView里调用数据请求可能导致重复请求(比如屏幕旋转时),建议把请求移到onViewCreated,并在onDestroyView里清理资源:

修复代码:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    listFilesFolders();
    checkForPremium();
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    // 清空Adapter避免内存泄漏
    filesRv.setAdapter(null);
    productRv.setAdapter(null);
    // 清空数据源
    contentList.clear();
    prodDetailsList.clear();
    skuList.clear();
    productList.clear();
    // 断开BillingClient连接
    if (billingClient != null && billingClient.isReady()) {
        billingClient.endConnection();
    }
}

调试小技巧

在各个Adapter设置方法里添加日志,确认数据是否正确传递:

private void displayPremiumData() {
    Log.d("PremiumDebug", "准备显示 " + prodDetailsList.size() + " 个商品");
    LinearLayoutManager llm2 = new LinearLayoutManager(getActivity());
    productsAdapter = new ProductsAdapter3(getActivity(), billingClient, prodDetailsList, path);
    productRv.setLayoutManager(llm2);
    productRv.setAdapter(productsAdapter);
    Log.d("PremiumDebug", "Adapter设置完成");
}

通过日志可以快速判断是数据没拿到,还是UI更新出了问题。

按照这些步骤修改后,你的两个RecyclerView应该能稳定显示数据了。如果还有问题,可以查看Logcat里的调试日志,看看数据是否正确加载,Adapter是否正常设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:22:44