В предыдущем уроке мы узнали об основах работы со службами (Services) в Android. Теперь, когда мы уже понимаем разницу между Service и IntentService, можем приступать к более сложным темам межпроцессного взаимодействия. Если вы еще не знакомыми с основами работы со службами, то желательно просмотреть этот материал по Service и IntentService в Android.
В этой статье мы научимся работать со службой, которая использует Messenger для целей межпроцессного взаимодействия.
Messenger в Android. Пример использования
В этой статье был сделан акцент на связанных службах, которые работают в фоновом режиме в разных процессах в однопоточной или многопоточной среде.
Messenger используется для отправки сообщений в другом процессе с помощью IPC (Inter-Process Communication) тем самым обеспечивая связь между клиентом и сервером. Messenger будет связан с обработчиком (handler), поэтому вся работа будет происходить в одиночном потоке обработчика.
Чтобы привязать Service, нужно передать ссылку на экзмепляр Messenger в метод onBind()
и передать ссылку обработчика при создании экземпляр Messenger. Давайте посмотрим небольшой пример создания службы, которая работает в другом процессе, используя Messenger, который связан с обработчиком:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
package com.javadevblog.messengerexampleapp; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.annotation.Nullable; import android.widget.Toast; public class SimpleServiceIPC extends Service { public static final int TASK_1 = 1; public static final int TASK_RESPONSE_1 = 2; Messenger messenger = new Messenger(new IncomingHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); } class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { Message message; Bundle bundle = new Bundle(); String messageText; switch (msg.what) { case TASK_1: messageText = msg.getData().getString("message"); message = Message.obtain(null, TASK_RESPONSE_1); Toast.makeText(getApplicationContext(), "Пришло с Activity: " + messageText, Toast.LENGTH_SHORT).show(); bundle.putString("message_res", messageText); message.setData(bundle); Messenger activityMessenger = msg.replyTo; try { activityMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } } } |
Как видно из кода, служба использует Messenger для общения с Activity. Все данные между Service и Acitivity передаются в объектах Bundle, что является очень удобным для передачи разного рода информации. Сама служба использует класс IncomingHandler — наследник Handler для обработки полученного сообщения.
Теперь давайте создадим Activity, чтобы привязать эту службу для отправки сообщений на сервер, и ответов сервера на клиент, используя обработчик Messenger:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
package com.javadevblog.messengerexampleapp; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private final Messenger mActivityMessenger = new Messenger(new ResponseHandler(this)); private Button mButtonSend; private EditText mEditTextMessage; private Messenger mMessenger; private boolean isBound; ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mMessenger = new Messenger(service); isBound = true; } @Override public void onServiceDisconnected(ComponentName name) { isBound = false; mMessenger = null; } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEditTextMessage = (EditText) findViewById(R.id.et_message); mButtonSend = (Button) findViewById(R.id.btn_send); mButtonSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String messageText = mEditTextMessage.getText().toString(); if (messageText.isEmpty()) { Toast.makeText(MainActivity.this, "Введите сообщение!", Toast.LENGTH_LONG).show(); } else { Message message = Message.obtain(null, SimpleServiceIPC.TASK_1); Bundle bundle = new Bundle(); bundle.putString("message", messageText); message.setData(bundle); message.replyTo = mActivityMessenger; try { mMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } } }); } @Override protected void onStart() { super.onStart(); if (!isBound) { // start service here Intent intent = new Intent(MainActivity.this, SimpleServiceIPC.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } } @Override protected void onStop() { super.onStop(); isBound = false; mMessenger = null; } private static class ResponseHandler extends Handler { private Context mContext; ResponseHandler(Context context) { mContext = context; } @Override public void handleMessage(Message msg) { switch (msg.what) { case SimpleServiceIPC.TASK_RESPONSE_1: String result = msg.getData().getString("message_res"); Toast.makeText(mContext, "Пришло из IPC службы: " + result, Toast.LENGTH_LONG).show(); break; default: super.handleMessage(msg); } } } } |
В этом приложении нам также требуется иметь ServiceConnection к службе для создания соединения между клиентом и сервером. ResponseHandler — наследник Handler обработает ответ Messenger’а и обновит пользовательский интерфейс.
Теперь добавим наш Service в AndroidManifest.xml
в секции application:
1 |
<service android:name=".SimpleServiceIPC" android:process=":remote"/> |
В файл макета добавим лишь поле ввода и кнопку для отправки сообщения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.javadevblog.messengerexampleapp.MainActivity"> <EditText android:id="@+id/et_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Введи сообщение..." /> <Button android:id="@+id/btn_send" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:background="@color/colorPrimaryDark" android:text="Отправить" android:textColor="#fff"/> </LinearLayout> |
Теперь запустим нашу програмку и посмотрим на результат:
Как видим, Messenger является отличным способом общения между сервером и клиентом.
Полный проект Android Studio вы найдете по ссылке.
В следующем уроке мы научимся работать с AIDL в разных процессах. Подписывайтесь на новости в соц. сетях и новые статьи.