Firebase/Android:将检索到的值从 Firebase 添加到 arraylist 会返回空指针异常

Posted

技术标签:

【中文标题】Firebase/Android:将检索到的值从 Firebase 添加到 arraylist 会返回空指针异常【英文标题】:Firebase/Android: Adding retrieved values from Firebase to arraylist returns null pointer exception 【发布时间】:2017-03-28 21:35:54 【问题描述】:

我正在尝试将检索到的值从 Firebase 数据库添加到 Arraylist 并从那里添加到 String 数组。我的检索方法工作正常。我可以在吐司中打印出所有值。但显然它没有被添加到数组列表中。

这是我在片段类的 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) 

            
        );

这就是我试图在 Fragment 类的 OnActivityResult() 方法中使用 arrayList 的地方,但我相信迭代器循环没有执行。没有看到吐司。尝试使用数组时出现空指针异常。我假设这些值不会被复制到品牌数组中。

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;
                                    
                                

这是我的数据库,以防万一。但我可以毫无问题地打印出 Toast 中所有检索到的值。

【问题讨论】:

【参考方案1】:

很难从您共享的代码中确定,我怀疑您可能会被所有数据都是从 Firebase 异步加载的事实所困扰。或者,您可能根本没有读取数据的权限。两者我都会给出答案。

数据是异步加载的

当您将一些日志语句添加到代码的最小 sn-p 中时,最容易理解这种行为:

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");

这个 sn-p 的输出将是:

附加监听器之前

附加监听器后

在 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();

【讨论】:

谢谢。是否可以将检索到的数据传递给 onActivityResult 方法?这样应用程序会等到检索完成,不是吗? 您可以在ChildEventListener 的方法中调用onActivityResult()。这些方法在主线程上调用。【参考方案2】:

试试这个(我写这个也是为了将来自己参考)

如您所见,我们在结束之前实施了重新刷新。可能有更好的方法来做到这一点。但是,它没有记录。此外,所有这些事件Listners都应该自动添加并由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;
  

【讨论】:

以上是关于Firebase/Android:将检索到的值从 Firebase 添加到 arraylist 会返回空指针异常的主要内容,如果未能解决你的问题,请参考以下文章

将从 spring-boot 检索到的数据转换为 JSON 并在 Angular 前端获取它

通过知道对象的值从对象中检索键[重复]

如何将变量的值从java类传递到jsp页面

将检索到的值与javascript和jquery结合起来[重复]

将检索到的值加载到 listView 时应用程序崩溃

如何连接从数据库中检索到的值[关闭]