با شروع نسخه 11.8.0 سرویسهای Google Play، برنامههای Wear OS باید از کلاس GoogleApiClient
خارج شوند و در عوض از اشیاء کلاینت مبتنی بر کلاس GoogleApi
استفاده کنند.
استفاده از GoogleApi
تنظیم عملیات ناهمزمان را آسان تر می کند. به عنوان مثال، همانطور که در مقدمه Tasks API توضیح داده شد، می توانید یک شی Task
به جای یک شی PendingResult
بدست آورید.
این صفحه شامل:
- جدول اجزای جایگزین
- نمونه ای از به روز رسانی یک برنامه موجود برای استفاده از Tasks API
توجه: این بهروزرسانی برای برنامههای Wear OS چین که معمولاً از نسخه 10.2.0 سرویسهای Google Play استفاده میکنند، اعمال نمیشود.
توجه: این API در حال حاضر فقط در تلفنهای Android و ساعتهای Wear OS که با تلفنهای Android جفت شدهاند در دسترس است. برای ساعتهای Wear OS جفتشده با تلفنهای iOS، اگر اتصال اینترنت در دسترس باشد، برنامهها میتوانند از دیگر APIهای مبتنی بر ابر جستجو کنند.
جایگزینی برای قطعات منسوخ شده
وقتی از کلاسهایی استفاده میکنید که کلاس GoogleApi
گسترش میدهند، مانند DataClient
و MessageClient
، SDK خدمات Google Play اتصالات به خدمات Google Play را برای شما مدیریت میکند.
برنامههایی که از کلاسهای جایگزین زیر استفاده میکنند، نیازی به ایجاد و مدیریت اشیاء GoogleApiClient
ندارند. همچنین دسترسی به APIهای Google و صفحه مرجع برای کلاس Wearable را ببینید.
جدول زیر شامل اجزای منسوخ شده و جایگزین های آنها است:
جزء منسوخ شده | جزء جایگزین |
CapabilityApi | CapabilityClient |
Channel | ChannelClient.Channel |
ChannelApi | ChannelClient |
DataApi | DataClient |
MessageApi | MessageClient |
NodeApi | NodeClient |
همچنین به موارد زیر توجه کنید:
- برای اعلان تغییرات در کانالها،
Channel.ChannelListener
باChannelClient.ChannelCallback
جایگزین میشود. - برای تنظیم رشته برای تماس های شنونده،
GoogleApiClient.Builder.setHandler
با روشsetLooper
WearableOptions.Builder
جایگزین می شود.
نمونه مهاجرت برای برنامه Wear
به عنوان یک نمونه انتقال، قطعه کد زیر نشان میدهد که چگونه نمونه Wear Data Layer که از API لایه داده استفاده میکند، برای نسخه 11.8.0 سرویسهای Google Play بهروزرسانی شد. اگر برنامه شما دارای ماژول تلفن است، بهروزرسانیهای آن ممکن است مشابه ماژول Wear باشد.
وابستگی به خدمات Google Play را به روز کنید
از آنجایی که برنامه شما ممکن است به نسخه قبلی سرویسهای Google Play وابسته باشد، وابستگی زیر را در فایل build.gradle
ماژول Wear خود بهروزرسانی کنید:
dependencies { ... compile 'com.google.android.gms:play-services-wearable:11.8.0' }
بیانیه های واردات برنامه خود را به روز کنید
کلاسهای لازم، از جمله کلاسهای موجود در Tasks API را وارد کنید.
برای مثال، قبلاً نمونه Wear Data Layer شامل عبارت import زیر در فایل MainActivity.java
بود. این عبارت import
باید حذف شود:
کاتلین
... import com.google.android.gms.common.api.GoogleApiClient ...
جاوا
... import com.google.android.gms.common.api.GoogleApiClient; ...
در نمونه Wear Data Layer ، عبارتهای import
مانند موارد فوق با موارد زیر جایگزین شدند (دومین مورد برای رسیدگی به استثنائات وظایف است):
کاتلین
... import com.google.android.gms.tasks.Tasks import java.util.concurrent.ExecutionException ...
جاوا
... import com.google.android.gms.tasks.Tasks; import java.util.concurrent.ExecutionException; ...
رابط های مشتری جدید را پیاده سازی کنید
هرگونه استفاده از کلاس GoogleApiClient
و رابط های مرتبط ( ConnectionCallbacks
، OnConnectionFailedListener
، و غیره) را حذف کنید و سایر پیاده سازی های Lister را با نسخه های جدید خود جایگزین کنید. روشهای واقعی برای لغو معمولاً همان نامهای قبلی را دارند، بنابراین تغییر اصلی مشابه مثال زیر است.
فعالیت اصلی نمونه Wear Data Layer (همانطور که در تفاوت در GitHub نشان داده شده است) برای مثال رابط CapabilityApi.CapabilityListener
را پیاده سازی کرده بود. اما اکنون، فعالیت اصلی CapabilityClient.OnCapabilityChangedListener
را پیاده سازی می کند.
در زیر مقایسه ای از تعاریف کلاس ارائه شده است.
در اینجا یک قطعه قبل از استفاده از نسخه 11.8.0 سرویس های Google Play آمده است:
کاتلین
class MainActivity : Activity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener, CapabilityApi.CapabilityListener
جاوا
public class MainActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener, CapabilityApi.CapabilityListener
در اینجا یک قطعه پس از استفاده از نسخه 11.8.0 سرویس های Google Play آمده است:
کاتلین
class MainActivity : Activity(), DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
جاوا
public class MainActivity extends Activity implements DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
شنوندگان را حذف و اضافه کنید
اشیاء مشتری جدید در حافظه پنهان ذخیره می شوند و بین نمونه های GoogleApi
به اشتراک گذاشته می شوند، بنابراین حفظ متغیرهای عضو ضروری نیست. ساخت مشتریان ارزان است و شنوندگان خود را از دست نمی دهند.
در زیر یک قطعه از نمونه اصلاح شده Wear Data Layer آمده است:
کاتلین
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) }
جاوا
@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 Data Layer نشان داده شده است، می توانید از Tasks API برای یافتن گره های متصل با هر قابلیتی استفاده کنید:
کاتلین
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() }
جاوا
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(); }
برای کدهای اضافی که از Wearable و Tasks API استفاده می کند، به نمونه Wear Data Layer مراجعه کنید. و به عنوان نمونه ای از استفاده از وظایف سنگین خارج از رشته رابط کاربری یا در یک سرویس، گزینه دیگری در دسترس است. در اینجا مثالی از نحوه مسدود کردن یک کار و گرفتن نتیجه به صورت همزمان آورده شده است:
کاتلین
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) } }
جاوا
@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); } }