Lesson 117. Widgets. Creature. Lifecycle

Lesson 117. Widgets. Creature. Lifecycle


In this lesson:

– create a simple widget
– Understand his Lifecycle

They also got to this long-awaited topic. In general, it would be interesting to look at the statistics of how many of the existing applications include widgets. I suspect no more than one in ten. These statistics may change these statistics in the next few lessons)

To understand the theme of the widgets, it is advisable to know what BroadcastReceiver is. I mentioned it in Lessons 96 and 100. It’s just a listener who logs in, catches an Intent Filter message (Intent), and executes some code. For some reason, I didn’t do a separate lesson on it. But, I think, I’ll still do. There are some interesting features you can talk about.

I think there is no particular need to explain in detail what widgets are. All of them saw on their devices. This is a type of mini-application located on the desktop (Home). They allow you to view any information from the major applications, or to influence the behavior of those applications. An example is weather forecast, current time, balance of any account, message list in different messengers, control of the status of WiFi / 3G / GPS / Bluetooth, screen brightness, etc. etc. In this tutorial, we’ll make a simple widget that displays static text.

To create the simplest widget, we need three details:

1) Layout file.

In it we form the appearance of the widget. Everything is similar to layout files for Activity and snippets, only the set of available components is limited here by the following list:

FrameLayout
LinearLayout
RelativeLayout
GridLayout

AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper

2) Metadata XML file

It specifies the various characteristics of the widget. For now, we will specify the following options:

– layout file (according to claim 1) to let the widget know what it will look like
– Widget size to let the widget know how much space it needs to occupy on the screen
– Update interval to let the system know how often it will need to update the widget

3) The class that inherits AppWidgetProvider. In this class, we will need to implement Lifecycle widget methods.

Let’s create three of these details. We will not need Activity, so be sure to remove the Create Activity check mark in the Wizard of creating a new project

Let’s create a project without Activity:

Project name: P1171_SimpleWidget
Build Target: Android 2.3.3
Application name: SimpleWidget
Package name: ru.startandroid.develop.p1171simplewidget

Add rows to strings.xml:

My first widget
Text in widget

We create a layout file widget.xml:



	
	

RelativeLayout, and inside is a green TextView with text centered. That is, the widget will simply show the text on a green background.

We create a metadata file res / xml / widget_metadata.xml:


In the attribute initialLayout specify the layout file for the widget.

attributes minHeight and minWidth contain the minimum size of the widget in height and width.

There is a certain algorithm for calculating these numbers. As you may have noticed, when placing a widget, the screen is split into cells, and the widget occupies one or more of those cells in width and height. To convert cells to dp, the formula 70 * n – 30 is used, where n is the number of cells. That is, if we, for example, want our widget to occupy 2 cells in width and 1 in height, we calculate width = 70 * 2 – 30 = 110 and height = 70 * 1 – 30 = 40. These obtained values ​​and we will use in the minWidth and minHeight attributes.

Attribute updatePeriodMillis contains the number of milliseconds. This is the widget update interval. As far as I understand help, we can specify here at least 5 seconds, but more often than every 30 minutes (1 800 000) the widget will not be updated anyway – this is a system restriction. For now, let’s set the 40 minute interval (2,400,000). In the following lessons, we will figure out how to update the widget at the required interval.

It remains to create a class that inherits AppWidgetProvider.

package ru.startandroid.develop.p1171simplewidget;

import java.util.Arrays;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.util.Log;

public class MyWidget extends AppWidgetProvider {

  final String LOG_TAG = "myLogs";

  @Override
  public void onEnabled(Context context) {
    super.onEnabled(context);
    Log.d(LOG_TAG, "onEnabled");
  }

  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
      int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    Log.d(LOG_TAG, "onUpdate " + Arrays.toString(appWidgetIds));
  }

  @Override
  public void onDeleted(Context context, int[] appWidgetIds) {
    super.onDeleted(context, appWidgetIds);
    Log.d(LOG_TAG, "onDeleted " + Arrays.toString(appWidgetIds));
  }

  @Override
  public void onDisabled(Context context) {
    super.onDisabled(context);
    Log.d(LOG_TAG, "onDisabled");
  }

}

onEnabled is called by the system when creating the first instance of the widget (we can add multiple instances of Home to the same element).

onUpdate is called when updating the widget. In addition to the context, the method receives an AppWidgetManager object and a list of instance instances of the widgets to be updated. This method usually contains code that updates the contents of the widget. To do this, we will need the AppWidgetManager, which we get as input.

onDeleted is invoked when deleting each instance of the widget. In addition to the context, the method receives a list of instance instances of the widgets being deleted.

onDisabled is called when the last instance of the widget is deleted.

In all methods we output the log of the same name text and list ID for onUpdate and onDeleted.

Again, onUpdate, we should, in theory, need some sort of widget update. That is, if our widget displays, for example, the current time, then the next update (onUpdate call), you need to get the current time and pass this info to the widget for display. In this lesson, we will not be bothered with this yet.

It remains to sketch the manifest a little. Add your class there as a Receiver

– Specify your own label and icon. You will see this text and this icon in the list of selected widgets when you add the widget to the screen.

– set up a filter for it with action = android.appwidget.action.APPWIDGET_UPDATE

– Add metadata with the name android.appwidget.provider and specifying the metadata file xml / widget_metadata.xml as a resource

Then the receiver section in the manifest should output something like this:


	
		
		
	
	
	

The widget is ready. We save and run everything. Of course, no Activity pops up. The following should appear in the console:

P1171_SimpleWidget bin P1171_SimpleWidget.apk installed on device
Done!

Open the widget creation dialog and see our widget in the list with the icon and text that we specified in the manifest for the receiver.

We select it and add it to the screen.

The widget has appeared, we look at logs.

onEnabled
onUpdate [8]

worked onEnabledBecause we added first instance of widget. And right after adding, the method worked onUpdate for this instance. We see that it is assigned ID = 8. (You will most likely have another ID). That is, the system added a copy of the widget to the screen and called the update method, indicating the instance ID.

Add another copy

we look at the log

onUpdate [9]

onEnabled did not work because the widget instance is already being added not the first. onUpdate same worked again for the newly added instance and received ID = 9 at the input.

Now let’s remove two of these widget instances from the screen. First the second. In the logs we will see:

onDeleted [9]

worked onDeleted and received the ID of the widget instance being deleted.

Delete the first copy. In the logs:

onDeleted [8]
onDisabled

worked again onDeleted – We were notified that a widget instance with ID = 8 had been deleted. And it worked onDisabledThat was deleted last instance of widget, no more running instances left.

Our widget is updated (receives a call to the onUpdate method) every 40 minutes. If not lazy, add a couple of widgets to the screen again and wait. When they recover again, it will be reflected in the logs.

This is how a simple widget is created and works. For now, let’s dwell on the scheme of creating a widget and its lifecycle methods. Of interest I would like to mention a couple of things.

BroadcastReceiver

The AppWidgetProvider class is an extension of the BroadcastReceiver class (in the manifesto we spelled it as Receiver). It simply receives from the system a message in onReceive, determines by value from Intent exactly what event happened (adding, deleting or updating the widget), and calling the appropriate method (onEnabled, onUpdate, etc.).

In the manifest, we have set up an action filter for our Receiver class that catches update events. How does this Receiver catch other events (such as deletion)? Help writes about it this way:

The element must include an element with the android: name attribute. This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast. This is the only broadcast that you must explicitly declare. The AppWidgetManager automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.

That is, ACTION_APPWIDGET_UPDATE is the only action that must be spelled out explicitly. The rest of AppWidgetManager events will somehow deliver to our AppWidgetProvider heir.

indents

If we place multiple instances of the widget next, we will see the following picture

Not a very pleasant sight. Indentation should be made.

We add android: padding = “8dp” to RelativeLayout in our layout file

Save, run.

The widgets on the screen have changed automatically and now look more decent.

By the way, onUpdate worked for them, see the logs. An ID array of all running widget instances was passed to the method.

In Android 4.0 (API Level 14) and above, this drawback has been eliminated, and you don’t have to manually indent any more. Let’s check it out. Remove the indentation previously added to RelativeLayout. And specify in the manifest android: targetSdkVersion version 14 (or higher) to let the system know that you can use standard features, not compatibility mode.

We save everything, launch our widget on the emulator from 4.1. We add three copies.

The system itself makes indentations between widgets.

It turns out for versions, below 4 should be indented in layout, and for older versions it is not necessary. Help tells you how to make your widget work correctly on all versions. Version qualifiers are used for this purpose.

In the layout for RelativeLayuot you specify:

android: padding = “@ dimen / widget_margin”

And when creating two files.

res / values ​​/ dimens.xml with entry:

8dp

and res / values-v14 / dimens.xml with entry:

0dp

In the manifesto android: targetSdkVersion should be 14 or higher.

Thus, on the old versions (without system indentation) the indentation will be 8dp, and on the new versions – 0dp and there will be only system indentation.

In the next lesson:

– customize the widget when placed
– We work with the view components of the widget when updating




Discuss in the forum [44 replies]

Leave a Comment