我正在使用Socket.IO来发送和接收消息的聊天应用程序。我面临的问题是当用户向其他用户发送消息时,其消息在recyclerview内被填充两次。
My Fragment代码: -
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(""));
}
};
}
我的适配器类,我用它来扩充已发送和已接收消息的布局。
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);
}
}
}
我无法弄清楚为什么同样的邮件会从左侧填充发件人,这实际上仅用于接收邮件。
答案 0 :(得分:0)
此代码实际上很好,问题在于发送方和接收方的硬编码值以及它们的if和else条件.....对于动态用户ID,我们不会要求用户使用if和else条件。从...发送者的用户ID ....到接收者用户ID是admin。
答案 1 :(得分:0)
只需像这样更改你的代码
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;
}