0

Part 1- I have a method readData() which takes an argument of an Interface FirebaseCallBack. I am calling readData() within getAdminInfo() method and the Log.d statement (8th line) isn't getting executed. And my application is crashing with null pointer exception.

Part 2- Also firebaseCallback.Callback(newVolunteer) is throwing error "local variable is accessed from within inner class; needs to be declared final". But on this video of stack overflow user @Alex_mamo it didn't show any error. Just an intuition that I did something wrong.

public String getAdminInfo(){
    dbRef = FirebaseDatabase.getInstance().getReference("Volunteer");
    uid= mAuth.getCurrentUser().getUid();

    readData(new FirebaseCallBack() {
        @Override
        public void Callback(Volunteer data) {
            Log.d("crashfix" ," I am not executing ");
            adminStatus = data.isAdmin();
        }
    });
    return adminStatus;
}

//Read data from firebase
private void readData(FirebaseCallBack firebaseCallBack){
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            newVolunteer.setFullName((String) dataSnapshot.child("fullName").getValue());
            newVolunteer.setAdmin((String) dataSnapshot.child("admin").getValue());
            newVolunteer.setEmail((String) dataSnapshot.child("email").getValue());
            newVolunteer.setGender((String) dataSnapshot.child("gender").getValue());
            Log.d("crashfix" ," name fetch: " + newVolunteer.getFullName());
            firebaseCallBack.Callback(newVolunteer);
        }


        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    };

    dbRef.child(uid).addListenerForSingleValueEvent(valueEventListener);
}

//Wait till the data is downloaded from firebase
private interface FirebaseCallBack{
    void Callback(Volunteer data);
}

at this line I am getting null pointer exception:-

String admin = getAdminInfo();
    Log.d("crashfix" ,"inside onCreate admin" + admin);
    //checking if current user is admin
    if(admin.equals("true")){
            Toast.makeText(this,"Welcome! " + newVolunteer.getFullName() , Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(this, Main2Activity.class);
            startActivity(intent);
            finish();
    }

Crash Log:-

2020-03-30 13:41:53.060 13021-13021/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.helpinghandsorg.helpinghands, PID: 13021
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.helpinghandsorg.helpinghands/com.helpinghandsorg.helpinghands.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3123)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3266)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1957)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7099)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
    at com.helpinghandsorg.helpinghands.MainActivity.onCreate(MainActivity.java:57)
    at android.app.Activity.performCreate(Activity.java:7327)
    at android.app.Activity.performCreate(Activity.java:7318)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3103)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3266) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1957) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7099) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965) 

2 Answers2

1

The null pointer exception error is pretty self explanatory.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.helpinghandsorg.helpinghands/com.helpinghandsorg.helpinghands.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference

While you have not revealed the code where this happens, it seems that you are trying to invoke the equals method on a null reference of a string. I would make sure to check if that variable is indeed not null.

That is the reason you are not seeing the log, because your application is crashing.

For your second issue, when inside the onDataChange method, you cannot access a local variable and therefore you are seeing that error.

Consider creating a variable inside the method and passing it with a callback to where your other variable resides.

UPDATE (due to OP's comment)

In order to receive the updated value for admin information, you can do the following:

public String getAdminInfo(successCallback, failureCallback){
   dbRef = FirebaseDatabase.getInstance().getReference("Volunteer");
   uid= mAuth.getCurrentUser().getUid();

   readData(new FirebaseCallBack() {
    @Override
      public void Callback(Volunteer data) {
        Log.d("crashfix" ," I am not executing ");
        adminStatus = data.isAdmin();
        //Here is where you insert your callback
        successCallback(adminStatus);
      }
   });
   return adminStatus;
 }

Somewhere in your code:

getAdminInfo(gotAdminInfoSuccess, gotAdminInfoFailure);


private void gotAdminInfoSuccess(String adminState) {
     Log.d("crashfix" ,"inside onCreate admin" + admin);
    //checking if current user is admin
    if(adminState.equals("true")){
            Toast.makeText(this,"Welcome! " + newVolunteer.getFullName() , Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(this, Main2Activity.class);
            startActivity(intent);
            finish();
    }

}

 private void gotAdminInfoFailure(String error) {
    //Do your failure logic here

 } 
tomerpacific
  • 4,704
  • 13
  • 34
  • 52
  • I updated the question with the line causing null pointer exception. getAdminInfo() should not return null, it is fetching data from firebase which isn't null. – Vinay Kharayat Mar 30 '20 at 10:46
  • For part 2- The whole point of creating callback instance is to fetch data outside onDataChange. Consider watching video I provided, it will clear you. – Vinay Kharayat Mar 30 '20 at 10:48
  • @VinayKharayat - getAdminInfo is an asynchronous task and therefore, **you are NOT WAITING** for the result and that is why you have a null pointer exception... – tomerpacific Mar 30 '20 at 10:58
  • @VinayKharayat - I updated my answer. Since it helped you, please mark it as such. – tomerpacific Mar 30 '20 at 13:51
  • https://pastebin.com/raw/F60gWG7T this is what I wrote till now – Vinay Kharayat Mar 31 '20 at 07:28
  • @VinayKharayat - it did help, but your failure to understand, does not indicate that it is not useful. I would highly advise you to do some searching online, on how to pass functions as parameters. [This](https://stackoverflow.com/questions/16800711/passing-function-as-a-parameter-in-java) is just one example. – tomerpacific Mar 31 '20 at 07:37
0

The problem in your code lies in the fact that you are still trying to return a result from an asynchronous operation, which is not possible. The getAdminInfo() cannot return that result in a synchronous manner. Basically, you're trying to return a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.

That being said, the only option that you have is to use the adminStatus status only inside the readData() or onDataChange() method.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • This is what I did till now, could you please have a look at this. https://pastebin.com/raw/F60gWG7T – Vinay Kharayat Mar 31 '20 at 07:27
  • You should save `data.isAdmin()` into a variable and use it further for your logic but only inside `readData()` method. The other parts of your code looks good to me. – Alex Mamo Mar 31 '20 at 10:20