Códifica un Widget Para Tu Aplicación Android: Actualización del Widget
Spanish (Español) translation by James (you can also view the original English article)
Widgets de aplicaciones proporcionan a que los usuarios con acceso fácil a la mayoría de la aplicación con frecuencia utilizan características, dando su aplicación una presencia en pantalla de inicio del usuario. Al añadir un widget a su proyecto, puede proporcionar una mejor experiencia de usuario, mientras que alentar a los usuarios a seguir participando con su aplicación, como verán cada vez que echar un vistazo a su pantalla de inicio widget, mostrando algunas de sus aplicaciones del más útil y contenidos interesantes.
En esta serie de tres partes, estamos construyendo un widget de aplicación que tiene toda la funcionalidad que usted encontrará en casi cada widget de la aplicación para Android.
En el primer post, hemos creado un widget que recupera y muestra los datos y realiza una acción única como respuesta a eventos onClick
. No obstante, nuestro widget todavía está faltando una pieza fundamental de la funcionalidad: nunca actualiza con nueva información. Un widget que nunca tiene nada nuevo que para ofrecer no tan útil, por lo que daremos nuestro widget dos maneras para actualizar.
Al final de esta serie, habremos ampliado nuestro widget para recuperar y mostrar nuevos datos automáticamente según un horario y en respuesta a la interacción con el usuario.
Nosotros estamos recogiendo derecho donde nos quedamos, así que si no tienes una copia del widget que creamos en el primer post, entonces usted puede descargar desde GitHub.
Actualización de Su Diseño
El primer paso es actualizar nuestro diseño para mostrar algunos datos que cambia con el tiempo. Para ayudarnos a ver exactamente cuando nuestro widget recibe cada actualización, voy a instruir el widget para recuperar y mostrar la hora actual, cuando realiza una actualización.
Voy a agregar lo siguiente en el diseño del widget:
- un
TextView
que muestra una etiqueta de la última actualización - un
TextView
que mostrará la hora de la última actualización
Mientras estamos trabajando en el archivo new_app_widget.xml, también voy a añadir el TextView
que finalmente le permiten al usuario iniciar una actualización manualmente:
1 |
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" |
2 |
android:layout_width="match_parent" |
3 |
android:layout_height="match_parent" |
4 |
android:padding="@dimen/widget_margin" |
5 |
android:background="@drawable/widget_background" |
6 |
android:orientation="vertical" > |
7 |
|
8 |
<LinearLayout
|
9 |
android:background="@drawable/tvbackground" |
10 |
style="@style/widget_views" |
11 |
android:layout_width="match_parent" |
12 |
android:layout_height="wrap_content" |
13 |
android:orientation="horizontal"> |
14 |
|
15 |
<TextView
|
16 |
android:id="@+id/id_label" |
17 |
android:layout_width="wrap_content" |
18 |
android:layout_height="wrap_content" |
19 |
android:text="@string/widget_id" |
20 |
style="@style/widget_text" /> |
21 |
|
22 |
<TextView
|
23 |
android:id="@+id/id_value" |
24 |
android:layout_width="wrap_content" |
25 |
android:layout_height="wrap_content" |
26 |
android:text="." |
27 |
style="@style/widget_text" /> |
28 |
|
29 |
</LinearLayout>
|
30 |
|
31 |
<TextView
|
32 |
android:id="@+id/launch_url" |
33 |
style="@style/widget_views" |
34 |
android:layout_width="wrap_content" |
35 |
android:layout_height="wrap_content" |
36 |
android:text="@string/URL" |
37 |
android:background="@drawable/tvbackground"/> |
38 |
|
39 |
//Add a ‘Tap to update’ TextView// |
40 |
|
41 |
<TextView
|
42 |
android:id="@+id/update" |
43 |
style="@style/widget_views" |
44 |
android:layout_width="wrap_content" |
45 |
android:layout_height="wrap_content" |
46 |
android:text="@string/update" |
47 |
android:background="@drawable/tvbackground"/> |
48 |
|
49 |
<LinearLayout
|
50 |
android:background="@drawable/tvbackground" |
51 |
style="@style/widget_views" |
52 |
android:layout_width="match_parent" |
53 |
android:layout_height="wrap_content" |
54 |
android:orientation="vertical"> |
55 |
|
56 |
//Add a TextView that’ll display our ‘Last Update’ label// |
57 |
|
58 |
<TextView
|
59 |
android:id="@+id/update_label" |
60 |
style="@style/widget_text" |
61 |
android:layout_width="match_parent" |
62 |
android:layout_height="wrap_content" |
63 |
android:text="@string/last_update" /> |
64 |
|
65 |
//Add the TextView that’ll display the time of the last update// |
66 |
|
67 |
<TextView
|
68 |
android:id="@+id/update_value" |
69 |
style="@style/widget_text" |
70 |
android:layout_width="match_parent" |
71 |
android:layout_height="wrap_content" |
72 |
android:text="@string/time" /> |
73 |
</LinearLayout>
|
74 |
|
75 |
</LinearLayout>
|
A continuación, definir los nuevos recursos de cadena que referenciamos en nuestro diseño:
1 |
<string name="update">Tap to update</string> |
2 |
<string name="last_update">Last Update</string> |
3 |
<string name="time">%1$s</string> |
La @string/time
se ve diferente de la típica cadena, ya que es sólo un marcador de posición que podrá ser reemplazado en tiempo de ejecución.
Esto nos da el diseño terminado:



Actualizar el Widget Basado en un Programa
Puesto que es el método más fácil de implementar, voy a empezar por actualizar nuestro widget automáticamente, después de un periodo de tiempo transcurrido.
Al crear este tipo de programa de actualización automática, 1.800.000 milisegundos (30 minutos) es el intervalo más pequeño se puede utilizar. Incluso si establece updatePeriodMillis
del proyecto a menos de 30 minutos, tu widget sólo se actualizará una vez cada media hora.
No es sencillo decidir con qué frecuencia debe actualizar el widget. Actualizaciones frecuentes son un mayor drenaje en el dispositivo de batería, pero estas actualizaciones demasiado lejos aparte y su widget pueden terminar Mostrar significativamente desactualizada información al usuario del sistema.
Para encontrar un equilibrio que funciona para su proyecto en particular, usted necesitará probar el widget en una gama de frecuencias de la actualización y medir el impacto que cada frecuencia tiene en la vida de la batería, vigilando si el contenido del widget nunca llega a ser perceptiblemente fuera de fecha.
Desde cómo frecuente-es-demasiado frecuentes es una de esas preguntas frustrantes, subjetivas donde no hay ninguna respuesta "correcta", puede ayudar a obtener una segunda opinión por organizar unas pruebas de usuario. Incluso puede establecer para arriba algunos A / B pruebas para comprobar si cierta actualización de frecuencias reciben más positivamente que otros.
Abra el archivo del proyecto AppWidgetProviderInfo (res/xml/new_app_widget_info.xml) y verás que ya define un intervalo de actualización predeterminado de 86,400,000 milisegundos (24 horas).
1 |
android:updatePeriodMillis="86400000" |
Hay un montón de widgets que se actualizan sólo una vez cada 24 horas; por ejemplo, un widget que muestra el pronóstico del tiempo sólo puede ser que necesite recuperar nueva información una vez al día. Sin embargo, aunque el widget sólo tiene que actualizar una vez al día, esto no es ideal cuando la aplicación de la prueba. Nadie quiere esperar 24 horas solo para ver si su método onUpdate()
es accionar correctamente, para usar normalmente el menor intervalo posible al realizar las pruebas iniciales y luego cambiar este valor más adelante, si es necesario.
Para que sea más fácil de probar nuestra aplicación, voy a utilizar el menor intervalo posible:
1 |
android:updatePeriodMillis="1800000" |
Recuperar y Mostrar la Hora Actual
El método onUpdate()
es responsable de la actualización de Views
de su widget con información nueva. Si abres proveedor de widget de su proyecto (java/values/NewAppWidget.java) a ver que ya contiene el esbozo de un método onUpdate()
:
1 |
@Override
|
2 |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { |
3 |
|
4 |
// There may be multiple widgets active, so update all of them//
|
5 |
|
6 |
for (int appWidgetId : appWidgetIds) { |
7 |
updateAppWidget(context, appWidgetManager, appWidgetId); |
8 |
}
|
9 |
}
|
Independientemente de si el widget se actualiza automáticamente o en respuesta a la interacción con el usuario, el proceso de actualización es exactamente el mismo: el Gerente de widget envía una intención de difusión con la acción de ACTION_APPWIDGET_UPDATE
, y la clase widget y el proveedor responde por llamar al método onUpdate()
, que a su vez llama al método updateAppWidget()
.
Una vez que hemos actualizado nuestra clase NewAppWidget.java para recuperar y mostrar la hora actual, el proyecto usará esta misma sección del código, independientemente de cómo se activa el método onUpdate()
:
1 |
import android.appwidget.AppWidgetManager; |
2 |
import android.appwidget.AppWidgetProvider; |
3 |
import android.content.Context; |
4 |
import android.widget.RemoteViews; |
5 |
import android.app.PendingIntent; |
6 |
import android.content.Intent; |
7 |
import android.net.Uri; |
8 |
import java.text.DateFormat; |
9 |
import java.util.Date; |
10 |
|
11 |
public class NewAppWidget extends AppWidgetProvider { |
12 |
|
13 |
static void updateAppWidget(Context context, |
14 |
AppWidgetManager appWidgetManager, |
15 |
int appWidgetId) { |
16 |
|
17 |
//Retrieve the time//
|
18 |
|
19 |
String timeString = |
20 |
DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()); |
21 |
|
22 |
//Construct the RemoteViews object//
|
23 |
|
24 |
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget); |
25 |
views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId)); |
26 |
|
27 |
//Retrieve and display the time//
|
28 |
|
29 |
views.setTextViewText(R.id.update_value, |
30 |
context.getResources().getString( |
31 |
R.string.time, timeString)); |
32 |
|
33 |
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/")); |
34 |
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); |
35 |
views.setOnClickPendingIntent(R.id.launch_url, pendingIntent); |
36 |
appWidgetManager.updateAppWidget(appWidgetId, views); |
37 |
}
|
38 |
|
39 |
@Override
|
40 |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { |
41 |
|
42 |
//If multiple widgets are active, then update them all//
|
43 |
|
44 |
for (int appWidgetId : appWidgetIds) { |
45 |
updateAppWidget(context, appWidgetManager, appWidgetId); |
46 |
}
|
47 |
}
|
48 |
}
|
Hay un problema con el código anterior: Si el usuario aprovecha el TextView
varias veces durante el lapso de un minuto, no habrá ninguna indicación visual que el widget se actualiza, simplemente porque no hay nuevo tiempo para mostrar. Esto probablemente no causará problemas a sus usuarios finales, que están poco probable que se sientan allí, golpeando el TextView
varias veces por minuto y preguntándose por qué el tiempo no ha cambiado. Sin embargo, esto puede ser un problema cuando pruebas tu aplicación, esto significa que usted tendrá que esperar por lo menos 60 segundos entre la activación del método onUpdate()
.
Para asegurarse de que siempre hay algún tipo de confirmación visual de que el método onUpdate()
ha ejecutado correctamente, voy a mostrar un brindis cuando onUpdate()
se llama:
1 |
import android.widget.Toast; |
2 |
...
|
3 |
...
|
4 |
...
|
5 |
|
6 |
@Override
|
7 |
|
8 |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { |
9 |
for (int appWidgetId : appWidgetIds) { |
10 |
updateAppWidget(context, appWidgetManager, appWidgetId); |
11 |
Toast.makeText(context, "Widget has been updated! ", Toast.LENGTH_SHORT).show(); |
12 |
|
13 |
}
|
14 |
}
|
15 |
}
|



Actualizar tu Widget en Respuesta a la Acción del Usuario
Nuestro widget ahora se actualizará automáticamente una vez cada media hora, pero ¿qué pasa con actualización en respuesta a la interacción con el usuario?
Ya hemos puesto un montón de las bases agregando un Toque para Actualizar TextView
a nuestro diseño y expansión de la clase NewAppWidget.java para recuperar y mostrar la hora actual cuando se llama onUpdate()
.
Lo único por hacer es crear un intento
con AppWidgetManager.ACTION_APPWIDGET_UPDATE
, que es una acción que informa el widget que es el momento de actualizar, y luego llamar a este propósito en respuesta al usuario interactuar con el Toque para Actualizar TextView
.
Aquí está la clase completa de NewAppWidget.java:
1 |
import android.appwidget.AppWidgetManager; |
2 |
import android.appwidget.AppWidgetProvider; |
3 |
import android.content.Context; |
4 |
import android.widget.RemoteViews; |
5 |
import android.app.PendingIntent; |
6 |
import android.content.Intent; |
7 |
import android.net.Uri; |
8 |
import java.text.DateFormat; |
9 |
import java.util.Date; |
10 |
import android.widget.Toast; |
11 |
|
12 |
public class NewAppWidget extends AppWidgetProvider { |
13 |
static void updateAppWidget(Context context, |
14 |
AppWidgetManager appWidgetManager, |
15 |
int appWidgetId) { |
16 |
|
17 |
//Retrieve the current time//
|
18 |
|
19 |
String timeString = |
20 |
DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()); |
21 |
|
22 |
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget); |
23 |
views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId)); |
24 |
views.setTextViewText(R.id.update_value, |
25 |
context.getResources().getString( |
26 |
R.string.time, timeString)); |
27 |
|
28 |
//Create an Intent with the AppWidgetManager.ACTION_APPWIDGET_UPDATE action//
|
29 |
|
30 |
Intent intentUpdate = new Intent(context, NewAppWidget.class); |
31 |
intentUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); |
32 |
|
33 |
//Update the current widget instance only, by creating an array that contains the widget’s unique ID//
|
34 |
|
35 |
int[] idArray = new int[]{appWidgetId}; |
36 |
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray); |
37 |
|
38 |
//Wrap the intent as a PendingIntent, using PendingIntent.getBroadcast()//
|
39 |
|
40 |
PendingIntent pendingUpdate = PendingIntent.getBroadcast( |
41 |
context, appWidgetId, intentUpdate, |
42 |
PendingIntent.FLAG_UPDATE_CURRENT); |
43 |
|
44 |
//Send the pending intent in response to the user tapping the ‘Update’ TextView//
|
45 |
|
46 |
views.setOnClickPendingIntent(R.id.update, pendingUpdate); |
47 |
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/")); |
48 |
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); |
49 |
views.setOnClickPendingIntent(R.id.launch_url, pendingIntent); |
50 |
|
51 |
//Request that the AppWidgetManager updates the application widget//
|
52 |
|
53 |
appWidgetManager.updateAppWidget(appWidgetId, views); |
54 |
}
|
55 |
|
56 |
@Override
|
57 |
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { |
58 |
for (int appWidgetId : appWidgetIds) { |
59 |
updateAppWidget(context, appWidgetManager, appWidgetId); |
60 |
Toast.makeText(context, "Widget has been updated! ", Toast.LENGTH_SHORT).show(); |
61 |
}
|
62 |
}
|
63 |
}
|
Ser capaz de actualizar un widget en la demanda puede ser inestimable cuando pruebas tu proyecto, esto significa que usted nunca tendrá que esperar a que transcurra el intervalo de actualización. Aunque no incluye esta funcionalidad en su aplicación final, puede que desee añadir un Toque para Actualizar, para simplificarle la vida al probar su proyecto.
Crear una Imagen de Vista Previa
Nuestro widget ahora parece totalmente diferente al widget que Android Studio genera para nosotros automáticamente, pero por el momento sigue utilizando la imagen de previsualización generada automáticamente.



Idealmente, la imagen de vista previa debe alentar a los usuarios seleccionar el widget en el selector Widget, pero por lo menos debe ser una representación exacta de cómo se ve realmente tu widget! Actualmente, nuestra imagen de vista previa no marca nunca de esas cajas, así que tenemos que crear uno nuevo.
El método más fácil es usar la aplicación Widget Preview que está incluida en el emulador de Android.
Crear un Widget Preview
En primer lugar, instalar su proyecto en un Dispositivo Virtual Android (AVD). Luego abrir el cajón de la aplicación de la AVD y ejecutar la aplicación Widget Preview. La AVD mostrará una lista de cada aplicación que se instala en el dispositivo, seleccione su aplicación de la lista.
El widget se mostrará sobre un fondo blanco. Dedicar un tiempo redimensionar y ajustar el widget para que se vea mejor y una vez que estés satisfecho con los resultados, seleccione Tomar Instantánea. La captura de pantalla se guardará como PNG en la carpeta de Descarga de la AVD. Para recuperar este archivo, volver a Android Studio y abra el Explorador de Archivos del Dispositivo, seleccione Vista > Herramienta Windows > Explorador de Archivos del Dispositivo de la barra de herramientas. En la vista de explorador de archivos del dispositivo, vaya a la carpeta sdcard/Download, donde se encuentra la imagen de previsualización que se guarda como [app_name]_ori_[orientation].png.



Arrastre esta imagen de estudio de Android y colóquelo en algún lugar de fácil acceso, como el escritorio. La imagen de dar un nombre más descriptivo y luego arrastrar y soltar la imagen en la carpeta drawable de su proyecto. Ahora puede abrir el archivo AppWidgetProviderInfo (en este caso, que es new_app_widget_info.xml) y cambiar la siguiente línea para hacer referencia a la nueva imagen de vista previa:
1 |
android:previewImage="@drawable/example_appwidget_preview" |
Finalmente, puede quitar el example_appwidget_preview innecesarias estas características de su proyecto.
Prueba de Widget
¡Es el momento de poner el widget terminado a prueba!
En primer lugar, instale el proyecto actualizado en su dispositivo Android físico o AVD. Quitar todas las instancias existentes de este widget desde tu pantalla de inicio, así que usted sabe que usted está trabajando con la última versión.
Para añadir el widget, pulse cualquier espacio vacío en la pantalla de inicio, toque el Widget y seleccione el widget. Tendrás una oportunidad para redimensionar y reposicionar el widget, como sea necesario.
El valor de la Ultima Actualización mostrará el tiempo que ha creado este widget. presione Tocar para Actualizar y el widget debería mostrar un brindis y un nuevo tiempo. Si se coloca una segunda instancia del widget en tu pantalla de inicio, debe mostrar un tiempo distinto al primero.



Puede actualizar cualquiera de estos casos de widget dando su Tocar para Actualizar TextView
un toque. Si lanzáis una actualización manual del primer widget, entonces no se actualizará el segundo widget y viceversa.
Además de las actualizaciones manuales, la aplicación Widget Manager para actualizar todas las instancias del widget una vez cada 30 minutos, basada en el tiempo cuando se creó la primera instancia. Aunque versiones manual pueden resultar en ocasiones mostrando diferentes momentos, una vez cada media hora que se actualizarán todas las instancias al mismo tiempo, momento en el que te muestran al mismo tiempo.
Puede que desee mantener unos pocos casos de este widget en tu pantalla de inicio, así que usted puede controlar cómo su contenido cambia con el tiempo en respuesta a una combinación de actualizaciones automáticas y manuales.
Conclusión
En esta serie, hemos estado creando un widget de la aplicación para Android que muestra cómo implementar todas las características más comunes encontradas los widgets de la aplicación. Si has estado siguiendo a lo largo desde el principio, en este punto usted habrá construido un widget que actualiza automáticamente y en respuesta a la entrada del usuario, y que es capaz de reaccionar a los eventos onClick (también puede descargar el proyecto completo desde GitHub).
En el próximo post, veremos algunas mejores prácticas para asegurar que tu widget proporciona una experiencia de usuario buena y cómo mejorar tu widget con una configuración de actividad.
- Android SDK¿Qué Es Android Aplicaciones Instantáneas?Jessica Thornsby
- Android SDKCreación de Aplicaciones Android AccesiblesJessica Thornsby
- Android SDKCrear una Interfaz con Fichas de Material Design en una Aplicación Para AndroidChike Mgbemena
- Android SDKConsejo Rápido: Crear una Ficha de configuración Rápida Para AndroidAshraff Hathibelagal