برنامه‌های Wear را به GoogleApi منتقل کنید

با شروع نسخه 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

همچنین به موارد زیر توجه کنید:

نمونه مهاجرت برای برنامه 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);
  }
}