如何在onDataChange内填充ArrayList,该ArrayList用于更新Adapter。

huangapple go评论78阅读模式
英文:

How to populate ArrayList inside onDataChange , arraylist being used to update Adapter

问题

我陷入了一个困境,我必须通过Firebase实时数据库填充ArrayList,现在这返回一个ViewHolder,但由于onDataChange是异步的,在onDataChange完成数据填充之前调用getItemSize(),导致它返回0,因此onCreateViewHolder从未被调用。如何使Adapter等待直到从onDataChange中获取所有数据,或通知Adapter它需要刷新?注意:所有这些都发生在Adapter类内部。

我尝试过实现回调,但是该回调在getItemSize()之后也被调用。

以下是我代码的简要部分:

public class SubjectAdapter extends RecyclerView.Adapter<SubjectHolder> {
    public interface MyCallback {
        void onCallback(Subjects s);
    }
    //声明

    public SubjectAdapter(Context context) {
        //初始化
        populateList(new MyCallback() {
            @Override
            public void onCallback(Subjects s) {
                subjectsArrayList.add(s);
                Log.e("callback", s.toString());
            }
        });
        mContext = context;
    }

    public void populateList(final MyCallback myCallback) {
        final ArrayList<String> units = new ArrayList<String>();

        semesterInfoReference.child("1").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot dsa : dataSnapshot.getChildren()) {
                    String subjectCode = dsa.getKey();
                    for (DataSnapshot ds : dsa.getChildren()) {
                        SubjectObj subjectObj = ds.getValue(SubjectObj.class);
                        units.add("Unit I"); units.add("Unit II");
                        units.add("Unit III"); units.add("Unit IV");
                        Subjects s = new Subjects(subjectObj.getProfessorName(), subjectCode, subjectObj.getSubjectName(), units);
                        myCallback.onCallback(s);
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

        Log.e("holder", String.valueOf(subjectsArrayList.size()));
    }

    @Override
    public void onBindViewHolder(@NonNull SubjectHolder holder, int position, @NonNull List payloads) {
        super.onBindViewHolder(holder, position, payloads);
    }

    @NonNull
    @Override
    public SubjectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //一些代码
    }

    @Override
    public void onBindViewHolder(@NonNull SubjectHolder holder, int position) {
        //一些代码
    }

    @Override
    public int getItemCount() {
        //返回项目数
    }
}

希望这部分翻译能够满足您的需求。如果您有任何进一步的问题或需要帮助,请随时问我。

英文:

I am stuck in a situation, I have to get populate ArrayList by FirebaseRealtimeDatabase, now this returns a ViewHolder, but since onDataChange is Asynchronous , a call to getItemSize() is made before onDataChange has completed data population, leading it to returns 0, and hence onCreateViewHoldwer is never called. How to make Adapter to wait until all data from onDataChange is fetched or else notify Adapter that it needs to refresh??
Note: This all is happening inside Adapter class.

I tried implementing a callback, but that callback is also called after getItemSize()

Here is minmized higlight of my code

public class SubjectAdapter extends RecyclerView.Adapter&lt;SubjectHolder&gt; {
public interface MyCallback{
void onCallback(Subjects s);
}
//declarations
public SubjectAdapter(Context context) {
//initialisations
populateList(new MyCallback() {
@Override
public void onCallback(Subjects s) {
subjectsArrayList.add(s);
Log.e(&quot;callback&quot;,s.toString());
}
});
mContext=context;
}
public void populateList(final MyCallback myCallback){
final ArrayList&lt;String&gt; units=new ArrayList&lt;String&gt;();
semesterInfoReference.child(&quot;1&quot;).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot dsa:dataSnapshot.getChildren()) {
//Log.e(&quot;dsa&quot;,dsa.getValue().toString());
String subjectCode = dsa.getKey();
for(DataSnapshot ds:dsa.getChildren()) {
SubjectObj subjectObj = ds.getValue(SubjectObj.class);
units.add(&quot;Unit I&quot;);units.add(&quot;Unit II&quot;);
units.add(&quot;Unit III&quot;);units.add(&quot;Unit IV&quot;);
Subjects s = new Subjects(subjectObj.getProfessorName(), subjectCode, subjectObj.getSubjectName(), units);
myCallback.onCallback(s);
//subjectsArrayList.add(s);
//Log.e(&quot;subjectArrayLIst&quot;, subjectsArrayList.toString());
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
Log.e(&quot;holder&quot;, String.valueOf(subjectsArrayList.size()));
}
@Override
public void onBindViewHolder(@NonNull SubjectHolder holder, int position, @NonNull List payloads) {
super.onBindViewHolder(holder, position, payloads);
}
@NonNull
@Override
public SubjectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//something
}
@Override
public void onBindViewHolder(@NonNull SubjectHolder holder, int position) {
//something
}
@Override
public int getItemCount()

}

答案1

得分: 1

你不能让适配器等待异步操作。你可以选择延迟创建适配器(从而将加载数据的代码移到适配器之外),或者让适配器处理其数据异步加载的事实。

你可以通过在数据加载完成时通知适配器来实现后者:

SubjectAdapter adapter = this;
semesterInfoReference.child("1").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot dsa : dataSnapshot.getChildren()) {
            //Log.e("dsa", dsa.getValue().toString());
            String subjectCode = dsa.getKey();
            for (DataSnapshot ds : dsa.getChildren()) {
                SubjectObj subjectObj = ds.getValue(SubjectObj.class);
                units.add("Unit I");
                units.add("Unit II");
                units.add("Unit III");
                units.add("Unit IV");
                Subjects s = new Subjects(subjectObj.getProfessorName(), subjectCode, subjectObj.getSubjectName(), units);
                myCallback.onCallback(s);
            }
            adapter.notifyDataSetChanged();
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        throw databaseError.toException(); // 不要忽略错误
    }
});
英文:

You can't make the adapter wait for the asynchronous operation. You can either hold off on creating the adapter (and thus move the code that loads the data outside of the adapter), or make the adapter handle the fact that its data is loaded asynchronously.

The latter you do by notifying the adapter when the data loads:

SubjectAdapter adapter = this;
semesterInfoReference.child(&quot;1&quot;).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot dsa:dataSnapshot.getChildren()) {
//Log.e(&quot;dsa&quot;,dsa.getValue().toString());
String subjectCode = dsa.getKey();
for(DataSnapshot ds:dsa.getChildren()) {
SubjectObj subjectObj = ds.getValue(SubjectObj.class);
units.add(&quot;Unit I&quot;);units.add(&quot;Unit II&quot;);
units.add(&quot;Unit III&quot;);units.add(&quot;Unit IV&quot;);
Subjects s = new Subjects(subjectObj.getProfessorName(), subjectCode, subjectObj.getSubjectName(), units);
myCallback.onCallback(s);
}
adapter.notifyDataSetChanged();
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});

huangapple
  • 本文由 发表于 2020年5月4日 21:19:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/61593179.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定