看过包建强的《App研发录》之后对其中的基础Activity类封装感到惊讶,一直想找一种方式去解决关于app中使用socket长连接问题,如何实现简易的封装来达到主活动中涉及socket相关的代码量少的效果。正常的实现socket的基本方式都是新建一个Socket服务,在活动中绑定服务和注册全局广播,通过绑定服务中的函数去发送数据,通过全局广播去接收数据。如果每个活动中都去写绑定服务和注册全局广播等内容就会造成一大堆的代码冗余且主活动中的其他业务不是很突出,故我借用包建强书中的相关封装方式,新建了一个SocketBaseActivity类,去实现绑定服务与注册全局广播的内容,其中将全局广播接收器中的接收函数做抽象,在主活动继承SocketBaseActivity,在初始化时,实例化接收器中的接收函数,如果不实例化则不会进行绑定服务和注册广播操作,如果需要发送则掉父类中相关变量的发送函数即可。

下面是具体实现细节:

SocketService类

package com.splxtech.powermanagor.engine;

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; import com.splxtech.powermanagor.IBackService; 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; /**
* Created by li300 on 2016/10/7 0007.
*/ public class SocketService extends Service {
private static final String TAG = "BackService";
//心跳包频率
private static final long HEART_BEAT_RATE = * ; public static final String HOST = "192.168.0.102";// //
public static final int PORT = ; public static final String MESSAGE_ACTION="com.splxtech.powermanagor.engine.socket";
public static final String HEART_BEAT_ACTION="com.splxtech.powermanagor.engine.socket.heart"; public static final String HEART_BEAT_STRING="";//心跳包内容 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(HEART_BEAT_STRING);//就发送一个HEART_BEAT_STRING过去 如果发送失败,就重新初始化一个socket
if (!isSuccess) {
mHandler.removeCallbacks(heartBeatRunnable);
mReadThread.release();
releaseLastSocket(mSocket);
new InitSocketThread().start();
}
}
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
}; private long sendTime = 0L;
private IBackService.Stub iBackService = new IBackService.Stub() { @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(String msg) {
if (null == mSocket || null == mSocket.get()) {
return false;
}
Socket soc = mSocket.get();
try {
if (!soc.isClosed() && !soc.isOutputShutdown()) {
OutputStream os = soc.getOutputStream();
String message = msg;
os.write(message.getBytes());
os.flush();
sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
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();
}
} 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[ * ];
int length = ;
while (!socket.isClosed() && !socket.isInputShutdown()
&& isStart && ((length = is.read(buffer)) != -)) {
if (length > ) {
String message = new String(Arrays.copyOf(buffer,
length)).trim();
Log.e(TAG, message);
//收到服务器过来的消息,就通过Broadcast发送出去
if(message.equals(HEART_BEAT_STRING)){//处理心跳回复
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();
}
}
}
}
}

上面有一个IBackService.aidl文件:

// IBackService.aidl
package com.splxtech.powermanagor; // Declare any non-default types here with import statements interface IBackService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
boolean sendMessage(String message);
}

下面是SocketBaseActivity类中的内容:

package com.splxtech.powermanagor.Base;

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.IBinder;
import android.support.v4.content.LocalBroadcastManager; import com.splxtech.powermanagor.IBackService;
import com.splxtech.powermanagor.engine.SocketService;
import com.splxtech.splxapplib.activity.BaseActivity; /**
* Created by li300 on 2016/10/7 0007.
*/ public abstract class SocketBaseActivity extends BaseActivity
{
//子类中完成抽象函数赋值
//实体中通过实现该全局接收器方法来处理接收到消息
public MessageBackReciver mReciver;
private IntentFilter mIntentFilter;
private Intent mServiceIntent;
private LocalBroadcastManager localBroadcastManager;
//通过调用该接口中的方法来实现数据发送
public IBackService iBackService;
//标记是否已经进行了服务绑定与全局消息注册
private boolean flag; private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iBackService = IBackService.Stub.asInterface(iBinder);
} @Override
public void onServiceDisconnected(ComponentName componentName) {
iBackService = null;
}
}; @Override
public void onStart()
{
flag = false;
if(mReciver!=null)
{
flag = true;
initSocket();
localBroadcastManager.registerReceiver(mReciver,mIntentFilter);
bindService(mServiceIntent,conn,BIND_ABOVE_CLIENT);
}
super.onStart();
} @Override
public void onDestroy()
{
if(flag==true) {
unbindService(conn);
localBroadcastManager.unregisterReceiver(mReciver);
}
super.onDestroy();
}
public void initSocket()
{
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//mReciver = new MessageBackReciver();
mServiceIntent = new Intent(this,SocketService.class);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(SocketService.HEART_BEAT_ACTION);
mIntentFilter.addAction(SocketService.MESSAGE_ACTION);
}
public abstract class MessageBackReciver extends BroadcastReceiver
{
@Override
public abstract void onReceive(Context context, Intent intent);
}
}

在主activity中如何使用:

package com.splxtech.powermanagor.activity.dqjc;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView; import com.splxtech.powermanagor.Base.SocketBaseActivity;
import com.splxtech.powermanagor.R;
import com.splxtech.powermanagor.adapter.DqItemAdapter;
import com.splxtech.powermanagor.engine.SocketService;
import com.splxtech.powermanagor.entity.Appliance;
import com.splxtech.powermanagor.utils.Utils;
import com.splxtech.splxapplib.activity.BaseActivity; import java.util.ArrayList; /**
* Created by li300 on 2016/10/6 0006.
*/ public class DqActivity extends SocketBaseActivity
{ @Override
protected void initVariables()
{
//给全局消息接收器赋值,并进行消息处理
mReciver = new MessageBackReciver(){
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(action.equals(SocketService.HEART_BEAT_ACTION))
{
Utils.toastShow(baseActivity,"Get a heart heat");
}
else
{
String message = intent.getStringExtra("message");
}
}
};
}
@Override
protected void initViews(Bundle savedInstanceState)
{ } @Override
public void loadData()
{ }
}

android端 socket长连接 架构的更多相关文章

  1. 基于心跳的socket长连接

    http://coach.iteye.com/blog/2024444 基于心跳的socket长连接 博客分类: http socket 案例: 心跳: socket模拟网页的报文连接某个网站,创建t ...

  2. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...

  3. 【Socket】关于socket长连接的心跳包

    TCP的socket本身就是长连接的,那么为什么还要心跳包呢? 在smack里有个30s发送一个空消息的线程,同样关于心跳包(keepalive) 据网络搜索到的资料解释如下 内网机器如果不主动向外发 ...

  4. 基于netty框架的socket长连接负载均衡解决方案

    socket通讯的单机瓶颈 物联网的项目socket使用方式有两种: 短连接的socket请求 维持socket长连接的请求 对于socket短链接来说就好比是http请求,请求服务器,服务器返回数据 ...

  5. socket长连接的维持

    长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的.如果,长时间未发送维持连接包,服务端程序将断开连接. 客户端:通过持有Client对象,可以随时(使用sendObject方法)发 ...

  6. iOS后台如何保持socket长连接和数据传输

    工程中使用tcp长连接来和服务端进行数据传输,在IOS平台上,由于苹果的后台机制,会有以下问题: 当程序退到后台的时候,所有线程被挂起,系统会回收所有的socket资源,那么socket连接就会被关闭 ...

  7. 6.1 socket 长连接、短连接

    一般情况下,服务器的长连接和短连接不是服务器说了算,而是客户端说了算.因为服务器是给别人提供业务的,一旦连接建立起来之后,服务器端不会主动把连接给close掉. 客户端发送一笔业务,没有关闭连接,然后 ...

  8. 使用http维持socket长连接

    项目中有遇到问题如下: 1.旧版的cs服务,因为每个用户和唯一的长连接是在登录后绑定的,并且所有的消息报文均是基于该长连接去发送接收的,所以要求node服务要维持一个长连接,然后根据该用户获取长连接, ...

  9. Socket长连接和短连接的区别

    https://blog.csdn.net/jasonjwl/article/details/52085264 短连接 连接->传输数据->关闭连接 HTTP是无状态的,浏览器和服务器每进 ...

随机推荐

  1. C# test

    //测试对象集合序列化 public void jsonTest() { List<moduleEntity> list = new List<moduleEntity>(); ...

  2. Restful API学习Day4 - DRF版本控制和认证

    参考文档: Django REST framework基础:版本控制 Django REST framework基础:认证.权限.限制 为什么要有版本? 某些客户端 使用低版本只维护不开发新功能 v1 ...

  3. luogu P3721 [AH2017/HNOI2017]单旋

    传送门 \(Spaly:\)??? 考虑在暴力模拟的基础上优化 如果要插入一个数,那么根据二叉查找树的性质,这个点一定插在他的前驱的右子树或者是后继的左子树,可以利用set维护当前树里面的数,方便查找 ...

  4. A Bayesian Approach to Deep Neural Network Adaptation with Applications to Robust Automatic Speech Recognition

    基于贝叶斯的深度神经网络自适应及其在鲁棒自动语音识别中的应用     直接贝叶斯DNN自适应 使用高斯先验对DNN进行MAP自适应 为何贝叶斯在模型自适应中很有用? 因为自适应问题可以视为后验估计问题 ...

  5. 集成JUnit测试错误java.lang.IllegalStateException: Failed to load ApplicationContext

    1 详细错误信息 java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.t ...

  6. 判断Python输入是否为数字、字符(包括正则表达式)

    当键入字符串时候,我们自己就可以判断了! 一:我们在程序把输入的数字当字符串处理 import re print("我现在要写一个文件数字猜游戏数字游戏:") temp=input ...

  7. vue请求java服务端并返回数据

    最近在自学vue怎么与java进行数据交互.其实axios还是挺简单的,与ajax请求几乎一样,无外乎也就是要解决下跨域的问题. 废话不多说了,直接贴代码,一看就懂! //向springmvc Con ...

  8. Linux(Ubuntu)下安装jdk

    一.下载 1)可以去官网下载:http://www.oracle.com/technetwork/java/javase/downloads/ea-jsp-142245.html,比较多,眼花~~· ...

  9. mkyaffs2image 生成不了120M的镜像文件的解决方法

    下载链接:   http://download.csdn.net/download/macrocrazier/3807761 用上述下载的链接会出现Failed to execute /linuxrc ...

  10. 【Thymeleaf】常用属性

    参考链接 Thymeleaf 常用属性