ArrayList add() 有时不会将从 Firebase 获取的元素添加到 ArrayList
Posted
技术标签:
【中文标题】ArrayList add() 有时不会将从 Firebase 获取的元素添加到 ArrayList【英文标题】:ArrayList add() sometimes does not add element obtained from Firebase to ArrayList 【发布时间】:2020-09-27 00:20:15 【问题描述】:所以,我正在尝试创建一个 listView 来显示已设置约会的房间。问题是在某些情况下,此类房间和约会日期不会添加到 ArrayLists 中。我必须不断地打开和关闭活动才能获得确实添加并显示在 ListView 中的情况。
// Global variables
ArrayList<Room> rooms = new ArrayList<>();
ArrayList<String> dates = new ArrayList<>();
private DatabaseReference appointmentsRef;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_history);
// Other stuff
appointmentsRef= FirebaseDatabase.getInstance().getReference();
appointmentsRef.child("appointment").addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
for(final DataSnapshot snapshot : dataSnapshot.getChildren())
final Appointment cita = snapshot.getValue(Appointment.class);
FirebaseDatabase.getInstance().getReference().child("room").addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot dS)
for(DataSnapshot ss : dS.getChildren())
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID()))
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
@Override
public void onCancelled(@NonNull DatabaseError databaseError)
Log.e("Canceled","Cancelled appointment loop");
);
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
@Override
public void onCancelled(@NonNull DatabaseError databaseError)
Log.e("Canceled","Cancelled room loop");
代码总是通过 if 条件,输出如下所示,但 ArrayLists 在日志文件中显示为空。
E/Rooms: []
E/Dates: []
E/Pass: Room 1b845370-39d0-4e35-9e15-b9eaf6d556b5 in appointment 1803b7a8-7cfc-4c43-8bad-573868d174f5 rented room 1b845370-39d0-4e35-9e15-b9eaf6d556b5
E/Pass: Room 6640904b-edc6-4b1e-b636-a68cb72241ad in appointment a206e8f5-76e3-40cc-91de-e64a976691e9 rented room 6640904b-edc6-4b1e-b636-a68cb72241ad
更新:我移动了在 if 语句后打印 ArrayLists 的 Log.e 作为回答。事实上,ArrayLists 从来都不是空的,那么为什么这些房间和日期没有显示在活动的列表视图中呢?
// Inside onCreate before appointmentsRef
ListView lv = findViewById(R.id.listViewHistory);
// after appointmentsRef
HistoryAdapter adapter = new HistoryAdapter(this, R.layout.history_adapter_view,rooms,dates);
lv.setAdapter(adapter);
历史适配器:
public class HistoryAdapter extends ArrayAdapter<Room>
private static final String TAG = "HistoryAdapter";
private Context mContext;
private int mResource;
//ViewHolder object
ViewHolder holder;
ArrayList<String> appointments;
private static class ViewHolder
TextView title;
TextView location;
TextView price;
TextView date;
ImageView image;
public HistoryAdapter(Context context, int resource, ArrayList<Room> objects,ArrayList<String> dates)
super(context, resource, objects);
mContext = context;
mResource = resource;
this.appointments = dates;
@NonNull
public View getView(int position, View convertView, ViewGroup parent)
//sets up the image loader library
setupImageLoader();
//get the Appointment information
// String currentUser = ""+ FirebaseAuth.getInstance().getCurrentUser().getUid();
//String day = "placeholder";
String day = appointments.get(position);
String title = getItem(position).getTitle();
String location = getItem(position).getLocation();
String price = "$"+getItem(position).getPrice();
String imgUrl = getItem(position).getPhoto();
Log.e("Position","Posición : "+ position);
//create the view result for showing the animation
final View result;
if(convertView == null)
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
holder= new HistoryAdapter.ViewHolder();
holder.title = convertView.findViewById(R.id.tvTitle);
holder.location = convertView.findViewById(R.id.tvLocation);
holder.price = convertView.findViewById(R.id.tvPrice);
holder.date = convertView.findViewById(R.id.tvDate);
holder.image = convertView.findViewById(R.id.image);
result = convertView;
convertView.setTag(holder);
else
holder = (HistoryAdapter.ViewHolder) convertView.getTag();
result = convertView;
// Animation animation = AnimationUtils.loadAnimation(mContext,
// (position > lastPosition) ? R.anim.load_down_anim : R.anim.load_up_anim);
//result.startAnimation(animation);
holder.title.setText(title);
holder.location.setText(location);
holder.price.setText(price);
holder.date.setText(day);
//create the imageloader object
ImageLoader imageLoader = ImageLoader.getInstance();
;
int defaultImage = mContext.getResources().getIdentifier("@drawable/logo_size",null,mContext.getPackageName());
//create display options
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheInMemory(true)
.cacheOnDisc(true).resetViewBeforeLoading(true)
.showImageForEmptyUri(defaultImage)
.showImageOnFail(defaultImage)
.showImageOnLoading(defaultImage).build();
//download and display image from url
imageLoader.displayImage(imgUrl, holder.image, options);
return convertView;
/**
* Required for setting up the Universal Image loader Library
*/
private void setupImageLoader()
// UNIVERSAL IMAGE LOADER SETUP
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheOnDisc(true).cacheInMemory(true)
.imageScaleType(ImageScaleType.EXACTLY)
.displayer(new FadeInBitmapDisplayer(300)).build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
mContext)
.defaultDisplayImageOptions(defaultOptions)
.memoryCache(new WeakMemoryCache())
.discCacheSize(100 * 1024 * 1024).build();
ImageLoader.getInstance().init(config);
// END - UNIVERSAL IMAGE LOADER SETUP
【问题讨论】:
您正在通过检查 if 条件“if(room.getId().equals(cita.getRoomID()))”来添加元素,您应该调试代码并在通过条件后检查您是否元素是否添加。我确信原因是你的条件。 好吧,你们对 Log.e 显示 emtpy arrayList 是正确的,因为它是异步更新的。我在 if 之后移动了它们,现在它显示确实有房间和日期添加到 ArrayList 中,那么为什么有时这些 ArrayLists 中的值没有显示在 Activity 的 ListView 中?如果我应该添加额外的代码块,请现在告诉我。 【参考方案1】:您的问题是您的 if
语句在 onDataChanged
方法中运行,该方法是异步的,并且将在不同的线程中运行。
换句话说,您将首先addValueEventListener
,然后代码将立即移至下一行代码,您将在其中记录列表。
如果您将日志移动到内部onDataChanged()
内的if
语句之后,您将看到它按预期工作。
【讨论】:
确实是这样,谢谢大家。至于为什么 ListView 是空的,那是因为 adapter.notifyDataSetChanged();需要在向 ArrayLists 添加值后调用。 我正忙着写一个解释这个的答案!很高兴你解决了它:)【参考方案2】:您正在子“房间”上添加 ValueEventListener ,然后调用 Log.e("Rooms", rooms.toString());
和 Log.e("Dates", dates.toString());
,但是将来更改数据时将调用以下函数。这就是房间和日期都是空的原因。
@Override
public void onDataChange(@NonNull DataSnapshot dS)
for(DataSnapshot ss : dS.getChildren())
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID()))
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
修改如下函数,然后查看输出:
@Override
public void onDataChange(@NonNull DataSnapshot dS)
for(DataSnapshot ss : dS.getChildren())
Room room = ss.getValue(Room.class);
if(room.getId().equals(cita.getRoomID()))
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + " rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
Log.e("Rooms", rooms.toString());
Log.e("Dates", dates.toString());
【讨论】:
【参考方案3】:ArrayList 是异步更新的。即使记录其内容的代码低于更新它们的代码,它实际上是首先运行的,而它们仍然是空的。如果您需要在更新后使用它们,请将您的代码放在回调中,如下所示:
for(DataSnapshot ss : dS.getChildren())
Room room = ss.getValue(Room.class);
if (room.getId().equals(cita.getRoomID()))
Log.e("Pass", "Room " + room.getId() + " in appointment " + cita.getId() + "
rented room " + cita.getRoomID());
rooms.add(room);
dates.add(cita.getDate());
// at this point rooms and dates have been populated. place code that needs
// to work with these populated ArrayLists here.
【讨论】:
以上是关于ArrayList add() 有时不会将从 Firebase 获取的元素添加到 ArrayList的主要内容,如果未能解决你的问题,请参考以下文章
ArrayList 使用 forEach 遍历时删除元素会报错吗?
java基础之ArrayList 和VectorCopyOnWriteArrayList