Как заполнить Android ListView информацией из запроса Firebase

Это мой первый пост, поэтому, если я не следовал какому-то протоколу, который должен был, приношу свои извинения.

Я пытаюсь заполнить ListView некоторой информацией из моей базы данных Firebase. Я думаю, что проблема, с которой я сталкиваюсь, заключается в том, что запрос к базе данных слишком медленный (поток, вероятно, загружает изображения), и моя активность загружает свой макет активности, не дожидаясь завершения выполнения потока. (Если я пройду через отладчик и немного подожду, я в конце концов увижу информацию, которую анализирую: имена пользователей, номера пользователей и изображения пользователей). Все, что я запросил, предполагает, что для этого я должен использовать AsyncTask. В отличие от использования блокировки потоков или семафора, b/c AsyncTask является потокобезопасным.

Насколько я понимаю, запросы Firebase уже выполняются асинхронно; поэтому метод doInBackground для AsyncTask, который я «пытался» реализовать, кажется избыточным. Кроме того, меня немного смущает перегруженная подпись AsyncTask и вызов: new someTask.execute("что-то в строке").

Любые предложения о том, как я могу это сделать? Любая обратная связь очень ценится!

// Пожалуйста, не обращайте внимания на небольшой отступ от вставки моего кода в

protected void onCreate(Bundle savedInstanceState) {
    ...
    new getFirebaseInfoTask();
}

private class getFirebaseInfoTask extends AsyncTask {

    @Override
    protected Object doInBackground(Object... args) {
        // Do stuff
        userInfoList = GetUserInfoFromFirebase.getUserInfo();
        // Unsure if I need to return here.
        return userInfoList;
    }

    @Override
    protected void onProgressUpdate(Object... args) {
        // Update your UI here
        populateUserInfoList();
    }
}


private void populateUserInfoList() {
    // Create list of items
    Collections.addAll(userInfoList);
    populateFriendsListView();

}


private void populateFriendsListView() {
    // Build the adapter
    ArrayAdapter<UserInfo> adapter = new MyListAdapter();

    // Configure the list view
    ListView listView = (ListView) findViewById(R.id.friends_listview);
    listView.setAdapter(adapter);

    registerClickCallBack();
}

... // More code


public class GetUserInfoFromFirebase {

public static ArrayList getUserInfo() {
    final ArrayList<UserInfo> list = new ArrayList<UserInfo>();
    Firebase firebase = new Firebase("https:......firebaseio.com");
    firebase.child("users").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            HashMap<String, Object> users = (HashMap<String, Object>) snapshot.getValue();
            for(Object user : users.values()) {
                HashMap<String, Object> userMap = (HashMap<String, Object>) user;
                String userNumber = (String) userMap.remove("number");
                if(!list.contains(userNumber)) {
                    String name = (String) userMap.remove("username");
                    String pic = (String) userMap.remove("profile_picture");
                    UserInfo info = new UserInfo(userNumber, name, pic);
                    list.add(info);
                }
            }
        }
        @Override
        public void onCancelled(FirebaseError firebaseError) {}
    });
    return list;
}

person coreyshort    schedule 11.12.2014    source источник
comment
Итак, я понял это. Я избавился от AsyncTask и переместил вызов метода, который хотел выполнить в onProgressUpdate, за пределы цикла for моего onDataChange, чтобы поток, который фактически получает доступ к методу onDataChange, вызывал мой метод populateFriendsView.   -  person coreyshort    schedule 11.12.2014
comment
Приятно слышать, что вы поняли это, и спасибо за отчет. Можете ли вы предоставить эту информацию в качестве ответа (возможно, вам придется немного подождать, прежде чем вам будет разрешено это сделать)? Затем вы также можете принять свой собственный ответ, что поможет повысить вашу репутацию.   -  person Frank van Puffelen    schedule 11.12.2014
comment
Спасибо за отзыв @FrankvanPuffelen.   -  person coreyshort    schedule 14.12.2014
comment
У Firebase также есть библиотека ОС, которая автоматизирует заполнение ListView: github.com/firebase/firebaseui-android   -  person Kato    schedule 20.01.2016


Ответы (3)


Итак, я понял это. Я избавился от AsyncTask и переместил вызов метода, который хотел выполнить в onProgressUpdate, за пределы цикла for моего onDataChange, чтобы поток, который фактически получает доступ к методу onDataChange, вызывал мой метод populateFriendsView.

private void populateUserInfoList() {
    userInfoList = new ArrayList<UserInfo>();
    firebase = new Firebase("https://....firebaseio.com");
    firebase.child("users").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            HashMap<String, Object> users = (HashMap<String, Object>) snapshot.getValue();
            for (Object user : users.values()) {
                HashMap<String, Object> userMap = (HashMap<String, Object>) user;
                String userNumber = (String) userMap.remove("number");
                if (!userInfoList.contains(userNumber)) {
                    String name = (String) userMap.remove("username");
                    String pic = (String) userMap.remove("profile_picture");
                    UserInfo info = new UserInfo(userNumber, name, pic);
                    userInfoList.add(info);
                }
            }
            // thread executing here can get info from database and make subsequent call
            Collections.addAll(userInfoList); 
            populateFriendsListView();
        }
        @Override
        public void onCancelled(FirebaseError firebaseError) {
            String message = "Server error. Refresh page";
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        }
    });
}
person coreyshort    schedule 13.12.2014

Сама Firebase предоставляет асинхронные методы для запроса данных. Они создали образец приложения, чтобы показать, как создать резервную копию Listview с информацией Firebase через чат Android.

проверьте это

В этом примере основная функциональность размещена в универсальном базовом адаптере под названием FirebaseListAdapter...

person sivaram636    schedule 20.04.2015
comment
У меня не было возможности подробно рассмотреть это, однако, спасибо! Поскольку я, несомненно, скоро взгляну на это. Кроме того, что касается моего предыдущего решения, я пришел к пониманию, что было бы лучше использовать прослушиватель для условной переменной, чтобы точно сигнализировать о завершении асинхронного вызова Firebase. Это явно было бы лучшим решением, чем вложение вызовов моих методов. - person coreyshort; 24.04.2015

Фрагмент из моей рабочей базы кода

  Firebase firebase = new Firebase(Constants.FREEBASE_DB_URL);
  Firebase childRef = firebase.child("sessions");


  childRef.addValueEventListener(new ValueEventListener() {

                @Override
                public void onDataChange(DataSnapshot snapshot) {
                    System.out.println(snapshot.getValue());

                    Map<String, Session> td = (HashMap<String, Session>) snapshot.getValue();

                    List<Session> valuesToMatch = new ArrayList<Session>(td.values());

                    apiClientCallback.onSuccess(valuesToMatch);

                }

                @Override
                public void onCancelled(FirebaseError error) {

                    Toast.makeText(context, "onCancelled" + error.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
person Hitesh Sahu    schedule 10.06.2016
comment
Я получаю эту ошибку: `java.lang.ClassCastException: java.util.ArrayList не может быть приведен к java.util.HashMap` - person Hesam; 12.06.2016
comment
@ Хесам, ты сделал это. не могли бы вы помочь мне решить эту ошибку - person Nihal Singh; 07.10.2017