android端 socket长连接 架构

看过包建强的《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 = 30 * 1000;

    public static final String HOST = "192.168.0.102";// //
    public static final int PORT = 51001;

    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="00";//心跳包内容

    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[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(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()
    {

    }
}
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值