📜 ⬆️ ⬇️

Socket client service and UI update via BroadcastReceiver

Task:
Make the client application "on sockets", so that when you close the main activation, the work continues and the connection is not lost.

Decision:
It is possible to do this with the help of services in android, there are many articles written about what a service is and how it works. Therefore, I will not go into details and start to implement it.

Our application consists of the 3 most important classes:


MainActivity:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.startService(new Intent(this, ServiceExchange.class)); //   } } private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onDataFromService(intent); } }; public void onResume() { super.onResume(); registerReceiver(broadcastReceiver, new IntentFilter(ServiceExchange.BROADCAST_ACTION)); } @Override public void onPause() { super.onPause(); unregisterReceiver(broadcastReceiver); } public void onDataFromService(Intent intent) { Log.d("onDataFromService", intent.getStringExtra("text")); } 

Here we start our service, and start the listener “broadcastReceiver” which will send us messages from the service to the onDataFromService function.
ServiceExchange.BROADCAST_ACTION it is necessary to indicate the tag of our message, otherwise they will be lost.
')
ServiceExchange:
 public class ServiceExchange extends Service { private Intent intent; public static final String BROADCAST_ACTION = "com.rheit.base.event"; //    @Override public void onCreate() { super.onCreate(); intent = new Intent(BROADCAST_ACTION); createConnect(); } Handler myUpdateHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case config.ERR_SOCKET_SERVER_UNAVAILABLE: //    createConnect(); //  sendBroadcast((Intent) msg.obj); //    UI break; case config.CODE_SOCKET_SERVER_ANSWER: //     //        sendBroadcast((Intent) msg.obj); //    UI break; case config.CODE_SOCKET_SERVER_CONNECTED: //     //        sendBroadcast((Intent) msg.obj); //    UI break; default: break; } super.handleMessage(msg); } }; @Override public IBinder onBind(Intent arg0) { Log.v(this.getClass().getName(), "---> Service binded."); return null; } @Override public void onDestroy() { Toast.makeText(this, "Service destoyed", Toast.LENGTH_LONG).show(); Log.v(this.getClass().getName(), "Service destoyed."); } private void createConnect() { if (ServerTask == null || ServerTask.getStatus().equals(AsyncTask.Status.FINISHED)) { ServerTask = new SocketAsync(myUpdateHandler); ServerTask.execute(); config.SOCKET_MESSAGE = ServerCommands.login("name", "pass"); } } } 

The service implements control of the connection to the server through the SocketAsync class, and data transfer from SocketAsync to the MainActivity via the BroadcastReceiver.

SocketAsync:
 class SocketAsync extends AsyncTask<Void, Integer, Void> { public Socket socket; public String message; public Handler threadHandler; public Context parent; public SocketAsync(Handler threadHandler) { this.threadHandler = threadHandler; } @Override protected Void doInBackground(Void... params) { try { if (config.SOCKET_CONNECTED == false) { InetAddress serverAddr = InetAddress .getByName(config.SERVER_ADDR); socket = new Socket(serverAddr, config.SERVER_PORT); config.SOCKET_CONNECTED = true; Intent intent = new Intent(ServiceExchange.BROADCAST_ACTION); intent.putExtra("SERVER_STATUS", true); Message threadMessage = new Message(); threadMessage.what = com.rheit.config.CODE_SOCKET_SERVER_CONNECTED; threadMessage.obj = intent; threadHandler.sendMessage(threadMessage); } } catch (Exception e) { Intent intent = new Intent(ServiceExchange.BROADCAST_ACTION); intent.putExtra("SERVER_STATUS", false); Message threadMessage = new Message(); threadMessage.what = com.rheit.config.ERR_SOCKET_SERVER_UNAVAILABLE; threadMessage.obj = intent; threadHandler.sendMessage(threadMessage); Log.e(SocketAsync.class.toString(), "ERR_SOCKET_SERVER_UNAVAILABLE doInBackground"); } Thread threadWrite = new Thread(new Runnable() { @Override public void run() { send(socket); } }); threadWrite.start(); //    while (socket != null && socket.isConnected()) { Message m = new Message(); m.what = config.CODE_SOCKET_SERVER_ANSWER; try { BufferedReader input = new BufferedReader( new InputStreamReader(socket.getInputStream())); String st = null; st = input.readLine(); if (st == null) { threadWrite.stop(); socket.close(); socket = null; } else { m.obj = st; myUpdateHandler.sendMessage(m); } } catch (IOException e) { e.printStackTrace(); } } threadWrite.stop(); return null; } protected void send(Socket socket) { while (socket != null && socket.isConnected()) { if (config.SOCKET_MESSAGE != null) { Log.d("Send Message", config.SOCKET_MESSAGE); try { PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); out.println(config.SOCKET_MESSAGE); } catch (Exception e) { Log.e("TCP", "S: Error", e); return; } config.SOCKET_MESSAGE = null; } } } protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); if (values.length > 0) { Log.d("onProgressUpdate", values[0].toString()); } } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); if (socket == null || !socket.isConnected()) { config.SOCKET_CONNECTED = false; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Intent intent = new Intent(ServiceExchange.BROADCAST_ACTION); intent.putExtra("SERVER_STATUS", false); Message threadMessage = new Message(); threadMessage.what = com.rheit.config.ERR_SOCKET_SERVER_UNAVAILABLE; threadMessage.obj = intent; threadHandler.sendMessage(threadMessage); Log.e(SocketAsync.class.toString(), "ERR_SOCKET_SERVER_UNAVAILABLE onPostExecute"); } } Handler myUpdateHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case config.CODE_SOCKET_SERVER_ANSWER: Intent intent = new Intent(ServiceExchange.BROADCAST_ACTION); intent.putExtra("text", "test"); Message threadMessage = new Message(); threadMessage.what = com.rheit.config.CODE_SOCKET_SERVER_ANSWER; threadMessage.obj = intent; threadHandler.sendMessage(threadMessage); break; default: break; } super.handleMessage(msg); } }; } 

When we started the SocketAsync task, we started connecting to the server if we connected, then send a message to the UI that we connected via:
 Intent intent = new Intent(ServiceExchange.BROADCAST_ACTION); intent.putExtra("SERVER_STATUS", true); Message threadMessage = new Message(); threadMessage.what = com.rheit.config.CODE_SOCKET_SERVER_CONNECTED; threadMessage.obj = intent; threadHandler.sendMessage(threadMessage); 

Then it goes to ServiceExchange to the myUpdateHandler we created, which in turn sends data to the UI via sendBroadcast:
 case config.CODE_SOCKET_SERVER_CONNECTED: //     //        sendBroadcast((Intent) msg.obj); //    UI break; 

After that, our data is transferred to MainActivity :
 private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onDataFromService(intent); } }; public void onDataFromService(Intent intent) { Log.d("onDataFromService", intent.getStringExtra("text")); } 


When we close our application, the unregisterReceiver function destroys the listener and everything that is transferred from our socket client is lost, for this I advise you to use the data coming from the outside to record in the database and use the BroadcastReceiver to notify you that you need to read something from the database.

Source: https://habr.com/ru/post/150742/


All Articles