החל מ-גרסה
גרסה 11.8.0 של Google Play Services, אפליקציות ל-Wear OS אמורות להפסיק את השימוש באפליקציות ל-Wear OS
מGoogleApiClient
ובמקום זאת להשתמש באובייקטים של לקוח שמבוססים על המחלקה
GoogleApi
.
השימוש ב-
GoogleApi
מקל על הגדרה של פעולות אסינכרוניות.
לדוגמה, כפי שמתואר במבוא
Tasks API, אפשר לקבל אובייקט Task
במקום
אובייקט
PendingResult
.
הדף הזה כולל:
- טבלה של רכיבים חלופיים
- דוגמה לעדכון של אפליקציה קיימת לשימוש ב-Tasks API
הערה: העדכון הזה לא חל על אפליקציות Wear OS עבור סין, שבה משתמשים בדרך כלל בגרסה 10.2.0 של Google Play Services.
הערה: ה-API הזה זמין כרגע רק בטלפונים עם Android ושעוני Wear OS שמותאמים לטלפונים עם Android. לשעוני Wear OS שמותאמים ל-iOS טלפונים, אפליקציות יכולות לשלוח שאילתות לממשקי API אחרים מבוססי-ענן אם קישוריות לאינטרנט זמינה.
החלפה של רכיבים שהוצאו משימוש
כשמשתמשים בכיתות שמרחיבות את המחלקה
GoogleApi
, כמו
DataClient
ו-
MessageClient
, ה-SDK של Google Play Services מנהל
חיבורים אל Google Play Services בשבילך.
באפליקציות שמשתמשות במחלקות החלופיות שבהמשך לא צריך ליצור
ניהול GoogleApiClient
אובייקטים. ראה גם גישה
Google APIs ו
דף עזר לסיווג 'גאדג'ט לביש'.
הטבלה הבאה מכילה רכיבים שהוצאו משימוש ואת החלפות:
רכיב שהוצא משימוש | רכיב חלופי |
CapabilityApi
|
CapabilityClient
|
Channel
|
ChannelClient.Channel
|
ChannelApi
|
ChannelClient
|
DataApi
|
DataClient
|
MessageApi
|
MessageClient
|
NodeApi
|
NodeClient
|
כמו כן, חשוב לשים לב לדברים הבאים:
- לקבלת התראות על שינויים בערוצים, הערך
Channel.ChannelListener
מוחלף ב-ChannelClient.ChannelCallback
- להגדרת ה-thread עבור קריאות חוזרות של מאזינים,
GoogleApiClient.Builder.setHandler
מוחלף ב- שיטתsetLooper
שלWearableOptions.Builder
דוגמה להעברה של אפליקציית Wear
כדוגמה להעברה, קטעי הקוד הבאים ממחישים איך נתוני Wear דוגמת השכבה, המשתמשת ב-Data Layer API, הייתה עודכנה לגרסה 11.8.0 של Google Play Services. אם לאפליקציה יש מודול של טלפון, העדכונים עשויים להיות דומים לאלו של מודול Wear.
עדכון התלות ב-Google Play Services
מכיוון שהאפליקציה עשויה להיות תלויה בגרסה קודמת של Google Play Services,
מעדכנים את התלות הבאה בקובץ build.gradle
של
מודול Wear:
dependencies { ... compile 'com.google.android.gms:play-services-wearable:11.8.0' }
עדכון הצהרות הייבוא של האפליקציה
לייבא את הכיתות הנדרשות, כולל כיתות ב-Tasks API.
לדוגמה, בעבר שכבת הנתונים של Wear
דוגמה כללה את הצהרת הייבוא הבאה
קובץ MainActivity.java
. דף החשבון הזה של import
יש להסיר:
Kotlin
... import com.google.android.gms.common.api.GoogleApiClient ...
Java
... import com.google.android.gms.common.api.GoogleApiClient; ...
ב-Wear
דוגמה של שכבת נתונים, import
הצהרות כמו שלמעלה
הוחלפו, לדוגמה, בטקסט הבא (השני הוא
טיפול בחריגות במשימות):
Kotlin
... import com.google.android.gms.tasks.Tasks import java.util.concurrent.ExecutionException ...
Java
... import com.google.android.gms.tasks.Tasks; import java.util.concurrent.ExecutionException; ...
הטמעת ממשקי הלקוח החדשים
להסיר כל שימוש ב-GoogleApiClient
class והממשקים המשויכים אליו (ConnectionCallbacks
,
OnConnectionFailedListener
, וכו') ומחליפים את הצד השני
הטמעות של מאזינים עם הגרסאות החדשות שלהם. השיטות בפועל
בדרך כלל יש להם שמות זהים לברירת המחדל, כך שהשינוי העיקרי הוא
בדומה לדוגמה שלמטה.
הפעילות העיקרית של מדגם Wear Data Layer (כפי שמצוין בהבדלים)
ב-
GitHub).
ממשק CapabilityApi.CapabilityListener
. אבל עכשיו,
הטמעה של הפעילות העיקרית
CapabilityClient.OnCapabilityChangedListener
בהמשך מוצגת השוואה בין הגדרות הכיתה.
קטע טקסט לפני השימוש בגרסה 11.8.0 של Google Play שירותים:
Kotlin
class MainActivity : Activity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener, CapabilityApi.CapabilityListener
Java
public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener, CapabilityApi.CapabilityListener
הנה קטע טקסט אחרי השימוש בגרסה 11.8.0 של Google Play שירותים:
Kotlin
class MainActivity : Activity(), DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
Java
public class MainActivity extends Activity implements DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
הסרה והוספה של מאזינים
האובייקטים החדשים של הלקוח נשמרים במטמון ומשותפים בין
GoogleApi
מכונות, לכן לא צריך להשאיר את הרכיב
משתנים; לא יקר ליצור אותם והם לא יאבדו את הבעלות
מאזינים.
למטה מופיע קטע טקסט משכבת הנתונים המתוקנת של Wear דוגמה:
Kotlin
override fun onResume() { super.onResume() Wearable.getDataClient(this).addListener(this) Wearable.getMessageClient(this).addListener(this) Wearable.getCapabilityClient(this) .addListener( this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE ) } override fun onPause() { super.onPause() Wearable.getDataClient(this).removeListener(this) Wearable.getMessageClient(this).removeListener(this) Wearable.getCapabilityClient(this).removeListener(this) }
Java
@Override protected void onResume() { super.onResume(); Wearable.getDataClient(this).addListener(this); Wearable.getMessageClient(this).addListener(this); Wearable.getCapabilityClient(this) .addListener( this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE); } @Override protected void onPause() { super.onPause(); Wearable.getDataClient(this).removeListener(this); Wearable.getMessageClient(this).removeListener(this); Wearable.getCapabilityClient(this).removeListener(this); }
בקשת מידע באמצעות Tasks API
כדאי לבקש מידע מחוץ למאזינים שיעדכנו
לאפליקציה כאשר יש שינוי בנתונים. במקרים כאלה, אפשר לשלוח בקשה באמצעות
לקוח כמו
DataClient
, בשילוב עם Tasks API ו-
מחלקה של תוצאה (כלומר, Task<ResultType>
).
לדוגמה, כפי שמוצג בשכבת הנתונים של Wear לדוגמה, אפשר להשתמש ב-Tasks API כדי למצוא צמתים מחוברים עם כל יכולת נתונה:
Kotlin
private fun showNodes(vararg capabilityNames: String) { Wearable.getCapabilityClient(this) .getAllCapabilities(CapabilityClient.FILTER_REACHABLE).apply { addOnSuccessListener { capabilityInfoMap -> val nodes: Set<Node> = capabilityInfoMap .filter { capabilityNames.contains(it.key) } .flatMap { it.value.nodes } .toSet() showDiscoveredNodes(nodes) } } } private fun showDiscoveredNodes(nodes: Set<Node>) { val nodesList: Set<String> = nodes.map { it.displayName }.toSet() val msg: String = if (nodesList.isEmpty()) { Log.d(TAG, "Connected Nodes: No connected device was found for the given capabilities") getString(R.string.no_device) } else { Log.d(TAG, "Connected Nodes: ${nodesList.joinToString(separator = ", ")}") getString(R.string.connected_nodes, nodesList) } Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show() }
Java
private void showNodes(final String... capabilityNames) { Task<Map<String, CapabilityInfo>> capabilitiesTask = Wearable.getCapabilityClient(this) .getAllCapabilities(CapabilityClient.FILTER_REACHABLE); capabilitiesTask.addOnSuccessListener(new OnSuccessListener<Map<String, CapabilityInfo>>() { @Override public void onSuccess(Map<String, CapabilityInfo> capabilityInfoMap) { Set<Node> nodes = new HashSet<>(); if (capabilityInfoMap.isEmpty()) { showDiscoveredNodes(nodes); return; } for (String capabilityName : capabilityNames) { CapabilityInfo capabilityInfo = capabilityInfoMap.get(capabilityName); if (capabilityInfo != null) { nodes.addAll(capabilityInfo.getNodes()); } } showDiscoveredNodes(nodes); } }); } private void showDiscoveredNodes(Set<Node> nodes) { List<String> nodesList = new ArrayList<>(); for (Node node : nodes) { nodesList.add(node.getDisplayName()); } LOGD(TAG, "Connected Nodes: " + (nodesList.isEmpty() ? "No connected device was found for the given capabilities" : TextUtils.join(",", nodesList))); String msg; if (!nodesList.isEmpty()) { msg = getString(R.string.connected_nodes, TextUtils.join(", ", nodesList)); } else { msg = getString(R.string.no_device); } Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show(); }
לקוד נוסף שמשתמש בממשקי ה-API של Wearable ו-Tasks: שכבת נתונים של Wear דוגמה. דוגמה לשימוש במשימות כבדות מחוץ לשרשור של ממשק המשתמש או בשירות, יש אפשרות אחרת. כאן יש דוגמה איך חוסמים משימה ומקבלים את התוצאה באופן סינכרוני:
Kotlin
override fun doInBackground(vararg params: Asset): Bitmap? { if (params.isNotEmpty()) { val asset = params[0] val getFdForAssetResponseTask: Task<DataClient.GetFdForAssetResponse> = Wearable.getDataClient(applicationContext).getFdForAsset(asset) return try { // Block on a task and get the result synchronously. This is generally done // when executing a task inside a separately managed background thread. Doing // this on the main (UI) thread can cause your application to become // unresponsive. val getFdForAssetResponse: DataClient.GetFdForAssetResponse = Tasks.await(getFdForAssetResponseTask) getFdForAssetResponse.inputStream?.let { assetInputStream -> BitmapFactory.decodeStream(assetInputStream) } ?: run { Log.w(TAG, "Requested an unknown Asset.") null } } catch (exception: ExecutionException) { Log.e(TAG, "Failed retrieving asset, Task failed: $exception") return null } catch (exception: InterruptedException) { Log.e(TAG, "Failed retrieving asset, interrupt occurred: $exception") return null } } else { Log.e(TAG, "Asset must be non-null") return null } } override fun onPostExecute(bitmap: Bitmap?) { bitmap?.also { Log.d(TAG, "Setting background image on second page..") moveToPage(1) assetFragment.setBackgroundImage(it) } }
Java
@Override protected Bitmap doInBackground(Asset... params) { if (params.length > 0) { Asset asset = params[0]; Task<DataClient.GetFdForAssetResponse> getFdForAssetResponseTask = Wearable.getDataClient(getApplicationContext()).getFdForAsset(asset); try { // Block on a task and get the result synchronously. This is generally done // when executing a task inside a separately managed background thread. Doing // this on the main (UI) thread can cause your application to become // unresponsive. DataClient.GetFdForAssetResponse getFdForAssetResponse = Tasks.await(getFdForAssetResponseTask); InputStream assetInputStream = getFdForAssetResponse.getInputStream(); if (assetInputStream != null) { return BitmapFactory.decodeStream(assetInputStream); } else { Log.w(TAG, "Requested an unknown Asset."); return null; } } catch (ExecutionException exception) { Log.e(TAG, "Failed retrieving asset, Task failed: " + exception); return null; } catch (InterruptedException exception) { Log.e(TAG, "Failed retrieving asset, interrupt occurred: " + exception); return null; } } else { Log.e(TAG, "Asset must be non-null"); return null; } } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { LOGD(TAG, "Setting background image on second page.."); moveToPage(1); assetFragment.setBackgroundImage(bitmap); } }