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

امتحان کردن روش Compose
Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه ساختن ابزاره بااستفاده از میاناهای برنامه‌سازی کاربردی سبک 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)

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

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

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

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

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

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

می‌توانید به کاربران اجازه دهید بسامد به‌روزرسانی‌ها را در پیکربندی تنظیم کنند. برای مثال، ممکن است بخواهند تابلوی قیمت سهام هر ۱۵ دقیقه یا فقط چهار بار در روز به‌روز شود. دراین‌صورت، 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 ارسال شده است اضافه کنید، وقتی کاربر روی بخش خاصی از ابزاره تک‌ضرب می‌زند.