サービス内のソケットクライアントとBroadcastReceiverを介したUIの更新

チャレンジ:

クライアントアプリケーションを「ソケット上」に作成して、メインアクティビティが閉じられたときに作業が続行され、接続が失われないようにします。



解決策:

Androidのサービスを使用してこれを行うことができます。サービスとは何か、どのように機能するかについて多くの記事が書かれているので、詳細には触れず実装を進めません。



このアプリケーションは、3つの最も重要なクラスで構成されています。





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")); }
      
      





ここで、サービスを起動し、リスナー「broadcastReceiver」を起動します。リスナーは、サービスからonDataFromService関数にメッセージを送信します。

ServiceExchange.BROADCAST_ACTIONにメッセージをタグ付けする必要があります。タグを付けないと、失われます。



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"); } } }
      
      





このサービスは、 SocketAsyncクラスを介したサーバーへの接続の制御、およびBroadcastReceiverを介したSocketAsyncからMainActivityへのデータ転送を実装します。



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); } }; }
      
      





SocketAsyncタスクを開始すると、サーバーへの接続を開始しました;接続すると、接続したUIにメッセージを送信します:

 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);
      
      





次に、作成したmyUpdateHandlerでServiceExchangeにアクセスし、 sendBroadcastを介してUIにデータを渡します。

 case config.CODE_SOCKET_SERVER_CONNECTED: //     //        sendBroadcast((Intent) msg.obj); //    UI break;
      
      





その後、データが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")); }
      
      







アプリケーションを閉じると、 unregisterReceiver関数はリスナーを破棄し、ソケットクライアントから転送されるものはすべて失われます。このため、外部からのデータを通知し、データベースに書き込み、 BroadcastReceiverを使用してデータベースから何かを読み取る必要があることを通知します。



All Articles