ایجاد ابزاره پیشرفته

امتحان کردن روش «نوشتن»
‫Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه ساختن ابزارک بااستفاده از APIهای سبک Compose آشنا شوید.

این صفحه روش‌های پیشنهادی برای ایجاد ابزارک پیشرفته‌تر برای تجربه کاربری بهتر را توضیح می‌دهد.

بهینه‌سازی برای به‌روزرسانی محتوای ابزاره

به‌روزرسانی محتوای ابزاره می‌تواند ازنظر محاسباتی پرهزینه باشد. برای صرفه‌جویی در مصرف باتری، نوع، بسامد، و زمان‌بندی به‌روزرسانی را بهینه‌سازی کنید.

انواع به‌روزرسانی‌های ابزاره

سه روش برای به‌روزرسانی ابزاره وجود دارد: به‌روزرسانی کامل، به‌روزرسانی جزئی، و در مورد ابزاره مجموعه، بازآوری داده‌ها. هرکدام هزینه‌های محاسباتی و پیامدهای متفاوتی دارند.

در زیر هر نوع به‌روزرسانی توضیح داده شده است و تکه‌کدهایی برای هرکدام ارائه شده است.

  • به‌روزرسانی کامل: برای به‌روزرسانی کامل ابزاره، با AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) تماس بگیرید. این RemoteViews ارائه‌شده قبلی را با RemoteViews جدید جایگزین می‌کند. این به‌روزرسانی ازنظر محاسباتی پرهزینه‌ترین است.

val appWidgetManager = AppWidgetManager.getInstance(context)
val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply {
    setTextViewText(R.id.textview_widget_layout1, "Updated text1")
    setTextViewText(R.id.textview_widget_layout2, "Updated text2")
}
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)

  • به‌روزرسانی جزئی: برای به‌روزرسانی بخش‌هایی از ابزارک، AppWidgetManager.partiallyUpdateAppWidget را فراخوانی کنید. این کار RemoteViews جدید را با RemoteViews قبلاً ارائه‌شده ادغام می‌کند. اگر ابزارک حداقل یک به‌روزرسانی کامل ازطریق updateAppWidget(int[], RemoteViews) دریافت نکند، این روش نادیده گرفته می‌شود.

val appWidgetManager = AppWidgetManager.getInstance(context)
val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply {
    setTextViewText(R.id.textview_widget_layout, "Updated text")
}
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)

  • بازآوری داده‌های مجموعه: برای نامعتبر کردن داده‌های نمای مجموعه در ابزارک، AppWidgetManager.notifyAppWidgetViewDataChanged را فراخوانی کنید. این کار باعث RemoteViewsFactory.onDataSetChanged می‌شود. در این فاصله، داده‌های قدیمی در ابزاره نمایش داده می‌شود. با این روش می‌توانید وظایف پرهزینه را به‌صورت هم‌زمان به‌طور ایمن انجام دهید.

val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)

می‌توانید این روش‌ها را از هرجایی در برنامه‌تان فراخوانی کنید، به‌شرطی که برنامه همان UID کلاس AppWidgetProvider مربوطه را داشته باشد.

تعیین کنید ابزاره چند وقت یک‌بار به‌روزرسانی شود

ابزارک‌ها بسته به مقدار ارائه‌شده برای مشخصه updatePeriodMillis به‌صورت دوره‌ای به‌روزرسانی می‌شوند. ابزاره می‌تواند در پاسخ به تعامل کاربر، به‌روزرسانی‌های همه‌فرستی، یا هر دو به‌روز شود.

به‌روزرسانی دوره‌ای

با مشخص کردن مقدار برای AppWidgetProviderInfo.updatePeriodMillis در appwidget-provider XML می‌توانید تعداد دفعات به‌روزرسانی دوره‌ای را کنترل کنید. هر به‌روزرسانی باعث راه‌اندازی روش AppWidgetProvider.onUpdate() می‌شود، که در آن می‌توانید کد را برای به‌روزرسانی ابزارک قرار دهید. بااین‌حال، اگر ابزارک شما نیاز دارد داده‌ها را به‌صورت ناهمزمان بار کند یا به‌روزرسانی آن بیش‌از ۱۰ ثانیه طول می‌کشد، جایگزین‌های به‌روزرسانی گیرنده همه‌فرستی را که در بخش زیر توضیح داده شده است درنظر بگیرید، زیرا پس‌از ۱۰ ثانیه، سیستم BroadcastReceiver را غیرپاسخ‌گو درنظر می‌گیرد.

‫updatePeriodMillis از مقادیر کمتر از ۳۰ دقیقه پشتیبانی نمی‌کند. بااین‌حال، اگر می‌خواهید به‌روزرسانی‌های دوره‌ای را غیرفعال کنید، می‌توانید ۰ را مشخص کنید.

می‌توانید به کاربران اجازه دهید بسامد به‌روزرسانی‌ها را در پیکربندی تنظیم کنند. برای مثال، ممکن است بخواهند یک تیکر سهام هر ۱۵ دقیقه یا فقط چهار بار در روز به‌روز شود. در این مورد، updatePeriodMillis را روی ۰ تنظیم کنید و درعوض از WorkManager استفاده کنید.

به‌روزرسانی در پاسخ به تعامل کاربر

در اینجا چند روش توصیه‌شده برای به‌روزرسانی ابزاره براساس تعامل کاربر ارائه شده است:

  • از فعالیت برنامه: مستقیماً AppWidgetManager.updateAppWidget را در پاسخ به تعامل کاربر، مانند ضربه کاربر، فراخوانی کنید.

  • از تعاملات از دور، مثل اعلان یا ابزارک برنامه: PendingIntent را بسازید، سپس ابزارک را از Activity، Broadcast، یا Service فراخوانده‌شده به‌روز کنید. می‌توانید اولویت خودتان را انتخاب کنید. برای مثال، اگر Broadcast را برای PendingIntent انتخاب کنید، می‌توانید پخش پیش‌زمینه‌ای را انتخاب کنید تا به BroadcastReceiver اولویت دهید.

به‌روزرسانی در پاسخ به رویداد همه‌فرستی

وقتی کاربر عکس می‌گیرد، رویداد همه‌فرستی نمونه‌ای است که برای به‌روزرسانی ابزاره به آن نیاز است. در این مورد، می‌خواهید وقتی عکس جدیدی شناسایی می‌شود ابزارک به‌روز شود.

می‌توانید کار را با WorkManager زمان‌بندی کنید و بااستفاده از روش Constraints.Builder.addContentUriTrigger محرک نشانی وب محتوا را مشخص کنید.

همچنین می‌توانید BroadcastReceiver را برای همه‌فرستی ثبت کنید—برای مثال، گوش دادن به ACTION_LOCALE_CHANGED. بااین‌حال، چون این کار منابع دستگاه را مصرف می‌کند، با دقت از آن استفاده کنید و فقط به همه‌فرستی خاص گوش دهید. با معرفی محدودیت‌های همه‌فرستی در Android 7.0 (سطح میانای برنامه کاربردی ۲۴) و Android 8.0 (سطح میانای برنامه کاربردی ۲۶)، برنامه‌ها نمی‌توانند همه‌فرستی‌های ضمنی را در مانیفست‌هایشان ثبت کنند، با استثناهای خاص.

ملاحظات هنگام به‌روزرسانی ابزاره از BroadcastReceiver

اگر ابزاره از BroadcastReceiver به‌روز شود، ازجمله AppWidgetProvider، ملاحظات زیر را درباره مدت و اولویت به‌روزرسانی ابزاره درنظر داشته باشید.

مدت به‌روزرسانی

به‌طور معمول، سیستم به گیرنده‌های همه‌فرستی که معمولاً در رشته اصلی برنامه اجرا می‌شوند اجازه می‌دهد تا ۱۰ ثانیه اجرا شوند و پس‌از آن آن‌ها را غیرپاسخ‌گو درنظر می‌گیرد و خطای برنامه پاسخ نمی‌دهد (ANR) را راه‌اندازی می‌کند. برای جلوگیری از مسدود شدن رشته اصلی درحین مدیریت همه‌فرستی، از روش goAsync استفاده کنید. اگر به‌روزرسانی ابزاره بیشتر طول می‌کشد، تکلیفی را بااستفاده از WorkManager زمان‌بندی کنید.

Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.

برای اطلاعات بیشتر، ملاحظات امنیتی و روال‌های مطلوب را ببینید.

اولویت به‌روزرسانی

به‌طور پیش‌فرض، همه‌فرستی‌ها—ازجمله همه‌فرستی‌های انجام‌شده بااستفاده از AppWidgetProvider.onUpdate—به‌صورت فرایندهای پس‌زمینه‌ای اجرا می‌شوند. این یعنی منابع سیستم بیش‌ازحد بارگذاری‌شده می‌تواند باعث تأخیر در فراخوانی گیرنده همه‌فرستی شود. برای اولویت‌بندی کردن همه‌فرستی، آن را به فرایند پیش‌زمینه‌ای تبدیل کنید.

برای مثال، پرچم Intent.FLAG_RECEIVER_FOREGROUND را به Intent منتقل‌شده به PendingIntent.getBroadcast اضافه کنید وقتی کاربر روی بخش خاصی از ابزارک تک‌ضرب می‌زند.