📜 ⬆️ ⬇️

Hello World widget for Android

Oddly enough, but in Russian there are almost no normal articles on widgets for Android. And there are almost no simple examples for starting in English-speaking resources, all the examples are for some reason complex and difficult to understand. I hasten to fix it.

The structure of the project and how to create it will not describe. It is assumed that you already know how to do it, but for those who do not know how, I advise you to read this article . For the widget we need to create 3 files:
  1. Widget provider info
  2. Widget provider
  3. Layout

Widget provider info - This is an xml file that describes the widget metadata. These include the size of the widget, its refresh rate, the template file, and the configuration class. This is how our file will look like (res / xml / hello_widget_provider.xml):
  1. <? xml version = "1.0" encoding = "utf-8" ?>
  2. <appwidget-provider xmlns: android = "schemas.android.com/apk/res/android"
  3. android: minWidth = "146dip"
  4. android: minHeight = "72dip"
  5. android: updatePeriodMillis = "86400000"
  6. android: initialLayout = "@ layout / main" />

The size of the widget can be any, but Google recommends sticking to the formula for calculating the size of the widget (number of cells * 74) - 2 . updatePeriodMillis is the update frequency of the widget, but no more than once every 30 minutes, in order to save battery. initialLayout is a widget template file.

Widget provider - This is a java file, it must be inherited from the AppWidgetProvider class. In our case, it will remain empty for now (src / ru / example / android / widget / HelloWidget.java).
  1. package ru.example.android.widget ;
  2. import android.appwidget.AppWidgetProvider ;
  3. public class HelloWidget extends AppWidgetProvider {
  4. }


Layout - This is a widget template or a View layer, as you like. It will look like this: (res / layout /main.xml).
  1. <? xml version = "1.0" encoding = "utf-8" ?>
  2. <LinearLayout xmlns: android = " schemas.android.com/apk/res/android"
  3. android: layout_width = "fill_parent"
  4. android: orientation = "vertical"
  5. android: background = "@android: color / white"
  6. android: layout_gravity = "center"
  7. android: layout_height = "wrap_content" >
  8. <TextView android: id = "@ + id / widget_textview"
  9. android: text = "Hello Widget"
  10. android: layout_height = "wrap_content"
  11. android: layout_width = "wrap_content"
  12. android: layout_gravity = "center_horizontal | center"
  13. android: textColor = "@android: color / black" />
  14. </ LinearLayout >

')
We did everything the main thing, it remains to register the widget in AndroidManifest.xml To do this, add the following code to the <application> ... </ application> section:
  1. <receiver android: name = ".widget.HelloWidget" android: label = "@ string / app_name" >
  2. <intent-filter >
  3. <action android: name = "android.appwidget.action.APPWIDGET_UPDATE" />
  4. </ intent-filter >
  5. <meta-data android: name = "android.appwidget.provider"
  6. android: resource = "@ xml / hello_widget_provider" />
  7. </ receiver >


Now we can compile the project and watch the result in the emulator!


Our widget, although it works, is absolutely useless. Let's make it react to a button click.

In the widget it is impossible to hang up a full event at the press of a button or even for any event, as you used to do in Activity. In this example, you will see how you can handle the event by pressing a button. Let's first add a button to our template (res / layout /main.xml).
  1. <? xml version = "1.0" encoding = "utf-8" ?>
  2. <LinearLayout xmlns: android = " schemas.android.com/apk/res/android"
  3. android: layout_width = "fill_parent"
  4. android: orientation = "vertical"
  5. android: background = "@android: color / white"
  6. android: layout_gravity = "center"
  7. android: layout_height = "wrap_content" >
  8. <TextView android: id = "@ + id / widget_textview"
  9. android: text = "Hello Widget"
  10. android: layout_height = "wrap_content"
  11. android: layout_width = "wrap_content"
  12. android: layout_gravity = "center_horizontal | center"
  13. android: textColor = "@android: color / black" />
  14. <Button android: id = "@ + id / widget_button"
  15. android: text = "click me"
  16. android: layout_height = "wrap_content"
  17. android: layout_width = "wrap_content" />
  18. </ LinearLayout >


All interactions with the widget will be done in the provider class (src / ru / example / android / widget / HelloWidget.java). Here is what the simplest event handling will look like:
  1. public class HelloWidget extends AppWidgetProvider {
  2. public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget" ;
  3. @ Override
  4. public void onUpdate ( Context context, AppWidgetManager appWidgetManager, int [ ] appWidgetIds ) {
  5. // Create a new RemoteViews
  6. RemoteViews remoteViews = new RemoteViews ( context. GetPackageName ( ) , R. layout . Main ) ;
  7. // Prepare Intent for Broadcast
  8. Intent active = new Intent ( context, HelloWidget. Class ) ;
  9. active. setAction ( ACTION_WIDGET_RECEIVER ) ;
  10. active. putExtra ( "msg" , "Hello Habrahabr" ) ;
  11. // create our event
  12. PendingIntent actionPendingIntent = PendingIntent. getBroadcast ( context, 0 , active, 0 ) ;
  13. // register our event
  14. remoteViews. setOnClickPendingIntent ( R. id . widget_button , actionPendingIntent ) ;
  15. // update widget
  16. appWidgetManager. updateAppWidget ( appWidgetIds, remoteViews ) ;
  17. }
  18. @ Override
  19. public void onReceive ( Context context, Intent intent ) {
  20. // We catch our Broadcast, check and display the message
  21. final String action = intent. getAction ( ) ;
  22. if ( ACTION_WIDGET_RECEIVER. equals ( action ) ) {
  23. String msg = "null" ;
  24. try {
  25. msg = intent. getStringExtra ( "msg" ) ;
  26. } catch ( NullPointerException e ) {
  27. Log e ( "Error" , "msg = null" ) ;
  28. }
  29. Toast. makeText ( context, msg, Toast. LENGTH_SHORT ) . show ( ) ;
  30. }
  31. super . onReceive ( context, intent ) ;
  32. }
  33. }

There are 2 methods in the class - onUpdate and onReceive. The onUpdate method is called when the widget is updated. We set the refresh rate in the res / xml / hello_widget_provider.xml file with the android updatePeriodMillis attribute = "86400000". The onReceive method inherits from the class BroadcastReceiver.
In the widget, you cannot update a single item, for example text, as in Activity. The entire views hierarchy is always updated. To update the widget, we need the RemoteViews class, with which we will change the entire hierarchy of Views. Unfortunately, the possibilities of this class are scarce. It allows us to change the text, pictures and hang the event on click. An event in a widget can be called a stretch event; api allows you to perform only 3 actions:In our case, we will be sending a Broadcast. The result will be something like normal event handling. Using the PendingIntent class, we create our event and register it in RemoteViews. Then update the widget. And in the onReceive method, we catch our “event” and process it, displaying a message using the Toast class.

We add changes to the AndroidManifest.xml file:
  1. <receiver android: name = ".widget.HelloWidget" android: label = "@ string / app_name" >
  2. <intent-filter >
  3. <action android: name = "android.appwidget.action.APPWIDGET_UPDATE" />
  4. <action android: name = "ru.example.android.widget.ACTION_WIDGET_RECEIVER" />
  5. </ intent-filter >
  6. <meta-data android: name = "android.appwidget.provider"
  7. android: resource = "@ xml / hello_widget_provider" />
  8. </ receiver >


We compile, and enjoy the result.


Related Links:


PS I tried to describe everything as simple as possible, so as not to clog my head, but to get a working example. In the following articles I will delve into the topic.

Source: https://habr.com/ru/post/114515/


All Articles