0

I am getting a null pointer exception (have tested 1 instead of i here)

This is the method

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

    }

This is where it is called from in separate activity

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

Here is the fill method, which is printing out the drivers names so appears to be filling the list, but then is null for some reason in my getLat method??

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

            }
        }); 

    }

NOTE When I pass it like this

intent.putStringArrayListExtra("arrayLat", arrayLat);

there is no problem using it in the other actvity like this

arrayLat = I.getStringArrayListExtra("arrayLat");

Although the values I use then in the next activity are stored values and do not update when my information(latitude) in firebase changes.

Thanks

2 Answers 2

1

The problem that is visible through naked eye, is that, the list is being populated in a listener or callback, and you are treating the whole thing as synchronous. Look over here

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

            }
        }); 

You are populating arrayLat inside onDataChange(DataSnapshot snapshot)

So, the fact is that since this is a callback the line arrayLat.get(i) is called even before the listener is fired and arrayLat is populated. Hope you got it. There are several ways to tackle this. You can create another interface to handle the callback or can directly write your code inside the callback. I will just write a simple solution. Change your code to this. First create an interface,

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

        }

Now change the other method to this.

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

    }

Now change

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

to this

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

The codes are directly written in SO, so there may be some syntax errors.

Sign up to request clarification or add additional context in comments.

4 Comments

What you are saying seems to make sense, thanks for the answer I have been stuck on this ages. Getting some errors with the code though. Few questions. The errors are on the last part of code you gave me, where I am creating appState. I need to create appState before I call appState.getLat(), I also need to change new SnapshotListener to Admin.snapshotListener or do I need to make the interface in a separate class?
The last part of code you have latString = arrayLat; But one is a String and one is an array so Im guessing you mean arrayLat.get(i) ? but that method doesnt return anything, and if i make it return something it still doesnt work
Sorry, I missed out that latString is a string. Yeah, you have to use latString = arrayLat.get(i). No need of separate class. You can do it, but it will work if you just create it anywhere in the class. I don't know your parent class name, if it is Admin, then of course Admin.SnapshotChangeListener. Since this entire thing is based on callbacks, i.e you are depending on a separate thread for its completion, you cannot return something. By proper code structuring, you won't need it. If a function returns something, it has to be synchronous. Are you getting my point?
Yes I think I understand, basically because it takes time to fill the arrays it is done async, So I cant call a sync (instant?) call to retrieve the array, i need to do that async too and complete whatever actions i need to use the array for async aswel? Think I have it working now, thanks so much
0

Driver Object have to check it

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.