赞
踩
安卓中使用TCP等网络模块时,需要新开线程来将网络的连接、收发等处理放到子线程中执行。前一篇使用AsyncTask实现了,但只能发送一次数据。只能说那个版本演示了网络Socket的创建和使用方式,探索了下子线程中发送网络数据实现,距使用还有很远距离。
此次尝试了下用Thread类实现子线程,利用Handler类实现主线程与子线程的通信。同时TCP客户端实现了发送与接收。
代码如下:
package com.miui.hongbao;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* Created by Administrator on 2016/7/11.
*/
public class NetClient extends Thread {
private Handler _outHandler; //snd msg to other thread through this
private Handler _curHandler; //rcv msg from other thread with this
private Socket _sockClient;
private String _strIp;
private int _nPort;
private OutputStream _os;
private InputStream _is;
private static final String STR_STATE_KEY = "state";
private static final String STR_PATN_CMD = "cmd";
private static final int INT_PATN_CMD = 1;
private static final int INT_PATN_FILE = 2;
private static final int SIZE_RCV_BUF=1000;
public int initSocket(String Ip, int nPort) throws IOException {
_strIp = Ip;
_nPort = nPort;
return 1;
}
/**
* put msg in que and send in sub thread. the pub interface for send.
* @param strCmd the str contend to send
* @return the len of send str
*/
public int putMsgInQue(String strCmd){
Message msg=_curHandler.obtainMessage();
Bundle b= new Bundle(); //form the msg frame.
b.putInt(STR_STATE_KEY, INT_PATN_CMD);
b.putString(STR_PATN_CMD,strCmd);
msg.setData(b);
_curHandler.sendMessage(msg);
return strCmd.length();
}
@Override
public void run() {
Looper.prepare();
try {
_sockClient=new Socket(_strIp,_nPort);
} catch (IOException e) {
e.printStackTrace();
}
_curHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.getData().getInt(STR_STATE_KEY)){
case INT_PATN_CMD: //send cmd to tcp server
try {
sendData(msg.getData().getString(STR_PATN_CMD));
System.out.println(rcvData());
} catch (IOException e) {
e.printStackTrace();
}
case INT_PATN_FILE:
;
}
}
};
Looper.loop();
}
/**
* @param strSnd the str to send
* @return the length of send str
* @throws IOException
*/
private int sendData(String strSnd) throws IOException, NullPointerException {
_os = _sockClient.getOutputStream();
_os.write(strSnd.getBytes());
return strSnd.length();
}
/**
* get the tcp data rcv. encode the bytes to gbk str.
* @return gbk str from tcp rcv bytes
* @throws IOException
*/
private String rcvData() throws IOException {
_is=_sockClient.getInputStream();
byte[] rcvBuf=new byte[SIZE_RCV_BUF];
_is.read(rcvBuf);
return new String(rcvBuf,"gbk");
}
}
调用代码:
mNetClient=new NetClient();
try {
mNetClient.initSocket(mTcpServIp,mTcpPort);
} catch (IOException e) {
e.printStackTrace();
}
mNetClient.start();
mNetClient.putMsgInQue("this is from android tcp client!");
有两个Handler实例,一个是用于其他线程向本线程发送消息,另一个用于此线程向其他线程发送消息。
提供一个公共接口putMsgInQue,将需要发送的字符串封装进msg中发送给Handler进行处理。
此设计有一个缺点:即线程的run循环被Looper独占了。无法直接把Tcp循环查询以接收数据放进run循环中,此处是在发送数据后立即进行数据接收查看Server端的回复。接收数据时将字节进行gbk编码成字符串再返回。
还有一个不满意的地方,通过Handler向其他线程传递消息时,是否能有一个共同的类来保证协议的一致。即在此类中需要封装数据然后传递给外部Handler,外部Handler对应的处理机制需要与类内的协议相一致才可以。这个协议能否以组合、接口的形式实现解耦呢。
Handler、Looper相关类的使用细节请参考其他资料。:)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。