问题
I am working on a chat application and Currently I am listening and emitting socket events in an Activity.
Now i want to listen all the socket events even when chat activity is not in foreground as i want to store all the messages from different users in the local DB at the same time i want to update LiveData to update UI.
In order to achieve this I am listening socket events in the Application class as following:
public class ChatApplication extends Application {
public Socket mSocket;
private Map<String, Boolean> receivedFriendEventsMap = new HashMap<>();
private List<Result> friendsList = new ArrayList<>();
private AppDatabase database;
@Override
public void onCreate() {
super.onCreate();
try {
mSocket = IO.socket(Constants.CHAT_SERVER_URL);
//mSocket.connect();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
Instance = this;
applicationHandler = new Handler(getInstance().getMainLooper());
NativeLoader.initNativeLibs(ChatApplication.getInstance());
//mSocket.connect();
database = AppDatabase.getDatabase(getApplicationContext());
mSocket.on("friend_status", new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d(TAG, "" + args[0] + args[1]);
receivedFriendEventsMap.put((String) args[0], (Boolean) args[1]);
}
});
mSocket.on("listen_friend_message", new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d(TAG, "listen_friend_message: " + (String) args[0] + args[1]);
SocketMessage socketMessage = new Gson().fromJson((String) args[0], SocketMessage.class);
//database.socketMessageDao().addMessage(socketMessage);
mSocket.emit("trigger_friend_message_delivered", socketMessage.getMsg_id(), socketMessage.getSender_id(), socketMessage.getReceiver_id(), args[1]);
}
});
SocketMessage socketMessage = new Gson().fromJson((String) result, SocketMessage.class);
//database.socketMessageDao().addMessage(socketMessage);
Log.d(TAG, new Gson().toJson(database.socketMessageDao().getAllMessages(), new TypeToken<List<SocketMessage>>() {
}.getType()));
}
Is this the right approach? If not, could anyone please suggest me some good solution. Any help is appreciated.
回答1:
You need to use LifeCycleService to connect and listen to sockets and then use service binding to observe changes in activity
This is a service class that connects to the socket and has MutableLiveData() socketData that observe the connection of the socket (You can create any type of LiveDataObject and observe inactivity)
class SocketService : LifecycleService() {
val socketData = MutableLiveData<String>()
var mSocket: Socket? = null
private val mBinder = SocketBinder()
override fun onCreate() {
super.onCreate()
mSocket?.let {
if (!it.connected()) it.connect()
} ?: run {
initSocketConnection()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
mSocket?.let {
if (!it.connected()) it.connect()
} ?: run {
initSocketConnection()
}
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
return mBinder
}
override fun onUnbind(intent: Intent?): Boolean {
return true
}
override fun onRebind(intent: Intent?) {
super.onRebind(intent)
}
private fun initSocketConnection() {
try {
val options = IO.Options()
options.timeout = 5000
options.transports = arrayOf(WebSocket.NAME)
mSocket = IO.socket(BuildConfig.SOCKET_SERVER_ADDRESS, options)
connectSocket()
} catch (e: URISyntaxException) {
throw RuntimeException(e)
}
}
private fun connectSocket() {
mSocket?.let {
it.connect()
it.on(Socket.EVENT_CONNECT) {
connectSocketListener()
Log.e(SOCKET_TAG, "Connection Successful")
socketData.postValue( "Connection Successful for live data")
}
it.on(Socket.EVENT_CONNECT_ERROR) { args ->
Log.e(SOCKET_TAG, "Connection Fail " + args[0].toString())
}
it.on(Socket.EVENT_CONNECT_TIMEOUT) { args ->
Log.e(SOCKET_TAG, "Connection Fail " + args[0].toString())
}
it.on(Socket.EVENT_ERROR) { args ->
Log.e(SOCKET_TAG, "Connection Fail " + args[0].toString())
}
it.on(Socket.EVENT_CONNECTING) {}
}
}
override fun onDestroy() {
super.onDestroy()
stopSocket()
}
private fun stopSocket() {
mSocket?.let {
it.disconnect()
it.off(Socket.EVENT_CONNECT) {}
it.off(Socket.EVENT_CONNECT_ERROR) {}
it.off(Socket.EVENT_CONNECT_TIMEOUT) {}
it.off(Socket.EVENT_ERROR) {}
it.off(Socket.EVENT_CONNECTING) {}
disconnectSocketListener()
}
}
private fun connectSocketListener() {
}
private fun disconnectSocketListener() {
}
inner class SocketBinder : Binder() {
fun getService(): SocketService = this@SocketService
}
}
Now in Activity you need to bind this service and listen to changes in LiveData object
class BaseActivity : AppCompatActivity() {
private var mService: SocketService? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
private val mConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mService = (service as SocketService.SocketBinder).getService()
mService?.let {
it.socketData.observe(it) { arg ->
Log.d(SOCKET_TAG, arg)
}
}
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
override fun onStart() {
super.onStart()
val intent = Intent(this, SocketService::class.java)
bindService(intent, mConnection, BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
try {
mService?.let {
unbindService(mConnection)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
You can see when socket is connected i am posting value in LiveData and when it is bounded I am registering an observer to listen data.
来源:https://stackoverflow.com/questions/54051614/listening-socket-io-events-and-updating-livedata-a-class-of-android-arch-lifecy