Firebase/Android: добавление полученных значений из Firebase в arraylist возвращает исключение нулевого указателя

Я пытаюсь добавить полученные значения из базы данных Firebase в Arraylist и оттуда в массив String. Мой метод поиска работает нормально. Я могу распечатать все значения в тосте. Но, видимо, это не добавляется в arraylist.

Вот мой код для поиска в onActivityCreated() класса фрагмента.

ArrayList<String> allBrands = new ArrayList<>();
brandRef=FirebaseDatabase.getInstance().getReferenceFromUrl("https://stockmanager-142503.firebaseio.com/Brands");
        q=brandRef.orderByChild("brandName");
        q.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
               allBrands.add((dataSnapshot.getValue(Brand.class)).getBrandName());
                Toast.makeText(getActivity(),(dataSnapshot.getValue(Brand.class)).getBrandName(), Toast.LENGTH_SHORT).show();

            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

И именно здесь я пытаюсь использовать arrayList в методе OnActivityResult() класса Fragment, но я считаю, что цикл итератора не выполняется. Тост не виден. Я получаю исключение нулевого указателя при попытке работать с массивом. Я предполагаю, что значения не копируются в массив брендов.

count=allBrands.size();
                                String[] brands=new String[count];
                                Iterator<String> itemIterator = allBrands.iterator();
                                if(itemIterator.hasNext()){
                                    //brands[i] = itemIterator.next();
                                    Toast.makeText(getActivity(), itemIterator.next(), Toast.LENGTH_SHORT).show();
                                   // i++;

                                }
                               for( i=0;i<count;i++){
                                    if(brands[i].compareTo(Brand)==0){
                                        f=1;break;
                                    }
                                }

Вот моя база данных на случай, если это поможет. Но я могу распечатать все полученные значения в тосте без проблем.

База данных

2 ответа

Решение

Трудно быть уверенным в коде, которым вы поделились, я подозреваю, что вас может укусить тот факт, что все данные загружаются из Firebase асинхронно. В качестве альтернативы у вас может просто не быть разрешения на чтение данных. Я дам ответ для обоих.

Данные загружаются асинхронно

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

System.out.println("Before attaching listener");
q.addChildEventListener(new ChildEventListener() {
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        System.out.println("In onChildAdded");    
    }
    public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
    public void onChildRemoved(DataSnapshot dataSnapshot) { }
    public void onChildMoved(DataSnapshot dataSnapshot, String s) { }
    public void onCancelled(DatabaseError databaseError) { }
});
System.out.println("After attaching listener");

Результат этого фрагмента будет:

Перед прикреплением слушателя

После прикрепления слушателя

В onChildAdded (вероятно, несколько раз)

Вероятно, это не тот порядок, в котором вы ожидали вывод. Это потому, что Firebase (как и большинство облачных API-интерфейсов) загружает данные из базы данных асинхронно: вместо ожидания возврата данных он продолжает выполнять код в основном потоке и затем перезванивает в ваш ChildEventListener.onChildAdded когда данные доступны.

Там нет возможности ждать данных на Android. Если вы сделаете это, ваши пользователи получат всплывающее диалоговое окно "Приложение не отвечает", и ваше приложение будет уничтожено.

Таким образом, единственный способ справиться с асинхронной природой этого API - поместить код, который должен содержать новые данные, в onChildAdded() обратный вызов (и, вероятно, в другие обратные вызовы тоже в какой-то момент):

q.addChildEventListener(new ChildEventListener() {
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        allBrands.add((dataSnapshot.getValue(Brand.class)).getBrandName());  
        System.out.println(allBrands.length); 
    }

Вам нужно разрешение на чтение данных

Вам нужно разрешение на чтение данных из местоположения. Если у вас нет разрешения, Firebase немедленно отменит слушателя. Вы должны обработать это условие в своем коде, иначе вы никогда не узнаете.

public void onCancelled(DatabaseError databaseError) {
    throw databaseError.toException();
}

Попробуйте это (я пишу это для будущих ссылок на себя.. тоже)

Как видите, мы осуществляем обновление до его окончания. Есть, вероятно, более хороший способ сделать это. Тем не менее, это не задокументировано. Также все списки событий должны быть добавлены автоматически и автоматически выпущены firebase, но они не делают этого по какой-то причине.

/**
   * @param uid  User's ID
   * @param Callable send as null just to implement a call to assure the callback is updapted before it's finished
   * @return returns ArrayList of all Games unique identification key enlisted in a User
   */
  private final ArrayList<String> mGamesPlaying = new ArrayList<>();
  public ArrayList<String> mGamesPlaying(final String uid, final Callable refresh) {


    final Firebase ref = FirebaseRef;
    Firebase usersRef = ref.child("users").child(uid).child("playing_games");

    usersRef.addValueEventListener(new ValueEventListener() {
      @Override
      public void onDataChange(DataSnapshot snapshot) {

        mGamesPlaying.clear();
        for (DataSnapshot child : snapshot.getChildren()) {
          Log.d(TAG, "Test Game" + child.getKey());
          mGamesPlaying.add(child.getKey());
        }

          try {

            refresh.call();
          } catch (Exception e) {
            e.printStackTrace();
          }

      }

      @Override
      public void onCancelled(FirebaseError firebaseError) {
      }
    });

    return mGamesPlaying;
  }
Другие вопросы по тегам