Site icon C1CTech

Android App Widgets with collections

<h3 id&equals;"implementing&lowbar;collections"><span style&equals;"color&colon; &num;000080&semi;"><strong>App widgets with collections<&sol;strong><&sol;span><&sol;h3>&NewLine;<p class&equals;"p1">In the earlier versions of Android&comma; app widgets could only display views like TextView&comma; ImageView&comma; etc&period; But what if we want to show a list of items in our widget&quest; For example&comma; a collection of pictures from a gallery app&comma; or a collection of emails&sol;messages from a communication app&period; <strong><span style&equals;"color&colon; &num;0000ff&semi;">Collection widgets<&sol;span><&sol;strong> were introduced in Android 3&period;0 to provide this additional benefit&period; Collection widgets support <strong>ListView<&sol;strong>&comma; <strong>GridView<&sol;strong> and <strong>StackView<&sol;strong> layouts&period;<&sol;p>&NewLine;<p class&equals;"p1">In this article&comma; we will talk about how the collection widget works with a simple <span style&equals;"color&colon; &num;008000&semi;"><strong>AppwidgetCollectionDemo<&sol;strong><&sol;span> application&period;<&sol;p>&NewLine;<p><strong><span style&equals;"color&colon; &num;0000ff&semi;">Get GITHUB code from <a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;github&period;com&sol;arunk7839&sol;AppWidgetCollectionDemo">here<&sol;a>&period;<&sol;span><&sol;strong><&sol;p>&NewLine;<p><amp-youtube layout&equals;"responsive" width&equals;"1200" height&equals;"675" data-videoid&equals;"wtJpaYbhzQY" title&equals;"Android App Widgets with Collections"><a placeholder href&equals;"https&colon;&sol;&sol;youtu&period;be&sol;wtJpaYbhzQY"><img src&equals;"https&colon;&sol;&sol;i&period;ytimg&period;com&sol;vi&sol;wtJpaYbhzQY&sol;hqdefault&period;jpg" layout&equals;"fill" object-fit&equals;"cover" alt&equals;"Android App Widgets with Collections"><&sol;a><&sol;amp-youtube><&sol;p>&NewLine;<p class&equals;"p1">I assume you already know how to make a basic app widget&period; If not please refer to <span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s1"><a style&equals;"color&colon; &num;0000ff&semi;" href&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;android-app-widgets-with-example&sol;">this article<&sol;a><&sol;span><&sol;strong><&sol;span> and come back when you are ready to build your own collection widgets&period;<&sol;p>&NewLine;<h3 id&equals;"implementing&lowbar;collections"><span style&equals;"color&colon; &num;000080&semi;"><strong>Implementing app widgets with collections<&sol;strong><&sol;span><&sol;h3>&NewLine;<p class&equals;"p1">To implement an app widget with collections&comma; you follow the same basic steps you would use to implement any app widget&period; The following sections describe the additional steps you need to perform to implement an app widget with collections&period;<&sol;p>&NewLine;<p class&equals;"p1"> To make a collection widget&comma; two main components are required in addition to the basic components&colon;<&sol;p>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1"><strong><span style&equals;"color&colon; &num;0000ff&semi;">RemoteViewsService<&sol;span><&sol;strong><&sol;li>&NewLine;<li class&equals;"li1"><strong><span style&equals;"color&colon; &num;0000ff&semi;">RemoteViewsFactory<&sol;span><&sol;strong><&sol;li>&NewLine;<&sol;ul>&NewLine;<p class&equals;"p1">Let’s understand what these components do&period;<&sol;p>&NewLine;<h4 class&equals;"p2"><span style&equals;"color&colon; &num;000080&semi;"><b>RemoteViewsFactory Interface<&sol;b><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1"><span style&equals;"color&colon; &num;008000&semi;"><strong><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;android&sol;widget&sol;RemoteViewsService&period;RemoteViewsFactory&period;html">RemoteViewsFactory<&sol;a><&sol;strong><&sol;span> serves the purpose of an adapter in the widget’s context&period; An adapter is used to connect the collection items&lpar;for example&comma; ListView items or GridView items&rpar; with the data set&period;<&sol;p>&NewLine;<p>The two most important methods you need to implement for your <span class&equals;"s1">RemoteViewsFactory<&sol;span> subclass are <span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s1">onCreate&lpar;&rpar;<&sol;span><&sol;strong><&sol;span> and <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">getViewAt&lpar;&rpar;<&sol;span><&sol;strong>&period;<&sol;p>&NewLine;<p class&equals;"p2">Let’s add this class into our project&period; Create a new Java class&comma; name it <span style&equals;"color&colon; &num;008000&semi;"><b>ListRemoteViewsFactory<&sol;b><&sol;span>&comma; and set it to implement the class RemoteViewsService&period;RemoteViewsFactory&period;<&sol;p>&NewLine;<pre>class ListRemoteViewsFactory implements RemoteViewsFactory&lbrace;&NewLine;&NewLine; private static final int mCount &equals; 10&semi;&NewLine; private List&lt&semi;WidgetItem&gt&semi; mWidgetItems &equals; new ArrayList&lt&semi;WidgetItem&gt&semi;&lpar;&rpar;&semi;&NewLine; private Context mContext&semi;&NewLine; private int mAppWidgetId&semi;&NewLine;&NewLine; public ListRemoteViewsFactory&lpar;Context context&comma;Intent intent&rpar; &lbrace;&NewLine; mContext &equals; context&semi;&NewLine; mAppWidgetId &equals; intent&period;getIntExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma;&NewLine; AppWidgetManager&period;INVALID&lowbar;APPWIDGET&lowbar;ID&rpar;&semi;&NewLine; &rcub;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Initialize the data set&period;<&sol;span><&sol;strong>&NewLine; &commat;Override&NewLine; public void onCreate&lpar;&rpar; &lbrace;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; In onCreate&lpar;&rpar; you setup any connections &sol; cursors to your data source&period; Heavy lifting&comma;&NewLine; &sol;&sol; for example downloading or creating content etc&comma; should be deferred to onDataSetChanged&lpar;&rpar;&NewLine; &sol;&sol; or getViewAt&lpar;&rpar;&period; Taking more than 20 seconds in this call will result in an ANR&period;<&sol;span><&sol;strong>&NewLine; for &lpar;int i &equals; 1&semi; i &lt&semi;&equals; mCount&semi; i&plus;&plus;&rpar; &lbrace;&NewLine; mWidgetItems&period;add&lpar;new WidgetItem&lpar;"Item" &plus; i&rpar;&rpar;&semi;&NewLine; &rcub;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; We sleep for 3 seconds here to show how the empty view appears in the interim&period;&NewLine; &sol;&sol; The empty view is set in the ListWidgetProvider and should be a sibling of the&NewLine; &sol;&sol; collection view&period;<&sol;span><&sol;strong>&NewLine; try &lbrace;&NewLine; Thread&period;sleep&lpar;3000&rpar;&semi;&NewLine; &rcub; catch &lpar;InterruptedException e&rpar; &lbrace;&NewLine; e&period;printStackTrace&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine; &rcub;&NewLine;&NewLine;&NewLine; &commat;Override&NewLine; public void onDestroy&lpar;&rpar; &lbrace;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; In onDestroy&lpar;&rpar; you should tear down anything that was setup for your data source&comma;&NewLine; &sol;&sol; eg&period; cursors&comma; connections&comma; etc&period;<&sol;strong><&sol;span>&NewLine; mWidgetItems&period;clear&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public int getCount&lpar;&rpar; &lbrace;&NewLine; return mCount&semi;&NewLine; &rcub;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Given the position &lpar;index&rpar; of a WidgetItem in the array&comma; use the item's text value in&NewLine; &sol;&sol; combination with the app widget item XML file to construct a RemoteViews object&period;<&sol;span><&sol;strong>&NewLine; &commat;Override&NewLine; public RemoteViews getViewAt&lpar;int position&rpar; &lbrace;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; position will always range from 0 to getCount&lpar;&rpar; - 1&period;&NewLine; &sol;&sol; construct a remote views item based on our widget item xml file&comma; and set the&NewLine; &sol;&sol; text based on the position&period;<&sol;span><&sol;strong>&NewLine; RemoteViews rv &equals; new RemoteViews&lpar;mContext&period;getPackageName&lpar;&rpar;&comma; R&period;layout&period;widget&lowbar;item&rpar;&semi;&NewLine; rv&period;setTextViewText&lpar;R&period;id&period;widget&lowbar;item&comma; mWidgetItems&period;get&lpar;position&rpar;&period;text&rpar;&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Next&comma; we set a fill-intent which will be used to fill-in the pending intent template&NewLine; &sol;&sol; which is set on the collection view in ListWidgetProvider&period;<&sol;strong><&sol;span>&NewLine; Bundle extras &equals; new Bundle&lpar;&rpar;&semi;&NewLine; extras&period;putInt&lpar;ListWidgetProvider&period;EXTRA&lowbar;ITEM&comma; position&rpar;&semi;&NewLine; Intent fillInIntent &equals; new Intent&lpar;&rpar;&semi;&NewLine; fillInIntent&period;putExtras&lpar;extras&rpar;&semi;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Make it possible to distinguish the individual on-click&NewLine; &sol;&sol; action of a given item<&sol;strong><&sol;span>&NewLine; rv&period;setOnClickFillInIntent&lpar;R&period;id&period;widget&lowbar;item&comma; fillInIntent&rpar;&semi;&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong>&NewLine; &sol;&sol; You can do heaving lifting in here&comma; synchronously&period; For example&comma; if you need to&NewLine; &sol;&sol; process an image&comma; fetch something from the network&comma; etc&period;&comma; it is ok to do it here&comma;&NewLine; &sol;&sol; synchronously&period; A loading view will show up in lieu of the actual contents in the&NewLine; &sol;&sol; interim&period;<&sol;strong><&sol;span>&NewLine; try &lbrace;&NewLine; System&period;out&period;println&lpar;"Loading view " &plus; position&rpar;&semi;&NewLine; Thread&period;sleep&lpar;500&rpar;&semi;&NewLine; &rcub; catch &lpar;InterruptedException e&rpar; &lbrace;&NewLine; e&period;printStackTrace&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Return the remote views object&period;&NewLine;<&sol;strong> <&sol;span> return rv&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public RemoteViews getLoadingView&lpar;&rpar; &lbrace;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; You can create a custom loading view &lpar;for instance when getViewAt&lpar;&rpar; is slow&period;&rpar; If you&NewLine; &sol;&sol; return null here&comma; you will get the default loading view&period;<&sol;strong><&sol;span>&NewLine; return null&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public int getViewTypeCount&lpar;&rpar; &lbrace;&NewLine; return 1&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public long getItemId&lpar;int position&rpar; &lbrace;&NewLine; return position&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public boolean hasStableIds&lpar;&rpar; &lbrace;&NewLine; return true&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public void onDataSetChanged&lpar;&rpar; &lbrace;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged&NewLine; &sol;&sol; on the collection view corresponding to this factory&period; You can do heaving lifting in&NewLine; &sol;&sol; here&comma; synchronously&period; For example&comma; if you need to process an image&comma; fetch something&NewLine; &sol;&sol; from the network&comma; etc&period;&comma; it is ok to do it here&comma; synchronously&period; The widget will remain&NewLine; &sol;&sol; in its current state while work is being done here&comma; so you don't need to worry about&NewLine; &sol;&sol; locking up the widget&period;<&sol;strong><&sol;span>&NewLine; &rcub;&NewLine;&NewLine;&rcub;<&sol;pre>&NewLine;<p class&equals;"p1">In the code above&comma; ListRemoteViewsFactory overrides a few methods from the <span style&equals;"color&colon; &num;008000&semi;"><strong>RemoteViewsFactory<&sol;strong><&sol;span> class&colon;<&sol;p>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>onCreate<&sol;strong><&sol;span> is called by the system when creating your factory for the first time&period; This is where you set up any connections and&sol;or cursors to your data source&period;<&sol;li>&NewLine;<li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>onDataSetChanged<&sol;strong><&sol;span> is called when notifyDataSetChanged&lpar;&rpar; is triggered on the remote adapter&period;<&sol;li>&NewLine;<li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>getCount<&sol;strong><&sol;span> returns the number of records in the cursor&period; &lpar;In our case&comma; the number of task items that need to be displayed in the app widget&rpar;<&sol;li>&NewLine;<li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>getViewAt<&sol;strong><&sol;span> handles all the processing work&period; It returns a RemoteViews object which in our case is the single list item&period;<&sol;li>&NewLine;<li class&equals;"li1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>getViewTypeCount<&sol;strong><&sol;span> returns the number of types of views we have in ListView&period; In our case&comma; we have same view type for each ListView item so we return 1 there&period;<&sol;li>&NewLine;<li><strong><strong><span style&equals;"color&colon; &num;0000ff&semi;">onDestroy <&sol;span><&sol;strong><&sol;strong><span style&equals;"color&colon; &num;0000ff&semi;"><span style&equals;"color&colon; &num;000000&semi;">is called when the last RemoteViewsAdapter that is associated with this factory is unbound&period; Here <&sol;span><&sol;span>you should tear down anything that was set up for your data source eg&period; cursors&comma; connections&comma; etc&period;<&sol;li>&NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>getLoadingView<&sol;strong><&sol;span> allows for the use of a custom loading view which appears between the time that <span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s1">getViewAt&lpar;int&rpar;<&sol;span><&sol;strong><&sol;span><span style&equals;"color&colon; var&lpar;--color-text&rpar;&semi;"> is called and returns&period;<&sol;span><&sol;li>&NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>hasStableIds<&sol;strong><&sol;span> Indicates whether the item ids are stable across changes to the underlying data&period; It returns <span style&equals;"color&colon; &num;008000&semi;"><strong>True<&sol;strong><&sol;span> if the same id always refers to the same object&period;<&sol;li>&NewLine;<li><span style&equals;"color&colon; &num;0000ff&semi;"><strong>getItemId<&sol;strong><&sol;span> gets the row id associated with the specified position in the list&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<h4 id&equals;"remoteviewsservice-class"><span style&equals;"color&colon; &num;000080&semi;"><strong>RemoteViewsService class<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">The main purpose of <strong><span style&equals;"color&colon; &num;008000&semi;">RemoteViewsService<&sol;span><&sol;strong> is to return a <span style&equals;"color&colon; &num;008000&semi;"><strong>RemoteViewsFactory<&sol;strong><&sol;span> object which further handles the task of filling the widget with appropriate data&period;<&sol;p>&NewLine;<p class&equals;"p1">Create a new class named <span style&equals;"color&colon; &num;008000&semi;"><b>ListWidgetService<&sol;b><&sol;span> extending the class RemoteViewsService&period;<&sol;p>&NewLine;<p><strong><span style&equals;"color&colon; &num;0000ff&semi;">ListWidgetService&period;java<&sol;span><&sol;strong><&sol;p>&NewLine;<pre>public class ListWidgetService extends RemoteViewsService &lbrace;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&commat;Override<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> public RemoteViewsFactory onGetViewFactory&lpar;Intent intent&rpar; &lbrace;<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> return new ListRemoteViewsFactory&lpar;getApplicationContext&lpar;&rpar;&comma;intent&rpar;&semi;<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &rcub;<&sol;span><&sol;strong>&NewLine;&NewLine; class ListRemoteViewsFactory implements RemoteViewsFactory&lbrace;&NewLine;&NewLine; private static final int mCount &equals; 10&semi;&NewLine; private List&lt&semi;WidgetItem&gt&semi; mWidgetItems &equals; new ArrayList&lt&semi;WidgetItem&gt&semi;&lpar;&rpar;&semi;&NewLine; private Context mContext&semi;&NewLine; private int mAppWidgetId&semi;&NewLine;&NewLine; public ListRemoteViewsFactory&lpar;Context context&comma;Intent intent&rpar; &lbrace;&NewLine; mContext &equals; context&semi;&NewLine; mAppWidgetId &equals; intent&period;getIntExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma;&NewLine; AppWidgetManager&period;INVALID&lowbar;APPWIDGET&lowbar;ID&rpar;&semi;&NewLine; &rcub;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Initialize the data set&period;<&sol;strong><&sol;span>&NewLine; &commat;Override&NewLine; public void onCreate&lpar;&rpar; &lbrace;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; In onCreate&lpar;&rpar; you setup any connections &sol; cursors to your data source&period; Heavy lifting&comma;<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; for example downloading or creating content etc&comma; should be deferred to onDataSetChanged&lpar;&rpar;<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; or getViewAt&lpar;&rpar;&period; Taking more than 20 seconds in this call will result in an ANR&period;<&sol;strong><&sol;span>&NewLine; for &lpar;int i &equals; 1&semi; i &lt&semi;&equals; mCount&semi; i&plus;&plus;&rpar; &lbrace;&NewLine; mWidgetItems&period;add&lpar;new WidgetItem&lpar;"Item" &plus; i&rpar;&rpar;&semi;&NewLine; &rcub;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; We sleep for 3 seconds here to show how the empty view appears in the interim&period;<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; The empty view is set in the ListWidgetProvider and should be a sibling of the<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; collection view&period;<&sol;span><&sol;strong>&NewLine; try &lbrace;&NewLine; Thread&period;sleep&lpar;3000&rpar;&semi;&NewLine; &rcub; catch &lpar;InterruptedException e&rpar; &lbrace;&NewLine; e&period;printStackTrace&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine; &rcub;&NewLine;&NewLine;&NewLine; &commat;Override&NewLine; public void onDestroy&lpar;&rpar; &lbrace;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; In onDestroy&lpar;&rpar; you should tear down anything that was setup for your data source&comma;<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; eg&period; cursors&comma; connections&comma; etc&period;<&sol;strong><&sol;span>&NewLine; mWidgetItems&period;clear&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public int getCount&lpar;&rpar; &lbrace;&NewLine; return mCount&semi;&NewLine; &rcub;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Given the position &lpar;index&rpar; of a WidgetItem in the array&comma; use the item's text value in<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; combination with the app widget item XML file to construct a RemoteViews object&period;<&sol;strong><&sol;span>&NewLine; &commat;Override&NewLine; public RemoteViews getViewAt&lpar;int position&rpar; &lbrace;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; position will always range from 0 to getCount&lpar;&rpar; - 1&period;<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; construct a remote views item based on our widget item xml file&comma; and set the<&sol;strong><&sol;span>&NewLine;<span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; text based on the position&period;<&sol;strong><&sol;span>&NewLine; RemoteViews rv &equals; new RemoteViews&lpar;mContext&period;getPackageName&lpar;&rpar;&comma; R&period;layout&period;widget&lowbar;item&rpar;&semi;&NewLine; rv&period;setTextViewText&lpar;R&period;id&period;widget&lowbar;item&comma; mWidgetItems&period;get&lpar;position&rpar;&period;text&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Next&comma; we set a fill-intent which will be used to fill-in the pending intent template<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; which is set on the collection view in ListWidgetProvider&period;<&sol;span><&sol;strong>&NewLine; Bundle extras &equals; new Bundle&lpar;&rpar;&semi;&NewLine; extras&period;putInt&lpar;ListWidgetProvider&period;EXTRA&lowbar;ITEM&comma; position&rpar;&semi;&NewLine; Intent fillInIntent &equals; new Intent&lpar;&rpar;&semi;&NewLine; fillInIntent&period;putExtras&lpar;extras&rpar;&semi;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; Make it possible to distinguish the individual on-click<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; action of a given item<&sol;span><&sol;strong>&NewLine; rv&period;setOnClickFillInIntent&lpar;R&period;id&period;widget&lowbar;item&comma; fillInIntent&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; You can do heaving lifting in here&comma; synchronously&period; For example&comma; if you need to<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; process an image&comma; fetch something from the network&comma; etc&period;&comma; it is ok to do it here&comma;<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; synchronously&period; A loading view will show up in lieu of the actual contents in the<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; interim&period;<&sol;span><&sol;strong>&NewLine; try &lbrace;&NewLine; System&period;out&period;println&lpar;"Loading view " &plus; position&rpar;&semi;&NewLine; Thread&period;sleep&lpar;500&rpar;&semi;&NewLine; &rcub; catch &lpar;InterruptedException e&rpar; &lbrace;&NewLine; e&period;printStackTrace&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; Return the remote views object&period;<&sol;span><&sol;strong>&NewLine; return rv&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public RemoteViews getLoadingView&lpar;&rpar; &lbrace;&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; You can create a custom loading view &lpar;for instance when getViewAt&lpar;&rpar; is slow&period;&rpar; If you<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; return null here&comma; you will get the default loading view&period;<&sol;span><&sol;strong>&NewLine; return null&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public int getViewTypeCount&lpar;&rpar; &lbrace;&NewLine; return 1&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public long getItemId&lpar;int position&rpar; &lbrace;&NewLine; return position&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public boolean hasStableIds&lpar;&rpar; &lbrace;&NewLine; return true&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public void onDataSetChanged&lpar;&rpar; &lbrace;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; on the collection view corresponding to this factory&period; You can do heaving lifting in<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; here&comma; synchronously&period; For example&comma; if you need to process an image&comma; fetch something<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; from the network&comma; etc&period;&comma; it is ok to do it here&comma; synchronously&period; The widget will remain<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; in its current state while work is being done here&comma; so you don't need to worry about<&sol;span><&sol;strong>&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; locking up the widget&period;<&sol;span><&sol;strong>&NewLine; &rcub;&NewLine;&NewLine; &rcub;&NewLine;&NewLine;&rcub;<&sol;pre>&NewLine;<p>As with all the other services in android&comma; we must register this service in the manifest file&period;<&sol;p>&NewLine;<&excl;-- WP QUADS Content Ad Plugin v&period; 2&period;0&period;98&period;1 -->&NewLine;<div class&equals;"quads-location quads-ad2" id&equals;"quads-ad2" style&equals;"float&colon;none&semi;margin&colon;0px&semi;">&NewLine;&NewLine;<&sol;div>&NewLine;&NewLine;<h4 id&equals;"manifest-for-app-widgets-with-collections"><span style&equals;"color&colon; &num;000080&semi;"><strong>Manifest for app widgets with collections<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">To make it possible for app widgets with collections to bind to your <span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s2">RemoteViewsService<&sol;span><&sol;strong><&sol;span>&comma; you must declare the service in your manifest file with the permission <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">BIND&lowbar;REMOTEVIEWS<&sol;span><&sol;strong>&period;<&sol;p>&NewLine;<pre>&lt&semi;service android&colon;name&equals;"&period;ListWidgetService"&NewLine; android&colon;permission&equals;"android&period;permission&period;BIND&lowbar;REMOTEVIEWS"&NewLine; android&colon;exported&equals;"false" &sol;&gt&semi;<&sol;pre>&NewLine;<p class&equals;"p1"><span style&equals;"color&colon; &num;0000ff&semi;"><strong>Note<&sol;strong><&sol;span> the special permission <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">BIND&lowbar;REMOTEVIEWS&period; <&sol;span><&sol;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&period;<&sol;p>&NewLine;<h4 id&equals;"layout-for-app-widgets-with-collections"><span style&equals;"color&colon; &num;000080&semi;"><strong>Layout for app widgets with collections<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">The main requirement for your app widget layout XML file is that it include one of the collection views&colon; <span style&equals;"color&colon; &num;008000&semi;"><strong><span class&equals;"s1">ListView<&sol;span>&comma; <span class&equals;"s1">GridView<&sol;span>&comma; <span class&equals;"s1">StackView<&sol;span>&comma; or <span class&equals;"s1">AdapterViewFlipper<&sol;span><&sol;strong><&sol;span>&period; Here is the <span class&equals;"s2">widget&lowbar;layout&period;xml<&sol;span> for the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>AppwidgetCollectionDemo<&sol;strong><&sol;span><span class&equals;"s3"> sample<&sol;span>&colon;<&sol;p>&NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong>widget&lowbar;layout&period;xml<&sol;strong><&sol;span><&sol;p>&NewLine;<pre>&lt&semi;RelativeLayout xmlns&colon;android&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res&sol;android"&NewLine; android&colon;layout&lowbar;width&equals;"match&lowbar;parent"&NewLine; android&colon;layout&lowbar;height&equals;"match&lowbar;parent"&NewLine; android&colon;layout&lowbar;margin&equals;"8dp"&gt&semi;&NewLine;&NewLine; &lt&semi;ListView&NewLine; android&colon;id&equals;"&commat;&plus;id&sol;list&lowbar;view"&NewLine; android&colon;layout&lowbar;width&equals;"match&lowbar;parent"&NewLine; android&colon;layout&lowbar;height&equals;"match&lowbar;parent"&NewLine; android&colon;gravity&equals;"center"&NewLine; android&colon;loopViews&equals;"true" &sol;&gt&semi;&NewLine;&NewLine; &lt&semi;TextView&NewLine; android&colon;id&equals;"&commat;&plus;id&sol;empty&lowbar;view"&NewLine; android&colon;layout&lowbar;width&equals;"match&lowbar;parent"&NewLine; android&colon;layout&lowbar;height&equals;"match&lowbar;parent"&NewLine; android&colon;background&equals;"&commat;drawable&sol;widget&lowbar;item&lowbar;background&lowbar;empty"&NewLine; android&colon;gravity&equals;"center"&NewLine; android&colon;text&equals;"Empty"&NewLine; android&colon;textColor&equals;"&num;ffffff"&NewLine; android&colon;textSize&equals;"20sp"&NewLine; android&colon;textStyle&equals;"bold" &sol;&gt&semi;&NewLine;&NewLine;&lt&semi;&sol;RelativeLayout&gt&semi;<&sol;pre>&NewLine;<p class&equals;"p1"><span style&equals;"color&colon; &num;000080&semi;"><strong>Note&colon;<&sol;strong><&sol;span> Empty views must be siblings of the collection view for which the empty view represents empty state&period;<&sol;p>&NewLine;<p class&equals;"p1">In addition to the layout file for your entire app widget&comma; you must create another layout file that defines the layout for each item in the collection&period; The <span style&equals;"color&colon; &num;0000ff&semi;"><strong>AppwidgetCollectionDemo<&sol;strong><&sol;span><span class&equals;"s3"> sample<&sol;span> only has one layout file&comma; <span class&equals;"s2">widget&lowbar;item&period;xml<&sol;span>&comma; since all items use the same layout&period;<&sol;p>&NewLine;<p><span style&equals;"color&colon; &num;0000ff&semi;"><strong><span class&equals;"s2">widget&lowbar;item&period;xml<&sol;span><&sol;strong><&sol;span><&sol;p>&NewLine;<pre>&lt&semi;&quest;xml version&equals;"1&period;0" encoding&equals;"utf-8"&quest;&gt&semi;&NewLine;&lt&semi;TextView xmlns&colon;android&equals;"http&colon;&sol;&sol;schemas&period;android&period;com&sol;apk&sol;res&sol;android"&NewLine; android&colon;id&equals;"&commat;&plus;id&sol;widget&lowbar;item"&NewLine; android&colon;layout&lowbar;width&equals;"match&lowbar;parent"&NewLine; android&colon;layout&lowbar;height&equals;"wrap&lowbar;content"&NewLine; android&colon;gravity&equals;"center"&NewLine; android&colon;background&equals;"&commat;drawable&sol;widget&lowbar;item&lowbar;background&lowbar;data"&NewLine; android&colon;padding&equals;"10dp"&NewLine; android&colon;textColor&equals;"&num;ffffff"&NewLine; android&colon;textStyle&equals;"bold"&NewLine; android&colon;text&equals;"Item n"&NewLine; android&colon;textSize&equals;"30sp"&gt&semi;&NewLine;&NewLine;&lt&semi;&sol;TextView&gt&semi;<&sol;pre>&NewLine;<h4 id&equals;"AppWidgetProvider-collections"><span style&equals;"color&colon; &num;000080&semi;"><strong>AppWidgetProvider class for app widgets with collections<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">The major difference in your implementation for <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">onUpdate&lpar;&rpar;<&sol;span><&sol;strong> when creating an app widget with collections is that you must call <strong><span class&equals;"s1" style&equals;"color&colon; &num;0000ff&semi;">setRemoteAdapter&lpar;&rpar;<&sol;span><&sol;strong>&period; This tells the collection view where to get its data&period;<&sol;p>&NewLine;<p class&equals;"p1">When you call <span class&equals;"s1">setRemoteAdapter&lpar;&rpar;<&sol;span> method&comma; you must pass an intent that points to your implementation of <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">RemoteViewsService<&sol;span><&sol;strong> and the app widget ID that specifies the app widget to update&period;&grave;<&sol;p>&NewLine;<p>The <span class&equals;"s1">RemoteViewsService<&sol;span> can then return your implementation of <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">RemoteViewsFactory<&sol;span><&sol;strong>&comma; and the widget can serve up the appropriate data&period;<&sol;p>&NewLine;<p class&equals;"p1">For example&comma; here&&num;8217&semi;s how the <span style&equals;"color&colon; &num;0000ff&semi;"><strong>AppWidgetCollectionDemo<&sol;strong><&sol;span> sample implements the <span style&equals;"color&colon; &num;000000&semi;"><span class&equals;"s1">onUpdate&lpar;&rpar;<&sol;span><&sol;span> callback method to set the <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">RemoteViewsService<&sol;span><&sol;strong> as the remote adapter for the app widget collection&colon;<&sol;p>&NewLine;<pre>&commat;Override&NewLine;public void onUpdate&lpar;Context context&comma; AppWidgetManager appWidgetManager&comma; int&lbrack;&rsqb; appWidgetIds&rpar; &lbrace;&NewLine;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; There may be multiple widgets active&comma; so update all of them&NewLine; &sol;&sol; update each of the widgets with the remote adapter<&sol;span><&sol;strong>&NewLine; for &lpar;int i &equals; 0&semi; i &lt&semi; appWidgetIds&period;length&semi; &plus;&plus;i&rpar; &lbrace;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Here we setup the intent which points to the StackViewService which will&NewLine; &sol;&sol; provide the views for this collection&period;<&sol;span><&sol;strong>&NewLine; Intent intent &equals; new Intent&lpar;context&comma; ListWidgetService&period;class&rpar;&semi;&NewLine; intent&period;putExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma; appWidgetIds&lbrack;i&rsqb;&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; When intents are compared&comma; the extras are ignored&comma; so we need to embed the extras&NewLine; &sol;&sol; into the data so that the extras will not be ignored&period;<&sol;span><&sol;strong>&NewLine; intent&period;setData&lpar;Uri&period;parse&lpar;intent&period;toUri&lpar;intent&period;URI&lowbar;INTENT&lowbar;SCHEME&rpar;&rpar;&rpar;&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Construct the RemoteViews object<&sol;strong><&sol;span>&NewLine; RemoteViews views &equals; new RemoteViews&lpar;context&period;getPackageName&lpar;&rpar;&comma; R&period;layout&period;widget&lowbar;layout&rpar;&semi;&NewLine; views&period;setRemoteAdapter&lpar;R&period;id&period;list&lowbar;view&comma; intent&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; The empty view is displayed when the collection has no items&period; It should be a sibling&NewLine; &sol;&sol; of the collection view&period;<&sol;span><&sol;strong>&NewLine; views&period;setEmptyView&lpar;R&period;id&period;list&lowbar;view&comma;R&period;id&period;empty&lowbar;view&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;"> &sol;&sol; This section makes it possible for items to have individualized behavior&period;&NewLine; &sol;&sol; It does this by setting up a pending intent template&period; Individuals items of a collection&NewLine; &sol;&sol; cannot set up their own pending intents&period; Instead&comma; the collection as a whole sets&NewLine; &sol;&sol; up a pending intent template&comma; and the individual items set a fillInIntent&NewLine; &sol;&sol; to create unique behavior on an item-by-item basis&period;<&sol;span><&sol;strong>&NewLine; Intent toastIntent &equals; new Intent&lpar;context&comma; StackWidgetProvider&period;class&rpar;&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Set the action for the intent&period;&NewLine; &sol;&sol; When the user touches a particular view&comma; it will have the effect of&NewLine; &sol;&sol; broadcasting TOAST&lowbar;ACTION&period;<&sol;strong><&sol;span>&NewLine; toastIntent&period;setAction&lpar;StackWidgetProvider&period;TOAST&lowbar;ACTION&rpar;&semi;&NewLine; toastIntent&period;putExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma; appWidgetIds&lbrack;i&rsqb;&rpar;&semi;&NewLine; intent&period;setData&lpar;Uri&period;parse&lpar;intent&period;toUri&lpar;Intent&period;URI&lowbar;INTENT&lowbar;SCHEME&rpar;&rpar;&rpar;&semi;&NewLine; PendingIntent toastPendingIntent &equals; PendingIntent&period;getBroadcast&lpar;context&comma; 0&comma; toastIntent&comma;&NewLine; PendingIntent&period;FLAG&lowbar;UPDATE&lowbar;CURRENT&rpar;&semi;&NewLine; views&period;setPendingIntentTemplate&lpar;R&period;id&period;list&lowbar;view&comma; toastPendingIntent&rpar;&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Instruct the widget manager to update the widget<&sol;strong><&sol;span>&NewLine; appWidgetManager&period;updateAppWidget&lpar;appWidgetIds&comma; views&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine;&rcub;<&sol;pre>&NewLine;<h3 id&equals;"behavior"><strong><span style&equals;"color&colon; &num;000080&semi;">Click events on ListView items<&sol;span><&sol;strong><&sol;h3>&NewLine;<p class&equals;"p1">The above sections show you how to bind your data to your app widget collection&period; But what if you want to add dynamic behavior to the individual items in your collection view&quest;<&sol;p>&NewLine;<p class&equals;"p1">We normally use <strong><span style&equals;"color&colon; &num;008000&semi;"><span class&equals;"s2"><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;android&sol;widget&sol;RemoteViews&period;html&num;setOnClickPendingIntent&lpar;int&comma;&percnt;20android&period;app&period;PendingIntent&rpar;">setOnClickPendingIntent<&sol;a>&lpar;&rpar;<&sol;span> <&sol;span><&sol;strong>to set an object&&num;8217&semi;s click behavior—such as to cause a button to launch an <span class&equals;"s2">Activity<&sol;span>&period; But this approach is not allowed for child views in an individual collection item &lpar;to clarify&comma; you could use <span class&equals;"s2">setOnClickPendingIntent&lpar;&rpar;<&sol;span> to set up a global button in the Gmail app widget that launches the app&comma; for example&comma; but not on the individual list items&rpar;&period;<&sol;p>&NewLine;<p class&equals;"p1">Instead&comma; to add click behavior to individual items in a collection&comma; you use <strong><span style&equals;"color&colon; &num;008000&semi;"><a style&equals;"color&colon; &num;008000&semi;" href&equals;"https&colon;&sol;&sol;developer&period;android&period;com&sol;reference&sol;android&sol;widget&sol;RemoteViews&period;html&num;setOnClickFillInIntent&lpar;int&comma;&percnt;20android&period;content&period;Intent&rpar;"><span class&equals;"s2">setOnClickFillInIntent&lpar;&rpar;<&sol;span><&sol;a>&period;<&sol;span><&sol;strong> This entails setting up a pending intent template for your collection view&comma; and then setting a fill-in intent on each item in the collection via your <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">RemoteViewsFactory<&sol;span><&sol;strong>&period;<&sol;p>&NewLine;<p class&equals;"p1">In the <strong><span style&equals;"color&colon; &num;0000ff&semi;">AppWidgetCollectionDemo<&sol;span><&sol;strong> sample&comma; if the user touches any item&comma; the app widget displays the <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">Toast<&sol;span><&sol;strong> message &&num;8220&semi;Item <em>n<&sol;em> selected&comma;&&num;8221&semi; where <i>n<&sol;i> is the index &lpar;position&rpar; of the touched view&period; This is how it works&colon;<&sol;p>&NewLine;<ul class&equals;"ul1">&NewLine;<li class&equals;"li1">The List<span class&equals;"s4">WidgetProvider<&sol;span> &lpar;an <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">AppWidgetProvider<&sol;span><&sol;strong> subclass&rpar; creates a pending intent that has a custom action called <span class&equals;"s4">TOAST&lowbar;ACTION<&sol;span>&period;<&sol;li>&NewLine;<li class&equals;"li1">When the user touches a view&comma; the intent is fired and it broadcasts <span class&equals;"s4">TOAST&lowbar;ACTION<&sol;span>&period;<&sol;li>&NewLine;<li class&equals;"li1">This broadcast is intercepted by the <span class&equals;"s4">ListWidgetProvider<&sol;span>&&num;8216&semi;s <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">onReceive&lpar;&rpar;<&sol;span><&sol;strong> method&comma; and the app widget displays the <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">Toast<&sol;span><&sol;strong> message for the touched view&period; The data for the collection items is provided by the <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">RemoteViewsFactory<&sol;span><&sol;strong>&comma; via the <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">RemoteViewsService<&sol;span><&sol;strong>&period;<&sol;li>&NewLine;<&sol;ul>&NewLine;<h4 id&equals;"setting-up-the-pending-intent-template"><span style&equals;"color&colon; &num;000080&semi;"><strong>Setting up the pending intent template<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">The List<span class&equals;"s1">WidgetProvider<&sol;span> &lpar;<strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">AppWidgetProvider<&sol;span><&sol;strong> subclass&rpar; sets up a pending intent&period; Individuals items of a collection cannot set up their own pending intents&period; Instead&comma; the collection as a whole sets up a pending intent template&comma; and the individual items set a fill-in intent to create unique behavior on an item-by-item basis&period;<&sol;p>&NewLine;<p class&equals;"p1">This class also receives the broadcast that is sent when the user touches a view&period; It processes this event in its <strong><span style&equals;"color&colon; &num;008000&semi;"><span class&equals;"s2">onReceive&lpar;&rpar;<&sol;span> <&sol;span><&sol;strong>method&period; If the intent&&num;8217&semi;s action is <span class&equals;"s1">TOAST&lowbar;ACTION<&sol;span>&comma; the app widget displays a <strong><span class&equals;"s2" style&equals;"color&colon; &num;008000&semi;">Toast<&sol;span><&sol;strong> message for the current view&period;<&sol;p>&NewLine;<pre>public class ListWidgetProvider extends AppWidgetProvider &lbrace;&NewLine;&NewLine; public static final String TOAST&lowbar;ACTION &equals; "com&period;example&period;android&period;stackwidget&period;TOAST&lowbar;ACTION"&semi;&NewLine; public static final String EXTRA&lowbar;ITEM &equals; "com&period;example&period;android&period;stackwidget&period;EXTRA&lowbar;ITEM"&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Called when the BroadcastReceiver receives an Intent broadcast&period;&NewLine; &sol;&sol; Checks to see whether the intent's action is TOAST&lowbar;ACTION&period; If it is&comma; the app widget&NewLine; &sol;&sol; displays a Toast message for the current item&period;<&sol;strong><&sol;span>&NewLine; &commat;Override&NewLine; public void onReceive&lpar;Context context&comma; Intent intent&rpar; &lbrace;&NewLine; AppWidgetManager mgr &equals; AppWidgetManager&period;getInstance&lpar;context&rpar;&semi;&NewLine; if &lpar;intent&period;getAction&lpar;&rpar;&period;equals&lpar;TOAST&lowbar;ACTION&rpar;&rpar; &lbrace;&NewLine; int appWidgetId &equals; intent&period;getIntExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma;&NewLine; AppWidgetManager&period;INVALID&lowbar;APPWIDGET&lowbar;ID&rpar;&semi;&NewLine; int viewIndex &equals; intent&period;getIntExtra&lpar;EXTRA&lowbar;ITEM&comma; 0&rpar;&semi;&NewLine; Toast&period;makeText&lpar;context&comma;"Item" &plus; &plus;&plus;viewIndex &plus; " selected"&comma; Toast&period;LENGTH&lowbar;SHORT&rpar;&period;show&lpar;&rpar;&semi;&NewLine; &rcub;&NewLine; super&period;onReceive&lpar;context&comma; intent&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; &commat;Override&NewLine; public void onUpdate&lpar;Context context&comma; AppWidgetManager appWidgetManager&comma; int&lbrack;&rsqb; appWidgetIds&rpar; &lbrace;&NewLine;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; There may be multiple widgets active&comma; so update all of them&NewLine; &sol;&sol; update each of the widgets with the remote adapter<&sol;strong><&sol;span>&NewLine; for &lpar;int i &equals; 0&semi; i &lt&semi; appWidgetIds&period;length&semi; &plus;&plus;i&rpar; &lbrace;&NewLine;&NewLine; Intent toastIntent &equals; new Intent&lpar;context&comma; StackWidgetProvider&period;class&rpar;&semi;&NewLine;<strong><span style&equals;"color&colon; &num;008000&semi;">&NewLine; &sol;&sol; Set the action for the intent&period;&NewLine; &sol;&sol; When the user touches a particular view&comma; it will have the effect of&NewLine; &sol;&sol; broadcasting TOAST&lowbar;ACTION&period;<&sol;span><&sol;strong>&NewLine; toastIntent&period;setAction&lpar;StackWidgetProvider&period;TOAST&lowbar;ACTION&rpar;&semi;&NewLine; toastIntent&period;putExtra&lpar;AppWidgetManager&period;EXTRA&lowbar;APPWIDGET&lowbar;ID&comma; appWidgetIds&lbrack;i&rsqb;&rpar;&semi;&NewLine; intent&period;setData&lpar;Uri&period;parse&lpar;intent&period;toUri&lpar;Intent&period;URI&lowbar;INTENT&lowbar;SCHEME&rpar;&rpar;&rpar;&semi;&NewLine; PendingIntent toastPendingIntent &equals; PendingIntent&period;getBroadcast&lpar;context&comma; 0&comma; toastIntent&comma;&NewLine; PendingIntent&period;FLAG&lowbar;UPDATE&lowbar;CURRENT&rpar;&semi;&NewLine; views&period;setPendingIntentTemplate&lpar;R&period;id&period;list&lowbar;view&comma; toastPendingIntent&rpar;&semi;&NewLine;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Instruct the widget manager to update the widget<&sol;strong><&sol;span>&NewLine; appWidgetManager&period;updateAppWidget&lpar;appWidgetIds&comma; views&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; &rcub;&NewLine;&rcub;<&sol;pre>&NewLine;<h4 id&equals;"setting-the-fill-in-intent"><span style&equals;"color&colon; &num;000080&semi;"><strong>Setting the fill-in Intent<&sol;strong><&sol;span><&sol;h4>&NewLine;<p class&equals;"p1">Your <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">RemoteViewsFactory<&sol;span><&sol;strong> must set a fill-in intent on each item in the collection&period; This makes it possible to distinguish the individual on-click action of a given item&period; The fill-in intent is then combined with the <strong><span class&equals;"s1" style&equals;"color&colon; &num;008000&semi;">PendingIntent<&sol;span><&sol;strong> template in order to determine the final intent that will be executed when the item is clicked&period;<&sol;p>&NewLine;<pre>public class ListWidgetService extends RemoteViewsService &lbrace;&NewLine;&NewLine; &commat;Override&NewLine; public RemoteViewsFactory onGetViewFactory&lpar;Intent intent&rpar; &lbrace;&NewLine; return new StackRemoteViewsFactory&lpar;getApplicationContext&lpar;&rpar;&comma;intent&rpar;&semi;&NewLine; &rcub;&NewLine;&NewLine; class StackRemoteViewsFactory implements RemoteViewsFactory&lbrace;&NewLine;&NewLine; private static final int mCount &equals; 10&semi;&NewLine; private List&lt&semi;WidgetItem&gt&semi; mWidgetItems &equals; new ArrayList&lt&semi;WidgetItem&gt&semi;&lpar;&rpar;&semi;&NewLine; private Context mContext&semi;&NewLine; private int mAppWidgetId&semi;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Given the position &lpar;index&rpar; of a WidgetItem in the array&comma; use the item's text value in&NewLine; &sol;&sol; combination with the app widget item XML file to construct a RemoteViews object&period;<&sol;span><&sol;strong>&NewLine; &commat;Override&NewLine; public RemoteViews getViewAt&lpar;int position&rpar; &lbrace;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; position will always range from 0 to getCount&lpar;&rpar; - 1&period;&NewLine; &sol;&sol; construct a remote views item based on our widget item xml file&comma; and set the&NewLine; &sol;&sol; text based on the position&period;<&sol;span><&sol;strong>&NewLine; RemoteViews rv &equals; new RemoteViews&lpar;mContext&period;getPackageName&lpar;&rpar;&comma; R&period;layout&period;widget&lowbar;item&rpar;&semi;&NewLine; rv&period;setTextViewText&lpar;R&period;id&period;widget&lowbar;item&comma; mWidgetItems&period;get&lpar;position&rpar;&period;text&rpar;&semi;&NewLine;&NewLine; <strong><span style&equals;"color&colon; &num;008000&semi;">&sol;&sol; Next&comma; we set a fill-intent which will be used to fill-in the pending intent template&NewLine; &sol;&sol; which is set on the collection view in StackWidgetProvider&period;<&sol;span><&sol;strong>&NewLine; Bundle extras &equals; new Bundle&lpar;&rpar;&semi;&NewLine; extras&period;putInt&lpar;StackWidgetProvider&period;EXTRA&lowbar;ITEM&comma; position&rpar;&semi;&NewLine; Intent fillInIntent &equals; new Intent&lpar;&rpar;&semi;&NewLine; fillInIntent&period;putExtras&lpar;extras&rpar;&semi;&NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong> &sol;&sol; Make it possible to distinguish the individual on-click&NewLine; &sol;&sol; action of a given item<&sol;strong><&sol;span>&NewLine; rv&period;setOnClickFillInIntent&lpar;R&period;id&period;widget&lowbar;item&comma; fillInIntent&rpar;&semi;&NewLine; &NewLine; <span style&equals;"color&colon; &num;008000&semi;"><strong>&sol;&sol; Return the remote views object&period;<&sol;strong><&sol;span>&NewLine; return rv&semi;&NewLine; &rcub;&NewLine;&rcub;<&sol;pre>&NewLine;<p>When you run the <span style&equals;"color&colon; &num;008000&semi;"><strong>AppwidgetCollectionDemo<&sol;strong><&sol;span> application it will look something like this&colon;<&sol;p>&NewLine;<p><img class&equals;"alignnone wp-image-1523" src&equals;"https&colon;&sol;&sol;c1ctech&period;com&sol;wp-content&sol;uploads&sol;2020&sol;02&sol;Screenshot&lowbar;1580828302&period;png" alt&equals;"Screenshot&lowbar;1580828302" width&equals;"346" height&equals;"615" &sol;><&sol;p>&NewLine;<p>I hope this article will help you in understanding how to work with collection widgets&period;&NewLine;

Exit mobile version