Closed denebchorny closed 5 years ago
Hello,
the app has do decide when to reconnect, the library simple cannot do this since this is a java library and therefore has no access to android apis.
Best regards, Marcel
Yes sir. My mistake was that I was trying to reconnect the socket when it's CLOSING. I was trying to understand and find a way to reconnect the socket when It closes.
I found the solution. If someone needs something similar I will paste the code.
To understand what is this:
I am using Dagger to inject the socket in the entire app. As the socket could need to be recreated in some conditions was neccesary to create a Wrapper class to handle this. Then, this wrapper is like the socket controller and its the object I use with dagger in the entire app.
When the socket reach onClose I try to reconnect it again. For this I execute a handler to check when the socket status chage from CLOSING to CLOSED.
For me there is not a stop condition. For this I just let the OS to kill the process once the app die.
If a stop condition is need it, it has to be added.
package com.hipcam.android.hipcam.core.sockets;
import android.content.Context;
import android.os.Handler;
import android.support.v4.util.Pair;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
import javax.net.ssl.SSLSocketFactory;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class MySocket {
private static final String TAG = MySocket.class.getSimpleName();
private static URI mServerUri;
private static Gson gson;
private final Context mContext;
private static WebSocketClient webSocketClient;
private static ObservableEmitter<Pair<String, JsonElement>> emit;
private static ObservableOnSubscribe<Pair<String, JsonElement>> emisible = e -> emit = e;
private static Observable<Pair<String, JsonElement>> observable;
private static boolean tryReconnecting = false;
private int mCountForReconnect = 0;
public static MySocket initSocket(Context context, String url) {
return new MySocket(context, url);
}
public MySocket(Context context, String url) {
this.mContext = context;
if (gson == null) {
gson = new Gson();
}
if (observable == null) {
observable = Observable.create(emisible);
}
if (webSocketClient == null) {
URI uri = null;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
e.printStackTrace();
}
mServerUri = uri;
if (mServerUri != null) {
createWebSocket();
}
} else {
reconnectIfNecessary();
}
}
public Observable<Pair<String, JsonElement>> getObservableListener() {
return observable
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
public synchronized void reconnectIfNecessary() {
if (tryReconnecting) {
return;
}
/*ESTADOS
*
* ReadyState.NOT_YET_CONNECTED
* ReadyState.CLOSED
* ReadyState.CLOSING
* ReadyState.OPEN
*
* */
if (webSocketClient == null) {
createWebSocket();
} else if (!webSocketClient.isOpen()) {
tryReconnecting = true;
invocarDentroDelTimerEspecial();
}
}
private void invocarDentroDelTimerEspecial() {
int delay;
if (webSocketClient == null) {
createWebSocket();
delay = 1;
mCountForReconnect = 1;
} else if (webSocketClient.isClosed()) {
webSocketClient.reconnect();
mCountForReconnect++;
delay = getCurrentFibonacci(mCountForReconnect);
} else if (webSocketClient.isOpen()) {
tryReconnecting = false;
mCountForReconnect = 1;
delay = 0;
} else {
mCountForReconnect++;
delay = getCurrentFibonacci(mCountForReconnect);
}
if (delay != 0) {
handler.postDelayed(runnableTimer, delay * 1000);
}
}
private void createWebSocket() {
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
webSocketClient = new WebSocketClient(mServerUri) {
@Override
public void onOpen(ServerHandshake handshakedata) {
// TODO your stuff when socket opens
}
@Override
public void onMessage(String message) {
Log.d(TAG + " socket", "onMessage" + message);
// TODO your stuff when message received
}
@Override
public void onClose(int code, String reason, boolean remote) {
reconnectIfNecessary();
}
@Override
public void onError(Exception ex) {
reconnectIfNecessary();
}
};
webSocketClient.setSocketFactory(socketFactory);
webSocketClient.connect();
}
public void send(String msg) {
if (isOpen()) {
webSocketClient.send(msg);
}
}
public boolean isOpen() {
return webSocketClient != null && webSocketClient.isOpen();
}
public boolean isClosed() {
return webSocketClient != null && webSocketClient.isClosed();
}
public boolean isClosing() {
return webSocketClient != null && webSocketClient.isClosing();
}
private final Handler handler = new Handler();
private final Runnable runnableTimer = this::invocarDentroDelTimerEspecial;
public static int getCurrentFibonacci(int item) {
int maxNumber = 1000;
int previousNumber = 0;
int nextNumber = 1;
int iterator=0;
for (int i = 1; i <= maxNumber; ++i) {
int sum = previousNumber + nextNumber;
previousNumber = nextNumber;
nextNumber = sum;
if(iterator++ == item){
return nextNumber;
}
}
return maxNumber;
}
}
@denebchorny thank you for sharing your code! :)
NOTE: Android Question
Describe what you would like to know or do I simply want to keep the socket alive meanwhile the application is executing. This mean that if the socket die/disconnect/etc there have to be a way to wake it up.
As the internet connection is unstable at all (Fluctuates) and sometimes the socket execute the onClose at this point without reconneting I would like to know what to do.
Describe the solution you'd considered I was thinking in try to reconnect when onClose is executed (Ready State closing) but I receive this message:
" You cannot initialize a reconnect out of the websocket thread. Use reconnect in another thread to insure a successful cleanup.".
I dont know how to do it. Could you bring me an example?
IDK if this is the correct way. Imagine putting airplane mode in the phone. This is gonna make the socket execute onclose and trying to reconnect again as crazy. If this is the solution please help me to understand how to econnect in another thread. If dont, please give me an advice :(.
The idea is to avoid the multiple instances staying alive in every new connection.
Additional context If this help, this is MySocket class. I am trying to make it as singleton. `public class MySocket { private static final String TAG = MySocket.class.getSimpleName();
}`