[Android通信]基于socket的聊天app(四):实现一对一通信

要实现一对一通信,要解决两个问题:


1.发送消息时,要找到对方在服务器端的socket,然后在输出流输出消息。这样,对方的客户端输入流就会收到消息了。所以问题就是如何找到对方在服务器端的socket。

解决方法:在客户端登录时将服务器端socket和账号关联起来,用一个HashMap存储起来。当发送消息时,同时发送对方的账号就可以了。


2.接受消息时,要把消息显示在相应的窗口中。群聊的消息不能出现在通信双方的聊天窗口那里,而通信双方的消息也不能出现在群聊的窗口里。当消息送到对方的客户端时,对方可能已经打开了多个聊天窗口,那么就要解决消息要送到哪个窗口。

解决方法:每条聊天消息包含三部分内容,fromID,content,toID,表示发送方,内容,接受方,而每个聊天窗口有一个toID,且在打开时初始化,表示在这个窗口输入的东西会发给谁。这样就可以让聊天窗口挑选信息进行显示了。


同时,还有注意的是,因为app中有多个聊天窗口,在退出某个聊天窗口时,消息记录肯定是不能删除的,所以这里我选择了fragment,退出聊天窗口时隐藏即可。

由于截图不能说明些啥,所以没了!这里给出核心代码:

服务器端:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket; 

import org.json.JSONException;
import org.json.JSONObject;

public class ChatSocket extends Thread{
	
	private Socket socket;
	private BufferedWriter bWriter;
	private BufferedReader bReader;
	
	public ChatSocket (Socket socket) {
		this.socket = socket;
		try {
			bWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"));
			bReader = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}

	public void out(String s) 
	{
		s += "\n";
		try {
			bWriter.write(s);
			bWriter.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
	
	@Override
	public void run() 
	{
		try 
		{
			String s;		
			while ((s = bReader.readLine()) != null) 
			{
				try 
				{
					JSONObject root = new JSONObject(s);
					if(root.has("content")) 
					{
						String toID = root.getString("toID");
						if(toID.equalsIgnoreCase("Group"))
						{
							ChatManager.getChatManager().publish(this, s);
						}
						else 
						{
							ChatSocket cs = ChatManager.getChatManager().hashMap.get(toID);
							if(cs != null)
							{
								cs.out(s);
							}
							else 
							{	
								System.out.println("没有该用户" + toID);	
							}
						}
					}
					else if(root.has("user") && root.has("password")) 
					{
						JSONObject a = new JSONObject();
						if(root.getString("user").equalsIgnoreCase(root.getString("password"))) 
						{
							if(!ChatManager.getChatManager().hashMap.containsKey("user"))
							{
								a.put("result", true);
								ChatManager.getChatManager().hashMap.put(root.getString("user"), this);
								System.out.println("用户" + root.getString("user") + "上线了!!");
							}
							else 
							{
								a.put("result", false);
							}
						}
						else 
						{
							a.put("result", false);
						}
						out(a.toString());
					}
				}
				catch (JSONException e)
				{
					e.printStackTrace();
				}			
			}
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}
}

客户端:

package com.example.mysocketclient;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import com.example.mysocketclient.LoginActivity.MessageReceiver;

import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.app.FragmentManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
import android.widget.Toast;

public class ChooseChatFragment extends Fragment implements OnClickListener,OnItemClickListener{
	
	private TextView textView;
	private EditText editText;
	private Button buttonAdd;
	private Button buttonGroup;
	
	private ListView listView;
	private FriendEntityViewAdapter adapter;
	private List<FriendEntity> list;
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		
		View view = inflater.inflate(R.layout.fragment_choose_chat, container, false);
		textView = (TextView)view.findViewById(R.id.titleText);
		editText = (EditText)view.findViewById(R.id.editText);
		buttonAdd = (Button)view.findViewById(R.id.buttonAdd);
		buttonGroup = (Button)view.findViewById(R.id.buttonGroup);
		listView = (ListView)view.findViewById(R.id.listview);
		
		textView.setText(UserInfo.getID() + "的通讯录");
		buttonAdd.setOnClickListener(this);
		buttonGroup.setOnClickListener(this);
		listView.setOnItemClickListener(this);
		
		list = new ArrayList<FriendEntity>();
		adapter = new FriendEntityViewAdapter(getActivity(), list);
		listView.setAdapter(adapter);
		
		return view;
	}

	@Override
	public void onClick(View v) {
		if(v.getId() == R.id.buttonAdd)
		{
			if(editText.getText().toString() != null)
			{
				FriendEntity fe = new FriendEntity();
				fe.setID(editText.getText().toString());
				
				list.add(fe);
				adapter.notifyDataSetChanged();//通知ListView,数据已发生改变
				listView.setSelection(listView.getCount() - 1);//发送一条消息时,ListView显示选择最后一项
				
				editText.setText("");
			}		
		}
		else if(v.getId() == R.id.buttonGroup)
		{		
			toChatFragment("Group");
		}	
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) 
	{
		toChatFragment(list.get(position).getID());
	}
	
	private void toChatFragment(String tag)
	{
		FragmentManager fm = getFragmentManager();
		FragmentTransaction tx = fm.beginTransaction(); 
		tx.hide(this);
		//保证只初始化一次
		//这里ChatFragment作为一个Fragment,有一个tag,方便Fragment之间的切换
		//同时ChatFragment作为一个聊天窗口,也有一个tag,表示跟谁的聊天,如tag为11,表示跟11的聊天
		//这样ChatFragment在接受信息时只接受跟自己tag相等的,就可以将对应的信息显示在对应的窗口
		if(fm.findFragmentByTag(tag) == null)
		{
			tx.add(R.id.content, new ChatFragment(tag), tag);
		}
		else 
		{  
	        tx.show(fm.findFragmentByTag(tag));
		}        
        tx.addToBackStack(null);
        tx.commit();
	}
}

package com.example.mysocketclient;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.R.bool;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ChatFragment extends Fragment implements OnClickListener{

	private EditText editText;
	private Button sendButton;
	private Button backButton;
	private TextView titleText;
	
	private ListView listView;
	private ChatMsgListViewAdapter adapter;
	private List<ChatMsgEntity> list;

	private String toID;//表示跟谁聊天的窗口
	private MessageReceiver messageReceiver;
	
	public ChatFragment(String toID)
	{
		this.toID = toID;
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.fragment_chat, container, false);
		editText = (EditText)view.findViewById(R.id.editText);
		sendButton = (Button)view.findViewById(R.id.btn_send);
		backButton = (Button)view.findViewById(R.id.btn_back);
		titleText = (TextView)view.findViewById(R.id.title);
		listView = (ListView)view.findViewById(R.id.listview);
		
		sendButton.setOnClickListener(this);
		backButton.setOnClickListener(this);
		titleText.setText("跟" + toID + "的聊天");
		
		list = new ArrayList<ChatMsgEntity>();
		adapter = new ChatMsgListViewAdapter(getActivity(), list);
		listView.setAdapter(adapter);
		
		initMessageReceiver();
		return view;
	}
	
	@Override
	public void onClick(View v) {
		if(v.getId() == R.id.btn_send) {
			send();
		}
		else if(v.getId() == R.id.btn_back) {
			FragmentManager fm = getFragmentManager();  
	        FragmentTransaction tx = fm.beginTransaction();  
	        tx.hide(this);
	        tx.show(fm.findFragmentByTag("ChooseChatFragment"));
	        tx.commit();
		}
	}
	
	private void send()
	{
		String content = editText.getText().toString();
		if(content.length() > 0) {
			ChatMsgEntity entity = new ChatMsgEntity();
			entity.setName(UserInfo.getID());
			entity.setDate(getDate());
			entity.setMessage(content);
			entity.setMsgType(true);
			
			list.add(entity);
			adapter.notifyDataSetChanged();//通知ListView,数据已发生改变
			listView.setSelection(listView.getCount() - 1);//发送一条消息时,ListView显示选择最后一项
			
			editText.setText("");
			
			try {
				JSONObject root = new JSONObject();
				root.put("content", content);
				root.put("fromID", UserInfo.getID());
				root.put("toID", toID);
				SocketService.send(root.toString());
			} catch (JSONException e) {
				e.printStackTrace();
			}	
		}	
	}
	
	private String getDate() 
	{
		long time = System.currentTimeMillis();;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date d = new Date(time);  
        return format.format(d);  
    } 
	
	private void initMessageReceiver()
	{
		messageReceiver = new MessageReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("SocketClient");
        getActivity().registerReceiver(messageReceiver,filter);
	}
	
//	@Override
//	public void onDestroy() {
//		super.onDestroy();
//		unregisterReceiver(messageReceiver);
//		stopService(new Intent(this,SocketService.class));
//	}
	
	public class MessageReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
						
			String content = intent.getStringExtra("jsonString");
			try 
			{
				JSONObject root = new JSONObject(content);
				
				//错误:root.getString("toID").equalsIgnoreCase(UserInfo.getID())
				//因为对于每一个窗口来说,UserInfo.getID()都一样
				//toID表示发信息给谁
				boolean a = (root.getString("toID").equalsIgnoreCase("Group")) && (toID.equalsIgnoreCase("Group"));
				boolean b = (!root.getString("toID").equalsIgnoreCase("Group")) && (toID.equalsIgnoreCase(root.getString("fromID")));
				if(a || b)
				{
					if(content != null) 
					{
						ChatMsgEntity entity = new ChatMsgEntity();
						entity.setName(root.getString("fromID"));
						entity.setDate(getDate());
						entity.setMessage(root.getString("content"));
						entity.setMsgType(false);
						
						list.add(entity);
						adapter.notifyDataSetChanged();//通知ListView,数据已发生改变
						listView.setSelection(listView.getCount() - 1);//发送一条消息时,ListView显示选择最后一项
					}
				}
				
			} catch (JSONException e) {
				e.printStackTrace();
			}		
		}		
    }
}


eclipse工程下载:

http://pan.baidu.com/s/1kT7yTH9


由于app的上交时间已经越来越近了,聊天的功能也勉强实现了,所以这个聊天app就这样了!后面本人肯定还会回来的!接下来打算添加地图功能,高德地图好像挺强大的!

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值