Firebase object access showing null pointer exception

Viewed 203

I am trying to output chat message text. But i am getting null pointer exception. Firebase structure looks lie below - enter image description here

public class ChatActivity extends AppCompatActivity {
    EditText chatEditText;
    ImageView sendImgView;
    TextView chatHolder;
    private DatabaseReference databaseReference;
    ArrayList<Chat> chatArrayList;
    ListView chatList;
    private ChatListAdapter chatListAdapter;

    private String currentUser;
    private String chatBuddy;
    private String msg, time;



    SimpleDateFormat formatter_from = new SimpleDateFormat("EEE MMM 
 dd hh:mm:ss ZZ yyyy");
    SimpleDateFormat formatter_to = new SimpleDateFormat("hh:mm");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);

        currentUser = getIntent().getStringExtra("currentUser");
        chatBuddy = getIntent().getStringExtra("chatBuddy");
        databaseReference = FirebaseDatabase.getInstance().getReference().child("chats");


        final Calendar cal = Calendar.getInstance();

        chatEditText = (EditText) findViewById(R.id.chatEditText);
        sendImgView = (ImageView) findViewById(R.id.sendButton);
        chatHolder = (TextView) findViewById(R.id.chatHolder);

        sendImgView = (ImageView) findViewById(R.id.sendButton);


        chatArrayList = new ArrayList<>();

        chatEditText = (EditText) findViewById(R.id.chatEditText);

        chatList = (ListView) findViewById(R.id.chatList);
        chatListAdapter = new ChatListAdapter(ChatActivity.this, R.layout.chatholder, chatArrayList);

        sendImgView.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                insertData();
                updateChatList();
            };

        });

    }

    public void onCancelled(@NonNull DatabaseError databaseError)
    {

        throw databaseError.toException();
    };
    public void insertData(){


databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    final Calendar cal = Calendar.getInstance();
                    String time = cal.getTime().toString();
                try {
                    Date d = formatter_from.parse(time);

                    Chat chat = new Chat(chatEditText.getText().toString(), formatter_to.format(d));
                    databaseReference.child(currentUser + "/" + currentUser + "_" + chatBuddy).push().setValue(chat);
                }catch (Exception ex){

                }
                    chatEditText.setText("");

            }

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

            }

        });

    }

    public void updateChatList(){

        databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot ds : dataSnapshot.getChildren()) {
                    ds.child(currentUser + "/" + currentUser + "_" + chatBuddy).getKey();
                    msg = ds.child("chatMsg").getValue(Chat.class).getChatMsg();
                    time = ds.child("chatTime").getValue(Chat.class).getChatTime();
                    Chat chatData = new Chat(msg,time);
                    chatArrayList.add(chatData);
                    chatListAdapter.notifyDataSetChanged();
                }
                chatList.setAdapter(chatListAdapter);

            }

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

            }
        });

    }

}

In above code currentUser is myself i.e Sakib and chatBuddy is a friend with whom i am chatting i.e sabir. Accordingly i am pushing data using below code -

Also please tell if database structure is valid or not or should i change the database structure. Error is as below

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.shaikhsakib.zimber, PID: 23261 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.shaikhsakib.zimber.Chat.getChatMsg()' on a null object reference at com.shaikhsakib.zimber.ChatActivity$3.onDataChange(ChatActivity.java:125) at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@19.2.0:179) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@19.2.0:75) at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@19.2.0:63) at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@19.2.0:55) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) I/Process: Sending signal. PID: 23261 SIG: 9

1 Answers

When you are using the following reference:

databaseReference = FirebaseDatabase.getInstance().getReference().child("chats");

And you are iterating through the DataSnapshot using:

for (DataSnapshot ds : dataSnapshot.getChildren()) { /* ... */ }

It means that you are trying to get all children beneath the node where the reference is pointing to. When you try to get deeper in the database tree using:

ds.child(currentUser + "/" + currentUser + "_" + chatBuddy).getKey();

You aren't going to get any results because according to the official documentation regarding the DataSnapshot class:

They have efficiently generated immutable copies of the data at a Firebase Database location.

This means that each time you make a .child() call, the initial object becomes a new DataSnapshot object. So to solve this, you need to store the result in a variable like this:

DataSnapshot snapshot = ds.child(currentUser + "/" + currentUser + "_" + chatBuddy);
time = snapshot.child("chatTime").getValue(Chat.class).getChatTime();

However, this is not the efficent way you should go ahead with because attaching a listener on the chats node, means that you get all children beneath that node, which is very costly. What you should do, is to attach a listener directly to the node you are interested in getting the children. So please use the following lines of code:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference currentUserChatBuddyRef = rootRef.child("chats").child(currentUser).child(currentUser + "_" + chatBuddy);
currentUserChatBuddyRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DataSnapshot> task) {
        if (task.isSuccessful()) {
            for (DataSnapshot ds : task.getResult().getChildren()) {
                Chat chat = ds.getValue(Chat.class);
                Log.d("TAG", chat.getChatMsg());
            }
        } else {
            Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
        }
    }
});

The result in the logcat will be:

thanks for your time
thanks again
Related