What are you going to achieve in this widget tutorial?

You will make a counter application that will count the number of clicks. You will set up a basic application that shows the number of clicks in an activity and the clicks will keep on increasing whenever you tap on the application’s widget. In this process you will learn how to create a basic widget, how to communicate data with the widget and how to handle widget resizing.

You can find the complete code for tis tutorial on this GitHub repo.

Layout Setup

Basic Layout Setup

First of all we will set up our main activity and its layout. This activity will have nothing to do with the widget at all.

activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Clicks" android:textSize="24dp" /> <TextView android:id="@+id/clicksTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="40dp" android:textStyle="bold" /> </LinearLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : app = "http://schemas.android.com/apk/res-auto" xmlns : tools = "http://schemas.android.com/tools" android : layout_width = "match_parent" android : layout_height = "match_parent" android : gravity = "center" android : orientation = "vertical" tools : context = ".MainActivity" > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "Clicks" android : textSize = "24dp" / > < TextView android : id = "@+id/clicksTextView" android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "0" android : textSize = "40dp" android : textStyle = "bold" / > < / LinearLayout >

As you can see you have a basic layout with 2 TextView’s.

Here is the code for MainActivity.

MainActivity.java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); int clicks = getSharedPreferences("sp", MODE_PRIVATE).getInt("clicks", 0); ((TextView) findViewById(R.id.clicksTextView)).setText(String.valueOf(clicks)); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class MainActivity extends AppCompatActivity { @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; } @ Override protected void onResume ( ) { super . onResume ( ) ; int clicks = getSharedPreferences ( "sp" , MODE_PRIVATE ) . getInt ( "clicks" , 0 ) ; ( ( TextView ) findViewById ( R . id . clicksTextView ) ) . setText ( String . valueOf ( clicks ) ) ; } }

In this you will extract the number of clicks which will be stored in SharedPreferences.

Widget Layout

Now you will set up layout for the widget you want to create. Thanks to Android Studio, it does this for you automatically.

Right click on res -> New -> Widget -> App Widget.

Once you click on it, a window will open. Provide a name for your widget (We give it MyAppWidget).

Now Android Studio will create 3 files for you.

MyAppWidget.java – The java file that contains the implementation of AppWidget, any widget logic will go here.

my_app_widget.xml – A regular layout xml file (but with limited functionality) for your widget.

my_app_widget_info.xml – This is an xml file that contains various properties for your widget such as refresh time, preview image, minimum height and widget.

public class MyAppWidget 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.custom_widget); 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 them for (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 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MyAppWidget 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 . custom_widget ) ; 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 them for ( 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 } }

This is the default code in MyAppWidget.java class. You will be provided with 3 functions by default. Go ahead and remove all the code from updateAppWidget function. Now you code will look something like this.

public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (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 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget ( Context context , AppWidgetManager appWidgetManager , int appWidgetId ) { } @ Override public void onUpdate ( Context context , AppWidgetManager appWidgetManager , int [ ] appWidgetIds ) { // There may be multiple widgets active, so update all of them for ( 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 } }

Here is the default code from my_app_widget.xml layout file.

my_app_widget.xml <RelativeLayout xmlns: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:textSize="24sp" android:textStyle="bold|italic" /> </RelativeLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 < RelativeLayout xmlns : 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 : textSize = "24sp" android : textStyle = "bold|italic" / > < / RelativeLayout >

Replace the original layout with the below layout (all we are doing is making the TextView simple).

my_app_widget.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/widget_margin"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="40sp" android:text="Nil" /> </RelativeLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 < RelativeLayout xmlns : android = "http://schemas.android.com/apk/res/android" android : layout_width = "match_parent" android : layout_height = "match_parent" android : padding = "@dimen/widget_margin" > < TextView android : id = "@+id/textView" android : layout_width = "match_parent" android : layout_height = "match_parent" android : textSize = "40sp" android : text = "Nil" / > < / RelativeLayout >

It will look something like this.

Now take a look at my_app_widget_info.xml.

my_app_widget_info.xml <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialKeyguardLayout="@layout/my_app_widget" android:initialLayout="@layout/my_app_widget" 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> 1 2 3 4 5 6 7 8 9 10 <? xml version = "1.0" encoding = "utf-8" ?> < appwidget - provider xmlns : android = "http://schemas.android.com/apk/res/android" android : initialKeyguardLayout = "@layout/my_app_widget" android : initialLayout = "@layout/my_app_widget" 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 >

Think of this file as a meta-data for your widget. Here are some of the properties explained.

minHeight & mingWidth – Minimum height and widget for your widget, when the user places your widget on the home screen it can’t be resized to dimensions smaller than this.

previewImage – This is the preview image seen by the user when browsing in the app drawer.

resizeMode – Whether the user can resize widget vertically and horizontally.

updatePeriodMillis – The time interval between widget is updated by calling the onUpdate function. This cannot be less than 30 mins, so lets make it 30 mins in our application.

Change the updatePeriodMillis to be 30 mins.

my_app_widget.xml <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialKeyguardLayout="@layout/my_app_widget" android:initialLayout="@layout/my_app_widget" android:minHeight="40dp" android:minWidth="40dp" android:previewImage="@drawable/ic_filter_1" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="1800000" android:widgetCategory="home_screen"> </appwidget-provider> 1 2 3 4 5 6 7 8 9 10 11 12 <? xml version = "1.0" encoding = "utf-8" ?> < appwidget - provider xmlns : android = "http://schemas.android.com/apk/res/android" android : initialKeyguardLayout = "@layout/my_app_widget" android : initialLayout = "@layout/my_app_widget" android : minHeight = "40dp" android : minWidth = "40dp" android : previewImage = "@drawable/ic_filter_1" android : resizeMode = "horizontal|vertical" android : updatePeriodMillis = "1800000" android : widgetCategory = "home_screen" > < / appwidget - provider >

Now if you look in your phone widget app drawer you will see this widget show up and you can place it anywhere you want. Right now when you tap on it, it doesn’t do anything.

Never miss a post from TheTechnoCafe

Adding Interaction

Now you will set up the widget to open up the MainActivity. It is not your general OnClickListener that will work here. Since the widget is not the part your actual app, per say, it takes a different set up for adding listeners.

First you will have to create something called a RemoteView which will give us access to add interaction to the widget. RemoteView is a special kind of view, its named appropriately. ‘Remote’ means something situated far from the main point, here it means some view situated away from the application. Since widget is independent from the ‘actual’ application it uses RemoteView.

public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { Intent intent = new Intent(context, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.custom_widget); remoteViews.setOnClickPendingIntent(R.id.textView, pendingIntent); appWidgetManager.updateAppWidget(appWidgetId, remoteViews); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (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 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget ( Context context , AppWidgetManager appWidgetManager , int appWidgetId ) { Intent intent = new Intent ( context , MainActivity . class ) ; PendingIntent pendingIntent = PendingIntent . getActivity ( context , 0 , intent , 0 ) ; RemoteViews remoteViews = new RemoteViews ( context . getPackageName ( ) , R . layout . custom_widget ) ; remoteViews . setOnClickPendingIntent ( R . id . textView , pendingIntent ) ; appWidgetManager . updateAppWidget ( appWidgetId , remoteViews ) ; } @ Override public void onUpdate ( Context context , AppWidgetManager appWidgetManager , int [ ] appWidgetIds ) { // There may be multiple widgets active, so update all of them for ( 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 } }

As stated above listener with RemoteView’s are not the same as normal View’s. First you create the Pending Intent to launch the Activity. Then create the a new RemoteView for the widget layout and using the setOnClickPendingIntent method on it register the intent for the TextView (so whenever the user clicks the TextView this Intent will be fired). Finally update the widget by calling updateAppWidget on AppWidgetManager. Now if you click on the widget MainActivity will launch.

Incrementing Count

You are not here to just launch an Activity. You are here to increment the counter!

Create an IntentService named ClickIntentService.

ClickIntentService.java public class ClickIntentService extends IntentService { public static final String ACTION_CLICK = "com.thetehnocafe.gurleensethi.widgets.click"; public ClickIntentService() { super("ClickIntentService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if (ACTION_CLICK.equals(action)) { handleClick(); } } } private void handleClick() { int clicks = getSharedPreferences("sp", MODE_PRIVATE).getInt("clicks", 0); clicks++; getSharedPreferences("sp", MODE_PRIVATE) .edit() .putInt("clicks", clicks) .commit(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class ClickIntentService extends IntentService { public static final String ACTION_CLICK = "com.thetehnocafe.gurleensethi.widgets.click" ; public ClickIntentService ( ) { super ( "ClickIntentService" ) ; } @ Override protected void onHandleIntent ( Intent intent ) { if ( intent != null ) { final String action = intent . getAction ( ) ; if ( ACTION_CLICK . equals ( action ) ) { handleClick ( ) ; } } } private void handleClick ( ) { int clicks = getSharedPreferences ( "sp" , MODE_PRIVATE ) . getInt ( "clicks" , 0 ) ; clicks ++ ; getSharedPreferences ( "sp" , MODE_PRIVATE ) . edit ( ) . putInt ( "clicks" , clicks ) . commit ( ) ; } }

What is happening in this Service is basically whenever it is started it increments the count in SharedPreference. Now let’s make the TextView start this service rather than MainActivity.

MyAppWidget.java public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget); Intent intent = new Intent(context, ClickIntentService.class); intent.setAction(ClickIntentService.ACTION_CLICK); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.textView, pendingIntent); int clicks = context.getSharedPreferences("sp", MODE_PRIVATE).getInt("clicks", 0); views.setTextViewText(R.id.textView, String.valueOf(clicks)); // 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 them for (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 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget ( Context context , AppWidgetManager appWidgetManager , int appWidgetId ) { // Construct the RemoteViews object RemoteViews views = new RemoteViews ( context . getPackageName ( ) , R . layout . my_app_widget ) ; Intent intent = new Intent ( context , ClickIntentService . class ) ; intent . setAction ( ClickIntentService . ACTION_CLICK ) ; PendingIntent pendingIntent = PendingIntent . getService ( context , 0 , intent , PendingIntent . FLAG_UPDATE_CURRENT ) ; views . setOnClickPendingIntent ( R . id . textView , pendingIntent ) ; int clicks = context . getSharedPreferences ( "sp" , MODE_PRIVATE ) . getInt ( "clicks" , 0 ) ; views . setTextViewText ( R . id . textView , String . valueOf ( clicks ) ) ; // 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 them for ( 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 } }

You changed the PendingIntent from getActivity to getService. You can also see the way to update text in RemoteView is different. If you run this app you will notice that the number of clicks increase but they don’t reflect immediately in the widget itself. You can verify this by opening the application and seeing the number of clicks.

Let’s fix this, every time you increment the counter in IntentService, you need to notify the widget to update the data as well.

ClickIntentService.java public class ClickIntentService extends IntentService { public static final String ACTION_CLICK = "com.thetehnocafe.gurleensethi.widgets.click"; public ClickIntentService() { super("ClickIntentService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if (ACTION_CLICK.equals(action)) { handleClick(); } } } private void handleClick() { int clicks = getSharedPreferences("sp", MODE_PRIVATE).getInt("clicks", 0); clicks++; getSharedPreferences("sp", MODE_PRIVATE) .edit() .putInt("clicks", clicks) .commit(); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); int[] widgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, MyAppWidget.class)); for (int appWidgetId : widgetIds) { MyAppWidget.updateAppWidget(getApplicationContext(), appWidgetManager, appWidgetId); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class ClickIntentService extends IntentService { public static final String ACTION_CLICK = "com.thetehnocafe.gurleensethi.widgets.click" ; public ClickIntentService ( ) { super ( "ClickIntentService" ) ; } @ Override protected void onHandleIntent ( Intent intent ) { if ( intent != null ) { final String action = intent . getAction ( ) ; if ( ACTION_CLICK . equals ( action ) ) { handleClick ( ) ; } } } private void handleClick ( ) { int clicks = getSharedPreferences ( "sp" , MODE_PRIVATE ) . getInt ( "clicks" , 0 ) ; clicks ++ ; getSharedPreferences ( "sp" , MODE_PRIVATE ) . edit ( ) . putInt ( "clicks" , clicks ) . commit ( ) ; AppWidgetManager appWidgetManager = AppWidgetManager . getInstance ( this ) ; int [ ] widgetIds = appWidgetManager . getAppWidgetIds ( new ComponentName ( this , MyAppWidget . class ) ) ; for ( int appWidgetId : widgetIds ) { MyAppWidget . updateAppWidget ( getApplicationContext ( ) , appWidgetManager , appWidgetId ) ; } } }

You will get the instance of AppWidgetManager, get all the widget id’s of MyAppWidget and call the updateAppWidget function on it.

Run the application and see the magic.

Handling Resizing

So the user can at anytime resize the widget and you want to adapt the layout according widget’s available width. Well this is not too hard to do, all you have to do is get the current width of the widget and take action accordingly. To get a demonstration you won’t be doing anything fancy. What you will do is whenever the width becomes less than 200, you will append an ‘s’ after the widget text and append an ‘L’ whenever it is larger than that width.

public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget); Intent intent = new Intent(context, ClickIntentService.class); intent.setAction(ClickIntentService.ACTION_CLICK); PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); views.setOnClickPendingIntent(R.id.textView, pendingIntent); int clicks = context.getSharedPreferences("sp", MODE_PRIVATE).getInt("clicks", 0); Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); int width = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH); String clicksStr; if (width < 200) { clicksStr = clicks + "s"; } else { clicksStr = clicks + "l"; } views.setTextViewText(R.id.textView, clicksStr); // 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 them for (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 } @Override public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); updateAppWidget(context, appWidgetManager, appWidgetId); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public class MyAppWidget extends AppWidgetProvider { static void updateAppWidget ( Context context , AppWidgetManager appWidgetManager , int appWidgetId ) { // Construct the RemoteViews object RemoteViews views = new RemoteViews ( context . getPackageName ( ) , R . layout . my_app_widget ) ; Intent intent = new Intent ( context , ClickIntentService . class ) ; intent . setAction ( ClickIntentService . ACTION_CLICK ) ; PendingIntent pendingIntent = PendingIntent . getService ( context , 0 , intent , PendingIntent . FLAG_UPDATE_CURRENT ) ; views . setOnClickPendingIntent ( R . id . textView , pendingIntent ) ; int clicks = context . getSharedPreferences ( "sp" , MODE_PRIVATE ) . getInt ( "clicks" , 0 ) ; Bundle options = appWidgetManager . getAppWidgetOptions ( appWidgetId ) ; int width = options . getInt ( AppWidgetManager . OPTION_APPWIDGET_MIN_WIDTH ) ; String clicksStr ; if ( width < 200 ) { clicksStr = clicks + "s" ; } else { clicksStr = clicks + "l" ; } views . setTextViewText ( R . id . textView , clicksStr ) ; // 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 them for ( 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 } @ Override public void onAppWidgetOptionsChanged ( Context context , AppWidgetManager appWidgetManager , int appWidgetId , Bundle newOptions ) { super . onAppWidgetOptionsChanged ( context , appWidgetManager , appWidgetId , newOptions ) ; updateAppWidget ( context , appWidgetManager , appWidgetId ) ; } }

You also have to override a function named onAppWidgetOptionsChanged which is called when the widget is resized.

You can find the complete code for tis tutorial on this GitHub repo.

How to make two pane layout in Android.

Guide to Notifications in Android.

Make a moving Gradient Background in Android.

Getting started with Retrofit in Android.