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

Android中如何在网络响应后向Fragment添加卡片

修复AsyncTask中动态添加卡片崩溃的问题

崩溃原因分析

问题主要出在这几个地方:

  1. LayoutInflater调用异常:onPostExecute里直接调用getLayoutInflater(),可能因为Fragment上下文状态不稳定,导致视图inflate失败。
  2. 数组越界风险:固定循环5次,但服务器返回的字符串分割后长度可能不足5,直接访问会触发数组越界异常。
  3. 静态变量滥用:把upcomingplans、view等设为static,容易引发内存泄漏,还可能在Fragment生命周期变化后导致引用失效。
  4. 布局参数缺失:inflate卡片时传null作为父布局,会让卡片没有正确的布局参数,添加到LinearLayout时可能引发布局异常。

修复后的代码

package com.example.theclassplan;

import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.os.AsyncTask;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import java.io.IOException;
import okhttp3.Response;

public class HomeFragment extends Fragment {
    private LinearLayout upcomingplans;
    private LinearLayout featuredplans;
    private LayoutInflater inflater;

    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";
    private String mParam1;
    private String mParam2;

    public HomeFragment() {
        // Required empty public constructor
    }

    public static HomeFragment newInstance(String param1, String param2) {
        HomeFragment fragment = new HomeFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        this.inflater = inflater;
        View view = inflater.inflate(R.layout.fragment_home, container, false);
        upcomingplans = view.findViewById(R.id.upcomingplans);
        featuredplans = view.findViewById(R.id.featuredplans);

        new ExampleAsync().execute();
        return view;
    }

    private class ExampleAsync extends AsyncTask<Integer, String, String> {

        @Override
        protected String doInBackground(Integer... integers) {
            String id = Homepage.id;
            String url = "http://localhost:10000/playlist?id=" + id;

            Request request = new Request.Builder()
                    .url(url)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Call call = client.newCall(request);

            String serverResponse = null;
            try {
                Response response = call.execute();
                if (response.isSuccessful() && response.body() != null) {
                    serverResponse = response.body().string();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("AsyncTask", "请求失败: " + e.getMessage());
            }
            return serverResponse;
        }

        @Override
        protected void onPostExecute(String serverResponse) {
            super.onPostExecute(serverResponse);
            if (serverResponse == null || serverResponse.isEmpty()) {
                Log.w("AsyncTask", "服务器返回为空");
                return;
            }

            Log.i("response", serverResponse);
            // 清空原有卡片,避免重复添加
            upcomingplans.removeAllViews();
            featuredplans.removeAllViews();

            String[] playlists = serverResponse.split("]");
            // 循环次数取数组长度和5的最小值,防止越界
            int loopCount = Math.min(playlists.length, 5);
            for (int i = 0; i < loopCount; i++) {
                String playlist = playlists[i].replaceAll("\\[", "").trim();
                if (playlist.isEmpty()) continue;

                // 使用Fragment持有的inflater,指定父布局获取正确参数
                View card = inflater.inflate(R.layout.card, upcomingplans, false);
                TextView title = card.findViewById(R.id.title);
                title.setText(playlist);
                upcomingplans.addView(card);

                // 给featuredplans添加卡片的逻辑
                View featuredCard = inflater.inflate(R.layout.card, featuredplans, false);
                TextView featuredTitle = featuredCard.findViewById(R.id.title);
                featuredTitle.setText(playlist);
                featuredplans.addView(featuredCard);
            }
        }
    }
}

关键修改说明

  1. 移除静态变量:把upcomingplans等改成成员变量,避免内存泄漏和上下文失效问题。
  2. 复用LayoutInflater:在onCreateView中保存inflater实例,onPostExecute里直接使用,inflater时指定父布局并传false,确保布局参数正确。
  3. 规避数组越界:用Math.min(playlists.length, 5)控制循环次数,同时过滤空字符串。
  4. 清空原有视图:添加新卡片前调用removeAllViews(),避免重复布局。
  5. 增加空值校验:对服务器返回结果做空值检查,防止空指针异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 23:00:02