Android: пользовательский ListView заполняется не сразу - PullRequest
0 голосов
/ 05 апреля 2020

Я хотел бы создать собственный ListView, заполненный пользовательским ArrayAdapter. Код работает нормально, но ListView не показывает данные сразу. Чтобы отобразить данные, мне нужно нажать на произвольный текст редактирования на той же странице, закрыть клавиатуру и волшебным образом ListView показывает данные. Я не знаю, может ли это оказать влияние, но адаптер используется во фрагменте, который извлекает данные из Firebase во время метода OnCreate. Ниже моего кода я удалил все ненужное для этой топи c и упростил массив.

Это мой класс элементов внутри массива:

public class ListItem {

private String Description;
private String Price;

public ListItem (String Description, String Price) {
    this.Description = Description;
    this.Price = Price;
}

public String getDescription() { return Description; }

public String getPrice() {
    return Price;
}

public void setDescription(String description) {
    Description = description;
}

public void setPrice(String price) {
    Price = price;
}

}

Адаптер следующий :

public class CustomListAdapter extends ArrayAdapter<ListItem> {

private Context mContext;
private Integer mResource;

private static class ViewHolder {
    TextView txt_description_item;
    TextView txt_price_item;
}

public CustomListAdapter(@NonNull Context context, int resource, @NonNull ArrayList<ListItem> objects) {
    super(context, resource, objects);
    mContext = context;
    mResource = resource;
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

    String Description = getItem(position).getDescription();
    String Price = getItem(position).getPrice();

    LayoutInflater inflater = LayoutInflater.from(mContext);
    convertView = inflater.inflate(mResource, parent, false);

    ViewHolder viewHolder = new ViewHolder();

    viewHolder.txt_description_item = convertView.findViewById(R.id.txt_description_item);
    viewHolder.txt_price_item = convertView.findViewById(R.id.txt_price_item);

    viewHolder.txt_description_item.setText(Description);
    viewHolder.txt_price_item.setText(Price);

    return convertView;
}

}

Наконец, это код фрагмента:

public class MyFragment extends Fragment {

private ListView view_list_items;
private FirebaseDatabase database;
private DatabaseReference refDatabase;
private static final String USER = "user";

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    final View v = inflater.inflate(R.layout.fragment_myprofile, container, false);
    view_list_items = v.findViewById(R.id.list_items);

    database = FirebaseDatabase.getInstance();
    refDatabase = database.getReference(USER);

    refDatabase.child("items").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            final ArrayList<ListItem> arr_items = new ArrayList<>();

            for (DataSnapshot ds : dataSnapshot.child("itemlist1").getChildren()) {
                final String description = ds.getKey();
                final String price = ds.getValue(String.class);

                ListItem listItem = new ListItem(description,price);
                arr_items.add(listItem);
            }

            CustomListAdapter adapter = new CustomListAdapter(getContext(),R.layout.layout_myItemList, arr_items);               
            view_list_items.setAdapter(adapter);
        }

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

        }
    });



}

РЕДАКТИРОВАТЬ : я решил проблему, установив адаптер в цикле «for». Возможно, это не самое элегантное решение, но оно отлично работает

for (DataSnapshot ds : dataSnapshot.child("itemlist1").getChildren()) {
                final String description = ds.getKey();
                final String price = ds.getValue(String.class);

                ListItem listItem = new ListItem(description,price);
                arr_items.add(listItem);

                CustomListAdapter adapter = new 
                CustomListAdapter(getContext(),R.layout.layout_myItemList, arr_items);               
                view_list_items.setAdapter(adapter);
            }

1 Ответ

1 голос
/ 05 апреля 2020

База данных firebase является асинхронной, т. Е. Компилятор не ждет, пока код внутри onDataChange () или onCancelled () вернет значение. Он немедленно вернет все значения, кроме тех, которые находятся внутри этих двух методов, а для этих двух методов он вернет значение, когда значение будет доступно из базы данных. Приведенный ниже код может помочь вам лучше понять

 refDatabase.child("items").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            System.out.println("Inside onDataChange method");
        }

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

        }
    });
System.out.println ("Outside onDataChange method");

Вывод будет выглядеть следующим образом:

Outside onDataChange method
Inside onDataChange method

Обратите внимание, что Outside onDataChange method сначала. Это причина, почему ваш listView не показывает данные сразу. Чтобы удержать пользователя вовлеченным, вы можете добавить в свое представление счетчик, который будет виден до тех пор, пока данные не будут извлечены из базы данных. Для этого попробуйте этот код.

        database = FirebaseDatabase.getInstance();
        refDatabase = database.getReference(USER);
        spinner.setVisibility(View.VISIBLE);

        refDatabase.child("items").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                spinner.setVisibility(View.INVISIBLE);
                //Your code goes here
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                //Error code goes here
            }
        });
...