Статьи

Get Wear OS и Android Talking: обмен информацией через носимый уровень данных

Когда дело доходит до выполнения быстрых, простых задач, носимые приложения имеют преимущество, так как умные часы, которые прямо на вашем запястье, всегда будут более доступными, чем смартфон или планшет, который плавает где-то в вашей сумке.

Но нет такого понятия, как идеальный гаджет, и никто не бредит по поводу времени автономной работы своих умных часов или заявляет, что он такой же быстрый и мощный, как их смартфон или планшет.

Чтобы обеспечить наилучшее взаимодействие с пользователем, вам необходимо использовать сильные стороны устройства. Если вы разрабатываете для Wear OS ( операционная система, ранее известная как Android-Wear ), то у вас есть уникальная возможность выбрать лучшие функции из двух совершенно разных устройств.

В принципе, вы можете иметь лучшее из обоих миров!

В этой статье я покажу вам, как максимально использовать все возможности ОС Android и Wear OS, открыв канал связи между ними. После того, как ваше портативное приложение и его носимый коллега общаются в чате, вы можете делегировать задачи на основе устройства, для которого оно лучше всего подходит — будь то разгрузка ресурсоемких задач на КПК или уверенность в том, что наиболее важная информация вашего приложения всегда легко доступна благодаря ее отображению. на запястье пользователя.

К концу этой статьи вы MessageClient портативное и носимое приложение, которое может обмениваться информацией через слой MessageClient данных и API-интерфейс MessageClient .

Уровень носимых данных обеспечивает доступ к различным классам клиентов, которые вы можете использовать для хранения и извлечения данных, без необходимости запачкать руки техническими деталями, такими как сериализация данных. Как только эта информация попадает на уровень данных, она становится доступной как для портативного, так и для носимого устройства.

В этой статье мы сосредоточимся на API-интерфейсе MessageClient , который является механизмом односторонней связи, который можно использовать для отправки информации на уровень носимых данных. Этот API особенно удобен для выполнения удаленных вызовов процедур (RPC), таких как удаленный запуск Activity на парном портативном или носимом устройстве.

Давайте рассмотрим пример: представьте, что вы создали навигационное приложение. Это приложение должно а) получать обновления местоположения, и б) давать указания пользователя.

Мониторинг местоположения устройства — интенсивная задача, которая может быстро разрядить ограниченную батарею, доступную обычному носителю. Используя MessageClient API, ваше носимое приложение может дать указание своему портативному коллеге выполнить эту работу. После того, как контроллер выполнил эту тяжелую работу, он может отправить полученную информацию обратно носимому устройству через уровень данных, чтобы ваше приложение получало необходимую информацию, не вынимая кусок оставшейся батареи носимого устройства.

Как правило, если вашему носимому приложению необходимо выполнить задачу, требующую значительной батареи или вычислительной мощности, или сложных взаимодействий с пользователем, вам следует рассмотреть возможность передачи этой работы в соответствующее портативное приложение. Напротив, если ваше приложение имеет дело с особенно чувствительной ко времени информацией или контентом, к которому пользователь может получить доступ на ходу, то вы должны отобразить эту информацию в носимом приложении.

В нашем примере с навигационным приложением нажатие каждого набора направлений от портативного устройства к носимому делает эту информацию более доступной, особенно для тех, кто находится вне дома и безнадежно потерян!

MessageClient API — это механизм односторонней связи, но вы можете реализовать двунаправленный обмен сообщениями, создав отправителя и получателя как в портативном, так и в носимом модуле вашего проекта, и это именно то, что мы собираемся сделать.

В этой статье мы собираемся создать носимое приложение, которое будет распознавать, когда его переносная копия отправляет новое сообщение на уровень данных. Это пригодное для носки приложение ответит, получив это сообщение и отобразив его как часть своего пользовательского интерфейса.

Затем мы ополаскиваем и повторяем, создавая портативное приложение, которое отслеживает уровень данных на наличие сообщений, отправляемых его носимым аналогом.

Информация, отправленная через MessageClient API, доступна только приложению, которое ее создало. Если система собирается идентифицировать ваш носимый и портативный компьютер как принадлежащий к одному и тому же приложению, тогда они должны будут иметь одинаковое имя пакета, код версии и сертификат подписи. Самый простой способ отметить все эти поля — создать проект, который состоит из переносного и портативного модуля:

  • Создайте новый проект под названием DataLayer .
  • На экране « Целевое устройство Android» выберите « Телефон и планшет» и « Износ» . Нажмите Далее .
  • Для модуля телефона и планшета выберите шаблон « Пустое действие» и нажмите « Далее» .
  • Для вашего носимого модуля выберите шаблон Blank Wear Activity , затем нажмите Next , а затем Finish .

Поскольку мы реализуем двунаправленную связь, как нашему карманному, так и мобильному модулям необходим собственный слушатель и отправитель. Давайте начнем с реализации этой функциональности в нашем портативном приложении.

Я собираюсь упростить задачу и создать пользовательский интерфейс, состоящий из TextView который будет отображать различные сообщения, извлеченные из уровня данных, и кнопку, которая при нажатии будет отправлять свое собственное сообщение на уровень данных.

Откройте файл activity_main.xml вашего мобильного модуля и добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<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»
   android:paddingBottom=»@dimen/vertical_margin»
   android:paddingLeft=»@dimen/horizontal_margin»
   android:paddingRight=»@dimen/horizontal_margin»
   android:paddingTop=»@dimen/vertical_margin»
   tools:context=».MainActivity»>
 
   <Button
       android:id=»@+id/talkButton»
       android:layout_width=»match_parent»
       android:layout_height=»wrap_content»
       android:text=»Talk to the wearable»
       android:onClick=»talkClick»/>
 
       <TextView
           android:id=»@+id/textView»
           android:layout_width=»match_parent»
           android:layout_height=»match_parent»/>
 
</LinearLayout>

Так как мы ссылались на несколько значений Dimens.xml , нам нужно предоставить определения для этих значений:

  • Control — щелкните каталог res / values мобильного модуля.
  • Выберите « Создать»> «Файл значений» .
  • Назовите этот файл Dimens.xml и нажмите кнопку ОК .
  • Добавьте следующее:
1
2
3
4
<resources>
   <dimen name=»horizontal_margin»>20dp</dimen>
   <dimen name=»vertical_margin»>20dp</dimen>
</resources>

Это дает нам следующий пользовательский интерфейс:

Create the user interface for your projects handheld component

Откройте файл build.gradle мобильного модуля и добавьте следующие зависимости:

1
2
3
4
5
6
7
dependencies {
   implementation fileTree(dir: ‘libs’, include: [‘*.jar’])
   wearApp project(‘:wear’)
   implementation ‘com.android.support:appcompat-v7:26.1.0’
   implementation ‘com.google.android.gms:play-services-wearable:+’
 
}

В MainActivity нам необходимо выполнить следующее:

  1. Держите пользователя в курсе!

Когда пользователь нажимает кнопку « Поговорить с носимым» , должны произойти две вещи:

  • Контроллер отправляет сообщение на носимый. Я собираюсь использовать « Я получил сообщение от портативного устройства ».
  • Контроллер предоставляет визуальное подтверждение того, что сообщение было успешно отправлено. Я собираюсь использовать « Я отправил сообщение на носимый ».

Когда пользователь нажимает кнопку « Разговор с носимым» на контроллере, он пытается отправить сообщение на уровень данных. Система считает, что это сообщение успешно отправлено, как только оно помещено в очередь для доставки на определенное устройство, что означает, что должно быть доступно хотя бы одно сопряженное устройство.

В лучшем случае пользователь нажимает кнопку « Поговорить с носимым» , сообщение ставится в очередь для доставки, и наш КПК торжественно заявляет, что: « Я только что отправил сообщение носимому устройству ».

Однако, если нет доступных носимых устройств, сообщение не помещается в очередь, и по умолчанию пользователь не получает подтверждения, что наше приложение даже пыталось отправить сообщение. Это может заставить пользователя задуматься, не сломано ли приложение, поэтому я также собираюсь отобразить сообщение об отправке… . уведомление, независимо от того, успешно ли сообщение поставлено в очередь или нет.

При тестировании этого приложения, вы также можете вызвать несколько сообщений в быстрой последовательности. Чтобы прояснить, когда каждое сообщение было поставлено в очередь для доставки, я добавляю счетчик к каждому сообщению, чтобы наш контроллер отображал сообщение « Я только что отправил сообщение носимому 2» , я просто отправил сообщение носимому 3 и так далее. на. На другой стороне соединения наш носимый дисплей покажет, что я только что получил сообщение от контроллера 2 , я только что получил сообщение от контроллера 3 и так далее.

2. Показать полученные сообщения

В следующем разделе мы MessageService который контролирует уровень данных и извлекает сообщения. Поскольку наш сервис будет выполнять свою работу в другом потоке, он будет передавать эту информацию в нашу MainActivity , которая затем будет отвечать за обновление пользовательского интерфейса.

3. Определите путь

Каждое сообщение, передаваемое через API-интерфейс MessageClient должно содержать путь, который представляет собой строку, которая уникальным образом идентифицирует сообщение и позволяет вашему приложению получать к нему доступ с другой стороны соединения.

Этот путь всегда начинается с косой черты (я использую / my_path ) и может также содержать дополнительную полезную нагрузку в виде байтового массива.

4. Проверьте свои узлы!

В сервисах Google Play 7.3.0 и выше вы можете подключить несколько носимых устройств к одному портативному устройству — например, пользователь может использовать несколько носимых устройств, которые они переключают или используют одновременно. Устройство Wear OS также может быть подключено к нескольким портативным устройствам в течение срока его службы, например, если пользователь владеет смартфоном Android и планшетом, или они заменяют свой старый смартфон на новый. Обратите внимание, что любое устройство, которое может подключиться к уровню данных, называется кодом в коде приложения.

В этой статье я собираюсь предположить, что будет только один доступный носимый. Кроме того, вы можете выбрать, на какие устройства вы отправляете сообщения, используя GetConnectedNodes или getLocalNode .

Давайте реализуем все это в нашей MainActivity :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import android.support.v7.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.widget.Button;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
 
import com.google.android.gms.wearable.Node;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.android.gms.wearable.Wearable;
 
import java.util.List;
import java.util.concurrent.ExecutionException;
 
public class MainActivity extends AppCompatActivity {
 
   Button talkbutton;
   TextView textview;
   protected Handler myHandler;
   int receivedMessageNumber = 1;
   int sentMessageNumber = 1;
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       talkbutton = findViewById(R.id.talkButton);
       textview = findViewById(R.id.textView);
 
      //Create a message handler//
 
       myHandler = new Handler(new Handler.Callback() {
           @Override
           public boolean handleMessage(Message msg) {
               Bundle stuff = msg.getData();
               messageText(stuff.getString(«messageText»));
               return true;
           }
       });
 
//Register to receive local broadcasts, which we’ll be creating in the next step//
 
       IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
       Receiver messageReceiver = new Receiver();
       LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
 
   }
 
   public void messageText(String newinfo) {
       if (newinfo.compareTo(«») != 0) {
           textview.append(«\n» + newinfo);
       }
   }
 
//Define a nested class that extends BroadcastReceiver//
 
   public class Receiver extends BroadcastReceiver {
       @Override
 
       public void onReceive(Context context, Intent intent) {
 
//Upon receiving each message from the wearable, display the following text//
 
           String message = «I just received a message from the wearable » + receivedMessageNumber++;;
 
           textview.setText(message);
 
       }
   }
 
   public void talkClick(View v) {
       String message = «Sending message…. «;
       textview.setText(message);
 
//Sending a message can block the main UI thread, so use a new thread//
 
       new NewThread(«/my_path», message).start();
 
   }
 
//Use a Bundle to encapsulate our message//
 
   public void sendmessage(String messageText) {
       Bundle bundle = new Bundle();
       bundle.putString(«messageText», messageText);
       Message msg = myHandler.obtainMessage();
       msg.setData(bundle);
       myHandler.sendMessage(msg);
 
   }
 
   class NewThread extends Thread {
       String path;
       String message;
 
//Constructor for sending information to the Data Layer//
 
       NewThread(String p, String m) {
           path = p;
           message = m;
       }
 
       public void run() {
 
//Retrieve the connected devices, known as nodes//
 
           Task<List<Node>> wearableList =
                   Wearable.getNodeClient(getApplicationContext()).getConnectedNodes();
           try {
 
               List<Node> nodes = Tasks.await(wearableList);
               for (Node node : nodes) {
                   Task<Integer> sendMessageTask =
 
//Send the message//
 
                           Wearable.getMessageClient(MainActivity.this).sendMessage(node.getId(), path, message.getBytes());
 
                   try {
 
//Block on a task and get the result synchronously//
 
                       Integer result = Tasks.await(sendMessageTask);
                       sendmessage(«I just sent the wearable a message » + sentMessageNumber++);
 
 //if the Task fails, then…..//
 
                   } catch (ExecutionException exception) {
 
                       //TO DO: Handle the exception//
 
                   } catch (InterruptedException exception) {
 
                //TO DO: Handle the exception//
 
                   }
 
               }
 
           } catch (ExecutionException exception) {
 
               //TO DO: Handle the exception//
 
           } catch (InterruptedException exception) {
 
               //TO DO: Handle the exception//
           }
 
       }
   }
}

На этом этапе наш контроллер может передавать сообщения на уровень данных, но, поскольку мы хотим реализовать двунаправленную связь, ему также необходимо прослушивать сообщения, поступающие на уровень данных.

В этом разделе мы собираемся создать сервис, который выполняет следующее:

  1. Мониторинг уровня данных на наличие событий

Вы можете отслеживать уровень данных, реализуя интерфейс DataClient.OnDataChangedListener или расширяя WearableListenerService . Я выбираю последнее, поскольку есть несколько преимуществ для расширения WearableListenerService . Во-первых, WearableListenerService работает с фоновым потоком, поэтому вам не нужно беспокоиться о блокировке основного потока пользовательского интерфейса. Во-вторых, система управляет жизненным циклом WearableListenerService чтобы гарантировать, что она не потребляет ненужные ресурсы, привязывая и отменяя привязку службы по мере необходимости.

Недостатком является то, что WearableListenerService будет прослушивать события, даже когда ваше приложение не запущено, и запускать его, если обнаружит соответствующее событие. Если ваше приложение должно реагировать на события только тогда, когда оно уже запущено, то WearableListenerService может излишне разряжать батарею устройства.

2. Переопределите соответствующие обратные вызовы данных

WearableListenerService может прослушивать диапазон событий уровня данных, поэтому вам нужно переопределить методы обратного вызова событий данных для событий, которые вы хотите обработать. В нашем сервисе я реализую onMessageReceived , который будет срабатывать при отправке сообщения с удаленного узла.

3. Проверьте путь

Каждый раз, когда сообщение отправляется на уровень данных, наше приложение должно проверять, имеет ли оно правильный идентификатор my_path .

4. Трансляция сообщений в MainActivity

Поскольку WearableListenerService работает в другом потоке, он не может обновлять интерфейс напрямую. Чтобы отобразить сообщение в нашем приложении, нам нужно переслать его в MainActivity , используя LocalBroadcastManager .

Чтобы создать сервис:

  • Убедитесь, что у вас выбран мобильный модуль.
  • Выберите « Создать»> «Сервис» на панели инструментов Android Studio.
  • Назовите этот сервис MessageService .
  • Добавьте следующее:
01
02
03
04
05
06
07
08
09
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
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;
 
//Extend WearableListenerService//
 
public class MessageService extends WearableListenerService {
 
   @Override
   public void onMessageReceived(MessageEvent messageEvent) {
 
//If the message’s path equals «/my_path»…//
 
       if (messageEvent.getPath().equals(«/my_path»)) {
 
//…retrieve the message//
 
           final String message = new String(messageEvent.getData());
 
           Intent messageIntent = new Intent();
           messageIntent.setAction(Intent.ACTION_SEND);
           messageIntent.putExtra(«message», message);
 
//Broadcast the received Data Layer messages locally//
 
         LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
       }
       else {
           super.onMessageReceived(messageEvent);
       }
   }
 
}

Наконец, откройте Manifest и добавьте некоторую информацию в запись MessageService :

01
02
03
04
05
06
07
08
09
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
<?xml version=»1.0″ encoding=»utf-8″?>
<manifest xmlns:android=»http://schemas.android.com/apk/res/android»
   package=»com.jessicathornsby.datalayer» >
 
   <application
       android:allowBackup=»true»
       android:icon=»@mipmap/ic_launcher»
       android:label=»@string/app_name»
       android:theme=»@style/AppTheme» >
       <activity
           android:name=».MainActivity»
           android:label=»@string/app_name» >
           <intent-filter>
               <action android:name=»android.intent.action.MAIN» />
               <category android:name=»android.intent.category.LAUNCHER» />
           </intent-filter>
       </activity>
 
       //Add metadata for Google Play Services//
 
       <meta-data
           android:name=»com.google.android.gms.version»
           android:value=»@integer/google_play_services_version» />
 
       <service
           android:name=».MessageService»
           android:enabled=»true»
           android:exported=»true» >
 
//Add the gms.wearable.MESSAGE_RECEIVED intent filter//
 
           <intent-filter>
               <action android:name=»com.google.android.gms.wearable.MESSAGE_RECEIVED» />
 
//Specify your path, and a host for the filter.
 
               <data android:scheme=»wear» android:host=»*» android:pathPrefix=»/my_path» />
           </intent-filter>
       </service>
   </application>
 
</manifest>

Как уже упоминалось, система считает сообщение успешно отправленным только после того, как оно поставлено в очередь для доставки, что может произойти только при наличии одного или нескольких носимых устройств.

Это можно увидеть в действии, установив мобильный модуль на совместимый смартфон или планшет или виртуальное устройство Android (AVD). Нажмите кнопку Talk to Wearable , и приложение отобразит сообщение об отправке … только текст . Я только что отправил носимый … текст не появится.

Если наше сообщение когда-либо будет поставлено в очередь для доставки, тогда нам нужно внедрить другой набор компонентов отправителя и получателя в носимый модуль нашего проекта.

Наше носимое приложение будет иметь такую ​​же функциональность, как и его портативный аналог, поэтому я пропущу весь код, который мы уже рассмотрели.

Еще раз, давайте начнем с создания пользовательского интерфейса приложения. Откройте файл activity_main.xml модуля износа и добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version=»1.0″ encoding=»utf-8″?>
 
//Wrap the layout in BoxInsetLayout so it displays correctly on both square and round watches//
 
<android.support.wear.widget.BoxInsetLayout
   xmlns:android=»http://schemas.android.com/apk/res/android»
   xmlns:app=»http://schemas.android.com/apk/res-auto»
   xmlns:tools=»http://schemas.android.com/tools»
   android:layout_width=»match_parent»
   android:layout_height=»match_parent»
   tools:context=».MainActivity»
   tools:deviceIds=»wear»>
 
   <LinearLayout
       android:layout_width=»match_parent»
       android:layout_height=»match_parent»
       android:gravity=»center_horizontal»
       android:orientation=»vertical»
       app:boxedEdges=»all»>
 
       <Button
           android:id=»@+id/talkClick»
           android:layout_width=»wrap_content»
           android:layout_height=»wrap_content»
           android:text=»Talk to the handheld»/>
 
       <TextView
           android:id=»@+id/text»
           android:layout_width=»wrap_content»
           android:layout_height=»wrap_content»/>
   </LinearLayout>
</android.support.wear.widget.BoxInsetLayout>

На этом этапе ваш пользовательский интерфейс должен выглядеть примерно так:

Create the UI for your Android projects Wear OS module

Откройте свой build.gradle и добавьте следующие зависимости:

1
2
3
4
5
6
7
dependencies {
   compile fileTree(dir: ‘libs’, include: [‘*.jar’])
   provided ‘com.google.android.wearable:wearable:2.2.0’
   implementation ‘com.google.android.support:wearable:2.2.0’
   implementation ‘com.google.android.gms:play-services-wearable:12.0.1’
   implementation ‘com.android.support:wear:26.1.0’
}

Теперь нам нужно отправить наше сообщение на уровень данных:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import android.content.BroadcastReceiver;
import android.os.Bundle;
import android.widget.Button;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.wearable.activity.WearableActivity;
import android.widget.TextView;
import android.view.View;
 
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.Node;
 
import java.util.List;
import java.util.concurrent.ExecutionException;
 
public class MainActivity extends WearableActivity {
 
   private TextView textView;
   Button talkButton;
   int receivedMessageNumber = 1;
   int sentMessageNumber = 1;
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       textView = findViewById(R.id.text);
       talkButton = findViewById(R.id.talkClick);
 
//Create an OnClickListener//
 
       talkButton.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               String onClickMessage = «I just sent the handheld a message » + sentMessageNumber++;
               textView.setText(onClickMessage);
 
//Use the same path//
 
               String datapath = «/my_path»;
               new SendMessage(datapath, onClickMessage).start();
 
           }
       });
 
//Register to receive local broadcasts, which we’ll be creating in the next step//
 
       IntentFilter newFilter = new IntentFilter(Intent.ACTION_SEND);
       Receiver messageReceiver = new Receiver();
 
       LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, newFilter);
 
   }
 
   public class Receiver extends BroadcastReceiver {
       @Override
       public void onReceive(Context context, Intent intent) {
 
//Display the following when a new message is received//
 
           String onMessageReceived = «I just received a message from the handheld » + receivedMessageNumber++;
           textView.setText(onMessageReceived);
            
       }
   }
 
   class SendMessage extends Thread {
       String path;
       String message;
 
//Constructor for sending information to the Data Layer//
 
       SendMessage(String p, String m) {
           path = p;
           message = m;
       }
 
       public void run() {
 
//Retrieve the connected devices//
 
           Task<List<Node>> nodeListTask =
                   Wearable.getNodeClient(getApplicationContext()).getConnectedNodes();
           try {
 
//Block on a task and get the result synchronously//
 
               List<Node> nodes = Tasks.await(nodeListTask);
               for (Node node : nodes) {
 
//Send the message///
 
                   Task<Integer> sendMessageTask =
                           Wearable.getMessageClient(MainActivity.this).sendMessage(node.getId(), path, message.getBytes());
 
                   try {
 
                       Integer result = Tasks.await(sendMessageTask);
 
//Handle the errors//
 
                   } catch (ExecutionException exception) {
 
//TO DO//
 
                   } catch (InterruptedException exception) {
 
//TO DO//
 
                   }
 
               }
 
           } catch (ExecutionException exception) {
 
//TO DO//
 
           } catch (InterruptedException exception) {
 
//TO DO//
 
           }
       }
   }
}

Затем нам нужно создать прослушиватель, который будет отслеживать уровень данных на наличие входящих сообщений и уведомлять MainActivity при получении нового сообщения:

  • Убедитесь, что выбран модуль износа .
  • Выберите « Создать»> «Сервис» на панели инструментов Android Studio.
  • Назовите этот сервис MessageService и добавьте следующее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import android.content.Intent;
import com.google.android.gms.wearable.MessageEvent;
import android.support.v4.content.LocalBroadcastManager;
import com.google.android.gms.wearable.WearableListenerService;
 
public class MessageService extends WearableListenerService {
 
   @Override
   public void onMessageReceived(MessageEvent messageEvent) {
 
//If the message’s path equals «/my_path»…//
 
       if (messageEvent.getPath().equals(«/my_path»)) {
 
//…retrieve the message//
 
           final String message = new String(messageEvent.getData());
           Intent messageIntent = new Intent();
           messageIntent.setAction(Intent.ACTION_SEND);
           messageIntent.putExtra(«message», message);
 
//Broadcast the received Data Layer messages locally//
 
           LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
       }
       else {
           super.onMessageReceived(messageEvent);
       }
   }
 
}

Откройте Manifest модуля и создайте фильтр намерений для WearableListenerService :

01
02
03
04
05
06
07
08
09
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
<?xml version=»1.0″ encoding=»utf-8″?>
<manifest xmlns:android=»http://schemas.android.com/apk/res/android»
   package=»com.jessicathornsby.datalayer» >
 
   <uses-feature android:name=»android.hardware.type.watch» />
 
   <application
       android:allowBackup=»true»
       android:icon=»@mipmap/ic_launcher»
       android:label=»@string/app_name»
       android:theme=»@android:style/Theme.DeviceDefault» >
       <activity
           android:name=».MainActivity»
           android:label=»@string/app_name» >
           <intent-filter>
               <action android:name=»android.intent.action.MAIN» />
               <category android:name=»android.intent.category.LAUNCHER» />
           </intent-filter>
       </activity>
       <service android:name=».MessageService»>
 
//Add the gms.wearable.MESSAGE_RECEIVED intent filter//
 
           <intent-filter>
               <action android:name=»com.google.android.gms.wearable.MESSAGE_RECEIVED» />
 
//Specify your path, and a host for the filter.
 
               <data android:scheme=»wear» android:host=»*» android:pathPrefix=»/my_path» />
 
           </intent-filter>
       </service>
   </application>
 
</manifest>

Вы можете скачать полный проект с GitHub .

На данный момент у вас есть два приложения, которые могут обмениваться сообщениями на уровне данных, но если вы собираетесь испытать эти навыки общения, вам необходимо установить свой проект на портативное и носимое устройство.

Если вы разработчик Android, скорее всего, у вас есть хотя бы один Android-смартфон или планшет, но носимые устройства все еще ощущаются как относительно новый и нишевый продукт, так что вы, возможно, еще не инвестировали в умные часы.

Если вы решите заняться разработкой Wear OS, вам следует в какой-то момент сделать решительный шаг и приобрести умные часы, поскольку ничто не заменит тестирования вашего приложения на реальном устройстве Android. Однако, если вы просто экспериментируете с Wear OS, тогда вы можете создать AVD, который имитирует носимый, точно так же, как вы создаете AVD, который имитирует смартфон или планшет. После этого вы можете подключить AVD и свое физическое устройство Android, используя переадресацию портов.

Первым шагом является создание носимого AVD и установка вашего модуля износа на этом эмулируемом устройстве:

  • Выберите Инструменты> Android> AVD Manager на панели инструментов Android Studio.
  • Нажмите Создать виртуальное устройство …
  • Выберите Износ в левом меню.
  • Выберите носимый, который вы хотите подражать, и нажмите кнопку Далее .
  • Выберите образ вашей системы и нажмите « Далее» .
  • Дайте вашему AVD имя, а затем нажмите « Готово» .
  • Выберите « Выполнить»> «Выполнить …» на панели инструментов Android Studio.
  • В появившемся маленьком всплывающем окне выберите Надеть …
  • Выберите носимый AVD, который вы только что создали. Через несколько секунд AVD запустится с уже установленным носимым компонентом.

Затем установите ручной модуль на свой смартфон или планшет:

  • Подключите ваше физическое устройство Android к вашей машине разработки.
  • Выберите « Выполнить»> «Выполнить …» на панели инструментов Android Studio.
  • Выберите мобильный телефон при появлении запроса.

Наконец, нам нужно, чтобы наше физическое устройство Android и наш AVD говорили:

  • Убедитесь, что Bluetooth включен на вашем контроллере (« Настройки»> «Bluetooth» ) и что он подключен к устройству разработки через USB-кабель.
  • На вашем портативном устройстве откройте Play Store и загрузите приложение Wear OS от Google (ранее Android Wear).
  • Запустите приложение Wear OS.
  • На эмулируемом носителе нажмите кнопку « Домой» на сопровождающей полосе кнопок (где курсор расположен на следующем снимке экрана) и затем откройте приложение « Настройки» .

Testing your project by connecting your emulator and your Android smartphone or tablet

  • Выберите Система> О программе и нажимайте номер сборки несколько раз, пока не увидите сообщение « Вы являетесь разработчиком» .
  • Вернитесь в главное меню настроек , дважды нажав кнопку « Назад» . Вы должны заметить новый пункт « Параметры разработчика» ; дать ему щелчок.
  • Выберите ADB Debugging .
  • На компьютере разработчика откройте новую командную строку (Windows) или терминал (Mac), а затем измените каталог ( cd ) так, чтобы он указывал на папку платформ инструментов Android SDK. Например, моя команда выглядит так:
1
cd /Users/jessicathornsby/Library/Android/sdk/platform-tools
  • Убедитесь, что ADB (Android Debug Bridge) распознает как эмулятор, так и подключенный смартфон или планшет, выполнив команду /.adb devices . Он должен вернуть коды для двух отдельных устройств.
  • Переадресуйте коммуникационный порт вашего AVD на подключенный смартфон или планшет, выполнив следующую команду в окне терминала / командной строки:
1
./adb -d forward tcp:5601 tcp:5601
  • Запустите приложение Wear OS на своем контроллере. Перемещайтесь по любым вводным диалогам, пока не дойдете до основного экрана Wear OS.
  • Откройте раскрывающийся список в верхнем левом углу и выберите Добавить новые часы .
  • Нажмите на пунктирный значок в правом верхнем углу и выберите « Сопряжение с эмулятором» . Через несколько секунд контроллер должен подключиться к вашему эмулятору.
Use the Wear OS app to pair your emulator with your Android smartphone or tablet

Теперь вы готовы протестировать свое приложение! Запустите компонент Wear на вашем эмуляторе и мобильный компонент на вашем контроллере и экспериментируйте, нажимая различные кнопки Talk ….

При нажатии кнопки « Разговор с носимым устройством» на контроллере должны появиться следующие сообщения:

  • КПК : «Я только что отправил на КПК сообщение».
  • Носимый: «Я только что получил сообщение от портативного устройства».
You can now exchange messages over the Data Layer using the MessageClient API

При нажатии кнопки « Поговорить с портативным устройством» на носителе должны появиться следующие сообщения:

  • Носимый: «Я только что отправил на КПК сообщение».
  • Карманный компьютер: «Я только что получил сообщение от носимого».

В этой статье мы рассмотрели, как обмениваться сообщениями между вашим карманным компьютером и носимым приложением через слой носимых данных.

В производстве вы, вероятно, использовали бы эту технику, чтобы сделать что-то более интересное, чем простой обмен одними и теми же строками текста! Например, если вы разработали приложение, которое воспроизводит музыку на смартфоне пользователя, вы можете дать им возможность воспроизводить, приостанавливать и пропускать песни непосредственно с их носимых устройств, отправляя эти инструкции с носимого устройства на портативный компьютер через уровень данных. ,

Вы можете узнать больше о слое носимых данных, в том числе о том, как синхронизировать более сложные данные, в официальных документах по Android .