<h3 id="implementing_collections"><span style="color: #000080;"><strong>App widgets with collections</strong></span></h3>
<p class="p1">In the earlier versions of Android, app widgets could only display views like TextView, ImageView, etc. But what if we want to show a list of items in our widget? For example, a collection of pictures from a gallery app, or a collection of emails/messages from a communication app. <strong><span style="color: #0000ff;">Collection widgets</span></strong> were introduced in Android 3.0 to provide this additional benefit. Collection widgets support <strong>ListView</strong>, <strong>GridView</strong> and <strong>StackView</strong> layouts.</p>
<p class="p1">In this article, we will talk about how the collection widget works with a simple <span style="color: #008000;"><strong>AppwidgetCollectionDemo</strong></span> application.</p>
<p><strong><span style="color: #0000ff;">Get GITHUB code from <a style="color: #0000ff;" href="https://github.com/arunk7839/AppWidgetCollectionDemo">here</a>.</span></strong></p>
<p><amp-youtube layout="responsive" width="1200" height="675" data-videoid="wtJpaYbhzQY" title="Android App Widgets with Collections"><a placeholder href="https://youtu.be/wtJpaYbhzQY"><img src="https://i.ytimg.com/vi/wtJpaYbhzQY/hqdefault.jpg" layout="fill" object-fit="cover" alt="Android App Widgets with Collections"></a></amp-youtube></p>
<p class="p1">I assume you already know how to make a basic app widget. If not please refer to <span style="color: #0000ff;"><strong><span class="s1"><a style="color: #0000ff;" href="https://c1ctech.com/android-app-widgets-with-example/">this article</a></span></strong></span> and come back when you are ready to build your own collection widgets.</p>
<h3 id="implementing_collections"><span style="color: #000080;"><strong>Implementing app widgets with collections</strong></span></h3>
<p class="p1">To implement an app widget with collections, you follow the same basic steps you would use to implement any app widget. The following sections describe the additional steps you need to perform to implement an app widget with collections.</p>
<p class="p1"> To make a collection widget, two main components are required in addition to the basic components:</p>
<ul class="ul1">
<li class="li1"><strong><span style="color: #0000ff;">RemoteViewsService</span></strong></li>
<li class="li1"><strong><span style="color: #0000ff;">RemoteViewsFactory</span></strong></li>
</ul>
<p class="p1">Let’s understand what these components do.</p>
<h4 class="p2"><span style="color: #000080;"><b>RemoteViewsFactory Interface</b></span></h4>
<p class="p1"><span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/android/widget/RemoteViewsService.RemoteViewsFactory.html">RemoteViewsFactory</a></strong></span> serves the purpose of an adapter in the widget’s context. An adapter is used to connect the collection items(for example, ListView items or GridView items) with the data set.</p>
<p>The two most important methods you need to implement for your <span class="s1">RemoteViewsFactory</span> subclass are <span style="color: #008000;"><strong><span class="s1">onCreate()</span></strong></span> and <strong><span class="s1" style="color: #008000;">getViewAt()</span></strong>.</p>
<p class="p2">Let’s add this class into our project. Create a new Java class, name it <span style="color: #008000;"><b>ListRemoteViewsFactory</b></span>, and set it to implement the class RemoteViewsService.RemoteViewsFactory.</p>
<pre>class ListRemoteViewsFactory implements RemoteViewsFactory{

 private static final int mCount = 10;
 private List<;WidgetItem>; mWidgetItems = new ArrayList<;WidgetItem>;();
 private Context mContext;
 private int mAppWidgetId;

 public ListRemoteViewsFactory(Context context,Intent intent) {
 mContext = context;
 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
 AppWidgetManager.INVALID_APPWIDGET_ID);
 }
 <strong><span style="color: #008000;">// Initialize the data set.</span></strong>
 @Override
 public void onCreate() {

 <strong><span style="color: #008000;">// In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
 // for example downloading or creating content etc, should be deferred to onDataSetChanged()
 // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.</span></strong>
 for (int i = 1; i <;= mCount; i++) {
 mWidgetItems.add(new WidgetItem("Item" + i));
 }
 <strong><span style="color: #008000;">// We sleep for 3 seconds here to show how the empty view appears in the interim.
 // The empty view is set in the ListWidgetProvider and should be a sibling of the
 // collection view.</span></strong>
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }


 @Override
 public void onDestroy() {
 <span style="color: #008000;"><strong>// In onDestroy() you should tear down anything that was setup for your data source,
 // eg. cursors, connections, etc.</strong></span>
 mWidgetItems.clear();
 }

 @Override
 public int getCount() {
 return mCount;
 }

 <strong><span style="color: #008000;">// Given the position (index) of a WidgetItem in the array, use the item's text value in
 // combination with the app widget item XML file to construct a RemoteViews object.</span></strong>
 @Override
 public RemoteViews getViewAt(int position) {

 <strong><span style="color: #008000;">// position will always range from 0 to getCount() - 1.
 // construct a remote views item based on our widget item xml file, and set the
 // text based on the position.</span></strong>
 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);

 <span style="color: #008000;"><strong> // Next, we set a fill-intent which will be used to fill-in the pending intent template
 // which is set on the collection view in ListWidgetProvider.</strong></span>
 Bundle extras = new Bundle();
 extras.putInt(ListWidgetProvider.EXTRA_ITEM, position);
 Intent fillInIntent = new Intent();
 fillInIntent.putExtras(extras);
 <span style="color: #008000;"><strong>// Make it possible to distinguish the individual on-click
 // action of a given item</strong></span>
 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
<span style="color: #008000;"><strong>
 // You can do heaving lifting in here, synchronously. For example, if you need to
 // process an image, fetch something from the network, etc., it is ok to do it here,
 // synchronously. A loading view will show up in lieu of the actual contents in the
 // interim.</strong></span>
 try {
 System.out.println("Loading view " + position);
 Thread.sleep(500);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }

<span style="color: #008000;"><strong> // Return the remote views object.
</strong> </span> return rv;
 }

 @Override
 public RemoteViews getLoadingView() {
 <span style="color: #008000;"><strong>// You can create a custom loading view (for instance when getViewAt() is slow.) If you
 // return null here, you will get the default loading view.</strong></span>
 return null;
 }

 @Override
 public int getViewTypeCount() {
 return 1;
 }

 @Override
 public long getItemId(int position) {
 return position;
 }

 @Override
 public boolean hasStableIds() {
 return true;
 }

 @Override
 public void onDataSetChanged() {
 <span style="color: #008000;"><strong>// This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged
 // on the collection view corresponding to this factory. You can do heaving lifting in
 // here, synchronously. For example, if you need to process an image, fetch something
 // from the network, etc., it is ok to do it here, synchronously. The widget will remain
 // in its current state while work is being done here, so you don't need to worry about
 // locking up the widget.</strong></span>
 }

}</pre>
<p class="p1">In the code above, ListRemoteViewsFactory overrides a few methods from the <span style="color: #008000;"><strong>RemoteViewsFactory</strong></span> class:</p>
<ul class="ul1">
<li class="li1"><span style="color: #0000ff;"><strong>onCreate</strong></span> is called by the system when creating your factory for the first time. This is where you set up any connections and/or cursors to your data source.</li>
<li class="li1"><span style="color: #0000ff;"><strong>onDataSetChanged</strong></span> is called when notifyDataSetChanged() is triggered on the remote adapter.</li>
<li class="li1"><span style="color: #0000ff;"><strong>getCount</strong></span> returns the number of records in the cursor. (In our case, the number of task items that need to be displayed in the app widget)</li>
<li class="li1"><span style="color: #0000ff;"><strong>getViewAt</strong></span> handles all the processing work. It returns a RemoteViews object which in our case is the single list item.</li>
<li class="li1"><span style="color: #0000ff;"><strong>getViewTypeCount</strong></span> returns the number of types of views we have in ListView. In our case, we have same view type for each ListView item so we return 1 there.</li>
<li><strong><strong><span style="color: #0000ff;">onDestroy </span></strong></strong><span style="color: #0000ff;"><span style="color: #000000;">is called when the last RemoteViewsAdapter that is associated with this factory is unbound. Here </span></span>you should tear down anything that was set up for your data source eg. cursors, connections, etc.</li>
<li><span style="color: #0000ff;"><strong>getLoadingView</strong></span> allows for the use of a custom loading view which appears between the time that <span style="color: #008000;"><strong><span class="s1">getViewAt(int)</span></strong></span><span style="color: var(--color-text);"> is called and returns.</span></li>
<li><span style="color: #0000ff;"><strong>hasStableIds</strong></span> Indicates whether the item ids are stable across changes to the underlying data. It returns <span style="color: #008000;"><strong>True</strong></span> if the same id always refers to the same object.</li>
<li><span style="color: #0000ff;"><strong>getItemId</strong></span> gets the row id associated with the specified position in the list.</li>
</ul>
<h4 id="remoteviewsservice-class"><span style="color: #000080;"><strong>RemoteViewsService class</strong></span></h4>
<p class="p1">The main purpose of <strong><span style="color: #008000;">RemoteViewsService</span></strong> is to return a <span style="color: #008000;"><strong>RemoteViewsFactory</strong></span> object which further handles the task of filling the widget with appropriate data.</p>
<p class="p1">Create a new class named <span style="color: #008000;"><b>ListWidgetService</b></span> extending the class RemoteViewsService.</p>
<p><strong><span style="color: #0000ff;">ListWidgetService.java</span></strong></p>
<pre>public class ListWidgetService extends RemoteViewsService {

 <strong><span style="color: #008000;">@Override</span></strong>
<strong><span style="color: #008000;"> public RemoteViewsFactory onGetViewFactory(Intent intent) {</span></strong>
<strong><span style="color: #008000;"> return new ListRemoteViewsFactory(getApplicationContext(),intent);</span></strong>
<strong><span style="color: #008000;"> }</span></strong>

 class ListRemoteViewsFactory implements RemoteViewsFactory{

 private static final int mCount = 10;
 private List<;WidgetItem>; mWidgetItems = new ArrayList<;WidgetItem>;();
 private Context mContext;
 private int mAppWidgetId;

 public ListRemoteViewsFactory(Context context,Intent intent) {
 mContext = context;
 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
 AppWidgetManager.INVALID_APPWIDGET_ID);
 }
 <span style="color: #008000;"><strong>// Initialize the data set.</strong></span>
 @Override
 public void onCreate() {

 <span style="color: #008000;"><strong>// In onCreate() you setup any connections / cursors to your data source. Heavy lifting,</strong></span>
<span style="color: #008000;"><strong> // for example downloading or creating content etc, should be deferred to onDataSetChanged()</strong></span>
<span style="color: #008000;"><strong> // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.</strong></span>
 for (int i = 1; i <;= mCount; i++) {
 mWidgetItems.add(new WidgetItem("Item" + i));
 }
 <strong><span style="color: #008000;"> // We sleep for 3 seconds here to show how the empty view appears in the interim.</span></strong>
<strong><span style="color: #008000;"> // The empty view is set in the ListWidgetProvider and should be a sibling of the</span></strong>
<strong><span style="color: #008000;"> // collection view.</span></strong>
 try {
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }


 @Override
 public void onDestroy() {
 <span style="color: #008000;"><strong> // In onDestroy() you should tear down anything that was setup for your data source,</strong></span>
<span style="color: #008000;"><strong> // eg. cursors, connections, etc.</strong></span>
 mWidgetItems.clear();
 }

 @Override
 public int getCount() {
 return mCount;
 }

 <span style="color: #008000;"><strong>// Given the position (index) of a WidgetItem in the array, use the item's text value in</strong></span>
<span style="color: #008000;"><strong> // combination with the app widget item XML file to construct a RemoteViews object.</strong></span>
 @Override
 public RemoteViews getViewAt(int position) {

 <span style="color: #008000;"><strong>// position will always range from 0 to getCount() - 1.</strong></span>
<span style="color: #008000;"><strong> // construct a remote views item based on our widget item xml file, and set the</strong></span>
<span style="color: #008000;"><strong> // text based on the position.</strong></span>
 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);

 <strong><span style="color: #008000;">// Next, we set a fill-intent which will be used to fill-in the pending intent template</span></strong>
<strong><span style="color: #008000;"> // which is set on the collection view in ListWidgetProvider.</span></strong>
 Bundle extras = new Bundle();
 extras.putInt(ListWidgetProvider.EXTRA_ITEM, position);
 Intent fillInIntent = new Intent();
 fillInIntent.putExtras(extras);
 <strong><span style="color: #008000;"> // Make it possible to distinguish the individual on-click</span></strong>
<strong><span style="color: #008000;"> // action of a given item</span></strong>
 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);

 <strong><span style="color: #008000;">// You can do heaving lifting in here, synchronously. For example, if you need to</span></strong>
<strong><span style="color: #008000;"> // process an image, fetch something from the network, etc., it is ok to do it here,</span></strong>
<strong><span style="color: #008000;"> // synchronously. A loading view will show up in lieu of the actual contents in the</span></strong>
<strong><span style="color: #008000;"> // interim.</span></strong>
 try {
 System.out.println("Loading view " + position);
 Thread.sleep(500);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }

 <strong><span style="color: #008000;"> // Return the remote views object.</span></strong>
 return rv;
 }

 @Override
 public RemoteViews getLoadingView() {
<strong><span style="color: #008000;"> // You can create a custom loading view (for instance when getViewAt() is slow.) If you</span></strong>
<strong><span style="color: #008000;"> // return null here, you will get the default loading view.</span></strong>
 return null;
 }

 @Override
 public int getViewTypeCount() {
 return 1;
 }

 @Override
 public long getItemId(int position) {
 return position;
 }

 @Override
 public boolean hasStableIds() {
 return true;
 }

 @Override
 public void onDataSetChanged() {
 <strong><span style="color: #008000;">// This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged</span></strong>
<strong><span style="color: #008000;"> // on the collection view corresponding to this factory. You can do heaving lifting in</span></strong>
<strong><span style="color: #008000;"> // here, synchronously. For example, if you need to process an image, fetch something</span></strong>
<strong><span style="color: #008000;"> // from the network, etc., it is ok to do it here, synchronously. The widget will remain</span></strong>
<strong><span style="color: #008000;"> // in its current state while work is being done here, so you don't need to worry about</span></strong>
<strong><span style="color: #008000;"> // locking up the widget.</span></strong>
 }

 }

}</pre>
<p>As with all the other services in android, we must register this service in the manifest file.</p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>

<h4 id="manifest-for-app-widgets-with-collections"><span style="color: #000080;"><strong>Manifest for app widgets with collections</strong></span></h4>
<p class="p1">To make it possible for app widgets with collections to bind to your <span style="color: #008000;"><strong><span class="s2">RemoteViewsService</span></strong></span>, you must declare the service in your manifest file with the permission <strong><span class="s2" style="color: #008000;">BIND_REMOTEVIEWS</span></strong>.</p>
<pre><;service android:name=".ListWidgetService"
 android:permission="android.permission.BIND_REMOTEVIEWS"
 android:exported="false" />;</pre>
<p class="p1"><span style="color: #0000ff;"><strong>Note</strong></span> the special permission <strong><span class="s2" style="color: #008000;">BIND_REMOTEVIEWS. </span></strong>This lets the system bind your service to create the widget views for each row and prevents other apps from accessing your widget’s data.</p>
<h4 id="layout-for-app-widgets-with-collections"><span style="color: #000080;"><strong>Layout for app widgets with collections</strong></span></h4>
<p class="p1">The main requirement for your app widget layout XML file is that it include one of the collection views: <span style="color: #008000;"><strong><span class="s1">ListView</span>, <span class="s1">GridView</span>, <span class="s1">StackView</span>, or <span class="s1">AdapterViewFlipper</span></strong></span>. Here is the <span class="s2">widget_layout.xml</span> for the <span style="color: #0000ff;"><strong>AppwidgetCollectionDemo</strong></span><span class="s3"> sample</span>:</p>
<p><span style="color: #0000ff;"><strong>widget_layout.xml</strong></span></p>
<pre><;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_margin="8dp">;

 <;ListView
 android:id="@+id/list_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center"
 android:loopViews="true" />;

 <;TextView
 android:id="@+id/empty_view"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@drawable/widget_item_background_empty"
 android:gravity="center"
 android:text="Empty"
 android:textColor="#ffffff"
 android:textSize="20sp"
 android:textStyle="bold" />;

<;/RelativeLayout>;</pre>
<p class="p1"><span style="color: #000080;"><strong>Note:</strong></span> Empty views must be siblings of the collection view for which the empty view represents empty state.</p>
<p class="p1">In addition to the layout file for your entire app widget, you must create another layout file that defines the layout for each item in the collection. The <span style="color: #0000ff;"><strong>AppwidgetCollectionDemo</strong></span><span class="s3"> sample</span> only has one layout file, <span class="s2">widget_item.xml</span>, since all items use the same layout.</p>
<p><span style="color: #0000ff;"><strong><span class="s2">widget_item.xml</span></strong></span></p>
<pre><;?xml version="1.0" encoding="utf-8"?>;
<;TextView xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/widget_item"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:gravity="center"
 android:background="@drawable/widget_item_background_data"
 android:padding="10dp"
 android:textColor="#ffffff"
 android:textStyle="bold"
 android:text="Item n"
 android:textSize="30sp">;

<;/TextView>;</pre>
<h4 id="AppWidgetProvider-collections"><span style="color: #000080;"><strong>AppWidgetProvider class for app widgets with collections</strong></span></h4>
<p class="p1">The major difference in your implementation for <strong><span class="s1" style="color: #008000;">onUpdate()</span></strong> when creating an app widget with collections is that you must call <strong><span class="s1" style="color: #0000ff;">setRemoteAdapter()</span></strong>. This tells the collection view where to get its data.</p>
<p class="p1">When you call <span class="s1">setRemoteAdapter()</span> method, you must pass an intent that points to your implementation of <strong><span class="s1" style="color: #008000;">RemoteViewsService</span></strong> and the app widget ID that specifies the app widget to update.`</p>
<p>The <span class="s1">RemoteViewsService</span> can then return your implementation of <strong><span class="s1" style="color: #008000;">RemoteViewsFactory</span></strong>, and the widget can serve up the appropriate data.</p>
<p class="p1">For example, here&#8217;s how the <span style="color: #0000ff;"><strong>AppWidgetCollectionDemo</strong></span> sample implements the <span style="color: #000000;"><span class="s1">onUpdate()</span></span> callback method to set the <strong><span class="s1" style="color: #008000;">RemoteViewsService</span></strong> as the remote adapter for the app widget collection:</p>
<pre>@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {


 <strong><span style="color: #008000;"> // There may be multiple widgets active, so update all of them
 // update each of the widgets with the remote adapter</span></strong>
 for (int i = 0; i <; appWidgetIds.length; ++i) {
 <strong><span style="color: #008000;">// Here we setup the intent which points to the StackViewService which will
 // provide the views for this collection.</span></strong>
 Intent intent = new Intent(context, ListWidgetService.class);
 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);

 <strong><span style="color: #008000;"> // When intents are compared, the extras are ignored, so we need to embed the extras
 // into the data so that the extras will not be ignored.</span></strong>
 intent.setData(Uri.parse(intent.toUri(intent.URI_INTENT_SCHEME)));

 <span style="color: #008000;"><strong> // Construct the RemoteViews object</strong></span>
 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
 views.setRemoteAdapter(R.id.list_view, intent);

 <strong><span style="color: #008000;">// The empty view is displayed when the collection has no items. It should be a sibling
 // of the collection view.</span></strong>
 views.setEmptyView(R.id.list_view,R.id.empty_view);

 <strong><span style="color: #008000;"> // This section makes it possible for items to have individualized behavior.
 // It does this by setting up a pending intent template. Individuals items of a collection
 // cannot set up their own pending intents. Instead, the collection as a whole sets
 // up a pending intent template, and the individual items set a fillInIntent
 // to create unique behavior on an item-by-item basis.</span></strong>
 Intent toastIntent = new Intent(context, StackWidgetProvider.class);

 <span style="color: #008000;"><strong>// Set the action for the intent.
 // When the user touches a particular view, it will have the effect of
 // broadcasting TOAST_ACTION.</strong></span>
 toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
 toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
 PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
 PendingIntent.FLAG_UPDATE_CURRENT);
 views.setPendingIntentTemplate(R.id.list_view, toastPendingIntent);

 <span style="color: #008000;"><strong>// Instruct the widget manager to update the widget</strong></span>
 appWidgetManager.updateAppWidget(appWidgetIds, views);
 }

}</pre>
<h3 id="behavior"><strong><span style="color: #000080;">Click events on ListView items</span></strong></h3>
<p class="p1">The above sections show you how to bind your data to your app widget collection. But what if you want to add dynamic behavior to the individual items in your collection view?</p>
<p class="p1">We normally use <strong><span style="color: #008000;"><span class="s2"><a style="color: #008000;" href="https://developer.android.com/reference/android/widget/RemoteViews.html#setOnClickPendingIntent(int,%20android.app.PendingIntent)">setOnClickPendingIntent</a>()</span> </span></strong>to set an object&#8217;s click behavior—such as to cause a button to launch an <span class="s2">Activity</span>. But this approach is not allowed for child views in an individual collection item (to clarify, you could use <span class="s2">setOnClickPendingIntent()</span> to set up a global button in the Gmail app widget that launches the app, for example, but not on the individual list items).</p>
<p class="p1">Instead, to add click behavior to individual items in a collection, you use <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/android/widget/RemoteViews.html#setOnClickFillInIntent(int,%20android.content.Intent)"><span class="s2">setOnClickFillInIntent()</span></a>.</span></strong> This entails setting up a pending intent template for your collection view, and then setting a fill-in intent on each item in the collection via your <strong><span class="s2" style="color: #008000;">RemoteViewsFactory</span></strong>.</p>
<p class="p1">In the <strong><span style="color: #0000ff;">AppWidgetCollectionDemo</span></strong> sample, if the user touches any item, the app widget displays the <strong><span class="s2" style="color: #008000;">Toast</span></strong> message &#8220;Item <em>n</em> selected,&#8221; where <i>n</i> is the index (position) of the touched view. This is how it works:</p>
<ul class="ul1">
<li class="li1">The List<span class="s4">WidgetProvider</span> (an <strong><span class="s2" style="color: #008000;">AppWidgetProvider</span></strong> subclass) creates a pending intent that has a custom action called <span class="s4">TOAST_ACTION</span>.</li>
<li class="li1">When the user touches a view, the intent is fired and it broadcasts <span class="s4">TOAST_ACTION</span>.</li>
<li class="li1">This broadcast is intercepted by the <span class="s4">ListWidgetProvider</span>&#8216;s <strong><span class="s2" style="color: #008000;">onReceive()</span></strong> method, and the app widget displays the <strong><span class="s2" style="color: #008000;">Toast</span></strong> message for the touched view. The data for the collection items is provided by the <strong><span class="s2" style="color: #008000;">RemoteViewsFactory</span></strong>, via the <strong><span class="s2" style="color: #008000;">RemoteViewsService</span></strong>.</li>
</ul>
<h4 id="setting-up-the-pending-intent-template"><span style="color: #000080;"><strong>Setting up the pending intent template</strong></span></h4>
<p class="p1">The List<span class="s1">WidgetProvider</span> (<strong><span class="s2" style="color: #008000;">AppWidgetProvider</span></strong> subclass) sets up a pending intent. Individuals items of a collection cannot set up their own pending intents. Instead, the collection as a whole sets up a pending intent template, and the individual items set a fill-in intent to create unique behavior on an item-by-item basis.</p>
<p class="p1">This class also receives the broadcast that is sent when the user touches a view. It processes this event in its <strong><span style="color: #008000;"><span class="s2">onReceive()</span> </span></strong>method. If the intent&#8217;s action is <span class="s1">TOAST_ACTION</span>, the app widget displays a <strong><span class="s2" style="color: #008000;">Toast</span></strong> message for the current view.</p>
<pre>public class ListWidgetProvider extends AppWidgetProvider {

 public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION";
 public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM";

 <span style="color: #008000;"><strong>// Called when the BroadcastReceiver receives an Intent broadcast.
 // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget
 // displays a Toast message for the current item.</strong></span>
 @Override
 public void onReceive(Context context, Intent intent) {
 AppWidgetManager mgr = AppWidgetManager.getInstance(context);
 if (intent.getAction().equals(TOAST_ACTION)) {
 int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
 AppWidgetManager.INVALID_APPWIDGET_ID);
 int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
 Toast.makeText(context,"Item" + ++viewIndex + " selected", Toast.LENGTH_SHORT).show();
 }
 super.onReceive(context, intent);
 }

 @Override
 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {


 <span style="color: #008000;"><strong>// There may be multiple widgets active, so update all of them
 // update each of the widgets with the remote adapter</strong></span>
 for (int i = 0; i <; appWidgetIds.length; ++i) {

 Intent toastIntent = new Intent(context, StackWidgetProvider.class);
<strong><span style="color: #008000;">
 // Set the action for the intent.
 // When the user touches a particular view, it will have the effect of
 // broadcasting TOAST_ACTION.</span></strong>
 toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
 toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
 PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
 PendingIntent.FLAG_UPDATE_CURRENT);
 views.setPendingIntentTemplate(R.id.list_view, toastPendingIntent);

 <span style="color: #008000;"><strong> // Instruct the widget manager to update the widget</strong></span>
 appWidgetManager.updateAppWidget(appWidgetIds, views);
 }

 }
}</pre>
<h4 id="setting-the-fill-in-intent"><span style="color: #000080;"><strong>Setting the fill-in Intent</strong></span></h4>
<p class="p1">Your <strong><span class="s1" style="color: #008000;">RemoteViewsFactory</span></strong> must set a fill-in intent on each item in the collection. This makes it possible to distinguish the individual on-click action of a given item. The fill-in intent is then combined with the <strong><span class="s1" style="color: #008000;">PendingIntent</span></strong> template in order to determine the final intent that will be executed when the item is clicked.</p>
<pre>public class ListWidgetService extends RemoteViewsService {

 @Override
 public RemoteViewsFactory onGetViewFactory(Intent intent) {
 return new StackRemoteViewsFactory(getApplicationContext(),intent);
 }

 class StackRemoteViewsFactory implements RemoteViewsFactory{

 private static final int mCount = 10;
 private List<;WidgetItem>; mWidgetItems = new ArrayList<;WidgetItem>;();
 private Context mContext;
 private int mAppWidgetId;
 <strong><span style="color: #008000;">// Given the position (index) of a WidgetItem in the array, use the item's text value in
 // combination with the app widget item XML file to construct a RemoteViews object.</span></strong>
 @Override
 public RemoteViews getViewAt(int position) {

 <strong><span style="color: #008000;">// position will always range from 0 to getCount() - 1.
 // construct a remote views item based on our widget item xml file, and set the
 // text based on the position.</span></strong>
 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);

 <strong><span style="color: #008000;">// Next, we set a fill-intent which will be used to fill-in the pending intent template
 // which is set on the collection view in StackWidgetProvider.</span></strong>
 Bundle extras = new Bundle();
 extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
 Intent fillInIntent = new Intent();
 fillInIntent.putExtras(extras);
 <span style="color: #008000;"><strong> // Make it possible to distinguish the individual on-click
 // action of a given item</strong></span>
 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
 
 <span style="color: #008000;"><strong>// Return the remote views object.</strong></span>
 return rv;
 }
}</pre>
<p>When you run the <span style="color: #008000;"><strong>AppwidgetCollectionDemo</strong></span> application it will look something like this:</p>
<p><img class="alignnone wp-image-1523" src="https://c1ctech.com/wp-content/uploads/2020/02/Screenshot_1580828302.png" alt="Screenshot_1580828302" width="346" height="615" /></p>
<p>I hope this article will help you in understanding how to work with collection widgets.

