Android 为多个活动存储 Socket.io 个对象

Android Storing Socket.io object for multiple activities

我正在制作我的第一个 Socket.io 基于 android 的应用程序。套接字从 Web 服务发送和接收数据。应用程序中有许多屏幕用于不同的功能。我如何在这些不同的活动中使用相同的套接字连接。

我已经尝试在应用程序中设置和存储套接字对象 class,它似乎运行良好,但是当应用程序进入后台并在那里停留一段时间时,应用程序被终止并且套接字对象然后是 NULL 导致 aoo 因空指针异常而崩溃。

public class MyApplication extends Application {

    private Socket mSocket;

    private final String TAG = "Application Class";

    public Socket getSocket() {
        return mSocket;
    }

    public Socket createSocket() {

    try {
        Manager manager = new Manager(new URI("http://0.0.0.0"));
    } catch (URISyntaxException URIse) {
        URIse.printStackTrace();
    }

        return mSocket;
    }

}

在活动中访问套接字

MyApplication app;
app = (MyApplication ) getApplication();
app.getSocket;

您可以为套接字创建单例管理器class。它将允许您保持整个应用程序可以访问单个套接字连接。请参阅以下代码并根据您的要求进行更改

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.util.Log;

import com.myapp.app.ui.adapter.OnSocketConnectionListener;

import java.util.ArrayList;
import java.util.List;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

/**
 * Created by penguin on 6/30/2016.
 * <p/>
 * SocketManager manages socket and internet connection.
 * It also provide listeners for connection status
 */
public class SocketManager {

    /**
     * The constant STATE_CONNECTING.
     */
    public static final int STATE_CONNECTING = 1;
    /**
     * The constant STATE_CONNECTED.
     */
    public static final int STATE_CONNECTED = 2;
    /**
     * The constant STATE_DISCONNECTED.
     */
    public static final int STATE_DISCONNECTED = 3;

    /**
     * The constant CONNECTING.
     */
    public static final String CONNECTING = "Connecting";
    /**
     * The constant CONNECTED.
     */
    public static final String CONNECTED = "Connected";
    /**
     * The constant DISCONNECTED.
     */
    public static final String DISCONNECTED = "Disconnected";

    private static SocketManager instance;

    private SocketManager() {
    }

    /**
     * Gets instance.
     *
     * @return the instance
     */
    public synchronized static SocketManager getInstance() {
        if (instance == null) {
            instance = new SocketManager();
        }
        return instance;
    }

    /**
     * The constant TAG.
     */
    public static final String TAG = SocketManager.class.getSimpleName();
    private Socket socket;
    private List<OnSocketConnectionListener> onSocketConnectionListenerList;

    /**
     * Connect socket.
     *
     * @param token  the token
     * @param userId the user id
     * @param host   the host
     * @param port   the port
     */
    public void connectSocket(String token,String userId, String host, String port) {
        try {
            if(socket==null){
                String serverAddress = host+":"+port;
                IO.Options opts = new IO.Options();
                opts.forceNew = true;
                opts.reconnection = true;
                opts.reconnectionAttempts=5;
                opts.secure = true;
                opts.query = "token=" + token + "&" + "user_id=" + userId;
                socket = IO.socket(serverAddress, opts);

                socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        fireSocketStatus(SocketManager.STATE_CONNECTED);
                        Log.i(TAG, "socket connected");
                    }
                }).on(Socket.EVENT_RECONNECTING, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.e(TAG, "Socket reconnecting");
                        fireSocketStatus(SocketManager.STATE_CONNECTING);
                    }
                }).on(Socket.EVENT_RECONNECT_FAILED, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.e(TAG, "Socket reconnection failed");
//                        fireSocketStatusIntent(SocketManager.STATE_DISCONNECTED);
                    }
                }).on(Socket.EVENT_RECONNECT_ERROR, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.e(TAG, "Socket reconnection error");
//                        fireSocketStatus(SocketManager.STATE_DISCONNECTED);
                    }
                }).on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.e(TAG, "Socket connect error");
                        fireSocketStatus(SocketManager.STATE_DISCONNECTED);
                        socket.disconnect();
                    }
                }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.e(TAG, "Socket disconnect event");
                        fireSocketStatus(SocketManager.STATE_DISCONNECTED);
                    }
                }).on(Socket.EVENT_ERROR, new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        try {
                            final String error = (String) args[0];
                            Log.e(TAG + " error EVENT_ERROR ", error);
                            if (error.contains("Unauthorized") && !socket.connected()) {
                                if (onSocketConnectionListenerList != null) {
                                    for (final OnSocketConnectionListener listener : onSocketConnectionListenerList) {
                                        new Handler(Looper.getMainLooper())
                                                .post(new Runnable() {
                                                    @Override
                                                    public void run() {
                                                        listener.onSocketEventFailed();
                                                    }
                                                });
                                    }
                                }
                            }
                        } catch (Exception e) {
                            Log.e(TAG, e.getMessage() != null ? e.getMessage() : "");
                        }
                    }
                }).on("Error", new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Log.d(TAG, " Error");
                    }
                });
                socket.connect();
            }else if(!socket.connected()){
                socket.connect();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private int lastState = -1;

    /**
     * Fire socket status intent.
     *
     * @param socketState the socket state
     */
    public synchronized void fireSocketStatus(final int socketState) {
        if(onSocketConnectionListenerList !=null && lastState!=socketState){
            lastState = socketState;
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    for(OnSocketConnectionListener listener: onSocketConnectionListenerList){
                        listener.onSocketConnectionStateChange(socketState);
                    }
                }
            });
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    lastState=-1;
                }
            },1000);
        }
    }

    /**
     * Fire internet status intent.
     *
     * @param socketState the socket state
     */
    public synchronized void fireInternetStatusIntent(final int socketState) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                if(onSocketConnectionListenerList !=null){
                    for(OnSocketConnectionListener listener: onSocketConnectionListenerList){
                        listener.onInternetConnectionStateChange(socketState);
                    }
                }
            }
        });
    }

    /**
     * Gets socket.
     *
     * @return the socket
     */
    public Socket getSocket() {
        return socket;
    }

    /**
     * Sets socket.
     *
     * @param socket the socket
     */
    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    /**
     * Destroy.
     */
    public void destroy(){
        if (socket != null) {
            socket.off();
            socket.disconnect();
            socket.close();
            socket=null;
        }
    }

    /**
     * Sets socket connection listener.
     *
     * @param onSocketConnectionListenerListener the on socket connection listener listener
     */
    public void setSocketConnectionListener(OnSocketConnectionListener onSocketConnectionListenerListener) {
        if(onSocketConnectionListenerList ==null){
            onSocketConnectionListenerList = new ArrayList<>();
            onSocketConnectionListenerList.add(onSocketConnectionListenerListener);
        }else if(!onSocketConnectionListenerList.contains(onSocketConnectionListenerListener)){
            onSocketConnectionListenerList.add(onSocketConnectionListenerListener);
        }
    }

    /**
     * Remove socket connection listener.
     *
     * @param onSocketConnectionListenerListener the on socket connection listener listener
     */
    public void removeSocketConnectionListener(OnSocketConnectionListener onSocketConnectionListenerListener) {
        if(onSocketConnectionListenerList !=null
                && onSocketConnectionListenerList.contains(onSocketConnectionListenerListener)){
            onSocketConnectionListenerList.remove(onSocketConnectionListenerListener);
        }
    }

    /**
     * Remove all socket connection listener.
     */
    public void removeAllSocketConnectionListener() {
        if(onSocketConnectionListenerList !=null){
            onSocketConnectionListenerList.clear();
        }
    }

    /**
     * The type Net receiver.
     */
    public static class NetReceiver extends BroadcastReceiver {

        /**
         * The Tag.
         */
        public final String TAG = NetReceiver.class.getSimpleName();

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager cm =
                    (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            boolean isConnected = activeNetwork != null &&
                    activeNetwork.isConnectedOrConnecting();

            SocketManager.getInstance().fireInternetStatusIntent(
                    isConnected?SocketManager.STATE_CONNECTED:SocketManager.STATE_DISCONNECTED);
            if (isConnected) {
                if(SocketManager.getInstance().getSocket()!=null
                        && !SocketManager.getInstance().getSocket().connected()){
                    SocketManager.getInstance().fireSocketStatus(SocketManager.STATE_CONNECTING);
                }
                PowerManager powerManager =
                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                boolean isScreenOn;
                if (android.os.Build.VERSION.SDK_INT
                        >= android.os.Build.VERSION_CODES.KITKAT_WATCH) {
                    isScreenOn = powerManager.isInteractive();
                }else{
                    //noinspection deprecation
                    isScreenOn = powerManager.isScreenOn();
                }

                if (isScreenOn && SocketManager.getInstance().getSocket() !=null) {
                    Log.d(TAG, "NetReceiver: Connecting Socket");
                    if(!SocketManager.getInstance().getSocket().connected()){
                        SocketManager.getInstance().getSocket().connect();
                    }
                }
            }else{
                SocketManager.getInstance().fireSocketStatus(SocketManager.STATE_DISCONNECTED);
                if(SocketManager.getInstance().getSocket() !=null){
                    Log.d(TAG, "NetReceiver: disconnecting socket");
                    SocketManager.getInstance().getSocket().disconnect();
                }
            }
        }
    }
}

连接插座

您可以 connecting/disconnect 来自任何 activity 或后台服务的套接字

    SocketManager.getInstance().connectSocket(user.getToken(), user.getUserId(),
            getResources().getString(R.string.host), "8000");

更新

如果您的应用程序在后台被终止,套接字也会被破坏。如果你想让套接字在后台保持连接,你必须让你自己的后台服务逻辑与套接字无关。

实施OnSocketConnectionListener

public interface OnSocketConnectionListener {
    void onSocketEventFailed();
    void onSocketConnectionStateChange(int socketState);
    void onInternetConnectionStateChange(int socketState);
}