Widgets en Android 1.5

El SDK Android 1.5 trae cosas muy interesantes. Para mí lo más interesante son los widget, me parecen útiles a rabiar. Han hecho bien el trabajo y es sencillo crear un widget para una aplicación, el único problema es el de siempre: la batería. El viernes pasado en el evento twitter de Barcelona, bromeábamos sobre ello diciendo: “¡Dentro de poco habrá que llevar una mochila-batería para poder aguantar un día!”. Realmente no es así, pero el desarrollador debe ser consciente de su trabajo y del rendimiento en máquina para evitar excesivo gasto de batería. A continuación el manual , explica la teoría con un ejemplo práctico y con consejos sobre el consumo de batería. Espero que os guste tanto como a mi.

Widgets en Android 1.5

Widget Android SDK 1.5

Una de las mejoras más excitantes del Android 1.5 SDK es el Framework AppWidget. Los widget pueden ser una vista rápida de un programa,  por ejemplo mostrar los próximos eventos del calendario, o ver la información  de la canción que se está reproduciendo en segundo plano. Los usuarios también pueden interactuar con un programa mediante el widget, por ejemplo pausar o cambiar canciones. Cuando un widget se pone en el escritorio, reserva un espacio para mostrar su contenido.

A alto nivel, cada widget es un BroadcastReceiver combinado con un fichero XML que contiene el metadato. Cuando el widget se actualiza, el Framework se comunica con él mediante broadcast intents. Las actualizaciones de los widget se construyen y envían usando RemoteViews. Una RemoteViews está formada por un diseño y su contenido. El diseño y contenido, que mostrará el widget en el escritorio.

Se puede añadir los widgets fácilmente dentro de las aplicaciones, y en este articulo mediante un ejemplo básico os enseñaré cómo. El objetivo es escribir un widget para mostrar la palabra del día de Wiktionary. El código disponible aquí.

Para empezar, se necesita un poco de XML para describir el widget, incluido el area de pantalla a reservar, un diseño inicial para mostrar, y con que frecuencia se quiere actualizar. El escritorio Android utiliza un diseño basado en celdas, es decir, redondea el tamaño pedido hasta el número de celdas más cercanos. Por ejemplo:

Tamaño mínimo en dip = (Número de celdas * 74dip) – 2dip

En este ejemplo, el widget será 2 celdas de ancho y 1 de alto, lo que significa un mínimo de 146dipx72dip. Además, el widget se actualizará una vez por día o 86,400,000 milisegundos. El XML quedaría de la siguiente forma:

<appwidget-provider
xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
android:minWidth=”146dip”
android:minHeight=”72dip”
android:initialLayout=”@layout/widget_message”
android:updatePeriodMillis=”86400000″
/>

Lo siguiente es emparejar el fichero XML con un BroadcastReceiver en el AndroidManifest:
<!– Broadcast Receiver that will process AppWidget updates –>
<receiver android:name=”.WordWidget” android:label=”@string/widget_name”>
<intent-filter>
<action android:name=”android.appwidget.action.APPWIDGET_UPDATE” />
</intent-filter>
<meta-data android:name=”android.appwidget.provider” android:resource=”@xml/widget_word” />
</receiver>

<!– Service to perform web API queries –>
<service android:name=”.WordWidget$UpdateService” />

Finalmente, toca escribir el código del BroadcastReceiver  para gestionar las peticiones del AppWidget. Hay una clase llamada AppWidgetProvider que ayuda a gestionar los diferentes eventos broadcast. Algo importante a tener en cuenta es que estamos lanzando como servicio en segundo plano para actualizar el widget. Los BroadcastReceivers están sujetos a Application Not Responding (ANR), alarma que aparece al usuario cuando el programa toma demasiado tiempo para ejecutarse y que provoca que tenga que cerrar forzosamente la aplicación. Así que para evitar este problema con la actualización, se ejecuta como servicio en segundo plano.

/**
* Define a simple widget that shows the Wiktionary “Word of the day.” To build
* an update we spawn a background {@link Service} to perform the API queries.
*/
public class WordWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// To prevent any ANR timeouts, we perform the update in a service
context.startService(new Intent(context, UpdateService.class));
}

public static class UpdateService extends Service {
@Override
public void onStart(Intent intent, int startId) {
// Build the widget update for today
RemoteViews updateViews = buildUpdate(this);

// Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(this, WordWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}

/**
* Build a widget update to show the current Wiktionary
* “Word of the day.” Will block until the online API returns.
*/
public RemoteViews buildUpdate(Context context) {
// Pick out month names from resources
Resources res = context.getResources();
String[] monthNames = res.getStringArray(R.array.month_names);

// Find current month and day
Time today = new Time();
today.setToNow();

// Build today’s page title, like “Wiktionary:Word of the day/March 21”
String pageName = res.getString(R.string.template_wotd_title,
monthNames[today.month], today.monthDay);
RemoteViews updateViews = null;
String pageContent = “”;

try {
// Try querying the Wiktionary API for today’s word
SimpleWikiHelper.prepareUserAgent(context);
pageContent = SimpleWikiHelper.getPageContent(pageName, false);
} catch (ApiException e) {
Log.e(“WordWidget”, “Couldn’t contact API”, e);
} catch (ParseException e) {
Log.e(“WordWidget”, “Couldn’t parse API response”, e);
}

// Use a regular expression to parse out the word and its definition
Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
Matcher matcher = pattern.matcher(pageContent);
if (matcher.find()) {
// Build an update that holds the updated widget contents
updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);

String wordTitle = matcher.group(1);
updateViews.setTextViewText(R.id.word_title, wordTitle);
updateViews.setTextViewText(R.id.word_type, matcher.group(2));
updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());

// When user clicks on widget, launch to Wiktionary definition page
String definePage = res.getString(R.string.template_define_url,
Uri.encode(wordTitle));
Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0 /* no requestCode */, defineIntent, 0 /* no flags */);
updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);

} else {
// Didn’t find word of day, so show error message
updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
CharSequence errorMessage = context.getText(R.string.widget_error);
updateViews.setTextViewText(R.id.message, errorMessage);
}
return updateViews;
}

@Override
public IBinder onBind(Intent intent) {
// We don’t need to bind to this service
return null;
}
}
}

Para terminar, un consejo, los widgets están diseñados para mostrar contenido que no se actualice con frecuencia, y hacer que se actualicen cada hora puede provocar que te quedes sin batería. Así que intenta hacer las actualizaciones en el mayor tiempo posible o deja al usuario que seleccione la frecuencia. Por ejemplo, las cotizaciones dependiendo de la gente querrán una actualización con más o menos frecuencia.

Artículo original | Android Developers Blog

12 comentarios sobre “Widgets en Android 1.5

  1. Pingback: Bitacoras.com
  2. I identified your guide on google and I need to admit it’s great. I’ve got a website too, and I’m making reviews of a excellent produtc, Muscle Warfare, which helps you constructing yous muscular tissues a lot faster with organic substances. Go to my website and have a search.

    Me gusta

  3. Oh my goodness! an incredible article dude. Thank you Nonetheless I am experiencing challenge with ur rss . Don? know why Unable to subscribe to it. Is there anyone getting equivalent rss drawback? Anyone who knows kindly respond. Thnkx

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s