看过包建强的《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. Android上禁止屏幕旋转

    看网上讲了很多,设置很多属性,设置了很多,其实最关键的一点是这个 @Overrideprotected void onResume() { /** * 设置为横屏 */ if(getRequested ...

  2. 添加Glide图片加载框架依赖

    1.添加依赖implementation 'com.github.bumptech.glide:glide:4.7.1' 2.放置一个ImageView.3.加载,ivGif是ImageView实例 ...

  3. 关于nexus的学习

    1.首先下载 解压版: 2.将nexus的bin目录路径  写入  环境变量path中: 3.修改 nexus配置文件wrapper.conf  15行  ,指定java.exe文件位置(例如:wra ...

  4. FlexPaper 2.3.6 远程命令执行漏洞 附Exp

    影响版本:小于FlexPaper 2.3.6的所有版本 FlexPaper (https://www.flowpaper.com) 是一个开源项目,遵循GPL协议,在互联网上非常流行.它为web客户端 ...

  5. mysql每组前N条

    SELECT * from ( select end rownum, else @prov:=t.province end prov, t.* from ( money UNION all money ...

  6. java中的绝对路径和相对路径

    1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如:C:/xyz/test.txt 代表了test.txt文件的绝对路径.http://www ...

  7. java 文档

    文档路径: https://docs.oracle.com/javase/10/docs/api/overview-summary.html

  8. 【tmos】SpringBoot+WebSocket打包时候的注意点

    要跳过测试打包:mvn package -DskipTests否则会报以下错误 Error creating bean with name 'serverEndpointExporter' defin ...

  9. CNN学习入门

    https://blog.csdn.net/ice_actor/article/details/78648780

  10. python模块-----pymysql

    一.安装 本模块为python第三方模块,需要单独安装.作用为调用mysql接口执行模块 pip3 install pyMySql 操作步骤: #!/usr/bin/python3 import py ...