近期在做一个与硬件交互的项目,通过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<ActivityManager.RunningAppProcessInfo> 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<ActivityManager.RunningAppProcessInfo> 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
<service android:name=".service.DetectionService" android:enabled="true" android:exported="true" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/detection_service_config" /> </service>亲测有效,有什么不妥之处请指出。非常感谢
