Android中如何在网络响应后向Fragment添加卡片
修复AsyncTask中动态添加卡片崩溃的问题
崩溃原因分析
问题主要出在这几个地方:
- LayoutInflater调用异常:
onPostExecute里直接调用getLayoutInflater(),可能因为Fragment上下文状态不稳定,导致视图inflate失败。 - 数组越界风险:固定循环5次,但服务器返回的字符串分割后长度可能不足5,直接访问会触发数组越界异常。
- 静态变量滥用:把
upcomingplans、view等设为static,容易引发内存泄漏,还可能在Fragment生命周期变化后导致引用失效。 - 布局参数缺失: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); } } } }
关键修改说明
- 移除静态变量:把
upcomingplans等改成成员变量,避免内存泄漏和上下文失效问题。 - 复用LayoutInflater:在
onCreateView中保存inflater实例,onPostExecute里直接使用,inflater时指定父布局并传false,确保布局参数正确。 - 规避数组越界:用
Math.min(playlists.length, 5)控制循环次数,同时过滤空字符串。 - 清空原有视图:添加新卡片前调用
removeAllViews(),避免重复布局。 - 增加空值校验:对服务器返回结果做空值检查,防止空指针异常。
内容的提问来源于stack exchange,提问作者user27100319
相关产品推荐
相关产品推荐

