یک ویجت پیشرفته ایجاد کنید

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

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

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

انواع به روز رسانی ویجت

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

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

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

    کاتلین

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

    جاوا

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
    remoteViews.setTextViewText(R.id.textview_widget_layout1, "Updated text1");
    remoteViews.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.getPackageName(), R.layout.widgetlayout).also {
    setTextViewText(R.id.textview_widget_layout, "Updated text")
    }
    appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)

    جاوا

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
    remoteViews.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)

    جاوا

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

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

تعیین کنید هر چند وقت یکبار یک ویجت را به روز کنید

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

به صورت دوره ای به روز کنید

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

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

می‌توانید به کاربران اجازه دهید فرکانس به‌روزرسانی‌ها را در یک پیکربندی تنظیم کنند. به عنوان مثال، آنها ممکن است بخواهند که یک علامت سهام هر 15 دقیقه یا فقط چهار بار در روز به روز شود. در این حالت، updatePeriodMillis را روی 0 قرار دهید و به جای آن WorkManager استفاده کنید.

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

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

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

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

به روز رسانی در پاسخ به یک رویداد پخش

نمونه ای از یک رویداد پخش که برای به روز رسانی به ویجت نیاز دارد، زمانی است که کاربر عکس می گیرد. در این حالت، شما می خواهید وقتی یک عکس جدید شناسایی شد، ویجت را به روز کنید.

می‌توانید یک کار را با JobScheduler زمان‌بندی کنید و با استفاده از روش JobInfo.Builder.addTriggerContentUri پخش را به عنوان محرک مشخص کنید.

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

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

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

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

به عنوان یک قاعده، سیستم به گیرنده‌های پخش که معمولاً در رشته اصلی برنامه اجرا می‌شوند، اجازه می‌دهد تا 10 ثانیه قبل از اینکه آنها را پاسخگو نمی‌داند و خطای Application Not Responding (ANR) را راه‌اندازی کند، کار کنند. اگر به‌روزرسانی ویجت بیشتر طول می‌کشد، گزینه‌های زیر را در نظر بگیرید:

  • با استفاده از WorkManager یک کار را برنامه ریزی کنید.

  • با روش goAsync به گیرنده زمان بیشتری بدهید. این به گیرنده ها اجازه می دهد تا 30 ثانیه اجرا شوند.

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

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

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

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

پیش نمایش های دقیقی بسازید که شامل موارد پویا باشد

شکل 1: یک پیش نمایش ویجت که هیچ مورد لیستی را نمایش نمی دهد.

این بخش روش توصیه شده برای نمایش چندین مورد در یک پیش‌نمایش ویجت را برای یک ویجت با نمای مجموعه توضیح می‌دهد - یعنی ویجتی که از ListView ، GridView یا StackView استفاده می‌کند.

اگر ویجت شما از یکی از این نماها استفاده می‌کند، ایجاد یک پیش‌نمایش مقیاس‌پذیر با ارائه مستقیم طرح‌بندی واقعی ویجت، زمانی که پیش‌نمایش ویجت هیچ موردی را نمایش نمی‌دهد، تجربه را کاهش می‌دهد. این به این دلیل رخ می دهد که داده های نمای مجموعه به صورت پویا در زمان اجرا تنظیم می شوند و شبیه تصویر نشان داده شده در شکل 1 به نظر می رسد.

برای اینکه پیش‌نمایش ویجت‌ها با نمای مجموعه به درستی در انتخابگر ویجت نمایش داده شوند، توصیه می‌کنیم یک فایل طرح‌بندی جداگانه که فقط برای پیش‌نمایش تعیین شده است نگهداری کنید. این فایل طرح‌بندی جداگانه شامل طرح‌بندی ویجت واقعی و نمای مجموعه مکان‌نما با موارد جعلی است. به عنوان مثال، می‌توانید با ارائه یک مکان نگهدار LinearLayout با چندین آیتم فهرست جعلی، ListView تقلید کنید.

برای نشان دادن مثالی برای ListView ، با یک فایل طرح بندی جداگانه شروع کنید:

// res/layout/widget_preview.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="@drawable/widget_background"
   android:orientation="vertical">

    // Include the actual widget layout that contains ListView.
    <include
        layout="@layout/widget_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    // The number of fake items you include depends on the values you provide
    // for minHeight or targetCellHeight in the AppWidgetProviderInfo
    // definition.

    <TextView android:text="@string/fake_item1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

    <TextView android:text="@string/fake_item2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginVertical="?attr/appWidgetInternalPadding" />

</LinearLayout>

هنگام ارائه ویژگی previewLayout فراداده AppWidgetProviderInfo ، فایل طرح بندی پیش نمایش را مشخص کنید. شما همچنان طرح بندی واقعی ویجت را برای ویژگی initialLayout مشخص می کنید و هنگام ساخت RemoteViews در زمان اجرا از طرح بندی واقعی ویجت استفاده می کنید.

<appwidget-provider
    previewLayout="@layout/widget_previe"
    initialLayout="@layout/widget_view" />

موارد لیست پیچیده

مثال در بخش قبل موارد جعلی لیست را ارائه می دهد، زیرا موارد لیست، اشیاء TextView هستند. اگر اقلام دارای طرح‌بندی پیچیده باشند، ارائه اقلام جعلی می‌تواند پیچیده‌تر باشد.

یک آیتم لیست را در نظر بگیرید که در widget_list_item.xml تعریف شده است و از دو شی TextView تشکیل شده است:

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <TextView android:id="@id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_title" />

    <TextView android:id="@id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fake_content" />
</LinearLayout>

برای ارائه آیتم‌های فهرست جعلی، می‌توانید طرح‌بندی را چندین بار اضافه کنید، اما این باعث می‌شود هر آیتم فهرست یکسان باشد. برای ارائه اقلام لیست منحصر به فرد، این مراحل را دنبال کنید:

  1. مجموعه ای از ویژگی ها را برای مقادیر متن ایجاد کنید:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. برای تنظیم متن از این ویژگی ها استفاده کنید:

    <LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
        <TextView android:id="@id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetTitle" />
    
        <TextView android:id="@id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="?widgetContent" />
    </LinearLayout>
    
  3. هر تعداد سبک که برای پیش نمایش لازم است ایجاد کنید. مقادیر را در هر سبک دوباره تعریف کنید:

    <resources>
    
        <style name="Theme.Widget.ListItem">
            <item name="widgetTitle"></item>
            <item name="widgetContent"></item>
        </style>
        <style name="Theme.Widget.ListItem.Preview1">
            <item name="widgetTitle">Fake Title 1</item>
            <item name="widgetContent">Fake content 1</item>
        </style>
        <style name="Theme.Widget.ListItem.Preview2">
            <item name="widgetTitle">Fake title 2</item>
            <item name="widgetContent">Fake content 2</item>
        </style>
    
    </resources>
    
  4. استایل‌ها را روی موارد جعلی در طرح‌بندی پیش‌نمایش اعمال کنید:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" ...>
    
        <include layout="@layout/widget_view" ... />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview1" />
    
        <include layout="@layout/widget_list_item"
            android:theme="@style/Theme.Widget.ListItem.Preview2" />
    
    </LinearLayout>