ArrayList未更新DataSnapshots对象,onCreate触发IndexOutOfBound异常求助
为什么从Firebase DataSnapshot获取的对象没加入ArrayList,还在onCreate末尾抛出IndexOutOfBounds异常?
这问题我见太多了——核心原因就是Firebase数据库的回调是异步执行的,你踩了异步操作的经典坑!
先给你拆解一下代码的执行顺序:
- 你在
onCreate里初始化了空的ArrayList<Question>。 - 你调用Firebase的
addValueEventListener(或者addListenerForSingleValueEvent)请求数据,这个方法会立刻返回,不会等数据加载完成。 - 代码直接跳到
onCreate的最后一行,此时onDataChange还没被执行过——你的ArrayList还是空的!这时候你要是去访问列表里的元素,比如questions.get(0),必然会抛出IndexOutOfBoundsException。 - 等Firebase从服务器(或本地缓存)拿到数据后,才会触发
onDataChange回调,这时候你创建的Question对象才会被添加到ArrayList里——所以你在回调里操作对象是完全正常的,但这时候onCreate早就跑完了。
举个直观的代码例子,你大概是这么写的:
ArrayList<Question> questions = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DatabaseReference questionRef = FirebaseDatabase.getInstance().getReference("questions"); questionRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // 这部分代码是异步执行的,onCreate结束后才会跑到这里! for (DataSnapshot snap : dataSnapshot.getChildren()) { Question q = snap.getValue(Question.class); questions.add(q); // 这里打印的话,能看到questions确实有数据 Log.d("Firebase", "Added question: " + q.getTitle()); } } @Override public void onCancelled(DatabaseError databaseError) { // 别忽略错误处理! Log.e("Firebase", "Load failed", databaseError.toException()); } }); // 这里是onCreate的最后一行,此时onDataChange还没执行,questions是空的! Question firstQuestion = questions.get(0); // 崩溃就在这儿! }
怎么解决?
所有依赖这个ArrayList数据的操作,必须放在onDataChange回调内部,或者从回调里调用专门处理数据的方法。比如把UI更新、数据处理的逻辑移到回调里:
@Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot snap : dataSnapshot.getChildren()) { Question q = snap.getValue(Question.class); questions.add(q); } // 数据加载完成后,再去处理它 processLoadedQuestions(); } private void processLoadedQuestions() { if (!questions.isEmpty()) { Question firstQ = questions.get(0); // 这里可以安全地使用数据,比如更新RecyclerView适配器、显示内容等 yourAdapter.notifyDataSetChanged(); } else { // 处理空数据的情况,比如显示"暂无题目" } }
记住:Firebase的数据库操作不会阻塞主线程(不然APP会卡顿),所以代码不会等数据加载完再往下走。你得把所有需要用数据的逻辑,都放到数据准备好的那个时机——也就是onDataChange触发的时候。
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

