Android Studio中Volley填充ArrayList后跳转Activity时列表为空
问题分析与解决方案:Volley异步加载导致集合为空&跨Activity数据传递问题
咱们来拆解你遇到的问题,点击按钮时miListaPartidos为空,主要有两个核心原因,同时你的代码还有一个隐藏的坑,我一起给你说明:
一、为什么miListaPartidos会为空?
这是因为Volley的网络请求是异步执行的:
你在onCreate里调用了getPartidos(),但这个方法只是发起了网络请求,请求会在后台线程执行,而主线程会继续加载界面、渲染按钮。这时候如果用户在网络请求还没完成(也就是onResponse还没执行、集合还没被填充)的时候点击按钮,miListaPartidos自然是空的,就会触发你看到的错误。
二、隐藏的坑:跨Activity传递对象集合会失败
你的Partido类没有实现序列化接口(Parcelable或Serializable),就算miListaPartidos被成功填充,通过Intent.putExtra传递的时候也会报错,因为Android要求跨组件传递的对象必须是可序列化的。
对应的解决方案
1. 解决异步加载导致的集合为空问题
有两种常用的处理方式,你可以选适合自己的:
方式一:数据加载完成前禁用按钮
在onCreate初始化按钮后,先把所有按钮设置为不可点击,等网络请求完成、集合填充完毕后再启用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_act1_1); // 初始化按钮 btns1=findViewById(R.id.btns1); btns2=findViewById(R.id.btns2); // ...其他按钮同理 btnE=findViewById(R.id.btnE); // 先禁用所有按钮 btns1.setEnabled(false); btns2.setEnabled(false); // ...其他按钮都设置setEnabled(false) btnE.setEnabled(false); getPartidos(); }
然后在getPartidos()的onResponse方法里,循环填充完集合后启用按钮:
public void getPartidos(){ RequestQueue requestQueue= Volley.newRequestQueue(this); JsonObjectRequest jSonObjectRequest=new JsonObjectRequest(Request.Method.GET,urlPartidos, null, new Response.Listener<JSONObject>(){ public void onResponse(JSONObject response){ try{ JSONArray jsonArrayPartidos=response.getJSONArray("results"); if(jsonArrayPartidos.length()>0) { for (int i = 0; i < jsonArrayPartidos.length(); i++) { JSONObject jsonPartido = jsonArrayPartidos.getJSONObject(i); final int id = jsonPartido.getInt("id"); final String detalles = jsonPartido.getString("details"); final String equipo1 = jsonPartido.getString("team1"); final String equipo2 = jsonPartido.getString("team2"); final int goles1 = jsonPartido.getInt("goals1"); final int goles2 = jsonPartido.getInt("goals2"); final Partido nuevoPartido = new Partido(id, detalles, equipo1, equipo2, goles1, goles2); miListaPartidos.add(nuevoPartido); } // 数据加载完成,启用所有按钮 btns1.setEnabled(true); btns2.setEnabled(true); // ...其他按钮同理 btnE.setEnabled(true); } } catch(JSONException je){ je.printStackTrace(); // 不要忽略异常,方便排查 } } }, new Response.ErrorListener() { public void onErrorResponse(VolleyError error) { error.printStackTrace(); // 打印错误日志 Toast.makeText(Act1_1.this, "数据加载失败,请检查网络", Toast.LENGTH_SHORT).show(); } } ); requestQueue.add(jSonObjectRequest); }
方式二:点击按钮时先判断集合状态
如果不想禁用按钮,可以在点击事件里先检查集合是否已加载完成,避免崩溃:
public void btnClick_Normal(View v){ // 先判断集合是否为空,或者长度是否满足后续循环的要求 if(miListaPartidos == null || miListaPartidos.size() < Integer.parseInt((String)v.getTag())*6){ Toast.makeText(this, "数据还在加载中,请稍等", Toast.LENGTH_SHORT).show(); return; } Intent intent=new Intent(getApplicationContext(),Act1_1_1.class); int id1=(Integer.parseInt((String)v.getTag())); ArrayList<Partido> listaEq=new ArrayList<>(); for(int i=(((id1-1)*6)); i<=(id1*6)-1;i++ ) { listaEq.add(miListaPartidos.get(i)); } intent.putExtra("listaEq", listaEq); startActivity(intent); }
2. 解决跨Activity传递对象集合的问题
推荐给Partido类实现Parcelable接口(比Serializable效率更高,更适合Android场景):
import android.os.Parcel; import android.os.Parcelable; public class Partido implements Parcelable { private int id; private String detalles; private String equipo1; private String equipo2; private int goles1; private int goles2; public Partido(int id, String detalles, String equipo1, String equipo2, int goles1, int goles2){ this.id=id; this.detalles=detalles; this.equipo1=equipo1; this.equipo2=equipo2; this.goles1=goles1; this.goles2=goles2; } // 从Parcel中读取数据的构造方法 protected Partido(Parcel in) { id = in.readInt(); detalles = in.readString(); equipo1 = in.readString(); equipo2 = in.readString(); goles1 = in.readInt(); goles2 = in.readInt(); } // Parcelable必须的CREATOR常量 public static final Creator<Partido> CREATOR = new Creator<Partido>() { @Override public Partido createFromParcel(Parcel in) { return new Partido(in); } @Override public Partido[] newArray(int size) { return new Partido[size]; } }; // 你的getter和setter方法保持不变 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getDetalles() { return detalles; } public void setDetalles(String detalles) { this.detalles = detalles; } public String getEquipo1() { return equipo1; } public void setEquipo1(String equipo1) { this.equipo1 = equipo1; } public String getEquipo2() { return equipo2; } public void setEquipo2(String equipo2) { this.equipo2 = equipo2; } public int getGoles1() { return goles1; } public void setGoles1(int goles1) { this.goles1 = goles1; } public int getGoles2() { return goles2; } public void setGoles2(int goles2) { this.goles2 = goles2; } // Parcelable接口要求实现的两个方法 @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(detalles); dest.writeString(equipo1); dest.writeString(equipo2); dest.writeInt(goles1); dest.writeInt(goles2); } }
之后在接收数据的Activity(比如Act1_1_1)里,这样获取集合:
ArrayList<Partido> listaEq = getIntent().getParcelableArrayListExtra("listaEq");
额外的优化建议
- 不要忽略异常和错误回调:在
JSONException和VolleyError的回调里添加printStackTrace()或者日志,方便你排查数据解析或网络问题。 - 可以添加一个
ProgressBar在界面上,网络请求时显示,请求完成后隐藏,提升用户体验。
内容的提问来源于stack exchange,提问作者Exiled Llama
相关产品推荐
相关产品推荐

