Dear Community,
finally found a promising forum for android. I apologize, if I post this one here wrong. My problem is, that I am getting a
I am also watching a tutorial to learn. When I implemented a "Delete your message in chat" function. The tutorial showed two versions. One, where you delete the message without leaving a text behind and second, where you leave a "Message deleted" text. I ran two tests with each version seperately, because of the tutorial ), they worked fine ) I liked the second version, so I've deleted the code for the first version ( only one line and the code just deletes message instead of replacing it ) but when I access the Chat Window/Layout it crashes, yesterday it worked fine. In the ChatActivity the "getReceiver" may produce a NullPointerException, it says. I really need help, because I cannot solve it.
finally found a promising forum for android. I apologize, if I post this one here wrong. My problem is, that I am getting a
com.example.networkusercommunication, PID: 20662 java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference at com.example.networkusercommunication.ChatActivity$5.onDataChange(ChatActivity.java:248)
I am also watching a tutorial to learn. When I implemented a "Delete your message in chat" function. The tutorial showed two versions. One, where you delete the message without leaving a text behind and second, where you leave a "Message deleted" text. I ran two tests with each version seperately, because of the tutorial ), they worked fine ) I liked the second version, so I've deleted the code for the first version ( only one line and the code just deletes message instead of replacing it ) but when I access the Chat Window/Layout it crashes, yesterday it worked fine. In the ChatActivity the "getReceiver" may produce a NullPointerException, it says. I really need help, because I cannot solve it.
Java:
package com.example.networkusercommunication;
import android.content.Intent;
import android.provider.ContactsContract;
import android.service.autofill.Dataset;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.networkusercommunication.adapter.AdapterChat;
import com.example.networkusercommunication.models.ModelChat;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class ChatActivity extends AppCompatActivity {
// views from xml
Toolbar toolbar;
RecyclerView recyclerView;
ImageView profileIv;
TextView nameTv, userStatusTv;
EditText messageEt;
ImageButton sendBtn;
//firebase auth
FirebaseAuth firebaseAuth;
FirebaseDatabase firebaseDatabase;
DatabaseReference usersDbRef;
// for checking if user has seen message or not
ValueEventListener seenListener;
DatabaseReference userRefForSeen;
List<ModelChat> chatList;
AdapterChat adapterChat;
String hisUid;
String myUid;
String hisImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
// init views
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("");
recyclerView = findViewById(R.id.chat_recyclerView);
profileIv = findViewById(R.id.profileIv);
nameTv = findViewById(R.id.nameTv);
userStatusTv = findViewById(R.id.userStatusTv);
messageEt = findViewById(R.id.messageEt);
sendBtn = findViewById(R.id.sendBtn);
// Layout ( LinearLayout ) for RecyclerView
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
// recyclerview properties
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
/* On clicking user from users list we have passed that user's UID using intent. So get that uid here to get the profile picture,
* name and start chat with user */
Intent intent = getIntent();
hisUid = intent.getStringExtra("hisUid");
// firebase auth instance
firebaseAuth = FirebaseAuth.getInstance();
firebaseDatabase = FirebaseDatabase.getInstance();
usersDbRef = firebaseDatabase.getReference("Users");
// search user to get that user's info
Query userQuery = usersDbRef.orderByChild("uid").equalTo(hisUid);
// get user picture and name
userQuery.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
// check until required info is received
for (DataSnapshot ds : dataSnapshot.getChildren()) {
// get data
String name = "" + ds.child("name").getValue();
hisImage = "" + ds.child("image").getValue();
String typingStatus = "" + ds.child("typingTo").getValue();
// check typing status
if (typingStatus.equals(myUid)) {
userStatusTv.setText("schreibt...");
} else {
// get value of onlineStatus
String onlineStatus = "" + ds.child("onlineStatus").getValue();
if (onlineStatus.equals("online")) {
userStatusTv.setText(onlineStatus);
} else {
// convert timestamp to proper time date
// convert time stamp to dd/mm/yyyy hh:mm am/pm
// Es gibt verschiedene Zeitstellungen ( auch Deutschland bzw. restliche Welt )
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
cal.setTimeInMillis(Long.parseLong(onlineStatus));
String dateTime = DateFormat.format("dd/MM/yyyy hh:mm aa", cal).toString();
userStatusTv.setText("Zuletzt online um: " + dateTime);
}
}
// set data
nameTv.setText(name);
try {
// image received, set it to imageview in toolbar
Picasso.get().load(hisImage).placeholder(R.drawable.ic_default_img_white).into(profileIv);
} catch (Exception e) {
// there is exception getting picture, set default picture
Picasso.get().load(R.drawable.ic_default_img_white).into(profileIv);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
// click button to send message
sendBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get text from edit text
String message = messageEt.getText().toString().trim();
// check if text is empty or not
if (TextUtils.isEmpty(message)) {
// text empty
Toast.makeText(ChatActivity.this, "Leere Nachricht kann nicht versenden werden", Toast.LENGTH_SHORT).show();
} else {
// text not empty
sendMessage(message);
}
}
});
// check edit text change listener
messageEt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().trim().length() == 0 ) {
checkTypingStatus("noOne");
} else {
checkTypingStatus(hisUid); // uid of receiver
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
readMessages();
seenMessage();
}
private void seenMessage() {
userRefForSeen = FirebaseDatabase.getInstance().getReference("Chats");
seenListener = userRefForSeen.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ModelChat chat = ds.getValue(ModelChat.class);
if ( chat.getReceiver().equals(myUid) && chat.getSender().equals(hisUid)) {
HashMap<String, Object> hasSeenHashMap = new HashMap<>();
hasSeenHashMap.put("isSeen", true);
ds.getRef().updateChildren(hasSeenHashMap);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
private void readMessages() {
chatList = new ArrayList<>();
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Chats");
dbRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
chatList.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ModelChat chat = ds.getValue(ModelChat.class);
if (chat.getReceiver().equals(myUid) ||
(chat.getReceiver().equals(hisUid) && chat.getSender().equals(myUid))) {
chatList.add(chat);
}
// adapter
adapterChat = new AdapterChat(ChatActivity.this, chatList, hisImage);
adapterChat.notifyDataSetChanged();
// set adapter to recyclerview
recyclerView.setAdapter(adapterChat);
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
private void sendMessage(String message) {
/* "Chats" node will be created, that will contain all chats. Whenever user
* sends message it will create a new child in "Chats" node and that child
* will contain the following key values.
* sender: UID of sender
* receiver: UID of receiver
* message: the actual message
*/
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
String timestamp = String.valueOf(System.currentTimeMillis());
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("sender", myUid);
hashMap.put("receiver", hisUid);
hashMap.put("message", message);
hashMap.put("timestamp", timestamp);
hashMap.put("isSeen", false);
databaseReference.child("Chats").push().setValue(hashMap);
// reset edittext after sending message
messageEt.setText("");
}
private void checkUserStatus() {
// get current user
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// user is signed in stay here
//set email of logged in user
//mProfileTv.setText(user.getEmail());
myUid = user.getUid(); // currently signed in user's uid
} else {
// user not signed in, go to main activity
startActivity(new Intent(this, MainActivity.class));
finish();
}
}
private void checkOnlineStatus(String status) {
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Users").child(myUid);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("onlineStatus", status);
// update value of onlineStatus of current user
dbRef.updateChildren(hashMap);
}
private void checkTypingStatus(String typing) {
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Users").child(myUid);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("typingTo", typing);
// update value of onlineStatus of current user
dbRef.updateChildren(hashMap);
}
@Override
protected void onStart() {
checkUserStatus();
// set online
checkOnlineStatus("online");
super.onStart();
}
@Override
protected void onPause() {
super.onPause();
// get timestamp
String timestamp = String.valueOf(System.currentTimeMillis());
// set offline with last seen time stamp
checkOnlineStatus(timestamp);
checkTypingStatus("noOne");
userRefForSeen.removeEventListener(seenListener);
}
@Override
protected void onResume() {
// set online
checkOnlineStatus("online");
super.onResume();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
// hide searchview, as we don't need it here
menu.findItem(R.id.action_search).setVisible(false);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_logout) {
firebaseAuth.signOut();
checkUserStatus();
}
return super.onOptionsItemSelected(item);
}
}
Java:
package com.example.networkusercommunication.models;
public class ModelChat {
String message, receiver, sender, timestamp;
boolean isSeen;
public ModelChat() {
}
public ModelChat(String message, String receiver, String sender, String timestamp, boolean isSeen) {
this.message = message;
this.receiver = receiver;
this.sender = sender;
this.timestamp = timestamp;
this.isSeen = isSeen;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public boolean isSeen() {
return isSeen;
}
public void setSeen(boolean seen) {
isSeen = seen;
}
}
Java:
package com.example.networkusercommunication.adapter;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.networkusercommunication.R;
import com.example.networkusercommunication.models.ModelChat;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import com.squareup.picasso.Picasso;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
public class AdapterChat extends RecyclerView.Adapter<AdapterChat.MyHolder> {
private static final int MSG_TYPE_LEFT = 0;
private static final int MSG_TYPE_RIGHT = 1;
Context context;
List<ModelChat> chatList;
String imageUrl;
FirebaseUser fUser;
public AdapterChat(Context context, List<ModelChat> chatList, String imageUrl) {
this.context = context;
this.chatList = chatList;
this.imageUrl = imageUrl;
}
@NonNull
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
// inflate layouts: row_chat_left.xml for receiver, row_chat_right.xml for sender
if (i == MSG_TYPE_RIGHT) {
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_right, viewGroup, false);
return new MyHolder(view);
} else {
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_left, viewGroup, false);
return new MyHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull MyHolder myHolder, final int i) {
// get data
String message = chatList.get(i).getMessage();
String timeStamp = chatList.get(i).getTimestamp();
// convert time stamp to dd/mm/yyyy hh:mm am/pm
// Es gibt verschiedene Zeitstellungen ( auch Deutschland bzw. restliche Welt )
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
cal.setTimeInMillis(Long.parseLong(timeStamp));
String dateTime = DateFormat.format("dd/MM/yyyy hh:mm aa", cal).toString();
// set data
myHolder.messageTv.setText(message);
myHolder.timeTv.setText(dateTime);
try {
Picasso.get().load(imageUrl).into(myHolder.profileIv);
} catch (Exception e) {
}
// click to show delete dialog
myHolder.messageLAyout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// show delete message confirm dialog
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Delete");
builder.setMessage("Are you sure to delete this message?");
// delete button
builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
deleteMessage(i);
}
});
// cancel delete button
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// dismiss dialog
dialog.dismiss();
}
});
// create and show dialog
builder.create().show();
}
});
// set seen/delivered status of message
if (i == chatList.size() - 1) {
if (chatList.get(i).isSeen()) {
myHolder.isSeenTv.setText("Gesehen");
} else {
myHolder.isSeenTv.setText("Versendet");
}
} else {
myHolder.isSeenTv.setVisibility(View.GONE);
}
}
private void deleteMessage(int position) {
final FirebaseUser myUID = FirebaseAuth.getInstance().getCurrentUser();
String msgTimeStamp = chatList.get(position).getTimestamp();
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Chats");
Query query = dbRef.orderByChild("timestamp").equalTo(msgTimeStamp);
query.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds:dataSnapshot.getChildren()) {
if (ds.child("sender").getValue().equals(myUID)) {
// Set value of message in "This message was deleted"
HashMap<String, Object > hashMap = new HashMap<>();
hashMap.put("message", "This message was deleted");
ds.getRef().updateChildren(hashMap);
Toast.makeText(context, "message deleted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Only your messages can be deleted", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
@Override
public int getItemCount() {
return chatList.size();
}
@Override
public int getItemViewType(int position) {
// get currently signed in user
fUser = FirebaseAuth.getInstance().getCurrentUser();
if (chatList.get(position).getSender().equals(fUser.getUid())) {
return MSG_TYPE_RIGHT;
} else {
return MSG_TYPE_LEFT;
}
}
// view holder class
class MyHolder extends RecyclerView.ViewHolder {
// views
ImageView profileIv;
TextView messageTv, timeTv, isSeenTv;
LinearLayout messageLAyout; // for click listener to show delete
public MyHolder(@NonNull View itemView) {
super(itemView);
// init views
profileIv = itemView.findViewById(R.id.profileIv);
messageTv = itemView.findViewById(R.id.messageTv);
timeTv = itemView.findViewById(R.id.timeTv);
isSeenTv = itemView.findViewById(R.id.isSeenTv);
messageLAyout = itemView.findViewById(R.id.messageLayout);
}
}
}
Last edited: