Socket长连接Android端心跳机制实现
来源:互联网 发布:redis可视化工具 知乎 编辑:程序博客网 时间:2024/06/05 19:13
前面用golang写的socket服务端请移步:http://blog.csdn.net/u010072711/article/details/76082176
1. 把socket链接和心跳功能都放在一个Service中,为什么要放在Service中?
一般我们这种socket几乎是跟app的生命周期一样长,甚至更长。不管在不在Service中去完成操作,我们都得开异步线程,虽然Service并不是异步操作,但是为了提升我们任务的优先级,我们最好是放在Service中,因为Service是由Android系统管理的,并且拥有比较高的优先级,线程是java中的异步任务载体,可以说Android系统不太认识线程。放在Service中可以很大程度上避免任务被回收或者关闭
2. 为什么需要心跳机制?
由于移动设备的网络的复杂性,经常会出现网络断开,如果没有心跳包的检测,客户端只会在需要发送数据的时候才知道自己已经断线,会延误,甚至丢失服务器发送过来的数据。我们可以每隔3秒钟或者每间隔1秒钟去判断一下socket是否断开,没断开就读取数据,断开了就重新连接socket。
3. Service与Activity之间怎么通信?
3.1 Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法
3.2 Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好
4.源代码
4.1 Service代码
package danxx.library.socket;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.ref.WeakReference;import java.net.Socket;import java.net.UnknownHostException;import java.util.Arrays;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.RemoteException;import android.support.v4.content.LocalBroadcastManager;import android.util.Log;/** * Created by dawish on 2017/7/24. * 由于移动设备的网络的复杂性,经常会出现网络断开,如果没有心跳包的检测, * 客户端只会在需要发送数据的时候才知道自己已经断线,会延误,甚至丢失服务器发送过来的数据。 */public class BackService extends Service { private static final String TAG = "danxx"; /**心跳频率*/ private static final long HEART_BEAT_RATE = 3 * 1000; /**服务器ip地址*/ public static final String HOST = "192.168.123.27";// "192.168.1.21";// /**服务器端口号*/ public static final int PORT = 9800; /**服务器消息回复广播*/ public static final String MESSAGE_ACTION="message_ACTION"; /**服务器心跳回复广播*/ public static final String HEART_BEAT_ACTION="heart_beat_ACTION"; /**读线程*/ private ReadThread mReadThread; private LocalBroadcastManager mLocalBroadcastManager; /***/ private WeakReference<Socket> mSocket; // For heart Beat private Handler mHandler = new Handler(); /**心跳任务,不断重复调用自己*/ private Runnable heartBeatRunnable = new Runnable() { @Override public void run() { if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) { boolean isSuccess = sendMsg("HeartBeat");//就发送一个\r\n过去 如果发送失败,就重新初始化一个socket if (!isSuccess) { mHandler.removeCallbacks(heartBeatRunnable); mReadThread.release(); releaseLastSocket(mSocket); new InitSocketThread().start(); } } mHandler.postDelayed(this, HEART_BEAT_RATE); } }; private long sendTime = 0L; /** * aidl通讯回调 */ private IBackService.Stub iBackService = new IBackService.Stub() { /** * 收到内容发送消息 * @param message 需要发送到服务器的消息 * @return * @throws RemoteException */ @Override public boolean sendMessage(String message) throws RemoteException { return sendMsg(message); } }; @Override public IBinder onBind(Intent arg0) { return iBackService; } @Override public void onCreate() { super.onCreate(); new InitSocketThread().start(); mLocalBroadcastManager=LocalBroadcastManager.getInstance(this); } public boolean sendMsg(final String msg) { if (null == mSocket || null == mSocket.get()) { return false; } final Socket soc = mSocket.get(); if (!soc.isClosed() && !soc.isOutputShutdown()) { new Thread(new Runnable() { @Override public void run() { try { OutputStream os = soc.getOutputStream(); String message = msg + "\r\n"; os.write(message.getBytes()); os.flush(); } catch (IOException e) { e.printStackTrace(); } } }).start(); sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间 } else { return false; } return true; } private void initSocket() {//初始化Socket try { Socket so = new Socket(HOST, PORT); mSocket = new WeakReference<Socket>(so); mReadThread = new ReadThread(so); mReadThread.start(); mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//初始化成功后,就准备发送心跳包 } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 心跳机制判断出socket已经断开后,就销毁连接方便重新创建连接 * @param mSocket */ private void releaseLastSocket(WeakReference<Socket> mSocket) { try { if (null != mSocket) { Socket sk = mSocket.get(); if (!sk.isClosed()) { sk.close(); } sk = null; mSocket = null; } } catch (IOException e) { e.printStackTrace(); } } class InitSocketThread extends Thread { @Override public void run() { super.run(); initSocket(); } } // Thread to read content from Socket class ReadThread extends Thread { private WeakReference<Socket> mWeakSocket; private boolean isStart = true; public ReadThread(Socket socket) { mWeakSocket = new WeakReference<Socket>(socket); } public void release() { isStart = false; releaseLastSocket(mWeakSocket); } @Override public void run() { super.run(); Socket socket = mWeakSocket.get(); if (null != socket) { try { InputStream is = socket.getInputStream(); byte[] buffer = new byte[1024 * 4]; int length = 0; while (!socket.isClosed() && !socket.isInputShutdown() && isStart && ((length = is.read(buffer)) != -1)) { if (length > 0) { String message = new String(Arrays.copyOf(buffer, length)).trim(); Log.e(TAG, message); //收到服务器过来的消息,就通过Broadcast发送出去 if(message.equals("ok")){//处理心跳回复 Intent intent=new Intent(HEART_BEAT_ACTION); mLocalBroadcastManager.sendBroadcast(intent); }else{ //其他消息回复 Intent intent=new Intent(MESSAGE_ACTION); intent.putExtra("message", message); mLocalBroadcastManager.sendBroadcast(intent); } } } } catch (IOException e) { e.printStackTrace(); } } } } @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(heartBeatRunnable); mReadThread.release(); releaseLastSocket(mSocket); }}
4.2 Activity代码
package com.danxx.views;import android.content.BroadcastReceiver;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v4.content.LocalBroadcastManager;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import java.lang.ref.WeakReference;import java.util.concurrent.Executors;import danxx.library.socket.BackService;import danxx.library.socket.IBackService;/** * Created by daish on 2017/7/24. */public class ActivityHeartSocket extends AppCompatActivity { private TextView mResultText; private EditText mEditText; private Intent mServiceIntent; private IBackService iBackService; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { iBackService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { iBackService = IBackService.Stub.asInterface(service); } }; class MessageBackReciver extends BroadcastReceiver { private WeakReference<TextView> textView; public MessageBackReciver(TextView tv) { textView = new WeakReference<TextView>(tv); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); TextView tv = textView.get(); if (action.equals(BackService.HEART_BEAT_ACTION)) { if (null != tv) { Log.i("danxx", "Get a heart heat"); tv.setText("Get a heart heat"); } } else { Log.i("danxx", "Get a heart heat"); String message = intent.getStringExtra("message"); tv.setText("服务器消息:"+message); } }; } private MessageBackReciver mReciver; private IntentFilter mIntentFilter; private LocalBroadcastManager mLocalBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_heart_socket); mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); mResultText = (TextView) findViewById(R.id.resule_text); mEditText = (EditText) findViewById(R.id.content_edit); mReciver = new MessageBackReciver(mResultText); mServiceIntent = new Intent(this, BackService.class); mIntentFilter = new IntentFilter(); mIntentFilter.addAction(BackService.HEART_BEAT_ACTION); mIntentFilter.addAction(BackService.MESSAGE_ACTION); } @Override protected void onStart() { super.onStart(); mLocalBroadcastManager.registerReceiver(mReciver, mIntentFilter); bindService(mServiceIntent, conn, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(conn); mLocalBroadcastManager.unregisterReceiver(mReciver); } public void onClick(View view) { switch (view.getId()) { case R.id.send: String content = mEditText.getText().toString(); try { boolean isSend = iBackService.sendMessage(content);//Send Content by socket Toast.makeText(this, isSend ? "success" : "fail", Toast.LENGTH_SHORT).show(); mEditText.setText(""); } catch (RemoteException e) { e.printStackTrace(); } break; default: break; } }}
5.效果图
5.1 golang服务端
5.2 Android客户端
Golang服务端代码:/Dawish/GoStudy/blob/master/src/main/SocketServer.go
Android客户端代码:AppLibrary/src/main/java/danxx/library/socket/BackService.java
- Socket长连接Android端心跳机制实现
- android长连接心跳机制
- Android长连接心跳机制
- android长连接心跳机制
- android长连接心跳机制
- Android TCP长连接 心跳机制及实现
- Android长连接,怎么处理心跳机制
- Android长连接,怎么处理心跳机制
- socket长连接、短连接以及心跳包机制
- Android中的socket长连接问题(包括心跳机制、多线程数据发送)
- Socket 长连接 心跳包
- Java 心跳 Socket 长连接
- Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)
- Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)
- Android的socket通信的长连接,有心跳检测
- Android socket通信的长连接与心跳检测
- android 长连接的心跳及推送机制
- 长连接和端连接 心跳包机制
- The REP prefix
- BigDansing: A System for Big Data Cleansing论文笔记
- 自定义Smarty(三)
- Java中进行异常处理时的三种输出结果
- ubuntu16.04安装nodejs
- Socket长连接Android端心跳机制实现
- Matplotlib中文乱码解决方案
- Tips2 好好调教你的程序(断点调试)
- 学习字符串string类
- 最后接电话的人
- ssm+maven整合
- JQuery学习(1)
- hdu1049 Climbing Worm(C语言)
- SpringBoot9-Spring MVC-Spring MVC高级配置