blob: c061a093bb297a1e6df91d091b2e3713dc4dd1cc [file] [log] [blame]
page.title=Optimizaciones en segundo plano
page.metaDescription=Nuevas restricciones para transmisiones implícitas.
page.keywords="android N", "implicit broadcasts", "job scheduler"
page.image=images/cards/card-nyc_2x.jpg
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>
En este documento
</h2>
<ol>
<li>
<a href="#connectivity-action">Restricciones en CONNECTIVITY_ACTION</a>
</li>
<li>
<a href="#sched-jobs">Programación de trabajos en red en conexiones
sin medición de uso</a>
</li>
<li>
<a href="#monitor-conn">Control de la conectividad de la red mientras la aplicación
se está ejecutando</a>
</li>
<li>
<a href="#media-broadcasts">Restricciones en NEW_PICTURE y
NEW_VIDEO</a>
</li>
<li>
<a href="#new-jobinfo">Nuevos métodos de JobInfo</a>
</li>
<li>
<a href="#new-jobparam">Nuevos métodos de JobParameter</a>
</li>
<li>
<a href="#further-optimization">Cómo optimizar aún más tu aplicación</a>
</li>
</ol>
</div>
</div>
<p>
Los procesos en segundo plano pueden consumir mucha memoria y batería. Por ejemplo, una
transmisión implícita puede iniciar muchos procesos en segundo plano registrados para
escucharla, aunque esos procesos quizá no desempeñen un trabajo considerable. Esto puede
afectar de forma significativa tanto el rendimiento del dispositivo como la experiencia de usuario.
</p>
<p>
Para corregir este problema, en Android N se aplican las siguientes
restricciones:
</p>
<ul>
<li>Las aplicaciones orientadas a la Preview no reciben transmisiones {@link
android.net.ConnectivityManager#CONNECTIVITY_ACTION} si
en su manifiesto registran que las reciben. Las aplicaciones que se ejecutan aún pueden
escuchar {@code CONNECTIVITY_CHANGE} en su subproceso principal mediante el registro de un
{@link android.content.BroadcastReceiver} con {@link
android.content.Context#registerReceiver Context.registerReceiver()}.
</li>
<li>Las aplicaciones no pueden enviar ni recibir transmisiones {@link
android.hardware.Camera#ACTION_NEW_PICTURE} ni {@link
android.hardware.Camera#ACTION_NEW_VIDEO}. Esta optimización
afecta a todas las aplicaciones, no solo a aquellas orientadas a la Preview.
</li>
</ul>
<p>
Si la aplicación utiliza cualquiera de estas intents, debes quitar las dependencias en
ellas lo antes posible a fin de poder orientar los dispositivos Android N correctamente.
El framework de Android ofrece varias soluciones para mitigar la necesidad de
estas transmisiones implícitas. Por ejemplo, {@link android.app.job.JobScheduler}
y <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
{@code GcmNetworkManager}</a> proporcionan mecanismos sólidos para programar operaciones
de red cuando se cumplen las condiciones especificadas, como una conexión a una
red de uso no medido. Ahora también puedes usar {@link android.app.job.JobScheduler}
para reaccionar a cambios en relación con los proveedores de contenido. Los objetos {@link android.app.job.JobInfo}
encapsulan los parámetros que usa {@link android.app.job.JobScheduler}
para programar el trabajo. Cuando se cumplen las condiciones del trabajo, el sistema
ejecuta ese trabajo en el {@link android.app.job.JobService} de tu aplicación.
</p>
<p>
En este documento, aprenderemos cómo usar métodos alternativos, como
{@link android.app.job.JobScheduler}, para adaptar tu aplicación a esas nuevas
restricciones.
</p>
<h2 id="connectivity-action">
Restricciones en CONNECTIVITY_ACTION
</h2>
<p>
Las aplicaciones orientadas a Android N no reciben transmisiones {@link
android.net.ConnectivityManager#CONNECTIVITY_ACTION} si en su manifiesto
registran que las reciben, y los procesos que dependan de esta
transmisión no se iniciarán. Esto podría ser un problema para aplicaciones que buscan
escuchar los cambios en la red o realizar múltiples actividades en red cuando el
dispositivo se conecta a una red sin medición de uso. Ya existen varias soluciones
en relación con esta restricción en el framework de Android, pero elegir
la correcta depende de lo que quieras lograr con tu aplicación.
</p>
<p class="note">
<strong>Nota:</strong> Un {@link android.content.BroadcastReceiver} registrado con
{@link android.content.Context#registerReceiver Context.registerReceiver()}
continúa recibiendo estas transmisiones mientras se ejecuta la aplicación.
</p>
<h3 id="sched-jobs">
Programación de trabajos en red en conexiones sin medición de uso
</h3>
<p>
Cuando uses la clase {@link android.app.job.JobInfo.Builder JobInfo.Builder}
para crear tu objeto {@link android.app.job.JobInfo}, aplica el método {@link
android.app.job.JobInfo.Builder#setRequiredNetworkType
setRequiredNetworkType()} y pasa {@link android.app.job.JobInfo
JobInfo.NETWORK_TYPE_UNMETERED} como parámetro de trabajo. El siguiente ejemplo de código
programa la ejecución de un servicio cuando el dispositivo se conecta a una red sin
medición de uso y se está cargando:
</p>
<pre>
public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
JobScheduler js =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(
MY_BACKGROUND_JOB,
new ComponentName(context, MyJobService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresCharging(true)
.build();
js.schedule(job);
}
</pre>
<p>
Cuando se cumplan las condiciones para tu trabajo, tu aplicación recibirá un callback para ejecutar
el método {@link android.app.job.JobService#onStartJob onStartJob()} en la
{@code JobService.class} especificada. Para ver más ejemplos de la implementación de {@link
android.app.job.JobScheduler}, consulta la <a href="{@docRoot}samples/JobScheduler/index.html">aplicación de ejemplo JobScheduler</a>.
</p>
<p>
Las aplicaciones que usan servicios de GMSCore y están orientadas a Android 5.0 (API nivel 21)
o anterior, pueden usar <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
{@code GcmNetworkManager}</a> y especificar {@code Task.NETWORK_STATE_UNMETERED}.
</p>
<h3 id="monitor-conn">
Control de la conectividad de la red mientras la aplicación se está ejecutando
</h3>
<p>
Las aplicaciones que se ejecutan aún pueden escuchar {@code CONNECTIVITY_CHANGE} con un
{@link android.content.BroadcastReceiver} registrado. No obstante, la API {@link
android.net.ConnectivityManager} ofrece un método más robusto para solicitar
un callback solo cuando se cumplen las condiciones de red especificadas.
</p>
<p>
Los objetos {@link android.net.NetworkRequest} definen los parámetros del
callback de la red en términos de {@link android.net.NetworkCapabilities}. Creas
objetos {@link android.net.NetworkRequest} con la clase {@link
android.net.NetworkRequest.Builder NetworkRequest.Builder}. {@link
android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
y luego pasa el objeto {@link android.net.NetworkRequest} al sistema. Cuando
se cumplen las condiciones de la red, la aplicación recibe un callback para ejecutar el método
{@link android.net.ConnectivityManager.NetworkCallback#onAvailable
onAvailable()} definido en su clase {@link
android.net.ConnectivityManager.NetworkCallback}.
</p>
<p>
La aplicación continuará recibiendo callbacks hasta que la aplicación salga o llame a
{@link android.net.ConnectivityManager#unregisterNetworkCallback
unregisterNetworkCallback()}.
</p>
<h2 id="media-broadcasts">
Restricciones en NEW_PICTURE y NEW_VIDEO
</h2>
<p>
En Android N, las aplicaciones no pueden enviar ni recibir transmisiones {@link
android.hardware.Camera#ACTION_NEW_PICTURE} ni {@link
android.hardware.Camera#ACTION_NEW_VIDEO}. Esta restricción ayuda a
aliviar el impacto en el rendimiento y la experiencia de usuario cuando varias aplicaciones deben
activarse para procesar una nueva imagen o video. Android N
extiende {@link android.app.job.JobInfo} y {@link
android.app.job.JobParameters} para proporcionar una solución alternativa.
</p>
<h3 id="new-jobinfo">
Nuevos métodos de JobInfo
</h3>
<p>
Para activar trabajos en los cambios del URI de contenido, Android N extiende
la API {@link android.app.job.JobInfo} con los siguientes métodos:
</p>
<dl>
<dt>
{@code JobInfo.TriggerContentUri()}
</dt>
<dd>
Encapsula parámetros necesarios para activar un trabajo en cambios del URI de contenido.
</dd>
<dt>
{@code JobInfo.Builder.addTriggerContentUri()}
</dt>
<dd>
Pasa un objeto {@code TriggerContentUri} a {@link
android.app.job.JobInfo}. Un {@link android.database.ContentObserver}
controla el URI de contenido encapsulado. Si hay múltiples objetos {@code
TriggerContentUri} asociados a un trabajo, el sistema proporciona un
callback aunque se informe un cambio en un solo URI de contenido.
</dd>
<dd>
Si cambia algún desencadenante del URI determinado, agrega el marcador {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} para
activar el trabajo. Este marcador
corresponde al parámetro {@code notifyForDescendants} pasado a {@link
android.content.ContentResolver#registerContentObserver
registerContentObserver()}.
</dd>
</dl>
<p class="note">
<strong>Nota:</strong> No se puede usar {@code TriggerContentUri()} junto
con {@link android.app.job.JobInfo.Builder#setPeriodic
setPeriodic()} ni {@link android.app.job.JobInfo.Builder#setPersisted
setPersisted()}. Para controlar de forma constante la presencia de cambios en el contenido, programa un nuevo
{@link android.app.job.JobInfo} antes de que el {@link
android.app.job.JobService} de la aplicación termine de administrar la callback más reciente.
</p>
<p>
El siguiente código de ejemplo programa la activación de un trabajo cuando el sistema informe
un cambio en el URI de contenido, {@code MEDIA_URI}:
</p>
<pre>
public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
JobScheduler js =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(
MY_BACKGROUND_JOB,
new ComponentName(context, MediaContentJob.class));
builder.addTriggerContentUri(
new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
js.schedule(builder.build());
}
</pre>
<p>
Cuando el sistema informa un cambio en el(los) URI de contenido especificado(s), tu aplicación
recibe un callback y se pasa un objeto {@link android.app.job.JobParameters}
al método {@link android.app.job.JobService#onStartJob onStartJob()}
en {@code MediaContentJob.class}.
</p>
<h3 id="new-jobparam">
Nuevos métodos de JobParameter
</h3>
<p>
Android N también amplía {@link android.app.job.JobParameters} para
permitir que tu aplicación reciba información útil sobre qué autoridades de contenido
y URI activaron el trabajo:
</p>
<dl>
<dt>
{@code Uri[] getTriggeredContentUris()}
</dt>
<dd>
Devuelve el arreglo de los URI que activaron el trabajo. Ese arreglo será {@code
null} si ningún URI activó el trabajo (por ejemplo, el trabajo
se activó debido al cumplimiento de un plazo o por otro motivo), o la cantidad de URI
modificados es superior a 50.
</dd>
<dt>
{@code String[] getTriggeredContentAuthorities()}
</dt>
<dd>
Devuelve el arreglo de cadenas de autoridades de contenido que activaron el trabajo.
Si el arreglo devuelto no es {@code null}, usa {@code getTriggeredContentUris()}
para recuperar los detalles de los URI que se modificaron.
</dd>
</dl>
<p>
El siguiente código de ejemplo anula el método {@link
android.app.job.JobService#onStartJob JobService.onStartJob()} y
registra las autoridades de contenido y los URI que activaron el trabajo:
</p>
<pre>
&#64;Override
public boolean onStartJob(JobParameters params) {
StringBuilder sb = new StringBuilder();
sb.append("Media content has changed:\n");
if (params.getTriggeredContentAuthorities() != null) {
sb.append("Authorities: ");
boolean first = true;
for (String auth :
params.getTriggeredContentAuthorities()) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(auth);
}
if (params.getTriggeredContentUris() != null) {
for (Uri uri : params.getTriggeredContentUris()) {
sb.append("\n");
sb.append(uri);
}
}
} else {
sb.append("(No content)");
}
Log.i(TAG, sb.toString());
return true;
}
</pre>
<h2 id="further-optimization">
Cómo optimizar aún más tu aplicación
</h2>
<p>
Optimizar tus aplicaciones para que se ejecuten en dispositivos con poca memoria o en condiciones de niveles bajos
de memoria puede mejorar el rendimiento y la experiencia del usuario. Eliminar
dependencias en servicios en segundo plano y receptores de transmisiones implícitas
registrados estadísticamente puede ayudar a que tu aplicación se ejecute mejor en esos dispositivos. Si bien
Android N toma medidas para reducir algunos de estos problemas, te
recomendamos que optimices tu aplicación para que pueda ejecutarse sin utilizar esos
procesos en segundo plano.
</p>
<p>
Android N presenta algunos comandos adicionales de <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> que
puedes usar para probar el comportamiento de la aplicación con esos procesos en segundo plano deshabilitados:
</p>
<ul>
<li>Para simular condiciones en las que no hay transmisiones implícitas ni servicios en segundo plano
disponibles, ingresa el siguiente comando:
</li>
<li style="list-style: none; display: inline">
<pre class="no-pretty-print">
{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND ignore}
</pre>
</li>
<li>Para volver a habilitar las transmisiones implícitas y los servicios en segundo plano, ingresa el
siguiente comando:
</li>
<li style="list-style: none; display: inline">
<pre class="no-pretty-print">
{@code $ adb shell cmd appops set &lt;package&gt; RUN_IN_BACKGROUND allow}
</pre>
</li>
</ul>