问题
I am working on chat application which uses Socket.IO for sending and receiving messages.Problem which i am facing is when a user send a message to other user,its message gets populated twice inside recyclerview.
My Fragment code :-
public class ChatFragment extends Fragment {
private static final String TAG = "MainFragment";
private static final int REQUEST_LOGIN = 0;
private static final int TYPING_TIMER_LENGTH = 600;
private RecyclerView mMessagesView;
private EditText mInputMessageView;
private ArrayList<Message> mMessages = new ArrayList<Message>();
private RecyclerView.Adapter mAdapter;
private boolean mTyping = false;
private Handler mTypingHandler = new Handler();
private String mUsername = "";
private Socket mSocket;
String myId ="abc";
String friendId = "xyz";
private Boolean isConnected = true;
public ChatFragment() {
super();
}
boolean isUser1 = false; // make false for user 2
@Override
public void onAttach(Context context) {
super.onAttach(context);
mAdapter = new MessageAdapter(mMessages, context);
if (context instanceof Activity) {
}
}
public String getSendMessageString(String message) {
try {
JSONObject jsonObject = new JSONObject();
if (isUser1) {////User 1
jsonObject.put("from", myId);
jsonObject.put("to", friendId);
} else {
jsonObject.put("to", friendId);
jsonObject.put("from", myId);
}
jsonObject.put("room", "vamediabox");
jsonObject.put("username", mUsername);
jsonObject.put("messageType", "1"); //1: text message 2: multimedia message
jsonObject.put("msg", message);
jsonObject.put("page", 1);
return jsonObject.toString();
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mUsername = isUser1? "Himanshu" : "Danish";
ChatApplication app = (ChatApplication) getActivity().getApplication();
mSocket = app.getSocket();
mSocket.on(Socket.EVENT_CONNECT, onConnect);
mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.on("new message", onNewMessage);
mSocket.on("user joined", onUserJoined);
mSocket.on("user left", onUserLeft);
mSocket.on("typing", onTyping);
mSocket.on("stop typing", onStopTyping);
mSocket.connect();
// startSignIn();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_chat, container, false);
}
@Override
public void onDestroy() {
super.onDestroy();
mSocket.disconnect();
mSocket.off(Socket.EVENT_CONNECT, onConnect);
mSocket.off(Socket.EVENT_DISCONNECT, onDisconnect);
mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.off("new message", onNewMessage);
mSocket.off("user joined", onUserJoined);
mSocket.off("user left", onUserLeft);
mSocket.off("typing", onTyping);
mSocket.off("stop typing", onStopTyping);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMessagesView = (RecyclerView) view.findViewById(R.id.rv_messages);
mMessagesView.setLayoutManager(new LinearLayoutManager(getActivity()));
mMessagesView.setAdapter(mAdapter);
mInputMessageView = (EditText) view.findViewById(R.id.et_message);
mInputMessageView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int id, KeyEvent event) {
if (id == R.id.send || id == EditorInfo.IME_NULL) {
attemptSend();
return true;
}
return false;
}
});
mInputMessageView.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 (null == mUsername) return;
if (!mSocket.connected()) return;
if (!mTyping) {
mTyping = true;
mSocket.emit("typing", getSendMessageString(""));
}
mTypingHandler.removeCallbacks(onTypingTimeout);
mTypingHandler.postDelayed(onTypingTimeout, TYPING_TIMER_LENGTH);
}
@Override
public void afterTextChanged(Editable s) {
}
});
Button sendButton = (Button) view.findViewById(R.id.btn_send);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
attemptSend();
}
});
}
private void addLog(String message) {
mMessages.add(new Message.Builder(Message.TYPE_LOG)
.message(message).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
private void addParticipantsLog(int numUsers) {
addLog(getResources().getQuantityString(R.plurals.message_participants, numUsers, numUsers));
}
private void addMessage(String username, String message , String sender) {
if(myId == sender){
mMessages.add(new Message.Builder(Message.SENDER)
.username(username).message(message).userId(sender).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}else{
mMessages.add(new Message.Builder(Message.RECEIVER)
.username(username).message(message).userId(sender).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
}
private void addTyping(String username) {
mMessages.add(new Message.Builder(Message.TYPE_ACTION)
.username(username).build());
mAdapter.notifyItemInserted(mMessages.size() - 1);
scrollToBottom();
}
private void removeTyping(String username) {
for (int i = mMessages.size() - 1; i >= 0; i--) {
Message message = mMessages.get(i);
if (message.getType() == Message.TYPE_ACTION && message.getUsername().equals(username)) {
mMessages.remove(i);
mAdapter.notifyItemRemoved(i);
}
}
}
private void attemptSend() {
if (null == mUsername) return;
if (!mSocket.connected()) return;
mTyping = false;
String message = mInputMessageView.getText().toString().trim();
if (TextUtils.isEmpty(message)) {
mInputMessageView.requestFocus();
return;
}
mInputMessageView.setText("");
addMessage(mUsername, message,myId);
// perform the sending message attempt.
mSocket.emit("new message", getSendMessageString(message));
}
private void leave() {
mUsername = null;
mSocket.disconnect();
mSocket.connect();
// startSignIn();
}
private void scrollToBottom() {
mMessagesView.scrollToPosition(mAdapter.getItemCount() - 1);
}
private Emitter.Listener onConnect = new Emitter.Listener() {
@Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isConnected) {
if (null != mUsername)
mSocket.emit("add user", getSendMessageString(""));
mSocket.emit("messages by page no", getSendMessageString(""));
Toast.makeText(getActivity().getApplicationContext(),
R.string.connect, Toast.LENGTH_LONG).show();
isConnected = true;
}
}
});
}
};
private Emitter.Listener onDisconnect = new Emitter.Listener() {
@Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "diconnected");
isConnected = false;
Toast.makeText(getActivity().getApplicationContext(),
R.string.disconnect, Toast.LENGTH_LONG).show();
}
});
}
};
private Emitter.Listener onConnectError = new Emitter.Listener() {
@Override
public void call(Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e(TAG, "Error connecting");
Toast.makeText(getActivity().getApplicationContext(),
R.string.error_connect, Toast.LENGTH_LONG).show();
}
});
}
};
private Emitter.Listener onNewMessage = new Emitter.Listener() {
@Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
String message;
String sender;
try {
username = data.getString("username");
message = data.getString("message");
sender = data.getString("sender");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
removeTyping(username);
if (myId == sender){
}else{
addMessage(username,message,sender);
}
}
});
}
};
private Emitter.Listener onUserJoined = new Emitter.Listener() {
@Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
int numUsers;
try {
username = data.getString("username");
numUsers = data.getInt("numUsers");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addLog(getResources().getString(R.string.message_user_joined, username));
addParticipantsLog(numUsers);
}
});
}
};
private Emitter.Listener onUserLeft = new Emitter.Listener() {
@Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
int numUsers;
try {
username = data.getString("username");
numUsers = data.getInt("numUsers");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addLog(getResources().getString(R.string.message_user_left, username));
addParticipantsLog(numUsers);
removeTyping(username);
}
});
}
};
private Emitter.Listener onTyping = new Emitter.Listener() {
@Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
try {
username = data.getString("username");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
addTyping(username);
}
});
}
};
private Emitter.Listener onStopTyping = new Emitter.Listener() {
@Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
String username;
try {
username = data.getString("username");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
return;
}
removeTyping(username);
}
});
}
};
private Runnable onTypingTimeout = new Runnable() {
@Override
public void run() {
if (!mTyping) return;
mTyping = false;
mSocket.emit("stop typing", getSendMessageString(""));
}
};
}
My Adapter Class which i am using to inflate the layouts for the sent and received messages.
public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
ArrayList<Message> arrayList;
Context context;
private int SENDER = Message.SENDER;
private int RECEIVER = Message.RECEIVER;
private final int TYPE_LOG = Message.TYPE_LOG;
private final int TYPE_ACTION = Message.TYPE_ACTION;
public MessageAdapter(ArrayList<Message> arrayList, Context context) {
this.arrayList = arrayList;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = null;
RecyclerView.ViewHolder vh = null;
if (viewType == TYPE_LOG || viewType == TYPE_ACTION)
{
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false);
vh = new LogMessageHolder(v);
} else {
if (viewType == SENDER) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message, parent, false);
vh = new SenderMessageHolder(v);
}else{
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message1, parent, false);
vh = new ReceiverMessageHolder(v); }
}
return vh;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Calendar currnetDateTime = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("HH:mm a");
String currentTime = df.format(currnetDateTime.getTime());
if (holder.getItemViewType() == TYPE_LOG || holder.getItemViewType() == TYPE_LOG) {
((LogMessageHolder) holder).log_msg.setText(arrayList.get(position).getMessage());
}
else {
if (holder.getItemViewType() == SENDER) {
((SenderMessageHolder) holder).txt_send_msg.setText(arrayList.get(position).getMessage());
((SenderMessageHolder) holder).send_time.setText(currentTime);
} else
{
// (holder.getItemViewType() == RECEIVER){
((ReceiverMessageHolder) holder).txt_recei_msg.setText(arrayList.get(position).getMessage());
((ReceiverMessageHolder) holder).recei_time.setText(currentTime);
}
}
}
@Override
public int getItemCount() {
return arrayList == null ? 0 : arrayList.size();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
if(arrayList.get(position).getType() == TYPE_LOG || arrayList.get(position).getType() == TYPE_ACTION ){
return TYPE_LOG;
}
else {
if (arrayList.get(position).getType() == SENDER){
return SENDER;
}
else {
return RECEIVER;
}
}
}
private class SenderMessageHolder extends RecyclerView.ViewHolder {
TextView txt_send_msg, send_time;
public SenderMessageHolder(View itemView) {
super(itemView);
txt_send_msg = (TextView) itemView.findViewById(R.id.txt_sender_msg);
send_time = (TextView) itemView.findViewById(R.id.txt_sender_time);
}
}
private class ReceiverMessageHolder extends RecyclerView.ViewHolder {
TextView txt_recei_msg, recei_time;
public ReceiverMessageHolder(View itemView) {
super(itemView);
txt_recei_msg = (TextView) itemView.findViewById(R.id.txt_recei_msg);
recei_time = (TextView) itemView.findViewById(R.id.txt_recei_time);
}
}
private class LogMessageHolder extends RecyclerView.ViewHolder {
TextView log_msg;
public LogMessageHolder(View itemView) {
super(itemView);
log_msg= (TextView) itemView.findViewById(R.id.message);
}
}
}
I am not able to figure out why the same message is getting populated for the sender that too from the left side which is actually meant for received messages only.
Here is the screenshot of the chat window.
回答1:
This code is actually fine the problem was with the hardcoded values of sender and receiver and their if and else condition .....with dynamic userid's we will not require if and else condition for the user ...it will be simple from ...sender's user id ....to receiver user id which is admin.
回答2:
just change your code like this
public String getSendMessageString(String message) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("from", sender id);
jsonObject.put("to", receiver id);
jsonObject.put("room", "vamediabox");
jsonObject.put("username", mUsername);
jsonObject.put("messageType", "1"); //1: text message 2: multimedia message
jsonObject.put("msg", message);
jsonObject.put("page", 1);
return jsonObject.toString();
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
来源:https://stackoverflow.com/questions/48644218/data-inside-recyclerview-is-getting-populated-twice-using-socket-io