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的更多相关文章

  1. JAVA基础知识之网络编程——-基于TCP通信的简单聊天室

    下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...

  2. Android笔记——Socket通信实现简单聊天室

    两部分,客户端和服务端 ---------------------------------------------------------------- 客户端  1.为防止ANR异常,互联网连接可用 ...

  3. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  4. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  5. AngularJS作出简单聊天机器人

    简单聊天机器人 很初级的对话框形式.以前做对话框使用js,今天尝试使用AngularJS做出来 这里直接使用自己写的JSON数据. <!DOCTYPE html> <html lan ...

  6. iOS中XMPP简单聊天实现 好友和聊天

    版权声明本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;微信公众号:陈怀哲(chenhuaizhe2016) ...

  7. Python Socket 简单聊天室2

    上篇文章写了一个简单的单线程的一问一答的简单聊天室.这次我们使用SocketServer模块搭建一个多线程异步的聊天室. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  8. Asp.Net SignalR - 简单聊天室实现

    简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...

  9. SpringBoot 搭建简单聊天室

    SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...

随机推荐

  1. sql server2008R2 无法连接到WMI提供程序。你没有权限或者该服务器无法访问

    在自己的Win8.1的系统在安装了Vs2013和Sqlserver2008R2 今天在打开ssms的时候发现连接不上数据库,且出现了以下问题 然后打开Sqlserver配置管理器准备看看sqlserv ...

  2. 文档的js

    /* 主站,子频道,定向站点共用 */ (function() { scrollToAnchor(); toggleSearchForm(); scrollTop(); initScrollBar() ...

  3. spring结合mockito

    转载:https://blog.csdn.net/apexlj/article/details/50298029 mockito可模拟依赖对象的行为,从而简化跨类的测试. maven获取mockito ...

  4. Android Studio打开出现:Default activity not found

    昨天项目可以正常打开,没有问题,今天打开的时候就出现了这个问题.可以编译,但是无法生成APK调试.当然,如果选择 Do not launch Activity就可以成功编译.出现这个 Default ...

  5. oracle数据分组

    一,什么是分组函数 分组函数作用于一组数据,并对一组数据返回一个值 二,分组函数类型 Avg ,count,max,min,stddev(标准方差),sum. 函数名称 函数描述 Count 返回找到 ...

  6. 微软BI 之SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表

    基于数据仓库上的 SSRS 报表展示,一般可以直接通过 SQL 查询,存储过程,视图或者表等多种方式将数据加载并呈现在报表中.但是如果是基于 Cube 多维数据集的数据查询,就不能再使用 SQL 的语 ...

  7. C#中将DLL文件打包到EXE文件

    1:在工程目录增加dll目录,然后将dll文件复制到此目录,例如: 2:增加引用,定位到工程的dll目录,选中要增加的dll文件 3:修改dll文件夹下面的dll文件属性 选中嵌入式资源,不复制. 4 ...

  8. NGINX高并发配置

    1.  worker_processes 8; nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8). 2.  worker_cpu_affinity 000 ...

  9. 常用API文档

    Python requtets PyQuery Pascal Delphi PHP ThinkPHP5.0完全开发手册 ThinkPHP3.2.3快速入门

  10. Python标准库:内置函数bytes([source[, encoding[, errors]]])

    返回一个新的数组对象,这个数组对象不能对数组元素进行改动.每一个元素值范围: 0 <= x < 256.bytes函数与bytearray函数主要差别是bytes函数产生的对象的元素不能改 ...