Key points for developing Android desktop widgets (time and date widgets)

Source: Internet
Author: User

In general, the main function of widgets is to display some information. Today, we write a simple widget that displays the time, date, day of week, and other information. To display the time information, you need to update it in real time, one second or one minute.

Recently, you need to write a date-time desktop Widget to associate the calendar program. In the past, desktop widgets were rarely written. I am not very familiar with this technology. Today I took the time to reorganize it and record the process of writing a simple time and date program.

Desktop widgets are actually a tool for displaying some information (some widgets with actual operation functions are also developed. For example, camera widgets can be taken directly on the desktop ). But in general, the main function of widgets is to display some information. Today, we write a simple widget that displays the time, date, day of week, and other information. To display the time message, you need to update the message in real time, one second or one minute.

This time Widget is made by referring to a demo example in the book (Android Application Development secrets). It only improves functions and interfaces. The following is the current one:



1. inherit from AppWidgetProvider
The desktop widgets we have compiled need to provide data updates. here we need to use AppWidgetProvider, which contains some system callback functions. Update data. AppWidgetProvider is a broadcast receiver. Let's take a look at several important callback methods of AppWidgetProvider:

Copy codeThe Code is as follows:
Class WidgetProvider extends AppWidgetProvider
{
Private static final String TAG = "mythou_Widget_Tag ";
// Call a broadcast message once if it is not received. It is frequently used.
Public void onReceive (Context context, Intent intent)
{
Log. d (TAG, "mythou ---------> onReceive ");
Super. onReceive (context, intent );
}

// This method is called once for each update and is frequently used.
Public void onUpdate (Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds)
{
Log. d (TAG, "mythou ---------> onUpdate ");
Super. onUpdate (context, appWidgetManager, appWidgetIds );
}

// Call once without deleting one
Public void onDeleted (Context context, int [] appWidgetIds)
{
Log. d (TAG, "mythou ---------> onDeleted ");
Super. onDeleted (context, appWidgetIds );
}

// This method is called when the Widget is added to the desktop for the first time. It can be added multiple times but only called for the first time.
Public void onEnabled (Context context)
{
Log. d (TAG, "mythou ---------> onEnabled ");
Super. onEnabled (context );
}

// When the last Widget is deleted, this method is called. Note that the last Widget is deleted.
Public void onDisabled (Context context)
{
Log. d (TAG, "mythou ---------> onDisabled ");
Super. onDisabled (context );
}
}


The onUpdate and onDelete methods are commonly used. I used a Service to refresh the time here. To regularly refresh the Service, an Alarm timer Service is also required. Here is my onUpdate method:

Copy codeThe Code is as follows:
Public void onUpdate (Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds)
{
Super. onUpdate (context, appWidgetManager, appWidgetIds );
Time time = new Time ();
Time. setToNow ();
// Update Time Using Service
Intent intent = new Intent (context, UpdateService. class );
PendingIntent pendingIntent = PendingIntent. getService (context, 0, intent, 0 );
// Use Alarm to regularly update interface data
AlarmManager alarm = (AlarmManager) context. getSystemService (Context. ALARM_SERVICE );
Alarm. setRepeating (AlarmManager. RTC, time. toMillis (true), 60*1000, pendingIntent );
}


2. AndroidManifest. xml configuration

Copy codeThe Code is as follows:
<Application
Android: icon = "@ drawable/icon"
Android: label = "@ string/app_name">
<! -- AppWidgetProvider registration mythou -->
<Cycler
Android: label = "@ string/app_name_timewidget"
Android: name = "com. owl. mythou. TimeWidget">
<Intent-filter>
<Action android: name = "android. appwidget. action. APPWIDGET_UPDATE"> </action>
</Intent-filter>
<Meta-data
Android: name = "android. appwidget. provider"
Android: resource = "@ xml/time_widget_config">
</Meta-data>
</Cycler>
<! -- Update the Time of the backend service mythou -->
<Service android: name = "com. owl. mythou. UpdateService"> </service>

</Application>


AndroidManifest is mainly used to configure a receiver, because AppWidgetProvider is a broadcast receiver. In addition, you need to provide an action, which is the system update widget action. You also need to specify the widget configuration file in meta-data. This configuration file needs to be placed under the resxml directory. Let's look at the configuration of time_widget_config.xml.

3. appWidget Configuration:

Copy codeThe Code is as follows:
<? Xml version = "1.0" encoding = "UTF-8"?>
<Appwidget-provider
Xmlns: android = "http://schemas.android.com/apk/res/android"
Android: initialLayout = "@ layout/time_widget_layout"
Android: minWidth = "286dip"
Android: minHeight = "142dip"
Android: updatePeriodMillis = "0">
</Appwidget-provider>


• Android: initialLayout specifies the Layout file of the interface Layout, which is the same as Layout of the activity.
• Android: minWidth: minimum width of your widget. Calculated based on the Layout cell (72 * Number of cells-2)
• Android: min height of your widget. The calculation method is the same as minwidth. (If you are not familiar with this, you can refer to my Launcher analysis article)
• Android: updatePerioMillis uses the system's Scheduled Update Service, in milliseconds.

Android: updatePerioMillis is a problem. To save power, the system is updated every 30 minutes by default. If the value you set is smaller than 30 minutes, the system will be updated every 30 minutes. The time Widget is obviously unreliable. Therefore, only one Alarm scheduled service update can be compiled by yourself.

4. Update the Service of the Widget

Copy codeThe Code is as follows:
Class UpdateService extends Service
{
@ Override
Public void onStart (Intent intent, int startId)
{
Super. onStart (intent, startId );
UpdateWidget (this );
}
Private void UpdateWidget (Context context)
{
// Don't use Calendar, Time has less cpu load
Time time = new Time ();
Time. setToNow ();
Int hour = time. hour;
Int min = time. minute;
Int second = time. second;
Int year = time. year;
Int month = time. month + 1;
Int day = time. monthDay;
String strTime = String. format ("% 02d: % 02d: % 02d % 04d-% 02d-% 02d", hour, min, second, year, month, day );
RemoteViews updateView = new RemoteViews (context. getPackageName (),
R. layout. time_widget_layout );

// Time image update
String packageString = "org. owl. mythou ";
String timePic = "time ";
Int hourHbit = hour/10;
UpdateView. setImageViewResource (R. id. hourHPic, getResources (). getIdentifier (timePic + hourHbit, "drawable", packageString ));
Int hourLbit = hour % 10;
UpdateView. setImageViewResource (R. id. hourLPic, getResources (). getIdentifier (timePic + hourLbit, "drawable", packageString ));
Int minHbit = min/10;
UpdateView. setImageViewResource (R. id. MinuteHPic, getResources (). getIdentifier (timePic + minHbit, "drawable", packageString ));
Int minLbit = min % 10;
UpdateView. setImageViewResource (R. id. MinuteLPic, getResources (). getIdentifier (timePic + minLbit, "drawable", packageString ));

// Day of the week
UpdateView. setTextViewText (R. id. weekInfo, getWeekString (time. weekDay + 1 ));

// Date update. The image is calculated based on the date.
String datePic = "date ";
Int year1bit = year/1000;
UpdateView. setImageViewResource (R. id. Year1BitPic, getResources (). getIdentifier (datePic + year1bit, "drawable", packageString ));
Int year2bit = (year % 1000)/100;
UpdateView. setImageViewResource (R. id. Year2BitPic, getResources (). getIdentifier (datePic + year2bit, "drawable", packageString ));
Int year3bit = (year % 100)/10;
UpdateView. setImageViewResource (R. id. Year3BitPic, getResources (). getIdentifier (datePic + year3bit, "drawable", packageString ));
Int year4bit = year % 10;
UpdateView. setImageViewResource (R. id. Year4BitPic, getResources (). getIdentifier (datePic + year4bit, "drawable", packageString ));
// Month
Int mouth1bit = month/10;
UpdateView. setImageViewResource (R. id. mouth1BitPic, getResources (). getIdentifier (datePic + mouth1bit, "drawable", packageString ));
Int mouth2bit = month % 10;
UpdateView. setImageViewResource (R. id. mouth2BitPic, getResources (). getIdentifier (datePic + mouth2bit, "drawable", packageString ));
// Day
Int day1bit = day/10;
UpdateView. setImageViewResource (R. id. day1BitPic, getResources (). getIdentifier (datePic + day1bit, "drawable", packageString ));
Int day2bit = day % 10;
UpdateView. setImageViewResource (R. id. day2BitPic, getResources (). getIdentifier (datePic + day2bit, "drawable", packageString ));

// Click the widget to start the calendar
Intent launchIntent = new Intent ();
LaunchIntent. setComponent (new ComponentName ("com. mythou. mycalendar ",
"Com. mythou. mycalendar. calendarMainActivity "));
LaunchIntent. setAction (Intent. ACTION_MAIN );
LaunchIntent. addCategory (Intent. CATEGORY_LAUNCHER );
LaunchIntent. setFlags (Intent. FLAG_ACTIVITY_NEW_TASK
| Intent. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED );
PendingIntent intentAction = PendingIntent. getActivity (context, 0,
LaunchIntent, 0 );
UpdateView. setOnClickPendingIntent (R. id. SmallBase, intentAction );
AppWidgetManager awg = AppWidgetManager. getInstance (context );
Awg. updateAppWidget (new ComponentName (context, TimeWidgetSmall. class ),
UpdateView );
}
}


The above is my Service, because my interface time and date are made of images (purely for the sake of viewing ). Therefore, there is a lot more code for calculating the image name based on the time and date. These are the actual processing of the image, which is not mentioned here.
One thing to note is that RemoteViews

Copy codeThe Code is as follows:
RemoteViews updateView = new RemoteViews (context. getPackageName (), R. layout. time_widget_layout );


Generate a remote Views update object from the configuration file on our interface. This allows you to operate the Views of other processes in different processes. Because widgets are running in the Launcher process, rather than an independent process. This is also a remote access mechanism. The last step is to add a click desktop Widget to start a program and use the PendingIntent method.

Writing a desktop Widget mainly involves these steps. Finally, the UI layout of the desktop Widget only supports some standard android controls. If you need to create a complex widget interface, you need to customize the widgets. This part will be available later ~

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.