2

今天是个好日子。

在我的项目中,我使用Java-WebSocket库。我有 WebSocketService,我的自定义 WebSocket 在其中侦听和发送消息。一切都会好的,但是在每个 WebSocketClient TIMEOUT 或强制(当服务被破坏时)关闭后,在我的 App 进程中会出现过多的线程,这会导致 CPU 使用率最大化和电池快速放电。

我做错了什么?

我的 WebSocketService 类:

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.IBinder;

public class WebSocketService extends Service {

    public enum ControlServiceType {
        NONE, START_SEND_USER_LOCATION, STOP_SEND_USER_LOCATION
    }

    private static final String CLASS_PATH = WebSocketService.class.getName();
    private static final String EXTRA_CONTROL_SERVICE_TYPE = CLASS_PATH + "EXTRA_CONTROL_SERVICE_TYPE";

    private static final int SLEEP_TIME = 5 * 60 * 1000;

    //VALUE's
    private LocationController mLocationController;
    private ConnectivityManager mConnectivityManager;

    private WebSocket mWebSocket;
    private Thread mThread;
    private boolean mNetworkAvailable;
    private boolean mSendUserLocationOnWebSocket;


    public static void startService(Context context) {
        final Intent intent = new Intent(context, WebSocketService.class);
        context.startService(intent);
    }

    public static void stopService(Context context) {
        final Intent intent = new Intent(context, WebSocketService.class);
        context.stopService(intent);
    }

    public static void controlService(Context context, ControlServiceType type) {
        final Intent intent = new Intent(context, WebSocketService.class);
        intent.putExtra(EXTRA_CONTROL_SERVICE_TYPE, type.ordinal());

        context.startService(intent);
    }

    public void onCreate() {
        super.onCreate();

        mLocationController = LocationController.getInstance(this);
        mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        mNetworkAvailable = isNetworkAvailable(mConnectivityManager.getActiveNetworkInfo());

        registerReceiver(mReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

        mWebSocket = WebSocket.getInstance(this);
        startSaveUserLocationOnWebSocket();

        Utils.toLog("\tWebSocketService\tonCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Utils.toLog("\tWebSocketService\tonStartCommand");

        if (intent != null) {
            final ControlServiceType type = ControlServiceType.
                    values()[intent.getIntExtra(EXTRA_CONTROL_SERVICE_TYPE, 0)];

            switch (type) {
                case START_SEND_USER_LOCATION:
                    startSaveUserLocationOnWebSocket();
                    break;

                case STOP_SEND_USER_LOCATION:
                    stopSaveUserLocationOnWebSocket();
                    break;

                default:
                    break;
            }
        }

        return super.onStartCommand(intent, flags, startId);
    }

    public void onDestroy() {
        super.onDestroy();

        unregisterReceiver(mReceiver);
        stopSaveUserLocationOnWebSocket();
        Utils.toLog("\tWebSocketService\tonDestroy");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void startSaveUserLocationOnWebSocket() {
        mSendUserLocationOnWebSocket = true;

        mThread = new SaveUserLocationOnWebSocket();
        mThread.start();
    }

    private void stopSaveUserLocationOnWebSocket() {
        mWebSocket.stopSocket();
        mSendUserLocationOnWebSocket = false;

        mThread.interrupt();
        mThread = null;
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()) && intent.getExtras() != null) {
                mNetworkAvailable = isNetworkAvailable(mConnectivityManager.getActiveNetworkInfo());
                if (mWebSocket != null) {
                    mWebSocket.setNetworkAvailable(mNetworkAvailable);
                }
            }
        }
    };

    private boolean isNetworkAvailable(NetworkInfo ni) {
        if (ni != null && ni.isConnected()) {
            return true;
        }
        return false;
    }

    private class SaveUserLocationOnWebSocket extends Thread {
        @Override
        public void run() {
            super.run();

            mWebSocket.startSocket(mNetworkAvailable);

            while (mSendUserLocationOnWebSocket) {
                mLocationController.getLastKnownLocationFromBestProvider();
                mWebSocket.sendMessage(MessageType.SAVE_USER_LOCATION);

                try {
                    Thread.sleep(SLEEP_TIME);

                } catch (InterruptedException e) {
                    return;
                }
            }
        }
    }
}

我的自定义 WebSocket 类:

import android.content.Context;
import android.os.Handler;

import org.java_websocket.client.DefaultSSLWebSocketClientFactory;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.client.WebSocketClient.WebSocketClientFactory;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

public class WebSocket {

    private static final String WEB_SOCKET_URI = "https://XX.XX.XX.XX:8888/echo/websocket";
    private static final int DELAY_MILLIS = 10;
    private static final int ERROR_DELAY_MILLIS = 1000;

    //SINGLETON
    private static WebSocket sWebSocket;

    //BASE
    private Context mContext;

    //VALUE's
    private URI mURI;
    private WebSocketClientFactory mClientFactory;
    private Handler mHandler;
    private Runnable mRunnable;

    private WebSocketClient mClient;

    private List<String> mMessagesList;
    private WebSocketMessages mMessages;
    private WebSocketSecretary mSecretary;

    private boolean mNetworkAvailable;
    private boolean mSocketWork;

    public static WebSocket getInstance(Context context) {
        if (sWebSocket == null) {
            synchronized (WebSocket.class) {
                if (sWebSocket == null) {
                    sWebSocket = new WebSocket(context);
                }
            }
        }
        return sWebSocket;
    }

    private WebSocket(Context context) {
        mContext = context.getApplicationContext();

        try {
            mURI = new URI(WEB_SOCKET_URI);

        } catch (URISyntaxException e) {
            Utils.toLog(e);
            throw new IllegalStateException(e.getMessage());
        }

        try {
            final KeyStore keyStore = getKeyStore(mContext);
            final KeyManager[] keyManagers = getKeyManagers(keyStore);
            final TrustManager[] trustManagers = getTrustManagers(keyStore);

            mClientFactory = getWebSocketClientFactory(keyManagers, trustManagers);

        } catch (Exception e) {
            Utils.toLog(e);
        }

        mHandler = new Handler();
        mRunnable = new Runnable() {
            @Override
            public void run() {
                initWebSocketClient();
            }
        };

        mMessagesList = new ArrayList<>();
        mMessages = WebSocketMessages.getInstance(mContext);
        mSecretary = new WebSocketSecretary(mContext);
    }

    public void startSocket(boolean networkAvailable) {
        mSocketWork = true;
        setNetworkAvailable(networkAvailable);
    }

    public void setNetworkAvailable(boolean networkAvailable) {
        mNetworkAvailable = networkAvailable;

        if (mNetworkAvailable) {
            initWebSocketClient();
        }
    }

    public void sendMessage(MessageType type) {
        sendMessage(mMessages.getMessage(type));
    }

    public void sendMessage(String bytes) {
        if (isOpen()) {
            mClient.send(bytes);

        } else {
            mMessagesList.add(bytes);
        }
    }

    public boolean isOpen() {
        return mSocketWork && mNetworkAvailable &&
    }

    public void stopSocket() {
        mSocketWork = false;
        mMessagesList.clear();

        if (mClient != null) {
            mClient.close();
            mClient = null;
        }
    }

    private void initWebSocketClient() {
        if (mClient != null) {
            return;
        }

        mClient = getWebSocketClient();
        mClient.connect();
    }

    private WebSocketClient getWebSocketClient() {
        final WebSocketClient client = getWebSocketClient(mURI);
        client.setWebSocketFactory(mClientFactory);

        return client;
    }

    private WebSocketClient getWebSocketClient(URI uri) {
        return new WebSocketClient(uri) {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                if (MApp.DEBUG) {
                    Utils.toLog("WebSocketClient\tonOpen");
                }

                send(mMessages.getByteMessage(MessageType.LOGIN_USER));

                if (!mMessagesList.isEmpty()) {
                    final Iterator<String> iterator = mMessagesList.iterator();
                    while (iterator.hasNext()) {
                        send(iterator.next());
                        iterator.remove();
                    }
                }
            }

            @Override
            public void onMessage(String s) {
                mSecretary.onMessage(s);
            }

            @Override
            public void onError(Exception e) {
                if (MApp.DEBUG) {
                    Utils.toLog("WebSocketClient\tonError");
                    Utils.toLog(e);
                }
            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                if (mClient != null) {
                    mClient.close();
                }
                mClient = null;

                if (mSocketWork && mNetworkAvailable) {
                    mHandler.postDelayed(mRunnable, code == -1 ? ERROR_DELAY_MILLIS : DELAY_MILLIS);
                }

                if (MApp.DEBUG) {
                    Utils.toLog("WebSocketClient\tonClose\tcode = " + code + "\treason = " + reason);
                }
            }
        };
    }

    public static KeyStore getKeyStore(Context context) throws Exception {
        final KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(context.getResources().openRawResource(R.raw.websocketcertificate),
                "password".toCharArray());

        return keyStore;
    }

    public static KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception {
        final KeyManagerFactory keyFactory = KeyManagerFactory.
                getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFactory.init(keyStore, null);

        return keyFactory.getKeyManagers();
    }

    public static TrustManager[] getTrustManagers(KeyStore keyStore) throws Exception {
        final TrustManagerFactory trustFactory = TrustManagerFactory.
                getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustFactory.init(keyStore);

        return trustFactory.getTrustManagers();
    }

    private static WebSocketClientFactory getWebSocketClientFactory(KeyManager[] keyManagers,
                                                                    TrustManager[] trustManagers)
            throws Exception {
        final SSLContext sslContext = SSLContext.getInstance("TLS", "HarmonyJSSE");
        sslContext.init(keyManagers, trustManagers, new SecureRandom());

        return new DefaultSSLWebSocketClientFactory(sslContext);
    }
}

我正常的 WebSocket 工作日志:

D/mLog    (28058):  WebSocketService    onCreate
D/mLog    (28058):  WebSocketService    onStartCommand
D/mLog    (28058): WebSocket : {"method":"saveUserLocation","params":{"lat":0,"lon":0}}

D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}
D/mLog    (28058): WebSocketClient  onClose code = 1006 reason = 

D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}
D/mLog    (28058): WebSocketClient  onClose code = 1006 reason = 

D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}
D/mLog    (28058): WebSocketClient  onClose code = 1006 reason = 

D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}
D/mLog    (28058): WebSocketClient  onClose code = 1006 reason = 

D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}
D/mLog    (28058): WebSocket : {"method":"saveUserLocation","params":{"lat":0,"lon":0}}

D/mLog    (28058): WebSocketClient  onClose code = 1006 reason = 
D/mLog    (28058): WebSocketClient  onOpen
D/mLog    (28058): WebSocket : {"method":"loginUser","params":"apiKey"}

D/mLog    (28058):  WebSocketService    onDestroy
D/mLog    (28058): WebSocketClient  onClose code = 1000 reason = 

提前感谢!

4

0 回答 0