【问题标题】:Android with Firebase - NullPointerException when trying to populate list带有 Firebase 的 Android - 尝试填充列表时出现 NullPointerException
【发布时间】:2017-08-18 21:54:35
【问题描述】:

我得到一个空指针异常(这里测试了 1 而不是 i)

这是方法

   public String getLat(int i) {
        fillDriverList();
        arrayLat.get(i);
        return"0.000";

    }

这是在单独的活动中调用它的地方

 AdminActivity appState = new AdminActivity();
                latString = appState.getLat(i);

这是填充方法,它打印出驱动程序名称,因此似乎正在填充列表,但由于某种原因在我的 getLat 方法中为空??

public void fillDriverList() {

        //Creating firebase object
        Firebase ref = new Firebase(Config.FIREBASE_URL);   

        //adding a value event listener so if data in database changes it does in textview also not needed at the minute
        ref.child("Driver").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snapshot) {
                arrayLat = new ArrayList<String>();

                for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                    Driver d = postSnapshot.getValue(Driver.class);

                    System.out.println("data snapshot Drivers name is -------------------> "+d.getName());

                    arrayLat.add(Double.toString(d.getLat()));


                }

            }

            /************had to implement this method****************/
            @Override
            public void onCancelled(FirebaseError firebaseError) {
                System.out.println("The read failed: " + firebaseError.getMessage());

            }
        }); 

    }

注意 当我像这样通过它时

intent.putStringArrayListExtra("arrayLat", arrayLat);

在这样的其他活动中使用它没有问题

arrayLat = I.getStringArrayListExtra("arrayLat");

虽然我在下一个活动中使用的值是存储值,并且当我在 firebase 中的信息(纬度)发生变化时不会更新。

谢谢

【问题讨论】:

    标签: java android android-studio firebase firebase-realtime-database


    【解决方案1】:

    驱动对象必须检查它

                for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                    Driver d = postSnapshot.getValue(Driver.class);
                    if(d!=null ){
                        arrayLat.add(Double.toString(d.getLat()));
                    }
                }
    

    【讨论】:

      【解决方案2】:

      肉眼可见的问题是,列表正在填充到侦听器或回调中,并且您将整个事情视为同步。 看这里

      ref.child("Driver").addValueEventListener(new ValueEventListener() {
                  @Override
                  public void onDataChange(DataSnapshot snapshot) {
                      arrayLat = new ArrayList<String>();
      
                      for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                          Driver d = postSnapshot.getValue(Driver.class);
      
                          System.out.println("data snapshot Drivers name is -------------------> "+d.getName());
      
                          arrayLat.add(Double.toString(d.getLat()));
      
      
                      }
      
                  }
      
                  /************had to implement this method****************/
                  @Override
                  public void onCancelled(FirebaseError firebaseError) {
                      System.out.println("The read failed: " + firebaseError.getMessage());
      
                  }
              }); 
      

      您正在 onDataChange(DataSnapshot 快照) 中填充 arrayLat

      因此,事实是,由于这是一个回调,因此即使在触发侦听器并填充 arrayLat 之前,也会调用行 arrayLat.get(i)。希望你明白了。 有几种方法可以解决这个问题。 您可以创建另一个接口来处理回调,也可以直接在回调中编写代码。我只会写一个简单的解决方案。 将您的代码更改为此。 首先创建一个接口,

      public interface SnapshotListener{
          void onListFilled(ArrayList<String> arrayLat);
          void onFailure();
      }
          public void getLat(int i, SnapshotListener listener) {
                  fillDriverList(listener);
                  //arrayLat.get(i);
                  //return"0.000";
      
              }
      

      现在把其他方法改成这个。

      public void fillDriverList(SnapshotListener listener) {
      
              //Creating firebase object
              Firebase ref = new Firebase(Config.FIREBASE_URL);   
      
              //adding a value event listener so if data in database changes it does in textview also not needed at the minute
              ref.child("Driver").addValueEventListener(new ValueEventListener() {
                  @Override
                  public void onDataChange(DataSnapshot snapshot) {
                      arrayLat = new ArrayList<String>();
      
                      for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                          Driver d = postSnapshot.getValue(Driver.class);
      
                          System.out.println("data snapshot Drivers name is -------------------> "+d.getName());
      
                          arrayLat.add(Double.toString(d.getLat()));
      
      
                      }
                      if(listener != null){
                          listener.onListFilled(arrayLat);
                      }
      
                  }
      
                  /************had to implement this method****************/
                  @Override
                  public void onCancelled(FirebaseError firebaseError) {
                      System.out.println("The read failed: " + firebaseError.getMessage());
                   if(listener != null){
                          listener.onFailure();
                      }
                  }
              }); 
      
          }
      

      现在改变

      AdminActivity appState = new AdminActivity();
                      latString = appState.getLat(i);
      

      到这里

      appState.getLat(i, new SnapshotListener{
        public void onListFilled(ArrayList<String> arrayLat){
          AdminActivity appState = new AdminActivity();
                          latString = arrayLat;
      }
          public void onFailure(){
           //go crazy
      }
      });
      

      代码是直接用SO写的,所以可能会有一些语法错误。

      【讨论】:

      • 你所说的似乎有道理,感谢我一直坚持这个年龄的答案。虽然代码出现了一些错误。几个问题。错误出现在你给我的代码的最后一部分,我正在这里创建 appState。我需要在调用 appState.getLat() 之前创建 appState,还需要将新的 SnapshotListener 更改为 Admin.snapshotListener 还是需要在单独的类中创建接口?
      • 你拥有的代码的最后一部分 latString = arrayLat;但是一个是字符串,一个是数组,所以我猜你的意思是 arrayLat.get(i) ?但是那个方法没有返回任何东西,如果我让它返回一些东西它仍然不起作用
      • 对不起,我错过了 latString 是一个字符串。是的,你必须使用 latString = arrayLat.get(i)。不需要单独上课。你可以这样做,但如果你只是在课堂上的任何地方创建它,它就会起作用。我不知道你的父类名,如果是Admin,那么当然是Admin.SnapshotChangeListener。由于这整个事情都是基于回调的,即你依赖一个单独的线程来完成它,你不能返回一些东西。通过适当的代码结构,您将不需要它。如果一个函数返回一些东西,它必须是同步的。你明白我的意思了吗?
      • 是的,我想我明白了,基本上是因为它需要时间来填充数组它是异步完成的,所以我不能调用同步(即时?)调用来检索数组,我需要异步也完成我需要使用数组进行异步 aswel 的任何操作?我想我现在可以工作了,非常感谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 2018-07-12
      • 2013-04-08
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      相关资源
      最近更新 更多