Подождите, пока не будут получены данные Firestore для запуска действия
Я составил список объектов POJO, которые получают значения из моей облачной базы данных Firestore. Этот список сам по себе является классом, предназначенным для извлечения атрибутов каждый раз, когда я создаю новый список. Дело в том, что список заполняется не при выполнении действия "При создании", а через некоторое время. Я пробовал добавлять циклы, задачи, ожидания, но не получал желаемого результата. Вот как я удовлетворительно извлекаю свои данные.:
private void retrieveData(){
reference = firestore.collection("attractions");
reference.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots,
@Nullable FirebaseFirestoreException e) {
attractionList.clear();
for (DocumentSnapshot snapshot : queryDocumentSnapshots) {
Attraction attraction = snapshot.toObject(Attraction.class);
addAttractions(attraction);
}
}
});
}
Я извлекаю данные каждый раз, когда создаю новый объект:
public AttractionList() {
firestore.setFirestoreSettings(settings);
reference = firestore.collection("attractions");
attractionList = new ArrayList<>();
retrieveData();
}
Затем, если я проверю размер списка в своем действии при создании:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attraction);
Toolbar toolbar = findViewById(R.id.tb_attraction);
setSupportActionBar(toolbar);
//Creating POJO List and retrieving data
attractionList = new AttractionList();
Log.e("List Size: ", ""+attractionList.getAttractionList().size());
//List Size: 0
}
Но если я использую то же время регистрации после, в любой кнопке:
@Override
public void onBackPressed(){
Log.e("List Size: ", ""+attractionList.getAttractionList().size());
//List Size: 16
}
Я действительно не хочу извлекать данные в каждом отдельном действии или создавать намерения для переноса объекта между действиями. Есть какой-нибудь способ, которым я мог бы это исправить?
PS: Это мой первый пост. Извините, если я сделал это неправильно. Большое спасибо.
Переведено автоматически
Ответ 1
Вы не можете использовать сейчас что-то, что еще не было загружено. Firestore загружает данные asynchronously
, поскольку для этого может потребоваться некоторое время. В зависимости от скорости вашего соединения и состояния, может потребоваться от нескольких сотен миллисекунд до нескольких секунд, прежде чем эти данные станут доступны. Если вы хотите передать список объектов типа Attraction
другому методу, просто вызовите этот метод внутри onSuccess()
метода и передайте этот список в качестве аргумента. Итак, быстрое решение было бы следующим:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference attractionsRef = rootRef.collection("attractions");
attractionsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<Attraction> attractionsList = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()) {
Attraction attraction = document.toObject(Attraction.class);
attractionsList.add(attraction);
}
methodToProcessTheList(attractionsList);
}
}
});
Итак, помните, onSuccess()
метод имеет асинхронное поведение, что означает, что он вызывается еще до того, как вы получаете данные из своей базы данных. Если вы хотите использовать attractionsList
вне этого метода, вам нужно создать свой собственный callback
. Для достижения этой цели сначала вам нужно создать интерфейс, подобный этому:
public interface MyCallback {
void onCallback(List<Attraction> attractionsList);
}
Затем вам нужно создать метод, который фактически получает данные из базы данных. Этот метод должен выглядеть следующим образом:
public void readData(MyCallback myCallback) {
attractionsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<Attraction> attractionsList = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()) {
Attraction attraction = snapshot.toObject(Attraction.class);
attractionsList.add(attraction);
}
myCallback.onCallback(attractionsList);
}
}
});
}
В конце просто вызовите readData()
метод и передайте экземпляр MyCallback
интерфейса в качестве аргумента везде, где вам это нужно, вот так:
readData(new MyCallback() {
@Override
public void onCallback(List<Attraction> attractionsList) {
//Do what you need to do with your list
}
});
Это единственный способ, которым вы можете использовать этот метод attractionsList
object outside onSuccess()
. Для получения дополнительной информации вы также можете взглянуть на это видео.