Android Studio Firebase DataChange 异步和捆绑问题 (Java)
当我从 Firebase 实时数据库调用时,onDataChange
方法遇到了某些问题。这些问题包括数据在 DataChange 方法之外消失。我尝试了此链接的解决方案, 如何返回 DataSnapshot 值作为方法?,它已经起作用了,但是,当我尝试将它传递给回调方法中的片段包时,它说值是 null 并且其中没有任何数据。对于我面临的这个问题有什么解决方法吗?非常感谢帮助,谢谢!
import edu.ntu.ssp4_rzdns_outhink.R;
import edu.ntu.ssp4_rzdns_outhink.modals.Attraction;
public class MostPopularRecyclerViewAdapter extends RecyclerView.Adapter<MostPopularRecyclerViewAdapter.ViewHolder>{
private static final String TAG = "MostPopularRecyclerViewAdapter";
private static final String SHARED_PREFS = "attractionsFile";
private ArrayList<Attraction> pops;
private Attraction attraction;
private Context mContext;
private FragmentManager fm;
private Bundle bundle;
SharedPreferences.Editor editor;
SharedPreferences attractionFile;
public MostPopularRecyclerViewAdapter(ArrayList<Attraction> pops, Context mContext, FragmentManager fm, Bundle bundle) {
this.pops = pops;
this.mContext = mContext;
this.fm = fm;
this.bundle = bundle;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "OnCreateViewHolder Called");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_more_list, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder Called");
Glide.with(mContext).asBitmap().load(pops.get(position).photo_url).into(holder.attractionImage);
holder.locationName.setText(pops.get(position).att_name);
holder.locationRating.setText(pops.get(position).att_rating.toString());
holder.locationAddress.setText(pops.get(position).att_address);
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String attraction_id = pops.get(holder.getBindingAdapterPosition()).id;
readData(new FirebaseCallback() {
@Override
public void onCallBack(Attraction attr) {
bundle.putString("attid", attr.id);
bundle.putString("name", attr.att_name);
bundle.putString("address", attr.att_address);
bundle.putString("desc", attr.att_desc);
bundle.putDouble("rating", attr.att_rating);
bundle.putString("url", attr.att_url);
bundle.putSerializable("ophrs", attr.att_op_hr);
bundle.putSerializable("adminrate",attr.att_admin_rate);
bundle.putString("photo_url", attr.photo_url);
}
},attraction_id);
}
});
}
@Override
public int getItemCount() {
return pops.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
ImageView attractionImage;
TextView locationName;
TextView locationAddress;
TextView locationRating;
RelativeLayout parentLayout;
public ViewHolder(@NonNull View itemView){
super(itemView);
attractionImage = itemView.findViewById(R.id.viewmoreImage);
locationName = itemView.findViewById(R.id.viewmoreName);
locationAddress = itemView.findViewById(R.id.viewmoreLocation);
locationRating = itemView.findViewById(R.id.viewmoreRating);
parentLayout = itemView.findViewById(R.id.parent_layout_view_more);
}
}
private void readData(FirebaseCallback firebaseCallback, String attrId){
Query query = FirebaseDatabase.getInstance().getReference("attractions");
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (!snapshot.exists()) {
System.out.println("Attraction Does Not Exist");
} else {
for (DataSnapshot attr : snapshot.getChildren()) {
if (attr.getKey().equals(attrId)) {
attraction = attr.getValue(Attraction.class);
attraction.setId(attr.getKey());
}
}
firebaseCallback.onCallBack(attraction);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private interface FirebaseCallback{
void onCallBack(Attraction attraction);
}
}
I have been getting certain issues with the onDataChange
method when I am calling from Firebase Realtime Database. These issues would include data disappearing outside of the DataChange method. I tried a solution from this link,
How to return DataSnapshot value as a result of a method?, it has worked, however, when I tried passing it to a fragment bundle within the callback method, it says the values are null and there isn't any data in it. Is there any workaround for this problem that I am facing? Help is really appreciated, thanks!
import edu.ntu.ssp4_rzdns_outhink.R;
import edu.ntu.ssp4_rzdns_outhink.modals.Attraction;
public class MostPopularRecyclerViewAdapter extends RecyclerView.Adapter<MostPopularRecyclerViewAdapter.ViewHolder>{
private static final String TAG = "MostPopularRecyclerViewAdapter";
private static final String SHARED_PREFS = "attractionsFile";
private ArrayList<Attraction> pops;
private Attraction attraction;
private Context mContext;
private FragmentManager fm;
private Bundle bundle;
SharedPreferences.Editor editor;
SharedPreferences attractionFile;
public MostPopularRecyclerViewAdapter(ArrayList<Attraction> pops, Context mContext, FragmentManager fm, Bundle bundle) {
this.pops = pops;
this.mContext = mContext;
this.fm = fm;
this.bundle = bundle;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Log.d(TAG, "OnCreateViewHolder Called");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_more_list, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder Called");
Glide.with(mContext).asBitmap().load(pops.get(position).photo_url).into(holder.attractionImage);
holder.locationName.setText(pops.get(position).att_name);
holder.locationRating.setText(pops.get(position).att_rating.toString());
holder.locationAddress.setText(pops.get(position).att_address);
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String attraction_id = pops.get(holder.getBindingAdapterPosition()).id;
readData(new FirebaseCallback() {
@Override
public void onCallBack(Attraction attr) {
bundle.putString("attid", attr.id);
bundle.putString("name", attr.att_name);
bundle.putString("address", attr.att_address);
bundle.putString("desc", attr.att_desc);
bundle.putDouble("rating", attr.att_rating);
bundle.putString("url", attr.att_url);
bundle.putSerializable("ophrs", attr.att_op_hr);
bundle.putSerializable("adminrate",attr.att_admin_rate);
bundle.putString("photo_url", attr.photo_url);
}
},attraction_id);
}
});
}
@Override
public int getItemCount() {
return pops.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder{
ImageView attractionImage;
TextView locationName;
TextView locationAddress;
TextView locationRating;
RelativeLayout parentLayout;
public ViewHolder(@NonNull View itemView){
super(itemView);
attractionImage = itemView.findViewById(R.id.viewmoreImage);
locationName = itemView.findViewById(R.id.viewmoreName);
locationAddress = itemView.findViewById(R.id.viewmoreLocation);
locationRating = itemView.findViewById(R.id.viewmoreRating);
parentLayout = itemView.findViewById(R.id.parent_layout_view_more);
}
}
private void readData(FirebaseCallback firebaseCallback, String attrId){
Query query = FirebaseDatabase.getInstance().getReference("attractions");
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (!snapshot.exists()) {
System.out.println("Attraction Does Not Exist");
} else {
for (DataSnapshot attr : snapshot.getChildren()) {
if (attr.getKey().equals(attrId)) {
attraction = attr.getValue(Attraction.class);
attraction.setId(attr.getKey());
}
}
firebaseCallback.onCallBack(attraction);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private interface FirebaseCallback{
void onCallBack(Attraction attraction);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据你最后的评论:
请注意,这是预期的行为。您的代码中存在多个不一致之处。首先,这不是您在适配器类中处理单击事件的方式。将点击侦听器附加到显示的每个元素并不是一个可行的解决方案。您应该为此创建一个接口,如您在 repo。
现在,每次单击 RecyclerView 中的特定元素时,都会调用
readData()
方法。当您收到数据时,将该数据添加到捆绑包中。问题在于打开新片段的操作发生的速度比从数据库获取数据的速度快。这就是你变得 null 的原因。为了解决这个问题,您可以仅在数据可用时导航到下一个片段,或者可以直接从第二个片段进行另一个调用。
According to your last comment:
Please note that this is the expected behavior. There are multiple inconsistencies in your code. First of all, that's not how you should handle the click event in your adapter class. Attaching a click listener to each element you display, isn't a feasible solution. You should create an interface for that as you can see in this repo.
Now, each time you click a particular element in your RecyclerView, you call the
readData()
method. When you receive the data, you add that data to the Bundle. The problem is that the operation that is opening the new fragment is happening faster than you get the data from the database. That's the reason why you are getting null.To solve this, you either navigate to the next fragment, only when the data is available or you can make another call, right from the second fragment.