首页 > 移动平台 > 详细

Andoird通信之简单聊天ChatApp

时间:2015-03-14 02:09:36      阅读:366      评论:0      收藏:0      [点我收藏+]

Andoird通信之简单聊天ChatApp

Android通信,大体上的逻辑是跟Java上的通信是差不多的,只是因为Android线程不能直接访问UI界面组件,所以在处理的时候有些麻烦,只要是通过Handle处理。

接下来是一个简单地手机聊天App,主要是手机终端与电脑之间的通信,比如发文字或者是发送图片。

因为涉及到发送不同类型的文件,所以需要制定以下协议:

1、消息类型,使用一个int表示,4个字节:

1、表示文字数据包;

2、表示鱼片数据包。

2、数据包的长度,使用一个int表示,4个字节

3、数据内容,使用字节数组进行传输。

?

关键性代码:

1、服务机与客户机之间的链接:

服务机:

ServerSocket?ss?=?new?ServerSocket(port);

Socket?socket?=?ss.accept();

客户机:

//这个地方不能填电脑的本机地址,一定要是局域网或公网的//IP地址,wifi

socket?=?new?Socket("10.96.23.74",?8888);

2、发送文字的代码:

//发送数据类型,?1-文本,?2-图片

dataOutputStream.writeInt(1);

//发送数据长度

dataOutputStream.writeInt(bytes.?length);

//发送数据内容

dataOutputStream.write(bytes);

3、发送图片的代码:

//把一个图片文件读取到一个字节数组中

FileInputStream?fis?=?new?FileInputStream("images/jobs.png");

int?len?=?fis.available();

byte[]?bytes?=?new?byte[len];

fis.read(bytes);

fis.close();

//发送数据类型,?1-文本,?2-图片

dataOutputStream.writeInt(2);

//数据长度

dataOutputStream.writeInt(bytes.?length);

//数据内容

dataOutputStream.write(bytes);

//刷新缓存

dataOutputStream.flush();

4、Handle处理UI界面:

在客户机线程里面,handler.sendMessage(msg);

MainActivity里面:

//创建Handler对象

Handler?handler?=?new?Handler(

//回调接口,当handler接收到消息时调用该接口的handleMessage方法

new?Callback()?{

//出理线程发送过来的数据

public?boolean?handleMessage(Message?msg)?{

if(msg.?what?==?1){

//把服务器发送过来的内容显示出来

textMsgLog.append("?服务器:?"?+?msg.?obj?.toString()?+

"\n");

}

if(msg.?what?==?2){

//服务器发送过来的图片

Bitmap?bitmap?=?(Bitmap)msg.?obj?;

ImageSpan?imageSpan?=?new?ImageSpan(MainActivity.?this,

bitmap);

//创建一个SpannableString对象,以便插//入用ImageSpan对象封装的图像

SpannableString?ss?=?new?SpannableString("img");

//?用imageSpan对象替换img

ss.setSpan(imageSpan,?0,?3,

Spannable.?SPAN_EXCLUSIVE_EXCLUSIVE);

//把图片显示在界面上

textMsgLog.append("?服务器:?");

textMsgLog.append(ss);

textMsgLog.append("\n");

}

return?true;

}

});

5、在?Android?Manifest.xml文件中添加网络权限:

在?uses-sdk?标签后面添加

<uses-permission?android:name="android.permission.INTERNET"/>

?

所以,对于服务机

import?java.io.IOException;

import?java.net.ServerSocket;

import?java.net.Socket;

?

public?class?Server?{

public?void?setUp(int?port){

try?{

//监听port端口

ServerSocket?ss?=?new?ServerSocket(port);

//循环接收客户端的访问

while(true){

Socket?socket?=?ss.accept();

//把客户端的连接放到线程里处理

SocketThread?st?=?new?SocketThread(socket);

st.start();

}

}?catch?(IOException?e)?{

e.printStackTrace();

}

}

?

public?static?void?main(String[]?args)?{

//服务器监听8888端口

new?Server().setUp(8888);

}

}

?

?

import?java.io.DataInputStream;

import?java.io.DataOutputStream;

import?java.io.FileInputStream;

import?java.io.IOException;

import?java.io.InputStream;

import?java.net.Socket;

?

public?class?SocketThread?extends?Thread?{

private?Socket?socket;

private?DataOutputStream?dataOutputStream;

?

public?SocketThread(Socket?socket)?{

this.?socket?=?socket;

}

?

public?void?run(){

try?{

//得到网络连接的输入输出流对象

InputStream?inputStream?=?socket.getInputStream();

//用数据输入流对原输入流进行封装,用于读取不同类型的数据

DataInputStream?dis?=?new?DataInputStream(inputStream);

//用数据输出流对原输出流进行封装,用于发送不同类型的数据

dataOutputStream?=?new?DataOutputStream(socket.getOutputStream());

while(true){

//读取一个int,注意:这里是readInt方法

int?msgType?=?dis.readInt();

//文字消息

if(msgType?==?1){

//读取数据包长度

int?len?=?dis.readInt();

//读取数据内容

byte[]?bytes?=?new?byte[len];

dis.readFully(bytes);

//转成字符串

String?content?=?new?String(bytes,?"GB2312");

System.?out.println("?客户端说:?"+content);

//客户端发送过来的字符串为image的话就发送一张图片过去

if(content.equals("image")){

sendImage();

}?else?{

//向客户端回应信息

String?replyString?=?"?服务器收到了("+content+")";

bytes?=?replyString.getBytes("GB2312");

//发送数据类型,?1-文本,?2-图片

dataOutputStream.writeInt(1);

//发送数据长度

dataOutputStream.writeInt(bytes.?length);

//发送数据内容

dataOutputStream.write(bytes);

//刷新缓存

dataOutputStream.flush();

}

}

//图片数据包

if(msgType?==?2){

//读取数据包长度

int?len?=?dis.readInt();

//读取数据内容

byte[]?bytes?=?new?byte[len];

dis.readFully(bytes);

//在这里可以把客户端发送的图片保存到文件,也可以做个界面显示出来,具体代码就不写了

?

?

?

}

}

}?catch?(IOException?e)?{

e.printStackTrace();

}

}

?

//向客户端发送一张图片

public?void?sendImage()?throws?IOException{

//把一个图片文件读取到一个字节数组中

//src/wo.jpg,以文件夹ChatAppServer为起始目录

FileInputStream?fis?=?new?FileInputStream("images/wo.jpg");

int?len?=?fis.available();

byte[]?bytes?=?new?byte[len];

fis.read(bytes);

fis.close();

//发送数据类型,?1-文本,?2-图片

dataOutputStream.writeInt(2);

//数据长度

dataOutputStream.writeInt(bytes.?length);

//数据内容

dataOutputStream.write(bytes);

//刷新缓存

dataOutputStream.flush();

}

}

?

对于客户机

首先是Android页面:

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

?android:layout_width="match_parent"

?android:layout_height="match_parent"

?android:orientation="vertical"?>

?

<TextView

?android:layout_width="wrap_content"

?android:layout_height="wrap_content"

?android:id="@+id/textMsgLog"

?android:text=""?/>

?

?<LinearLayout

?android:layout_width="match_parent"

?android:layout_height="match_parent"

?android:orientation="horizontal">

?

?<EditText

android:id="@+id/editInput"

?android:layout_width="220dp"

?android:layout_height="wrap_content"?/>

?

?<Button

?android:id="@+id/btnSend"

?android:layout_width="wrap_content"

?android:layout_height="wrap_content"

?android:onClick="send"

?android:text="发送"?/>

?

</LinearLayout>

</LinearLayout>

?

主页面:

package?com.cyw.chatapp;

?

import?android.app.Activity;

import?android.graphics.Bitmap;

import?android.os.Bundle;

import?android.os.Handler;

import?android.os.Handler.Callback;

import?android.os.Message;

import?android.text.Spannable;

import?android.text.SpannableString;

import?android.text.style.ImageSpan;

import?android.view.View;

import?android.widget.EditText;

import?android.widget.TextView;

import?android.widget.Toast;

?

public?class?MainActivity?extends?Activity?{

private?TextView?textMsgLog;

private?ClientThread?clientThread;

?

protected?void?onCreate(Bundle?savedInstanceState)?{

super.onCreate(savedInstanceState);

setContentView(R.layout.?activity_main);

?

//聊天记录组件

textMsgLog?=?(TextView)findViewById(R.id.?textMsgLog);

//创建Handler对象

Handler?handler?=?new?Handler(

//回调接口,当handler接收到消息时调用该接口的handleMessage方法

new?Callback()?{

//出理线程发送过来的数据

public?boolean?handleMessage(Message?msg)?{

if(msg.?what?==?1){

//把服务器发送过来的内容显示出来

textMsgLog.append("?服务器:?"?+?msg.?obj?.toString()?+

"\n");

}

if(msg.?what?==?2){

//服务器发送过来的图片

Bitmap?bitmap?=?(Bitmap)msg.?obj?;

ImageSpan?imageSpan?=?new?ImageSpan(MainActivity.?this,

bitmap);

//创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像

SpannableString?ss?=?new?SpannableString("img");

//?用imageSpan对象替换img

ss.setSpan(imageSpan,?0,?3,

Spannable.?SPAN_EXCLUSIVE_EXCLUSIVE);

//把图片显示在界面上

textMsgLog.append("?服务器:?");

textMsgLog.append(ss);

textMsgLog.append("\n");

}

return?true;

}

});

?

//通信线程,通过handler对象与UI主现象发送数据

clientThread?=?new?ClientThread(handler);

clientThread.start();

}

?

//向服务器发送文本内容

public?void?send(View?v){

EditText?editInput?=?(EditText)findViewById(R.id.?editInput);

String?msg?=?editInput.getText().toString();

boolean?result?=?clientThread.sendText(msg);

if(result){

textMsgLog.append("?我:?"+msg+"\n");

editInput.setText("");

}?else?{

Toast.?makeText(this,?"?发送失败",?Toast.?LENGTH_LONG).show();

}

}

}

?

客户端处理线程:

package?com.cyw.chatapp;

?

import?java.io.DataInputStream;

import?java.io.DataOutputStream;

import?java.io.IOException;

import?java.net.Socket;

import?java.net.UnknownHostException;

import?android.graphics.Bitmap;

import?android.graphics.BitmapFactory;

import?android.os.Handler;

import?android.os.Message;

?

public?class?ClientThread?extends?Thread?{

//与UI主线程通信的中间代理

private?Handler?handler;

private?DataOutputStream?dataOutputStream;

private?DataInputStream?dataInputStream;

private?Socket?socket;

?

public?ClientThread(Handler?handler){

this.?handler?=?handler;

}

?

//一定记得要在线程里访问网络

public?void?run(){

try?{

//因为连接网络比较耗时间,会阻塞UI主线程

//所以连接到服务器的操作一定要放在线程的run里面

connect();

while(true){

//读取一个int,注意:这里是readInt方法

int?msgType?=?dataInputStream.readInt();

//文字消息

if(msgType?==?1){

//读取数据包长度

int?len?=?dataInputStream.readInt();

//读取数据内容

byte[]?bytes?=?new?byte[len];

dataInputStream.readFully(bytes);

//转成字符串

String?content?=?new?String(bytes,?"GB2312");

Message?msg?=?new?Message();

//消息类型

msg.?what?=?1;

//消息内容

msg.?obj?=?content;

//发送给UI主线程

handler.sendMessage(msg);

}

//图片数据包

if(msgType?==?2){

//读取数据包长度

int?len?=?dataInputStream.readInt();

//读取数据内容

byte[]?bytes?=?new?byte[len];

dataInputStream.readFully(bytes);

//把字节数组还原成一个图片

Bitmap?bitmap?=?BitmapFactory.?decodeByteArray(bytes,

0,?len);

Message?msg?=?new?Message();

//消息类型

msg.?what?=?2;

//消息内容

msg.?obj?=?bitmap;

//发送给UI主线程

handler.sendMessage(msg);

}

}

}?catch?(IOException?e)?{

e.printStackTrace();

}?finally?{

close();

}

}

?

//链接主机

private?void?connect()?throws?UnknownHostException,?IOException?{

//这个地方不能填电脑的本机地址,一定要是局域网或公网的IP地址,wifi

//IPv4?地址:?10.96.23.74??IPv6?地址:?2001:250:4400:d000::3:97b8

socket?=?new?Socket("10.96.23.74",?8888);

//得到输入输出流对象

dataInputStream?=?new?DataInputStream(socket.getInputStream());

dataOutputStream?=?new?DataOutputStream(socket.getOutputStream());

}

?

//关闭网络连接

private?void?close(){

if(dataInputStream?!=?null){

try?{

dataInputStream.close();

}?catch?(IOException?e)?{

}

}

if(dataOutputStream?!=?null){

try?{

dataOutputStream.close();

}?catch?(IOException?e)?{

}

}

if(socket?!=?null){

try?{

socket.close();

}?catch?(IOException?e)?{

}

}

}

?

//向服务器发送数据

public?boolean?sendText(String?content){

try?{

//把字符串转成字节数组

byte[]?bytes?=?content.getBytes("GB2312");

//消息类型

dataOutputStream.writeInt(1);

//数据长度

dataOutputStream.writeInt(bytes.?length);

//发送数据

dataOutputStream.write(bytes);

dataOutputStream.flush();

return?true;

}?catch?(IOException?e)?{

e.printStackTrace();

}

return?false;

}

}

?

<!--EndFragment-->

Andoird通信之简单聊天ChatApp

原文:http://cyw.iteye.com/blog/2192049

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!