这款app是基于socket来写的,为何选择socket来写,暂定为老师要求的。。。
这款app的运行条件是首先要运行服务端,之后再登录客户端,登录后就可以开始聊天了,聊天内容用了listview来显示,在网上搜罗了一些适配器加上的
新手的话对于消息处理机制肯定不是很理解,这里附上参考网址:http://www.cnblogs.com/yaozhenfa/p/np_android_Handler.html
首先上代码
必要条件:
AndroidManifest.xml文件当中必须加入下面这句话
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
服务端:
/**
* 多线程服务器
*/
public class Server implements Runnable{
private Socket socket;
private Ponline ponline;
public Server(Socket socket) {
this.socket = socket;
ponline = Ponline.getInstance();
}
@Override
public void run() {
try {
System.out.println("child thread is running...");
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = null;
System.out.println("waiting for msg...");
while ((msg = reader.readLine()) != null) {
System.out.println(msg);
if(!msg.startsWith("send")){
ponline.putSockets(msg, socket);
System.out.println("******save a client socket******");
}else{
//use another login socket outputstream
String [] msgs = msg.split(":");
if(msgs[2] == null){//group chat
Set<String> allSockets = ponline.getAllSockets();
for(String user : allSockets){
if (user != msgs[1]) {
PrintWriter writer = new PrintWriter(ponline.getSockets(user).getOutputStream());
writer.println(msg);
writer.flush();
}
}
}else{//single chat
PrintWriter writer = new PrintWriter(ponline.getSockets(msgs[2]).getOutputStream());
writer.println(msg);
writer.flush();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
boolean flag = true;
while (flag) {
Socket socket = serverSocket.accept();
new Thread(new Server(socket)).start();
}
}
}
服务端保存在线用户类:
/**
* 存放连接的客户端socket
*/
public class Ponline {
private static Ponline mOnline;
private HashMap<String,Socket> sockets = new HashMap<>();
public Ponline(){}
public synchronized static Ponline getInstance() {
if(null == mOnline) {
mOnline = new Ponline();
}
return mOnline;
}
public void putSockets(String str, Socket socket) {
sockets.put(str, socket);
}
public Socket getSockets(String str) {
return sockets.get(str);
}
public void remove(String str){
sockets.remove(str);
}
public Set<String> getAllSockets() {
return sockets.keySet();
}
}
客户端:
public class Chat extends Activity {//ChatClient
private Button btnSend ;
private EditText eTmsg;
private ListView listView;
private Socket socket;
private String userName;
private String singleChat;
private boolean isConnected = false;
private final String IP = "192.168.1.102";
private final int PORT = 8888;
private List<Map<String, String>> mData = new ArrayList<Map<String, String>>();
private MyAdapter adapter;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//修改UI控件操作
if(msg.what == 0x123){
String [] arr = (String[])msg.obj;
String from = arr[0];
String msgs = arr[1];
Map<String, String> temp = new HashMap<String, String>();
temp.put("user",from);
temp.put("msg", msgs);
mData.add(temp);
adapter.notifyDataSetChanged();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
btnSend = (Button) findViewById(R.id.btnSend);
eTmsg = (EditText) findViewById(R.id.eTmsg);
listView = (ListView) findViewById(R.id.listView);
userName = getIntent().getStringExtra("user");
singleChat = getIntent().getStringExtra("isSingle");
adapter = new MyAdapter(this);
listView.setAdapter(adapter);
//connect to server when activity start
new Thread(new Runnable() {
@Override
public void run() {
try {
Socket socket = new Socket(IP, PORT);
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.println(userName);
writer.flush();
PConnection.socket = socket;
new ChatThread(socket).start();//start child thread
System.out.println("connect to server");
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = eTmsg.getText().toString().trim();
sendMsg(userName, singleChat, str);
eTmsg.setText("");
}
});
}
/*
* send msg to server
* */
public void sendMsg (final String from,final String to,final String msg) {
new Thread(new Runnable() {
@Override
public void run() {
try {
socket = PConnection.socket;
OutputStream os = socket.getOutputStream();
PrintWriter writer = new PrintWriter(os);
writer.println("send:" + from + ":" + to + ":" + msg);
writer.flush();
System.out.println("send msg to server");
Message message = handler.obtainMessage(0x123, new String[] {from , msg});
message.sendToTarget();
} catch(Exception e) {
e.printStackTrace();
}
}
}).start();
}
/*
* ViewHolder静态类
* */
static class ViewHolder
{
public TextView user;
public TextView msg;
}
/*
* listView适配器
* */
private class MyAdapter extends BaseAdapter
{
private LayoutInflater mInflater = null;
private MyAdapter(Context context)
{
//根据context上下文加载布局,这里的是Demo17Activity本身,即this
this.mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
//How many items are in the data set represented by this Adapter.
//在此适配器中所代表的数据集中的条目数
return mData.size();
}
@Override
public Object getItem(int position) {
// Get the data item associated with the specified position in the data set.
//获取数据集中与指定索引对应的数据项
return position;
}
@Override
public long getItemId(int position) {
//Get the row id associated with the specified position in the list.
//获取在列表中与指定索引对应的行id
return position;
}
//Get a View that displays the data at the specified position in the data set.
//获取一个在数据集中指定索引的视图来显示数据
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
//如果缓存convertView为空,则需要创建View
if(convertView == null)
{
holder = new ViewHolder();
//根据自定义的Item布局加载布局
convertView = mInflater.inflate(R.layout.list_item, null);
holder.user = (TextView)convertView.findViewById(R.id.tv);
holder.msg = (TextView)convertView.findViewById(R.id.info);
//将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag
convertView.setTag(holder);
}else
{
holder = (ViewHolder)convertView.getTag();
}
holder.user.setText((String)mData.get(position).get("user"));
holder.msg.setText((String)mData.get(position).get("msg"));
return convertView;
}
}
class ChatThread extends Thread{
private Socket s;
public ChatThread(Socket s) {
super();
this.s = s;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
while (true) {
String content = null;
while((content = br.readLine()) != null) {
System.out.println("rec msg from server:"+content);
String [] msg = content.split(":");
Message message = handler.obtainMessage(0x123, new String[] {msg[1] , msg[3]});
message.sendToTarget();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端保存socket类:
/**
* 存放登录后的socket,在发送消息和接收消息时使用该socket
*/
public class PConnection {
public static Socket socket;
}