看过包建强的《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. Python中json一点小知识

    import json dic={ "name":"杨林" } ret=json.dumps(dic,ensure_ascii=False) #因为json.d ...

  2. luogu 4377 Talent show 01分数规划+背包dp

    01分数规划+背包dp 将分式下面的部分向右边挪过去,通过二分答案验证, 注意二分答案中如果验证的mid是int那么l=mid+1,r=mid-1,double类型中r=mid,l=mid; 背包dp ...

  3. Windows Docker Toolbox 安装Redis等开发环境

    Redis作者不接受微软的补丁 Redis文档(https://redis.io/topics/quickstart) redis-server 是 Redis Server 本身 redis-sen ...

  4. jQuery.extend 函数使用

    JQuery的extend扩展方法:      Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解.      一.Jquery的扩展方 ...

  5. Python读取导入非安装文件库的方法

    一.将文件库放到和.py文件同一目录下: 二..py文件头导入文件库的格式为(以导入CIFAR-10数据的类为例)[其实就在文件库前面加个.]: from .cifar10 import cifar1 ...

  6. linux下搭建lamp环境以及安装swoole扩展

    linux下搭建lamp环境以及安装swoole扩展   一.CentOS 6.5使用yum快速搭建LAMP环境 准备工作:先更新一下yum源  我安装的环境是:apache2.2.15+mysql5 ...

  7. IDEA 启动项目前的配置--或过程遇到的问题

    配置JDK 配置Maven路径和 仓库路径:文件->设置 配置Tomcat Server  文件-->设置 运行时 选择一个tomcat服务器 ==拓展: 本人台式机 的2016版本,因汉 ...

  8. 假设result 是一个float型变量,value是一个int型变量。执行以下赋值语句以后,变量value将是什么类型?为什么?

    假设result 是一个float型变量,value是一个int型变量.执行以下赋值语句以后,变量value将是什么类型?为什么? 在执行这条语句的过程中,保存在vulue变量中的值被读取出来并转化为 ...

  9. IDEA在同一窗口导入多个项目

    在同一窗口打开多个项目 1. 当前窗口: 2. 3.  选择import module即可.然后一直点击next导入OK即可. 同一窗口目录下创建多个项目 1.File→New→Module 2.Ja ...

  10. roslaunch & gdb 调试指南(待补充)

    1. 安装xterm sudo apt-get install xterm 2. 在launch文件中添加如下内容: <node name="navigation" pkg= ...