What is a AppWidget

An AppWidget is a small application that can be displayed directly on the Android desktop.

The yellow arrows in the figure indicate appWidgets. Some applications that users use frequently can be made into AppWidgets for easy use. Typical programs are clocks, weather, music players, etc. AppWidget is a part of Android application development. It has a special purpose and can be used properly to make an app better. It works by embedding widgets from one process into another process’s window. To add the AppWidget to the desktop, hold down and drag out the corresponding AppWidget.

How do I develop an AppWidget

Appwidgets are controlled by BroadCastReceiver. The main class used to develop AppWidgets is AppWidgetProvider, which is derived from BroadCastReceiver. To implement desktop widgets, developers simply subclass AppWidgetProvider and override its onUpdate() method. Generally speaking, the method can be overridden by the following steps:

1. Create a RemoteViews object that, when loaded, specifies the desktop widget’s interface layout file.

2. Set the attributes of each element in the layout file loaded when RemoteViews was created.

3. Create a ComponentName object

4. Call AppWidgetManager to update the desktop widget.

Let’s take a look at an example in action, using an example generated automatically by Android Studio.

Create a new HelloWorld project, create a new AppWidget, name it MyAppWidgetProvider, and follow the default next step to complete the development of the simplest AppWidget. After you run the program, add the widget to the desktop. The operation procedure and default effects are as follows:

What code does AS automatically generate for us? Let’s look at the steps mentioned above.

First, there is a class called MyAppWidgetProvider.

package com.example.joy.remoteviewstest; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.widget.RemoteViews; /** * Implementation of App Widget functionality. */ public class MyAppWidgetProvider extends AppWidgetProvider { static  void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { CharSequence widgetText = context.getString(R.string.appwidget_text);     // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider); views.setTextViewText(R.id.appwidget_text, widgetText); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of themfor (int appWidgetId : appWidgetIds) {
  updateAppWidget(context, appWidgetManager, appWidgetId);
 }
 }
 
 @Override
 public void onEnabled(Context context) {
 // Enter relevant functionality for when the first widget is created
 }
 
 @Override
 public void onDisabled(Context context) {
 // Enter relevant functionality for when the last widget is disabled
 }
}
Copy the code

This class inherits from AppWidgetProvider. By default, AS overrides the onUpdate() method, traverses appWidgetIds, and calls the updateAppWidget() method. Now look at the updateAppWidget() method, which is simple, just four lines:

First line, CharSequence widgetText = Context.getString (r.string.appWidget_text); Declares a string;

RemoteViews = new RemoteViews(context.getPackagename (), r.layout.my_app_widget_provider);

Create a RemoteViews object with the first parameter passing the application package name and the second parameter specifying the layout file that RemoteViews loaded. This line corresponds to point 1 in the previous step. My_app_widget_provider. XML is automatically generated by AS in the res/layout/ directory.

`<``RelativeLayout` `xmlns:android``=``"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"`

`android:layout_width``=``"match_parent"`

`android:layout_height``=``"match_parent"`

`android:background``=``"#09C"`

`android:padding``=``"@dimen/widget_margin"``>`

`<``TextView`

`android:id``=``"@+id/appwidget_text"`

`android:layout_width``=``"wrap_content"`

`android:layout_height``=``"wrap_content"`

`android:layout_centerHorizontal``=``"true"`

`android:layout_centerVertical``=``"true"`

`android:layout_margin``=``"8dp"`

`android:background``=``"#09C"`

`android:contentDescription``=``"@string/appwidget_text"`

`android:text``=``"@string/appwidget_text"`

`android:textColor``=``"#ffffff"`

`android:textStyle``=``"bold|italic"` `/>`

`</``RelativeLayout``>`
Copy the code

This file is what the desktop widget looks like at last, with a single TextView in the layout file. This is where you might ask, can I add pictures? Yes, just add ImageView to your normal Activity layout. You might be smart enough to start thinking about customizing your widget style by adding powerful, beautiful, and high-looking custom controls. Unfortunately, you can’t. The widgets layout file is limited in the number of components that can be added to it; more on that later in RemoteViews.

Views.settextviewtext (r.id.appwidget_text, widgetText);

Assign the string declared in the first line to the TextView in the layout file above. Note that when assigning, specify the ID of the TextView. This line matches the second point in the previous step.

In the fourth row, appWidgetManager. UpdateAppWidget (appWidgetId, views).

Here called the appWidgetManager. UpdateAppWidget () method, update the widget. This line corresponds to step 4 above.

Create a ComponentName object (ComponentName, ComponentName, ComponentName) And indeed, it’s not used in this example either. If we hand on the fourth step code, AS smart tips will tell you that appWidgetManager. UpdateAppWidget () has three overloaded methods. The three methods are not written together in the source code. For convenience, HERE I copy and post the introduction from the official API

void	
  updateAppWidget(ComponentName provider, RemoteViews views)

Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
Copy the code
 void	
 updateAppWidget(int[] appWidgetIds, RemoteViews views)

Set the RemoteViews to use for the specified appWidgetIds.
Copy the code
void	
updateAppWidget(int appWidgetId, RemoteViews views)

Set the RemoteViews to use for the specified appWidgetId.
Copy the code

Each of these three methods takes two arguments, the second of which is a RemoteViews object. The first method takes a ComponentName object and updates all AppWidget instances provided by the AppWidgetProvider, the second method updates the AppWidget object set with the specified Id, and the third method, Updates an AppWidget object with an explicitly specified Id. So we generally use the first method, which can be updated selectively for all AppWidget objects as needed.

At this point, all the steps are done, right? Not yet. As mentioned earlier, the custom MyAppWidgetProvider extends from AppWidgetProvider, which in turn extends from BroadCastReceiver.

So MyAppWidgetProvider is essentially a broadcast receiver, one of the four components that needs to be registered in our manifest file. If you open the Androidmanifest.xml file, you can see that the widget is indeed registered as follows:

<receiver android:name=".MyAppWidgetProvider"> &emsp; &emsp; <intent-filter> &emsp; &emsp; &emsp; &emsp; <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
 
<meta-data
 android:name="android.appwidget.provider"
 android:resource="@xml/my_app_widget_provider_info" />
</receiver>
Copy the code

There is an Action in the code above that must be added and cannot be changed. This Action belongs to the system specification and exists as the identity of the widget. If not, the Receiver will not appear in the widget list. Then you see that the widget specifies @xml/ my_app_widget_PROVIDer_info as meta-data, and you notice that an XML folder has been created under the res/ directory, Create a new my_app_widget_PROVIDer_info.xml file with the following contents:

` <? ``xml` `version``=``"1.0"` `encoding``=``"utf-8"` `? >` `<``appwidget-provider` `xmlns:android``=``"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"`

`android:initialKeyguardLayout``=``"@layout/my_app_widget_provider"`

`android:initialLayout``=``"@layout/my_app_widget_provider"`

`android:minHeight``=``"40dp"`

`android:minWidth``=``"40dp"`

`android:previewImage``=``"@drawable/example_appwidget_preview"`

`android:resizeMode``=``"horizontal|vertical"`

`android:updatePeriodMillis``=``"86400000"`

`android:widgetCategory``=``"home_screen"``>`

`</``appwidget-provider``>`

Copy the code

Some basic widget information is configured here. Common attributes are initialLayout, which is the initialLayout of the widget, minHeight, which defines the minimum height of the widget, and previewImage, which specifies the previewImage of the widget in the widget list. UpdatePeriodMillis specifies the widget update period in milliseconds. For more properties, see the API documentation.

At this point, the very simple widget development process above is really over. To develop more powerful widgets, we need to learn more about RemoteViews and AppWidgetProvider.

AppWidget makeup – RemoteViews

Here are a few classes related to RemoteViews.

1.1 RemoteViews

RemoteViews, literally, is a remote view. Is a remote View that is displayed in another process but can be updated in another process. RemoteViews is used in Android in the following scenarios: custom notification bars and desktop widgets.

In the RemoteViews constructor, the second argument receives a layout file to determine the RemoteViews view; We then call the Set method in RemoteViews to set each component of a Layout, for example, setTextViewText() to set the text of the TextView component.

As mentioned earlier, the widget layout file is limited in the number of components it can add. It supports four View types: FrameLayout, LinearLayout, RelativeLayout, GridLayout, and 13 Views: AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView, Adapte RViewFlipper, ViewSub. Note that RemoteViews does not support subclasses of View.

RemoteViews provides a series of setXXX() methods to set properties for the widget’s child views. Refer to the API documentation for details.

1.2 RemoteViewsService

RemoteViewsService is the service that manages RemoteViews. In general, RemoteViewsService is used to update and manage appWidgets when they contain GridView, ListView, StackView, etc. The general steps for RemoteViewsService to update the collection view are:

Set RemoteViews to RemoteViewsService using setRemoteAdapter().

(02) Implement the RemoteViewsFactory interface in RemoteViewsService. Then set the individual children of the collection view, such as each Item in the ListView, in the RemoteViewsFactory interface.

1.3 RemoteViewsFactory

RemoteViewsService (RemoteViewsService, RemoteViewsFactory, etc.) RemoteViewsFactory is an internal interface within RemoteViewsService. RemoteViewsFactory provides a set of methods to manage each item in a collection view. Such as:

RemoteViews getViewAt(int position)

GetViewAt () to get the view of the position item in the Collection View, which is returned as an object of RemoteViews.

int getCount()

Get the total number of all subitems in the Collection view by getCount().

AppWidget beauty — AppWidgetProvider

In addition to the clothes and makeup she wears, I think the main reason why we call a female colleague beautiful is that she is beautiful herself. Similarly, the widget’s ability to stick to the desktop and update views across processes is largely due to the fact that AppWidgetProvider is a broadcast receiver.

OnEnable () and onDisable() are both null implementations. When will these two methods be called? MyAppWidgetProvider is a subclass of BroadCastReceiver. And we didn’t override the onReceiver() method as we would a regular broadcast receiver? Follow the AppWidgetProvider source code to find out.

This class doesn’t have much code. In fact, AppWidgetProvider only has the following methods outside of the constructor:

OnEnable () : Calls back to this method when the widget is first added to the desktop, which can be added multiple times, but only the first time. The Action for pair broadcast is ACTION_APPWIDGET_ENABLE.

OnUpdate (): This method is called once when the widget is added or every time the widget is updated. UpdatePeriodMillis, the widget’s update period configured in the configuration file, is called every update. The corresponding broadcast actions are ACTION_APPWIDGET_UPDATE and ACTION_APPWIDGET_RESTORED.

OnDisabled (): called when the last widget of this type is removed from the desktop, and the corresponding broadcast Action is ACTION_APPWIDGET_DISABLED.

OnDeleted (): called every time a widget is deleted. The corresponding broadcast Action is ACTION_APPWIDGET_DELETED.

OnRestored (): used only infrequently when a widget is restored from a backup or Settings. The corresponding broadcast Action was ACTION_APPWIDGET_RESTORED.

OnAppWidgetOptionsChanged () : called when the widget layout changes. The broadcast Action is ACTION_APPWIDGET_OPTIONS_CHANGED.

Finally, there is the onReceive() method, which AppWidgetProvider overrides to distribute specific times to the above method. Look at the source code:

public void onReceive(Context context, Intent intent) {
 // Protect against rogue update broadcasts (not really a security issue,
 // just filter bad broacasts out so subclasses are less likely to crash).
 String action = intent.getAction();
 if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
  Bundle extras = intent.getExtras();
  if(extras ! = null) { int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);if(appWidgetIds ! = null && appWidgetIds.length > 0) { this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds); }}}else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
  Bundle extras = intent.getExtras();
  if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
  final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
  this.onDeleted(context, new int[] { appWidgetId });
  }
 } else if (AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) {
  Bundle extras = intent.getExtras();
  if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)
   && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) {
  int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
  Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
  this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context),
   appWidgetId, widgetExtras);
  }
 } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
  this.onEnabled(context);
 } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
  this.onDisabled(context);
 } else if (AppWidgetManager.ACTION_APPWIDGET_RESTORED.equals(action)) {
  Bundle extras = intent.getExtras();
  if(extras ! = null) { int[] oldIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS); int[] newIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);if(oldIds ! = null && oldIds.length > 0) { this.onRestored(context, oldIds, newIds); this.onUpdate(context, AppWidgetManager.getInstance(context), newIds); }}}}Copy the code

AppWidget practice

Here’s another example to learn more about RemoteViews. This example uses button and ListView for widget layout. The code:

The layout file for the widget, mul_app_widget_provider.xml, is as follows:

` <? ``xml` `version``=``"1.0"` `encoding``=``"utf-8"` `? >` `<``LinearLayout` `xmlns:android``=``"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"`

`android:orientation``=``"horizontal"`

`android:layout_width``=``"match_parent"`

`android:layout_height``=``"match_parent"``>`

`<``LinearLayout`

`android:layout_width``=``"100dp"`

`android:layout_height``=``"200dp"`

`android:orientation``=``"vertical"``>`

`<``ImageView`

`android:id``=``"@+id/iv_test"`

`android:layout_width``=``"match_parent"`

`android:layout_height``=``"100dp"`

`android:src``=``"@mipmap/ic_launcher"``/>`

`<``Button`

`android:id``=``"@+id/btn_test"`

`android:layout_width``=``"match_parent"`

`android:layout_height``=``"wrap_content"`

`android:text``=``"Click to jump"``/>`

`</``LinearLayout``>`

`<``TextView`

`android:layout_width``=``"1dp"`

`android:layout_height``=``"200dp"`

`android:layout_marginLeft``=``"5dp"`

`android:layout_marginRight``=``"5dp"`

`android:background``=``"#f00"``/>`

`<``ListView`

`android:id``=``"@+id/lv_test"`

`android:layout_width``=``"100dp"`

`android:layout_height``=``"200dp"``>`

`</``ListView``>`

`</``LinearLayout``>`
Copy the code

The configuration information for the widget, mul_app_widget_PROVIDer_info.xml, is as follows:

` <? ``xml` `version``=``"1.0"` `encoding``=``"utf-8"` `? >` `<``appwidget-provider` `xmlns:android``=``"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"`

`android:initialLayout``=``"@layout/mul_app_widget_provider"`

`android:minHeight``=``"200dp"`

`android:minWidth``=``"200dp"`

`android:previewImage``=``"@mipmap/a1"`

`android:updatePeriodMillis``=``"86400000"``>`

`</``appwidget-provider``>`
Copy the code

MulAppWidgetProvider. Java:

package com.example.joy.remoteviewstest;
 
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.RemoteViews;
import android.widget.Toast;
 
public class MulAppWidgetProvider extends AppWidgetProvider {
 
 public static final String CHANGE_IMAGE = "com.example.joy.action.CHANGE_IMAGE";
 
 private RemoteViews mRemoteViews;
 private ComponentName mComponentName;
 
 private int[] imgs = new int[]{
  R.mipmap.a1,
  R.mipmap.b2,
  R.mipmap.c3,
  R.mipmap.d4,
  R.mipmap.e5,
  R.mipmap.f6
 };
 
 
 @Override
 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
 mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.mul_app_widget_provider);
 mRemoteViews.setImageViewResource(R.id.iv_test, R.mipmap.ic_launcher);
 mRemoteViews.setTextViewText(R.id.btn_test, "Click to jump to Activity"); Intent skipIntent = new Intent(context, MainActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 200, skipIntent, PendingIntent.FLAG_CANCEL_CURRENT); mRemoteViews.setOnClickPendingIntent(R.id.btn_test, pi); // Set the Adapter of the ListView. // (01) Intents: intents that initiate ListViewService(RemoteViewsService)setRemoteAdapter: Sets the ListView adapter // throughsetRemoteAdapter associates ListView with ListViewService, Intent lvIntent = new Intent(context, listViewService.class); mRemoteViews.setRemoteAdapter(R.id.lv_test, lvIntent); mRemoteViews.setEmptyView(R.id.lv_test,android.R.id.empty); // Set the intent template that responds to the ListView // note: "Collection controls (such as GridView, ListView, StackView, etc.)" contain many child elements, such as GridView contains many cells. // They don't pass like normal buttonssetOnClickPendingIntent Sets the click event in two steps. / / (01)setPendingIntentTemplate sets the "Intent template", which is more than necessary! // (02) is then passed in the getViewAt() interface of the RemoteViewsFactory class that handles the "collection control"setOnClickFillInIntent sets "Data for an item of the collection control" /* *setPendingIntentTemplate Sets the pendingIntent template *setPendingIntent toIntent = new Intent(CHANGE_IMAGE); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 200, toIntent, PendingIntent.FLAG_UPDATE_CURRENT); mRemoteViews.setPendingIntentTemplate(R.id.lv_test, pendingIntent); mComponentName = new ComponentName(context, MulAppWidgetProvider.class); appWidgetManager.updateAppWidget(mComponentName, mRemoteViews); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent);if(TextUtils.equals(CHANGE_IMAGE,intent.getAction())){ Bundle extras = intent.getExtras(); int position = extras.getInt(ListViewService.INITENT_DATA); mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.mul_app_widget_provider); mRemoteViews.setImageViewResource(R.id.iv_test, imgs[position]); mComponentName = new ComponentName(context, MulAppWidgetProvider.class); AppWidgetManager.getInstance(context).updateAppWidget(mComponentName, mRemoteViews); }}}Copy the code

MainActivity. Java:

ge com.example.joy.remoteviewstest;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main); }}Copy the code

The following focuses on the use of ListView in widgets:

 com.example.joy.remoteviewstest;
 
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
 
import java.util.ArrayList;
import java.util.List;
 
public class ListViewService extends RemoteViewsService {
 public static final String INITENT_DATA = "extra_data";
 
 @Override
 public RemoteViewsFactory onGetViewFactory(Intent intent) {
 return new ListRemoteViewsFactory(this.getApplicationContext(), intent);
 }
 
 private class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
 
 private Context mContext;
 
 private List<String> mList = new ArrayList<>();
 
 public ListRemoteViewsFactory(Context context, Intent intent) {
  mContext = context;
 }
 
 @Override
 public void onCreate() {
  mList.add("一");
  mList.add("二");
  mList.add("Three");
  mList.add("Four");
  mList.add("Five");
  mList.add("Six");
 }
 
 @Override
 public void onDataSetChanged() {
 
 }
 
 @Override
 public void onDestroy() {
  mList.clear();
 }
 
 @Override
 public int getCount() {
  return mList.size();
 }
 
 @Override
 public RemoteViews getViewAt(int position) {
  RemoteViews views = new RemoteViews(mContext.getPackageName(), android.R.layout.simple_list_item_1);
  views.setTextViewText(android.R.id.text1, "item:"+ mList.get(position)); Bundle extras = new Bundle(); extras.putInt(ListViewService.INITENT_DATA, position); Intent changeIntent = new Intent(); changeIntent.setAction(MulAppWidgetProvider.CHANGE_IMAGE); changeIntent.putExtras(extras); /* android.r.layout. simple_list_item_1 -- id -- text1 * listView item click: Send a changeIntent, * changeIntent, which by default has an action used by the providersetPendingIntentTemplate set action * / views. SetOnClickFillInIntent (android, R.i which the ext, changeIntent);returnviews; } /* The update screen will show loading if it takes time. If null is returned, the default interface is displayed. If not, a custom interface is loaded. RemoteViews is returnedgetLoadingView() {
  return null;
 }
 
 @Override
 public int getViewTypeCount() {
  return 1;
 }
 
 @Override
 public long getItemId(int position) {
  return position;
 }
 
 @Override
 public boolean hasStableIds() {
  return false; }}}Copy the code

Finally, look at the manifest file:

` <? ``xml` `version``=``"1.0"` `encoding``=``"utf-8"` `? >` `<``manifest` `xmlns:android``=``"[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"`

`package``=``"com.example.joy.remoteviewstest"``>`

`<``application`

`android:allowBackup``=``"true"`

`android:icon``=``"@mipmap/ic_launcher"`

`android:label``=``"@string/app_name"`

`android:supportsRtl``=``"true"`

`android:theme``=``"@style/AppTheme"``>`

`<``activity` `android:name``=``".MainActivity"``>`

`<``intent-filter``>`

`<``action` `android:name``=``"android.intent.action.MAIN"` `/>`

`<``category` `android:name``=``"android.intent.category.LAUNCHER"` `/>`

`</``intent-filter``>`

`</``activity``>`

`<``receiver` `android:name``=``".MulAppWidgetProvider"`

`android:label``=``"@string/app_name"``>`

`<``intent-filter``>`

`<``action` `android:name``=``"com.example.joy.action.CHANGE_IMAGE"``/>`

`<``action` `android:name``=``"android.appwidget.action.APPWIDGET_UPDATE"``/>`

`</``intent-filter``>`

`<``meta-data`

`android:name``=``"android.appwidget.provider"`

`android:resource``=``"@xml/mul_app_widget_provider_info"``>`

`</``meta-data``>`

`</``receiver``>`

`<``service` `android:name``=``".ListViewService"`

`android:permission``=``"android.permission.BIND_REMOTEVIEWS"`

`android:exported``=``"false"`

`android:enabled``=``"true"``/>`

`</``application``>`

`</``manifest``>`
Copy the code

When the widget is added to the desktop, an ImageView shows the little robot, with a Button below and a ListView to the right.

Here’s a look at how Button and ListView are used in RemoteViews. ,

Button setting Text is the same as TextView, because the Button itself inherits from TextView. Button setting click events are as follows:

Intent skipIntent = new Intent(context, MainActivity.class);
 PendingIntent pi = PendingIntent.getActivity(context, 200, skipIntent, PendingIntent.FLAG_CANCEL_CURRENT);
 mRemoteViews.setOnClickPendingIntent(R.id.btn_test, pi);
Copy the code

Use the setOnClickPendingIntent method, which represents a delayed Intent, as used in notifications. Click here to jump to MainActivity.

The ListView usage is a little more complicated. You first need to define a class inherits from RemoteViewsServices, pay equal attention to write onGetViewFactory method, returns RemoteViewsService. RemoteViewsFactory interface object. An internal class is defined to implement this interface, requiring multiple methods to be overridden, much like ListView’s multi-layout adaptation. The key approach is

1 public RemoteViews getViewAt(int position){} public RemoteViews getViewAt(int position){} Set the click event to the item with either setOnClickFillInIntent() or setOnClickPendingIntent(). So what I’m doing here is I’m clicking on item and replacing the image in the ImageView on the left. Rewrote the onReceiver method of the MulAppWidgetProvider class to handle the logic of replacing images.

The running effect of the program is shown as follows: