• 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()
        {
    
        }
    }
  • 相关阅读:
    技术必备:推荐一款接口自动化测试数据校验神器
    提高GUI自动化测试稳定性解决方案
    新特性,推荐一款超强接口管理神器 Apifox
    测试开发:从0到1学习如何测试API网关
    接口自动化测试,一键快速校验接口返回值全部字段
    测试工程师必学:测试人员如何深入了解项目
    Django+Vue+Docker搭建接口测试平台实战
    如何开展线上全链路压测思路分享
    刚转行1年测试新手:学习Python编程经验实战分享
    测开新手:从0到1,自动化测试接入Jenkins学习
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/6800309.html
Copyright © 2020-2023  润新知