近期在做一个与硬件交互的项目,通过TCP/IP协议通讯。
首先来看一下Socket通信模型
思路是使用service,需要频繁的与服务端交互所以使用BindService
创建绑定服务
必须使用IBinder,用以提供客户端与服务交互的接口
@Nullable
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return socketBinder;
}
public class SocketBinder extends Binder {
public SocketService getService() {
return SocketService.this;
}
}
初始化socket,使用EventBus发送连接状态
/**
* 初始化socket
*/
private void initSocket() {
if (socket == null && connectThread == null) {
connectThread = new Thread(new Runnable() {
@Override
public void run() {
socket = new Socket();
try {
socket.connect(new InetSocketAddress(Parameter.SERVER_IP, Parameter.PORT), 2000);//超时时间为2秒
if (socket.isConnected()) {//发送心跳包
toastMsg("socket已连接");
EventMsg msg = new EventMsg();
msg.setTag("success");
EventBus.getDefault().post(msg);
sendBeatData();//发送心跳数据
}
} catch (IOException e) {
e.printStackTrace();
if (e instanceof SocketTimeoutException) {
toastMsg("连接超时,正在重连");
releaseSocket();
} else if (e instanceof NoRouteToHostException) {
toastMsg("该地址不存在,请检查");
stopSelf();
} else if (e instanceof ConnectException) {
toastMsg("连接异常或被拒绝,请检查");
stopSelf();
}
}
}
});
connectThread.start();
}
}
使用TimerTask发送心跳数据,如果断开连接则重连
/**
* 定时发送数据
*/
private void sendBeatData() {
if (timer == null) {
timer = new Timer();
}
if (task == null) {
task = new TimerTask() {
@Override
public void run() {
try {
outputStream = socket.getOutputStream();
byte[] b = {1};
outputStream.write(b);
outputStream.flush();
} catch (Exception e) {
// toastMsg("连接断开,正在重连");
releaseSocket();//重连
e.printStackTrace();
}
}
};
}
timer.schedule(task, 0, 5000);
}
判断是否需要重连,如果应用在后台把是否重连置为false
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(getPackageName())) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
Log.i(TAG, "后台 " + appProcess.processName);
isReConnect = false;
} else {
Log.i(TAG, "前台 " + appProcess.processName);
isReConnect = true;
}
}
}
解绑服务释放资源
/**
* 释放资源
*/
private void releaseSocket() {
if (task != null) {
task.cancel();
task = null;
}
if (timer != null) {
timer.purge();
timer.cancel();
timer = null;
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
outputStream = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
}
socket = null;
}
if (connectThread != null) {
connectThread = null;
}
//...
}
向服务端发送数据
/**
* 发送数据
*/
public void sendOrder(final byte[] b) {
if (socket != null && socket.isConnected()) {
new Thread(new Runnable() {
@Override
public void run() {
try {
outputStream = socket.getOutputStream();
if (outputStream != null) {
outputStream.write(b);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} else {
toastMsg("socket连接错误,请重试");
}
}
Activity调用服务
调用bindService(),传递ServiceConnection
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
SocketService.SocketBinder binder = (SocketService.SocketBinder) iBinder;
mSocketService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Intent intent = new Intent(this, SocketService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
应用退出时解绑服务调用unBindService()
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
应用从后台回到前台需要把重连置为true,重新初始化socket连接
@Override
protected void onStart() {
super.onStart();
if (null != mSocketService)
mSocketService.setIsReConnect(true);
}
完整service
package com.aole.PEConsole.service;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;
import com.aole.PEConsole.event.EventMsg;
import com.aole.PEConsole.wiget.Parameter;
import org.greenrobot.eventbus.EventBus;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* author valiant
* date 2019/5/20.
* describe socket服务
*/
public class SocketService extends Service {
private static final String TAG = "SocketService1";
private Socket socket;
private Thread connectThread;
private Timer timer = new Timer();
private OutputStream outputStream;
private SocketBinder socketBinder = new SocketBinder();
private TimerTask task;
private boolean isReConnect = true;//默认重连
private Handler handler = new Handler();
public SocketService() {
}
@Override
public void onCreate() {
super.onCreate();
initSocket();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return socketBinder;
}
public class SocketBinder extends Binder {
public SocketService getService() {
return SocketService.this;
}
}
/**
* 初始化socket
*/
private void initSocket() {
if (socket == null && connectThread == null) {
connectThread = new Thread(new Runnable() {
@Override
public void run() {
socket = new Socket();
try {
socket.connect(new InetSocketAddress(Parameter.SERVER_IP, Parameter.PORT), 2000);//超时时间为2秒
if (socket.isConnected()) {//发送心跳包
toastMsg("socket已连接");
EventMsg msg = new EventMsg();
msg.setTag("success");
EventBus.getDefault().post(msg);
sendBeatData();//发送心跳数据
}
} catch (IOException e) {
e.printStackTrace();
if (e instanceof SocketTimeoutException) {
toastMsg("连接超时,正在重连");
releaseSocket();
} else if (e instanceof NoRouteToHostException) {
toastMsg("该地址不存在,请检查");
stopSelf();
} else if (e instanceof ConnectException) {
toastMsg("连接异常或被拒绝,请检查");
stopSelf();
}
}
}
});
connectThread.start();
}
}
private void toastMsg(final String msg) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
});
}
public void setIsReConnect(boolean isReConnect) {
this.isReConnect = isReConnect;
if (isReConnect && null == socket) {
initSocket();
}
}
/**
* 发送数据
*/
public void sendOrder(final byte[] b) {
if (socket != null && socket.isConnected()) {
new Thread(new Runnable() {
@Override
public void run() {
try {
outputStream = socket.getOutputStream();
if (outputStream != null) {
outputStream.write(b);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} else {
toastMsg("socket连接错误,请重试");
}
}
/**
* 定时发送数据
*/
private void sendBeatData() {
if (timer == null) {
timer = new Timer();
}
if (task == null) {
task = new TimerTask() {
@Override
public void run() {
try {
outputStream = socket.getOutputStream();
byte[] b = {1};
outputStream.write(b);
outputStream.flush();
} catch (Exception e) {
// toastMsg("连接断开,正在重连");
releaseSocket();//重连
e.printStackTrace();
}
}
};
}
timer.schedule(task, 0, 5000);
}
/**
* 释放资源
*/
private void releaseSocket() {
if (task != null) {
task.cancel();
task = null;
}
if (timer != null) {
timer.purge();
timer.cancel();
timer = null;
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
outputStream = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
}
socket = null;
}
if (connectThread != null) {
connectThread = null;
}
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(getPackageName())) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
Log.i(TAG, "后台 " + appProcess.processName);
isReConnect = false;
} else {
Log.i(TAG, "前台 " + appProcess.processName);
isReConnect = true;
}
}
}
//重新初始化socket
if (isReConnect) {
toastMsg("连接断开,正在重连");
initSocket();
}
}
}
不要忘记在manifest文件中注册service
亲测有效,有什么不妥之处请指出。非常感谢