I have MyRepository that obtains a live feed from a server via a socket.
It provides its data to MyViewModel via a MutableLiveData object which can be observed from a Fragment.
To avoid wasting resources, I don't want MyRepository to be obtaining data from the server when there are no observers.
I'd like to know how to monitor MyRepository's MutableLiveData, so if there are no observers then MyRepository can stop retrieving data from the server. Similarly, if an observer is added, then data retrieval can (re)start.
Currently, I'm just using a basic Thread (see the createObserversMonitorThread() method) as the monitor:
public class MyRepository {
private static final String TAG = MyRepository.class.getSimpleName();
private MutableLiveData<String> mutableLiveData;
private Socket mSocket = null;
public MyRepository(Application application) {
mutableLiveData = new MutableLiveData<>();
createSocket();
createObserversMonitorThread();
}
private void createObserversMonitorThread() {
Thread thread = new Thread() {
@Override
public void run() {
try {
while (isAlive()) {
if (mutableLiveData.hasActiveObservers()) {
// We have observers, so connect to the server.
if (!mSocket.connected()) {
mSocket.connect();
}
}
else {
// We don't have observers, so disconnect from the server.
if (mSocket.connected()) {
mSocket.disconnect();
}
}
// Wait until next loop.
Thread.sleep(1000);
}
}
catch(Exception e) {
Log.e(TAG, "Exception", e);
}
}
};
thread.setName("MutableLiveData Observers Monitor");
thread.setPriority(1);
thread.setDaemon(true);
thread.start();
}
public LiveData<String> getMutableLiveData() {
return mutableLiveData;
}
/**
* This method posts retrieved data to mutableLiveData.
*/
private void createSocket() {
try {
mSocket = IO.socket(Constants.SERVER_URL);
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d(TAG, "Connected.");
}
}).on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
if (args[0] instanceof Exception) {
Log.e(TAG, "Connect error: ", (Exception)args[0]);
}
else {
Log.e(TAG, "Connect error: " + args[0]);
}
}
}).on(Socket.EVENT_RECONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d(TAG, "Reconnected.");
}
}).on(Socket.EVENT_RECONNECT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
if (args[0] instanceof Exception) {
Log.e(TAG, "Reconnect error: ", (Exception)args[0]);
}
else {
Log.e(TAG, "Reconnect error: " + args[0]);
}
}
}).on(Socket.EVENT_MESSAGE, new Emitter.Listener() {
@Override
public void call(Object... args) {
//Log.d(TAG, "Data received.");
String s = (String) args[0];
mutableLiveData.postValue(s);
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d(TAG, "Disconnected.");
}
}).on(Socket.EVENT_ERROR, new Emitter.Listener() {
@Override
public void call(Object... args) {
if (args[0] instanceof Exception) {
Log.e(TAG, "Error: ", (Exception)args[0]);
}
else {
Log.e(TAG, "Error: " + args[0]);
}
}
});
}
catch(Exception e) {
Log.e(TAG, "Could not create socket", e);
}
}
}
It works, but is there a better way?
UPDATE
Solution, thanks to EpicPandaForce's answer:
public class MyRepository {
private static final String TAG = MyRepository.class.getSimpleName();
private MutableLiveData<String> mutableLiveData;
private Socket mSocket = null;
public MyRepository(Application application) {
createSocket();
mutableLiveData = new MutableLiveData<String>() {
@Override
protected void onActive() {
super.onActive();
// Connect to server. This will (re)start data being posted on mutableLiveData.
if (!mSocket.connected()) {
mSocket.connect();
}
}
@Override
protected void onInactive() {
super.onInactive();
// Disconnect from server. This will stop data being posted on mutableLiveData.
if (mSocket.connected()) {
mSocket.disconnect();
}
}
};
}
public LiveData<String> getMutableLiveData() {
return mutableLiveData;
}
/**
* This method posts retrieved data to mutableLiveData.
*/
private void createSocket() {
// Same code as before.
}
}