diff options
Diffstat (limited to 'docs')
49 files changed, 6605 insertions, 0 deletions
diff --git a/docs/html-intl/es/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/es/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..08a42dd --- /dev/null +++ b/docs/html-intl/es/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=Cómo controlar el nivel de batería y el estado de carga +parent.title=Cómo optimizar la duración de la batería +parent.link=index.html + +trainingnavtop=true +next.title=Cómo determinar y controlar el tipo de conector y el estado de la conexión +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#DetermineChargeState">Cómo determinar el estado de carga actual</a></li> + <li><a href="#MonitorChargeState">Cómo supervisar los cambios en el estado de carga</a></li> + <li><a href="#CurrentLevel">Cómo determinar el nivel de batería actual</a></li> + <li><a href="#MonitorLevel">Cómo supervisar cambios importantes en el nivel de batería</a></li> +</ol> + +<h2>También puedes consultar:</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Intentos y filtros de intentos</a> +</ul> + +</div> +</div> + +<p>Al modificar la frecuencia de las actualizaciones en segundo plano para reducir el efecto de las mismas en la duración de la batería, te recomendamos que comiences por comprobar el estado de carga y el nivel actual de la batería.</p> + +<p>El impacto derivado de actualizar aplicaciones en la duración de la batería varía en función del nivel de batería y del estado de carga del dispositivo, mientras que es insignificante cuando este está conectado a la corriente. Por ello, en la mayoría de los casos, puedes maximizar la frecuencia de actualización cuando el dispositivo esté conectado a un cargador. Por el contrario, si el dispositivo está en proceso de descarga, disminuir la frecuencia de actualización te permitirá aumentar la duración de la batería.</p> + +<p>Del mismo modo, puedes comprobar el nivel de carga de la batería y reducir la frecuencia de las actualizaciones o incluso detenerlas cuando la batería esté a punto de agotarse.</p> + + +<h2 id="DetermineChargeState">Cómo determinar el estado de carga actual</h2> + +<p>En primer lugar, te recomendamos que determines el estado de carga actual. {@link android.os.BatteryManager} envía los detalles de carga y de la batería en un {@link android.content.Intent} persistente que incluye el estado de carga.</p> + +<p>Se trata de un intento persistente, por lo que no es necesario registrar un {@link android.content.BroadcastReceiver}. Para ello, solo tienes que ejecutar {@code registerReceiver} transmitiendo {@code null} como el receptor (como se muestra en el siguiente fragmento). A continuación, se devuelve el intento de estado actual de la batería. Puedes transmitir un objeto {@link android.content.BroadcastReceiver} real, pero hablaremos sobre las actualizaciones en otra sección, por lo que no es necesario ahora.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Puedes extraer el estado de carga actual y, si el dispositivo está cargando, puedes saber también si se está usando un cargador de corriente alterna o USB:<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>Normalmente, debes maximizar la frecuencia de las actualizaciones en segundo plano si el dispositivo está conectado a un cargador de corriente alterna, disminuir esa frecuencia si se utiliza un cargador USB y reducirla aún más si la batería se está descargando.</p> + + +<h2 id="MonitorChargeState">Cómo supervisar los cambios en el estado de carga</h2> + +<p>Modificar el estado de carga es tan fácil como conectar el dispositivo a un enchufe o USB. Por ello, es importante que supervises el estado de carga por si se producen cambios y modifiques la frecuencia de actualización según corresponda.</p> + +<p>{@link android.os.BatteryManager} emite una acción siempre que el dispositivo se conecta o desconecta de la corriente. Es importante recibir estos eventos aunque la aplicación no esté en ejecución (especialmente porque estos eventos pueden afectar a la frecuencia con la que inicias tu aplicación para actualizarla en segundo plano), por lo que debes registrar un {@link android.content.BroadcastReceiver} en tu archivo de manifiesto para detectar ambos eventos definiendo {@link android.content.Intent#ACTION_POWER_CONNECTED} y {@link android.content.Intent#ACTION_POWER_DISCONNECTED} en un filtro de intentos.</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>En la implementación de {@link android.content.BroadcastReceiver} asociada, puedes extraer el método y el estado de carga actual como se describe en el paso anterior.</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">Cómo determinar el nivel de batería actual</h2> + +<p>En algunos casos, también es útil determinar el nivel de batería actual. Puedes disminuir la frecuencia de las actualizaciones en segundo plano si el nivel de carga de la batería es inferior a un valor determinado.</p> + +<p>Puedes consultar la carga actual de la batería extrayendo el nivel actual de la batería y subir a partir del intento de estado de batería, como se muestra a continuación:</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">Cómo supervisar cambios importantes en el nivel de batería</h2> + +<p>No puedes controlar el estado de la batería de forma continua fácilmente, pero tampoco es necesario.</p> + +<p>En términos generales, el impacto sobre la batería derivado de controlar continuamente el nivel de batería es mayor que el comportamiento habitual de la aplicación. Por ello, te recomendamos que supervises únicamente los cambios en el nivel de batería más significativos, especialmente cuando el dispositivo tenga poca batería o acabe de cargarse.</p> + +<p>El fragmento de manifiesto que aparece a continuación se ha extraído del elemento de filtro de intento de un receptor de emisión. El receptor detecta {@link android.content.Intent#ACTION_BATTERY_LOW} y {@link android.content.Intent#ACTION_BATTERY_OKAY} y se activa cuando el nivel de batería del dispositivo es bajo o cuando se sale de un estado bajo de batería.</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>Cuando la batería esté a punto de agotarse, te recomendamos que inhabilites las actualizaciones en segundo plano. Si el teléfono se apaga antes de poder utilizar las aplicaciones, no importa que tengan los datos actualizados.</p> + +<p>En muchos casos, el hecho de cargar un dispositivo coincide con la acción de utilizar un conector. En la próxima sección, hablaremos sobre cómo determinar el estado de conexión actual y cómo supervisar los cambios que se produzcan al conectar el dispositivo.</p> + diff --git a/docs/html-intl/es/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/es/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..2a5ff12 --- /dev/null +++ b/docs/html-intl/es/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=Cómo determinar y controlar el estado de la conectividad +parent.title=Cómo optimizar la duración de la batería +parent.link=index.html + +trainingnavtop=true + +previous.title=Cómo determinar y controlar el tipo de conector y el estado de la conexión +previous.link=docking-monitoring.html +next.title=Cómo manipular los receptores de emisión bajo demanda +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#DetermineConnection">Cómo determinar si tienes conexión a Internet</a></li> + <li><a href="#DetermineType">Cómo determinar el tipo de conexión a Internet</a></li> + <li><a href="#MonitorChanges">Cómo supervisar los cambios en la conectividad</a></li> +</ol> + + +<h2>También puedes consultar:</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Intentos y filtros de intentos</a> +</ul> + +</div> +</div> + +<p>Algunos de los usos más comunes para las alarmas con repetición y los servicios en segundo plano es programar actualizaciones regulares de los datos de aplicaciones a partir de recursos de Internet, almacenar datos en la memoria caché o ejecutar descargas a largo plazo. Sin embargo, si no estás conectado a Internet o la conexión es demasiado débil para completar la descarga, ¿para qué activar el dispositivo y programar la actualización?</p> + +<p>Puedes utilizar {@link android.net.ConnectivityManager} para comprobar si estás conectado a Internet y, en ese caso, el tipo de conexión que estás utilizando.</p> + + +<h2 id="DetermineConnection">Cómo determinar si tienes conexión a Internet</h2> + +<p>No es necesario programar una actualización basada en un recurso de Internet si no estás conectado. En el fragmento que aparece a continuación, se muestra cómo utilizar {@link android.net.ConnectivityManager} para consultar la red activa y determinar si hay conexión a Internet.</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">Cómo determinar el tipo de conexión a Internet</h2> + +<p>También puedes determinar el tipo de conexión a Internet que hay disponible.</p> + +<p>El dispositivo se puede conectar a Internet a través de conexiones Ethernet, Wi-Fi, WiMAX y de datos móviles. Al consultar el tipo de red activa, como se muestra a continuación, puedes modificar la frecuencia de actualización en función del ancho de banda disponible.</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>El coste de las conexiones de datos móviles suele ser superior al de las conexiones Wi-Fi, por lo que en la mayoría de los casos, la frecuencia de actualización de tu aplicación debería ser menor si utilizas conexiones móviles. Del mismo modo, las descargas grandes deberían cancelarse hasta que estés conectado a una red Wi-Fi.</p> + +<p>Cuando hayas inhabilitado las actualizaciones, es importante que detectes si se hay cambios en la conectividad para poder reanudarlas cuando se haya establecido una conexión a Internet.</p> + + +<h2 id="MonitorChanges">Cómo supervisar los cambios en la conectividad</h2> + +<p>{@link android.net.ConnectivityManager} emite la acción {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code "android.net.conn.CONNECTIVITY_CHANGE"}) cuando se han modificado los detalles de la conectividad. Puedes registrar un receptor de emisión en el archivo de manifiesto para detectar estos cambios y reanudar (o cancelar) las actualizaciones en segundo plano según corresponda.</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>Los cambios en la conectividad de un dispositivo pueden ser muy frecuentes (esta emisión se activa siempre que cambias de una conexión de datos móviles a una conexión Wi-Fi). Como resultado, te recomendamos que supervises esta emisión únicamente cuando hayas cancelado anteriormente las actualizaciones o las descargas para reanudarlas. Normalmente, basta con comprobar la conexión a Internet antes de iniciar una actualización y, si no hay ninguna, cancelar el resto de actualizaciones hasta que se restablezca la conexión.</p> + +<p>Esta técnica requiere que alternes receptores de emisión que hayas declarado en el archivo de manifiesto, que se describe en la próxima sección.</p> diff --git a/docs/html-intl/es/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/es/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..d612281 --- /dev/null +++ b/docs/html-intl/es/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=Cómo determinar y controlar el tipo de conector y el estado de la conexión +parent.title=Cómo optimizar la duración de la batería +parent.link=index.html + +trainingnavtop=true +previous.title=Cómo controlar el nivel de batería y el estado de carga +previous.link=battery-monitoring.html +next.title=Cómo determinar y controlar el estado de la conectividad +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#CurrentDockState">Cómo solicitar el foco de audio</a></li> + <li><a href="#DockType">Cómo determinar el tipo de conector actual</a></li> + <li><a href="#MonitorDockState">Cómo supervisar los cambios en el tipo de conector o en el estado del mismo</a></li> +</ol> + + +<h2>También puedes consultar:</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Intentos y filtros de intentos</a> +</ul> + +</div> +</div> + +<p>Los dispositivos Android se pueden conectar a distintos tipos de conectores. Por ejemplo, se puede utilizar conectores para coche o domésticos y tanto digitales como analógicos. Normalmente, el estado del conector está vinculado al estado de carga, ya que muchos conectores cargan el dispositivo mientras está conectado.</p> + +<p>El modo en el que el estado del conector del teléfono afecta a la frecuencia de actualización depende de tu aplicación. Puedes aumentar la frecuencia de actualización de una aplicación sobre noticias cuando el dispositivo esté conectado a un conector de escritorio o inhabilitar las actualizaciones completamente si está conectado a un conector de coche. Por el contrario, puedes maximizar las actualizaciones si el dispositivo está conectado a un conector de coche y tu servicio en segundo plano se actualiza con el estado del tráfico.</p> + +<p>El estado del conector se emite también como un {@link android.content.Intent} persistente, lo que te permite consultar si el dispositivo está conectado o no y, si lo está, determinar el tipo de conector.</p> + + +<h2 id="CurrentDockState">Cómo determinar el estado de conexión actual</h2> + +<p>La información sobre el estado del conector se incluye como información adicional en una emisión persistente de la acción {@link android.content.Intent#ACTION_DOCK_EVENT}. Por ello, no es necesario registrar un {@link android.content.BroadcastReceiver}. Solo tienes que ejecutar {@link android.content.Context#registerReceiver registerReceiver()} transmitiendo {@code null} como el receptor de emisión, como se muestra en el fragmento de código que aparece a continuación.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Puedes extraer el estado actual de la conexión de la información adicional de {@code EXTRA_DOCK_STATE}:<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">Cómo determinar el tipo de conector actual</h2> + +<p>Si un dispositivo está insertado en un conector, se puede conectar a cualquiera de estos cuatro tipos de conectores: +<ul><li>coche,</li> +<li>escritorio,</li> +<li>escritorio de gama baja (analógico),</li> +<li>escritorio de gama alta (digital).</li></ul></p> + +<p>Ten en cuenta que las últimas dos opciones se introdujeron en Android únicamente en el nivel 11 del API. Por ello, te recomendamos que compruebes las tres opciones solo cuando te interese más el tipo de conector que si se trata de un conector digital o analógico:</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">Cómo supervisar los cambios en el tipo de conector o en el estado del mismo</h2> + +<p>Cuando el dispositivo está conectado a un conector o desconectado del mismo, se emite la acción {@link android.content.Intent#ACTION_DOCK_EVENT}. Para controlar los cambios que se produzcan en el estado del conector del dispositivo, solo tienes que registrar un receptor de emisión en el archivo de manifiesto de la aplicación, como se muestra en el fragmento que aparece a continuación:</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>Puedes extraer el estado y el tipo de conector en la implementación del receptor con las mismas técnicas que se han descrito en el paso anterior.</p> diff --git a/docs/html-intl/es/training/monitoring-device-state/index.jd b/docs/html-intl/es/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..bf6b1c1 --- /dev/null +++ b/docs/html-intl/es/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=Cómo optimizar la duración de la batería + +trainingnavtop=true +startpage=true +next.title=Cómo controlar el nivel de batería y el estado de carga +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Dependencias y requisitos previos</h2> +<ul> + <li>Android 2.0 (nivel 5 del API) o superior</li> + <li>Experiencia con <a href="{@docRoot}guide/components/intents-filters.html">Intentos y filtros de intentos</a></li> +</ul> + +<h2>También puedes consultar:</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">Servicios</a> +</ul> + +</div> +</div> + +<p>Uno de los objetivos de tu aplicación debe ser limitar su impacto en la duración de la batería del dispositivo en el que esté instalada. Después de leer estas secciones, podrás desarrollar aplicaciones que optimizarán el uso de la batería en función del estado del dispositivo en el que estén instaladas.</p> + +<p>Al tomar medidas como inhabilitar las actualizaciones de servicios en segundo plano o disminuir la frecuencia de dichas actualizaciones cuando el nivel de batería sea bajo, puedes garantizar que se minimice el impacto de tu aplicación en la duración de la batería sin afectar a la experiencia del usuario.</p> + +<h2>Secciones</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">Cómo controlar el nivel de batería y el estado de carga</a></b></dt> + <dd>Obtén más información sobre cómo determinar y controlar el nivel de batería actual y los cambios en el estado de carga para modificar la frecuencia de actualizaciones en segundo plano de tu aplicación.</dd> + + <dt><b><a href="docking-monitoring.html">Cómo determinar y controlar el tipo de conector y el estado de la conexión</a></b></dt> + <dd>La frecuencia de actualización óptima puede variar en función de cómo se utilice el dispositivo en el que está instalada la aplicación. Obtén más información sobre cómo determinar y controlar cuándo el dispositivo está conectado a algún sistema de acoplamiento u otra conexión.</dd> + + <dt><b><a href="connectivity-monitoring.html">Cómo determinar y controlar el estado de la conectividad</a></b></dt> + <dd>Si no tienes conexión a Internet, no puedes actualizar tu aplicación a partir de una fuente online. Obtén más información sobre cómo comprobar el estado de la conectividad para modificar la frecuencia de actualización en segundo plano de tu aplicación. También puedes obtener más información sobre cómo comprobar la conectividad móvil o Wi-Fi antes de iniciar operaciones que requieran un nivel elevado de ancho de banda.</dd> + + <dt><b><a href="manifest-receivers.html">Cómo manipular los receptores de emisión bajo demanda</a></b></dt> + <dd>Los receptores de emisión que declaras en el archivo de manifiesto se pueden alternar durante la ejecución para inhabilitar los que no son necesarios debido al estado actual del dispositivo. Obtén más información sobre cómo alternar y superponer receptores de cambio de estado para mejorar el rendimiento y cómo posponer acciones hasta que el dispositivo se encuentre en un estado concreto.</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/es/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/es/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..a90468e --- /dev/null +++ b/docs/html-intl/es/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=Cómo manipular los receptores de emisión bajo demanda +parent.title=Cómo optimizar la duración de la batería +parent.link=index.html + +trainingnavtop=true + +previous.title=Cómo determinar y controlar el estado de la conectividad +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#ToggleReceivers">Cómo alternar y superponer receptores de cambio de estado para mejorar el rendimiento</a></li> +</ol> + + +<h2>También puedes consultar:</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Intentos y filtros de intentos</a> +</ul> + +</div> +</div> + +<p>La forma más sencilla de controlar los cambios en el estado del dispositivo es crear un {@link android.content.BroadcastReceiver} para cada estado que vayas a controlar y registrar cada uno de ellos en el archivo de manifiesto de tu aplicación. A continuación, en cada uno de esos receptores solo tienes que volver a programar las alarmas recurrentes en función del estado actual del dispositivo.</p> + +<p>Un efecto secundario de este método es que tu aplicación activará el dispositivo siempre que uno de los receptores se active (probablemente, con más frecuencia de la necesaria).</p> + +<p>Te recomendamos que inhabilites o habilites los receptores de emisión en el momento de la ejecución. De este modo, puedes utilizar los receptores que hayas declarado en el archivo de manifiesto como alarmas pasivas que se activan mediante los eventos del sistema solo cuando es necesario.</p> + + +<h2 id="ToggleReceivers">Cómo alternar y superponer receptores de cambio de estado para mejorar el rendimiento </h2> + +<p>Se puede utilizar el {@link android.content.pm.PackageManager} para alternar el estado habilitado en cualquier componente definido en el archivo de manifiesto, incluidos los receptores de emisión que quieras habilitar o inhabilitar, como se muestra en el fragmento que aparece a continuación:</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>Al utilizar esta técnica, si determinas que la conectividad se ha perdido, puedes inhabilitar todos los receptores excepto el receptor de cambio de conectividad. Por el contrario, cuando estés conectado, puedes dejar de detectar cambios de conectividad y solo comprobar si tienes conexión antes de realizar una actualización y de volver a programar una alarma de actualización recurrente.</p> + +<p>Puedes utilizar la misma técnica para posponer una descarga que requiera un nivel de ancho de banda superior para completarse. Solo tienes que habilitar un receptor de emisión que detecte los cambios de conectividad y que inicie la descarga solo cuando estés conectado a una red Wi-Fi.</p> diff --git a/docs/html-intl/es/training/multiscreen/adaptui.jd b/docs/html-intl/es/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..61f0735 --- /dev/null +++ b/docs/html-intl/es/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=Cómo implementar interfaces de usuario adaptables +parent.title=Cómo diseñar aplicaciones para varias pantallas +parent.link=index.html + +trainingnavtop=true +previous.title=Cómo admitir varias densidades de pantalla +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">Cómo determinar el diseño actual</a></li> + <li><a href="#TaskReactToLayout">Cómo reaccionar en función del diseño actual</a></li> + <li><a href="#TaskReuseFrag">Cómo volver a utilizar fragmentos en otras actividades</a></li> + <li><a href="#TaskHandleConfigChanges">Cómo gestionar los cambios en la configuración de la pantalla</a></li> +</ol> + +<h2>También puedes consultar:</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Cómo admitir tablets y dispositivos móviles</a></li> +</ul> + +<h2>¡Pruébalo!</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Descargar la aplicación de ejemplo</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>En función del diseño actual de tu aplicación, la interfaz puede variar. Por ejemplo, si tu aplicación está en modo de panel dual, haz clic en un elemento del panel izquierdo para que aparezca en el panel de la derecha. Asimismo, si está en modo de panel único, el contenido debería aparecer por sí mismo (en otra actividad).</p> + + +<h2 id="TaskDetermineCurLayout">Cómo determinar el diseño actual</h2> + +<p>Dado que la implementación de cada diseño variará en cierta medida, probablemente una de las primeras cosas que tendrás que hacer será determinar el diseño que el usuario puede ver en ese momento. Por ejemplo, puedes determinar si el usuario utiliza el modo de "panel único" o de "panel dual". Para ello, puedes consultar si una vista determinada existe y es visible:</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>Ten en cuenta que este código consulta la disponibilidad del panel del "artículo", lo que es mucho más flexible que incluir una consulta para un diseño determinado.</p> + +<p>Otro ejemplo de cómo puedes adaptar la existencia de diferentes componentes es comprobar su disponibilidad antes de realizar una operación relacionada con los mismos. Por ejemplo, en la aplicación de ejemplo News Reader, hay un botón que abre un menú, pero ese botón solo aparece en las versiones anteriores a Android 3.0 (porque <PH>{@link android.app.ActionBar}</PH> en el nivel 11 del API y en niveles superiores). Por tanto, para añadir el detector de eventos para este botón, puedes hacer lo siguiente:</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">Cómo reaccionar en función del diseño actual</h2> + +<p>El resultado de algunas acciones puede variar en función del diseño actual. Por ejemplo, en el ejemplo de News Reader, al hacer clic en un encabezado de la lista se abrirá el artículo del panel situado a la derecha si la interfaz de usuario está en modo de panel dual, pero se iniciará una actividad independiente si esta está en modo de panel único:</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>De igual modo, si la aplicación está en modo de panel dual, debe configurar la barra de acción con pestañas para la navegación, mientras que si la aplicación está en modo de panel único, debe configurar la navegación con un widget giratorio. Por tanto, el código debe comprobar también cuál es el caso adecuado:</p> + +<pre> +final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">Cómo volver a utilizar fragmentos en otras actividades</h2> + +<p>Un patrón recurrente a la hora de diseñar para distintas pantallas es utilizar una parte de la interfaz que se implementa como un panel en algunas configuraciones de pantalla y como actividad independiente en otras. Por ejemplo, en el ejemplo de News Reader, el texto del artículo de noticias se presenta en el panel de la derecha en las pantallas grandes, pero es una actividad independiente en las pantallas más pequeñas.</p> + +<p>En otros casos similares, puedes evitar la duplicación de código reutilizando la misma <PH>{@link android.app.Fragment}</PH> en distintas actividades. Por ejemplo, <code>ArticleFragment</code> se utiliza en el diseño de panel dual:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>A continuación, se vuelve a utilizar (sin diseño) en el diseño de actividad para pantallas más pequeñas (<code>ArticleActivity</code>):</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>Evidentemente, esto tiene el mismo efecto que declarar el fragmento en un diseño XML. Sin embargo, en este caso, un diseño XML sería un trabajo innecesario porque el fragmento del artículo es el único componente de esta actividad.</p> + +<p>Un punto muy importante que debes tener en cuenta al diseñar tus fragmentos es no crear un acoplamiento fuerte para una actividad determinada. Para ello, normalmente puedes definir una interfaz que resuma todas las formas en las que tiene que interactuar el fragmento con su actividad principal y, a continuación, la actividad principal implementa esa interfaz:</p> + +<p>Por ejemplo, ese es precisamente el objetivo del <code>HeadlinesFragment</code> de la aplicación News Reader:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>A continuación, cuando el usuario selecciona un encabezado, el fragmento notifica el detector especificado por la actividad principal (en lugar de notificar una actividad predefinida específica):</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p>Si quieres obtener más información sobre esta técnica, puedes consultar la guía sobre <a +href="{@docRoot}guide/practices/tablets-and-handsets.html">Cómo admitir tablets y dispositivos móviles</a>.</p> + + +<h2 id="TaskHandleConfigChanges">Cómo gestionar los cambios en la configuración de la pantalla</h2> + +<p>Si utilizas actividades independientes para implementar partes individuales de tu interfaz, debes tener en cuenta que es posible que tengas que reaccionar ante determinados cambios en la configuración (como un cambio de rotación) para mantener la homogeneidad de tu interfaz.</p> + +<p>Por ejemplo, en un tablet de 7" que utilice Android 3.0 o una versión superior, el ejemplo de News Reader utiliza una actividad independiente para mostrar el artículo de noticias en el modo vertical, pero utiliza el diseño de panel dual en el modo horizontal.</p> + +<p>Esto significa que cuando el usuario utiliza el modo vertical y está consultando un artículo, tienes que detectar que la orientación ha cambiado al modo horizontal y reaccionar de forma adecuada finalizando la actividad. A continuación, debes volver a la actividad principal para que el contenido pueda mostrarse en el diseño de panel dual:</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/es/training/multiscreen/index.jd b/docs/html-intl/es/training/multiscreen/index.jd new file mode 100644 index 0000000..0a1461b --- /dev/null +++ b/docs/html-intl/es/training/multiscreen/index.jd @@ -0,0 +1,63 @@ +page.title=Cómo diseñar aplicaciones para varias pantallas +trainingnavtop=true +startpage=true +next.title=Cómo admitir varios tamaños de pantalla +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Dependencias y requisitos previos</h2> + +<ul> + <li>Android 1.6 o superior (Android 2.1 o superior para la aplicación de ejemplo)</li> + <li>Conocimiento básico de <a +href="http://developer.android.com/guide/components/activities.html">Actividades</a> y <a href="http://developer.android.com/guide/components/fragments.html">Fragmentos</a></li> + <li>Experiencia en el desarrollo de una <a +href="http://developer.android.com/guide/topics/ui/index.html">Interfaz de usuario</a> de Android</li> + <li>Algunas funciones requieren el uso de la <a +href="{@docRoot}tools/extras/support-library.html">biblioteca de compatibilidad</a></li> +</ul> + +<h2>También puedes consultar:</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Cómo admitir varias pantallas</a></li> +</ul> + +<h2>¡Pruébalo!</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Descargar la aplicación de ejemplo</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>Android se utiliza en cientos de dispositivos con diferentes tamaños de pantalla, desde pequeños teléfonos hasta enormes televisores. Por ello, es importante que diseñes tu aplicación para que sea compatible con todos los tamaños de pantalla y esté disponible para el mayor número de usuarios posible.</p> + +<p>Sin embargo, no es suficiente con que tu aplicación sea compatible con diferentes dispositivos. Cada tamaño de pantalla ofrece diferentes posibilidades y retos para la interacción del usuario. Por ello, para satisfacer completamente a tus usuarios e impresionarlos, tu aplicación debe ir más allá de simplemente <em>admitir</em> varias pantallas: debe <em>optimizar</em> la experiencia de usuario para cada configuración de pantalla.</p> + +<p>En esta sección se explica cómo implementar una interfaz de usuario que esté optimizada para diferentes configuraciones de pantalla.</p> + +<p>El código que aparece en cada sección se ha extraído de una aplicación de ejemplo para explicar las prácticas recomendadas a la hora de optimizar tu aplicación para varias pantallas. Puedes descargar el ejemplo (situado a la derecha) y utilizarlo como fuente de código reutilizable para tu propia aplicación.</p> + +<p class="note"><strong>Nota:</strong> en esta sección y en el ejemplo correspondiente, se utiliza la <a +href="{@docRoot}tools/extras/support-library.html">biblioteca de compatibilidad</a> para poder usar las API de <PH>{@link android.app.Fragment}</PH> en versiones anteriores a Android 3.0. Debes descargar y la biblioteca y añadirla a tu aplicación para poder utilizar todas las API que se indican en esta sección.</p> + + +<h2>Secciones</h2> + +<dl> + <dt><b><a href="screensizes.html">Cómo admitir varios tamaños de pantalla</a></b></dt> + <dd>En esta sección se explica cómo crear diseños que se adapten a diferentes tamaños de pantalla (mediante dimensiones flexibles para vistas, <PH>{@link android.widget.RelativeLayout}</PH>, calificadores de orientación y tamaño de pantalla, filtros de alias y mapas de bits de la clase NinePatch).</dd> + + <dt><b><a href="screendensities.html">Cómo admitir varias densidades de pantalla</a></b></dt> + <dd>En esta sección se explica cómo admitir pantallas con diferentes densidades de píxeles (mediante píxeles independientes de la densidad y mapas de bits adecuados a cada densidad).</dd> + + <dt><b><a href="adaptui.html">Cómo implementar interfaces de usuario adaptables</a></b></dt> + <dd>En esta sección se explica cómo implementar tu interfaz de usuario para que se adapte a varias combinaciones de densidad o de tamaño de pantalla (detección de tiempo de ejecución del diseño activo, cómo reaccionar en función del diseño actual y cómo administrar los cambios en la configuración de la pantalla).</dd> +</dl> diff --git a/docs/html-intl/es/training/multiscreen/screendensities.jd b/docs/html-intl/es/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..0edb89f --- /dev/null +++ b/docs/html-intl/es/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=Cómo admitir varias densidades de pantalla +parent.title=Cómo diseñar aplicaciones para varias pantallas +parent.link=index.html + +trainingnavtop=true +previous.title=Cómo admitir varios tamaños de pantalla +previous.link=screensizes.html +next.title=Cómo implementar interfaces de usuario adaptables +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#TaskUseDP">Cómo utilizar píxeles independientes de la densidad</a></li> + <li><a href="#TaskProvideAltBmp">Cómo proporcionar mapas de bits alternativos</a></li> +</ol> + +<h2>También puedes consultar:</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Cómo admitir varias pantallas</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Directrices para diseñar iconos</a></li> +</ul> + +<h2>¡Pruébalo!</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Descargar la aplicación de ejemplo</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>En esta sección se explica cómo proporcionar diferentes recursos y utilizar unidades de medida de resolución independiente para admitir diferentes densidades de pantalla.</p> + +<h2 id="TaskUseDP">Cómo utilizar píxeles independientes de la densidad</h2> + +<p>Un error común que debes evitar al crear tus diseños es utilizar píxeles absolutos para definir distancias o tamaños. Definir dimensiones de diseño mediante píxeles es problemático porque cada pantalla tiene densidades de píxeles diferentes, por lo que es posible que el mismo número de píxeles corresponda a varios tamaños físicos en distintos dispositivos. Por tanto, al especificar dimensiones, debes utilizar siempre unidades <code>dp</code> o <code>sp</code>. <code>dp</code> es un píxel independiente de la densidad que corresponde al tamaño físico de un píxel a 160 dpi. <code>sp</code> es la misma unidad de base, pero aumentada en función del tamaño de letra preferido por el usuario (se trata de un píxel independiente de la escala). Por tanto, debes utilizar esta unidad de medida para definir el tamaño de letra (pero no para tamaños de diseños).</p> + +<p>Por ejemplo, al especificar un espacio entre dos vistas, debes utilizar <code>dp</code> en lugar de <code>px</code>:</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>Al especificar el tamaño de letra, debes usar siempre <code>sp</code>:</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">Cómo proporcionar mapas de bits alternativos</h2> + +<p>Dado que Android se ejecuta en dispositivos con diferentes densidades de pantalla, siempre debes proporcionar tus recursos de mapas de bits adaptados a los conjuntos de densidades generalizados: baja, media, alta y muy alta. De este modo, podrás conseguir un rendimiento y una calidad gráfica óptimos en todas las densidades de pantalla.</p> + +<p>Para generar estas imágenes, debes empezar con tu recurso genérico en formato vectorial y generar las imágenes para cada densidad con la siguiente escala de tamaños:</p> + +<p><ul> + <li><code>xhdpi</code>: 2,0 + <li><code>hdpi</code>: 1,5 + <li><code>mdpi</code>: 1.0 (base) + <li><code>ldpi</code>: 0,75 +</ul></p> + +<p>Esto significa que si generas una imagen de 200 x 200 para dispositivos <code>xhdpi</code>, debes generar el mismo recurso en 150 x 150 para <code>hdpi</code>, en 100 x 100 para <code>mdpi</code> y, por último, una imagen de 75 x 75 para dispositivos <code>ldpi</code>.</p> + +<p>A continuación, sitúa los archivos de imagen generados en el subdirectorio adecuado en <code>res/</code> y el sistema seleccionará el archivo correspondiente automáticamente en función de la densidad de la pantalla del dispositivo en el que se esté ejecutando la aplicación:</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>Por tanto, cada vez que hagas referencia a <code>@drawable/awesomeimage</code>, el sistema seleccionará el mapa de bits adecuado en función de los puntos por pulgada de la pantalla.</p> + +<p>Para consultar más sugerencias y directrices sobre cómo crear recursos de iconos para tu aplicación, consulta la sección <a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Directrices para diseñar iconos</a>.</p> + diff --git a/docs/html-intl/es/training/multiscreen/screensizes.jd b/docs/html-intl/es/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..9a971d1 --- /dev/null +++ b/docs/html-intl/es/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=Cómo admitir varios tamaños de pantalla +parent.title=Cómo diseñar aplicaciones para varias pantallas +parent.link=index.html + +trainingnavtop=true +next.title=Cómo admitir varias densidades de pantalla +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>En esta sección puedes aprender:</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">Cómo utilizar los valores "wrap_content" y "match_parent"</a></li> + <li><a href="#TaskUseRelativeLayout">Cómo utilizar RelativeLayout</a></li> + <li><a href="#TaskUseSizeQuali">Cómo utilizar calificadores de tamaño</a></li> + <li><a href="#TaskUseSWQuali">Cómo utilizar el calificador de ancho más pequeño</a></li> + <li><a href="#TaskUseAliasFilters">Cómo utilizar alias de diseño</a></li> + <li><a href="#TaskUseOriQuali">Cómo utilizar calificadores de orientación</a></li> + <li><a href="#TaskUse9Patch">Cómo utilizar mapas de bits de la clase NinePatch</a></li> +</ol> + +<h2>También puedes consultar:</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Cómo admitir varias pantallas</a></li> +</ul> + +<h2>¡Pruébalo!</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Descargar la aplicación de ejemplo</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>En esta sección se explica cómo admitir varios tamaños de pantalla. Para ello, sigue estos pasos:</p> +<ul> + <li>Asegúrate de que el diseño se haya ajustado correctamente al tamaño de la pantalla.</li> + <li>Configura la pantalla con el diseño de interfaz adecuado.</li> + <li>Asegúrate de aplicar el diseño adecuado a la pantalla correspondiente.</li> + <li>Utiliza el mapa de bits con la escala adecuada.</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">Cómo utilizar los valores "wrap_content" y "match_parent"</h2> + +<p>Para garantizar que el diseño es flexible y que se adapta a varios tamaños de pantalla, debes utilizar los valores <code>"wrap_content"</code> y <code>"match_parent"</code> para la altura y el ancho de algunos componentes de la vista. Si utilizas <code>"wrap_content"</code>, el ancho o la altura de la vista se establece en el tamaño mínimo necesario para adaptar el contenido a esta vista, mientras que <code>"match_parent"</code> (también conocido como <code>"fill_parent"</code> antes del nivel 8 del API) provoca que el componente se amplíe hasta coincidir con el tamaño de la vista principal.</p> + +<p>Al utilizar los valores de tamaño <code>"wrap_content"</code> y <code>"match_parent"</code> en lugar de los tamaños predefinidos, las vistas pueden utilizar únicamente el espacio requerido para esa vista o ampliarse hasta rellenar el espacio disponible respectivamente. Por ejemplo:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>Observa cómo se utilizan en el ejemplo los valores <code>"wrap_content"</code> y <code>"match_parent"</code> para los tamaños de los componentes en lugar de dimensiones específicas. Esto permite que el diseño se adapte correctamente a diferentes tamaños y orientaciones de la pantalla.</p> + +<p>Por ejemplo, esta es la apariencia del diseño en modo horizontal y vertical. Ten en cuenta que los tamaños de los componentes se adaptan automáticamente a la altura y al ancho:</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>Figura 1.</strong> La aplicación de ejemplo News Reader en modo vertical (izquierda) y horizontal (derecha)</p> + + +<h2 id="TaskUseRelativeLayout">Cómo utilizar RelativeLayout</h2> + +<p>Puedes crear diseños de un cierto nivel de complejidad con instancias anidadas de <PH>{@link android.widget.LinearLayout}</PH> y combinaciones de los valores de tamaño <code>"wrap_content"</code> y <code>"match_parent"</code>. Sin embargo, <PH>{@link android.widget.LinearLayout}</PH> no te permite controlar con precisión las relaciones espaciales de las vistas secundarias; las vistas de <PH>{@link android.widget.LinearLayout}</PH> simplemente se alinean en paralelo. Si quieres orientar las vistas secundarias de una forma que no sea una línea recta, a menudo la mejor solución es utilizar <PH>{@link android.widget.RelativeLayout}</PH>que te permite especificar el diseño según las relaciones espaciales entre los componentes. Por ejemplo, puedes alinear una vista secundaria en el lateral izquierdo y otra vista en el lateral derecho de la pantalla.</p> + +<p>Por ejemplo:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>La figura 2 indica cómo se muestra este diseño en una pantalla QVGA.</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>Figura 2.</strong> Captura de pantalla de una pantalla QVGA (pantalla pequeña)</p> + +<p>La figura 3 indica cómo se muestra este diseño en una pantalla más grande.</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>Figura 3.</strong> Captura de pantalla de una pantalla WSVGA (pantalla grande)</p> + +<p>Ten en cuenta que aunque el tamaño de los componentes es diferente, las relaciones espaciales se mantienen según se ha especificado con <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH>.</p> + + +<h2 id="TaskUseSizeQuali">Cómo utilizar calificadores de tamaño</h2> + +<p>Hay mucha diferencia entre un diseño flexible y un diseño relativo como el que se ha utilizado en las secciones anteriores. Aunque ambos diseños se adaptan a diferentes pantalla estirando el espacio dentro de los componentes y alrededor de los mismos, puede que no ofrezcan la mejor experiencia de usuario para cada tamaño de pantalla. Por tanto, tu aplicación no solo debe implementar los diseños flexibles, sino que también debe ofrecer varios diseños alternativos para diferentes configuraciones de pantalla. Para ello, se utilizan <a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">calificadores de configuración</a>, que permiten que el tiempo de ejecución seleccione el recurso adecuado en función de la configuración actual del dispositivo (por ejemplo, un diseño diferente para diferentes tamaños de pantalla).</p> + +<p>Por ejemplo, muchas aplicaciones implementan el patrón de "panel dual" para pantallas grandes (la aplicación mostraría una lista de elementos en un panel y el contenido en otro panel). Aunque los tablets y las televisiones son lo suficientemente grandes como para que los dos paneles aparezcan simultáneamente en la pantalla, las pantallas de los teléfonos tienen que mostrarlos por separado. Para implementar estos diseños, puedes utilizar los siguientes archivos:</p> + +<ul> + <li><code>res/layout/main.xml</code>, diseño de panel único (predeterminado): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>, diseño de panel dual: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Observa el calificador <code>large</code> en el nombre de directorio del segundo diseño. Este diseño se seleccionará en dispositivos con pantallas clasificadas como grandes (por ejemplo, tablets de 7" y superiores). El otro diseño (sin calificadores) se seleccionará en el caso de dispositivos más pequeños.</p> + + +<h2 id="TaskUseSWQuali">Cómo utilizar el calificador de ancho mínimo</h2> + +<p>Una de las dificultades a las que se enfrentaron los desarrolladores con los dispositivos Android anteriores a la versión 3.2 fue el contenedor de tamaño de pantalla "grande". Algunos ejemplos de este tipo de dispositivo son el tablet Dell Streak, el tablet Galaxy Tab original y los tablets de 7" en general. Sin embargo, es posible que muchas aplicaciones quieran mostrar varios diseños para diferentes dispositivos de esta categoría (por ejemplo, para dispositivos de 5" y de 7"), aunque todos estos dispositivos se consideren de pantalla grande. Por esta razón, Android introdujo el calificador de "ancho mínimo" (entre otros) en Android 3.2.</p> + +<p>Este calificador te permite mostrar contenido en pantallas que tengan un ancho mínimo determinado en píxeles independientes de la densidad. Por ejemplo, el tablet típico de 7" tiene un ancho mínimo de 600 dp, por lo que si quieres que la interfaz de usuario sea de panel dual en esta pantalla (y una única lista en pantallas más pequeñas), puedes utilizar los mismos dos diseños de la sección anterior para los diseños de panel único y de panel dual, solo que en lugar de utilizar el calificador de tamaño <code>large</code>, debes utilizar <code>sw600dp</code> para indicar que el diseño de panel dual se utiliza con las pantallas cuyo ancho mínimo sea de 600 dp:</p> + +<ul> + <li><code>res/layout/main.xml</code>, diseño de panel único (predeterminado): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>, diseño de panel dual: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Esto significa que los dispositivos cuyo ancho mínimo sea igual o superior a 600 dp utilizarán el diseño <code>layout-sw600dp/main.xml</code> (panel dual), mientras que las pantallas más pequeñas utilizarán el diseño <code>layout/main.xml</code> (panel único).</p> + +<p>No obstante, esto no funcionará en los dispositivos anteriores a Android 3.2 porque no reconocen <code>sw600dp</code> como calificador de tamaño, por lo que también tendrás que seguir utilizando el calificador <code>large</code>. Por tanto, debes tener un archivo con el nombre <code>res/layout-large/main.xml</code> idéntico a <code>res/layout-sw600dp/main.xml</code>. En la siguiente sección, obtendrás información sobre una técnica que te permite evitar que se dupliquen los archivos de diseños.</p> + + +<h2 id="TaskUseAliasFilters">Cómo utilizar alias de diseño</h2> + +<p>El calificador de ancho mínimo solo está disponible en Android 3.2 o superior. Por tanto, tendrás que seguir utilizando los contenedores de tamaño abstractos (pequeño, normal, grande y extragrande) para que sean compatibles con versiones anteriores. Por ejemplo, si quieres que tu interfaz de usuario sea de panel único en teléfonos pero multipanel en tablets de 7", televisiones y otros dispositivos grandes, tendrás que utilizar los siguientes archivos:</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> diseño de panel único,</li> +<li><code>res/layout-large:</code> diseño multipanel,</li> +<li><code>res/layout-sw600dp:</code> diseño multipanel.</li> +</ul></p> + +<p>Los dos últimos archivos son idénticos porque uno de ellos se utilizará con dispositivos Android 3.2 y el otro con tablets y televisiones que utilicen versiones anteriores de Android.</p> + +<p>Para evitar la duplicación del mismo archivo para tablets y televisiones (así como todos los problemas que esto conlleva), puedes utilizar archivos alias. Por ejemplo, puedes establecer los siguientes diseños:</p> + +<ul> +<li><code>res/layout/main.xml</code>: diseño de panel único,</li> +<li><code>res/layout/main_twopanes.xml</code>: diseño de panel dual.</li> +</ul> + +<p>Añade estos dos archivos:</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>Estos dos últimos archivos tienen el mismo contenido, pero en realidad no definen el diseño. Solo configuran <PH>{@code main}</PH> para que sea un alias de <PH>{@code main_twopanes}</PH>. Como los archivos tienen selectores <code>large</code> y <code>sw600dp</code>, se aplican a tablets y a televisiones independientemente de la versión de Android (las televisiones y los tablets anteriores a la versión 3.2 utilizarán +<PH>{@code large}</PH>y las televisiones y los tablets posteriores a la versión 3.2 utilizarán <code>sw600dp</code>).</p> + + +<h2 id="TaskUseOriQuali">Cómo utilizar calificadores de orientación</h2> + +<p>Aunque algunos diseños se pueden utilizar tanto en modo horizontal como vertical, la mayoría de ellos pueden beneficiarse de los ajustes. A continuación, se indica cómo se comporta el diseño según cada tamaño y orientación de la pantalla en la aplicación de ejemplo News Reader:</p> + +<p><ul> +<li><b>pantalla pequeña, vertical:</b> panel único con logotipo,</li> +<li><b>pantalla pequeña, horizontal:</b> panel único con logotipo,</li> +<li><b>tablet de 7", vertical:</b> panel único con barra de acciones,</li> +<li><b>tablet de 7", horizontal:</b> panel dual ancho con barra de acciones,</li> +<li><b>tablet de 10", vertical:</b> panel dual estrecho con barra de acciones,</li> +<li><b>tablet de 10", horizontal:</b> panel dual ancho con barra de acciones,</li> +<li><b>televisión, horizontal:</b> panel dual ancho con barra de acciones.</li> +</ul></p> + +<p>Cada uno de estos diseños se establecen en un archivo XML en el directorio <code>res/layout/</code>. Para definir posteriormente las diferentes configuraciones de pantalla, la aplicación utiliza alias de diseño para asignarlos a cada configuración:</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>Una vez que se hayan definido todos los diseños posibles, solo se debe asignar el diseño adecuado a cada configuración a través de calificadores de configuración. Ahora ya puedes utilizar la técnica de los alias de diseño:</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">Cómo utilizar mapas de bits de la clase NinePatch</h2> + +<p>Admitir diferentes tamaños de pantalla normalmente implica que las fuentes de imagen también deben poder adaptarse a varios tamaños. Por ejemplo, un fondo de botón debe adaptarse a cualquier forma de botón a la que se aplique.</p> + +<p>Si utilizas imágenes sencillas en componentes que pueden cambiar de tamaño, observarás rápidamente que los resultados no es que sean precisamente impresionantes, ya que las imágenes se estirarán o estrecharán. La solución es utilizar mapas de bits de la clase NinePatch, que son archivos PNG con un formato especial que indican las áreas que se pueden y no se pueden estirar.</p> + +<p>Por tanto, al diseñar mapas de bits que se vayan a utilizar en componentes con tamaño variable, utiliza siempre mapas de bits de la clase NinePatch. Para convertir un mapa de bits en uno de la clase NinePatch, puedes empezar con una imagen normal (consulta la figura 4, que se ha ampliado cuatro veces para obtener una mayor claridad).</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>Figura 4.</strong> <code>button.png</code></p> + +<p>A continuación, puedes pasar a la utilidad <ode +href="{@docRoot}tools/help/draw9patch.html"><code>draw9patch</code></a> del SDK (que se localiza en el directorio <code>tools/</code>) en la que puedes marcar las áreas que se deben estirar dibujando píxeles a lo largo de los bordes superior e izquierdo. También puedes marcar el área que debe incluir el contenido dibujando píxeles a lo largo de los bordes inferior y derecho, como se muestra en la figura 5.</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>Figura 5.</strong> <code>button.9.png</code></p> + +<p>Observa los píxeles de color negro situados junto a los bordes. Los que aparecen en los bordes superior e izquierdo indican los lugares en los que se puede estirar la imagen, mientras que los que aparecen en los bordes inferior y derecho indican dónde se debe situar el contenido.</p> + +<p>Además, observa la extensión <code>.9.png</code>. Debes utilizar esta extensión, ya que, de este modo, el marco detecta que se trata de una imagen de la clase NinePatch, en lugar de una imagen PNG normal.</p> + +<p>Cuando aplicas este fondo a un componente (definiendo <code>android:background="@drawable/button"</code>), el marco estira la imagen de forma adecuada para adaptarla al botón, como se muestra en varios tamaños de la figura 6.</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>Figura 6.</strong> Botón que utiliza la clase NinePatch <code>button.9.png</code> en varios tamaños</p> + diff --git a/docs/html-intl/ja/guide/publishing/app-signing.jd b/docs/html-intl/ja/guide/publishing/app-signing.jd new file mode 100644 index 0000000..2d2acfa --- /dev/null +++ b/docs/html-intl/ja/guide/publishing/app-signing.jd @@ -0,0 +1,336 @@ +page.title=アプリケーションへの署名 +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>署名の概略</h2> + +<ul> +<li>Android アプリケーションはすべて<em>署名する必要がある</em></a></li> +<li>自己署名キーで署名可能</li> +<li>アプリケーションの署名方法は重要です。このドキュメントをよくお読みください</li> +<li>開発プロセスの初期段階で署名戦略を決定します</li> +</ul> + +<h2>このドキュメントの内容</h2> + +<ol> +<li><a href="#overview">概要</a></li> +<li><a href="#strategies">署名戦略</a></li> +<li><a href="#setup">署名の基本設定</a></li> +<li><a href="#debugmode">デバッグ モードでの署名</a></li> +<li><a href="#releasemode">公開リリースへの署名</a> + <ol> + <li><a href="#releasecompile">リリース向けのコンパイル</a></li> + <li><a href="#cert">適切な秘密鍵の取得</a></li> + <li><a href="#signapp">アプリケーションの署名</a></li> + <li><a href="#ExportWizard">Eclipse ADT によるコンパイルと署名</a></li> + </ol> +</li> +<li><a href="#secure-key">秘密鍵のセキュリティ設定</a></li> + +</ol> + +<h2>関連項目</h2> + +<ol> +<li><a href="{@docRoot}tools/publishing/versioning.html">アプリケーションのバージョニング</a></li> +<li><a href="{@docRoot}tools/publishing/preparing.html">公開の準備</a></li> +</ol> + +</div> +</div> + +<p>このドキュメントでは、Android アプリケーションを携帯端末ユーザーに公開する前に署名する方法について説明します。</p> + +<h2 id="overview">概要</h2> + +<p>Android システムでは、インストールするすべてのアプリケーションに対してデジタル署名されて証明書を必要とします。この証明書の秘密鍵は、アプリケーションのデベロッパーが所持するものです。Android システムは証明書をアプリケーションの作成者の識別手段、およびアプリケーション間の信頼関係の確立手段として使用します。証明書は、ユーザーがどのアプリケーションをインストールできるかを制御するものではありません。証明書は認証機関によって署名される必要はありません。通常の Android アプリケーションは自己署名証明書を使用して正常に機能します。</p> + +<p>Android アプリケーションの署名について、次の点を理解することが重要です:</p> + +<ul> + <li>すべてのアプリケーションは<em>署名される必要があります</em>。署名されていないアプリケーションはシステムにインストールされません。</li> + <li>アプリケーションの署名に、自己署名証明書を使用できます。認証機関は不要です。</li> + <li>アプリケーションをエンド ユーザーにリリースする準備ができたら、適切な秘密鍵を使用してアプリケーションに署名する必要があります。SDK ツールで生成されたデバッグ キーで署名されたアプリケーションは、公開できません。 + </li> + <li>システムが署名証明書の有効期限を確認するのは、インストール時のみです。アプリケーションのインストール後に署名者証明書が期限切れになった場合、アプリケーションは正常な動作を継続します。</li> + <li>標準ツールである Keytool と Jarsigner を使用してキーを生成し、アプリケーションの .apk ファイルに署名できます。</li> +</ul> + +<p>Android システムは、適切に署名されていないアプリケーションをインストールせず、実行もしません。この規則は、実際のデバイスでもエミュレータでも、Android システムが実行されるすべての状況で適用されます。このため、エミュレータまたはデバイス上で実行またはデバッグする前に、アプリケーションの署名を設定する必要があります。</p> + +<p>Android SDK ツールは、デバッグ時のアプリケーション署名を支援します。「ADT Plugin for Eclipse」と「Ant ビルド ツール」では両方とも、<em>デバッグ モード</em>と<em>リリース モード</em>の 2 種類の署名モードを利用できます。 + +<ul> +<li>開発およびテスト中は、デバッグ モードでコンパイルできます。デバッグ モードでは、ビルド ツールは JDK に付属の Keytool ユーティリティを使用して、キーストアとキーを既知のエイリアスとパスワードで作成します。コンパイルのたびに、ツールはデバッグ キーを使用してアプリケーションの .apk ファイルに署名します。パスワードは既知のものなので、コンパイルのたびにツールにキーストア/キー パスワードを入力する必要はありません。</li> + +<li>アプリケーションをリリースする準備ができたら、リリース モードでコンパイルして、.apk に<span style="color:red">秘密鍵</span>で署名する必要があります。次の 2 通りの方法があります: + <ul> + <li>Keytool と Jarsigner をコマンド ラインで使用する方法。このアプローチでは、まずアプリケーションを<em>署名されていない</em> .apk にコンパイルします。次に、Jarsigner(または類似のツール)を使用して秘密鍵で .apk に手動で署名します。適切な秘密鍵を所持していない場合は、Keytool を手動で実行して独自のキーストア/キーを生成し、Jarsigner でアプリケーションに署名できます。</li> + <li>ADT Export Wizard を使用する方法。ADT プラグイン搭載の Eclipse を使用して開発している場合、Export Wizard を使用してアプリケーションをコンパイルし、秘密鍵を生成して(必要な場合)、.apk に署名できます。この作業をすべて Export Wizard を使用して 1 つのプロセスで実行できます。 + </li> + </ul> +</li> +</ul> + +<h2 id="strategies">署名戦略</h2> + +<p>アプリケーションの署名は、開発アプローチに一部影響します。特に、複数のアプリケーションをリリースする予定の場合、高い影響を与えます。 </p> + +<p>一般に、すべてのデベロッパーに推奨される戦略は、アプリケーションの予期される使用期間を通じて同じ証明書ですべてのアプリケーションに署名することです。このようにするには、複数の理由があります: </p> + +<ul> +<li>アプリケーションのアップグレード - アプリケーションのアップグレードをリリースするとき、ユーザーが新バージョンにシームレスにアップグレードできるように、アップグレードされたアプリケーションにも同じ証明書で署名します。システムがアプリケーションのアップデートをインストールする際は、新バージョンの証明書のいずれかが旧バージョンの証明書と一致する場合、システムがアップデートを許可します。一致する証明書を使用せずに署名する場合は、アプリケーションに別のパッケージ名を割り当てる必要があります。この場合、新しいバージョンがまったく新しいアプリケーションとしてインストールされます。 </li> + +<li>アプリケーションのモジュール性 - Android システムでは、アプリケーションが要求する場合、同じ証明書で署名されたアプリケーションを同じプロセスで実行できます。これにより、システムはこれらを単一のアプリケーションとして取り扱います。このようにすればアプリケーションをモジュールとして配備でき、ユーザーは必要に応じて各モジュールを個別に更新できます。</li> + +<li>許可によるコード/データ共有 - Android システムでは、署名ベースの権限付与を実施しているため、アプリケーションは指定された証明書で署名されている別のアプリケーションに機能を提供できます。同じ証明書で複数のアプリケーションに署名し、署名に基づいた権限のチェックを行うことで、アプリケーションはコードとデータを安全な方法で共有できます。 </li> + +</ul> + +<p>署名戦略を決定する際のもう 1 つの重要な検討事項として、アプリケーションの署名に使用するキーの有効期間の設定方法があります。</p> + +<ul> +<li>アプリケーションのアップグレードをサポートするには、キーの有効期間は、アプリケーションの予定される試用期間以上である必要があります。有効期間は、25年以上であることが推奨されます。キーの有効期間が切れた場合、ユーザーはアプリケーションの新バージョンにシームレスにアップグレードできなくなります。</li> + +<li>同じキーで複数の異なるアプリケーションに署名する場合、キーの有効期間が、今後のアプリケーション スイートに追加される依存アプリケーションを含め、<em>すべてのアプリケーションのすべてのバージョンの</em>予定される使用期間を超えることを確認してください。 </li> + +<li>アプリケーションを Android マーケットに公開する予定の場合、アプリケーションの署名に使用するキーの有効期間を、2033 年 10 月 22 日以降の期限に設定する必要があります。マーケット サーバーは、新バージョンが公開されたときにユーザーがマーケット アプリケーションをシームレスにアップグレードできるよう、この要件を義務付けています。 </li> +</ul> + +<p>アプリケーションの設計時にこれらの点を考慮し、アプリケーションの署名に<a href="#cert">適切な証明書</a>を使用してください。 </p> + +<h2 id="setup">署名の基本設定</h2> + +<p>キーストアとデバッグ キーの生成をサポートするため、SDK ビルド ツールで Keytool を使用できることを初めに確認してください。たいていの場合、「JAVA_HOME」環境変数を設定して適切な JDK を参照させることで、SDK ビルド ツールで Keytool を認識できます。または、JDK バージョンの Keytool を PATH 変数に追加しても認識できます。</p> + +<p>Linux バージョンに付属されている GNU Java コンパイラで開発している場合は、gcj バージョンではなく、JDK バージョンの Keytool を使用していることを確認してください。Keytool が既に PATH に指定されている場合は、<code>/usr/bin/keytool</code> の symlink を指していることがあります。この場合は、symlink ターゲットが JDK の Keytool を指していることを確認してください。</p> + +<p>アプリケーションを公開する場合は、Jarsigner ツールをコンピュータで使用できるようにする必要があります。Jarsigner と Keytool の両方が JDK によって提供されます。 </p> + +<h2 id="debugmode">デバッグ モードでの署名</h2> + +<p>Android ビルド ツールにはデバッグ署名モードがあり、アプリケーションの開発とデバッグがスムーズに行えます。また、.apk をエミュレータまたはデバイスにインストールする際の、署名に対する Android システム要件を満たします。デバッグモードでは、SDK ツールは Keytool を呼び出してデバッグ キーストアとキーを作成します。</p> + +<p>SDK ツールは事前に指定された名前とパスワードを使用してデバッグ キーストア/キーを作成します。</p> +<ul> +<li>キーストア名 – 「debug.keystore」</li> +<li>キーストアのパスワード – 「android」</li> +<li>キーのエイリアス – 「androiddebugkey」</li> +<li>キーのパスワード – 「android」</li> +<li>CN – 「CN=Android Debug,O=Android,C=US」</li> +</ul></p> + +<p>必要に応じて、デバッグ キーストア/キーの場所および名前を変更できます。また、自分で作成したデバッグ キーストア/キーを指定することもできます。Eclipse/ADT で、[[]<strong>ウィンドウ(Windows)</strong>] > [[]<strong>設定(Prefs)</strong>] > [[]<strong>Android</strong>] > [[]<strong>ビルド(Build)</strong>] を選択します。ただし、自分で作成したデバッグ キーストア/キーは、デフォルトのデバッグ キー(上述)と同じキーストア/キー名とパスワードを使用する必要があります。</p> + +<p class="note"><strong>注:</strong> デバッグ証明書で署名した場合は、アプリケーションを<em>公開できません</em>。</p> + +<h3>Eclipse ユーザー</h3> + +<p>Eclipse/ADT で開発し、Keytool を上記のように設定してある場合は、デバッグモードにおける署名はデフォルトで有効になっています。アプリケーションを実行またはデバッグするときに、ADT は .apk にデバッグ証明書で署名し、エミュレータにインストールします。ADT が Keytool にアクセスできる場合は、ユーザーは特に操作する必要はありません。</p> + +<h3>Ant ユーザー</h3> + +<p>Ant を使用して .apk ファイルを構築する場合、デバッグ署名モードは <code>debug</code> オプションを使用することで有効になります(<code>android</code> ツールで生成された <code>build.xml</code> ファイルを使用していることが前提となります)。<code>ant debug</code> を実行してアプリケーションをコンパイルする際、ビルド スクリプトはキーストア/キーを生成し、.apk に署名します。ユーザーは操作する必要はありません。詳細は、<a href="{@docRoot}guide/developing/other-ide.html#DebugMode">その他の統合開発環境での開発: デバッグモードにおけるビルド </a> をお読みください。</p> + + +<h3 id="debugexpiry">デバッグ証明書の有効期限</h3> + +<p>デバッグ モード(Eclipse/ADT と Ant ビルドのデフォルト)でのアプリケーション署名に使用した自己署名証明書には、作成日から 365 日の有効期限が設定されます。</p> + +<p>証明書の期限が切れると、ビルド エラーが発生します。Ant ビルドでは、エラーは次のようになります:</p> + +<pre>debug: +[echo] Packaging bin/samples-debug.apk, and signing it with a debug key... +[exec] Debug Certificate expired on 8/4/08 3:43 PM</pre> + +<p>Eclipse/ADT では、Android コンソールに同様のエラーが表示されます。</p> + +<p>この問題を解決するには、<code>debug.keystore</code> ファイルを削除します。AVD のデフォルトの格納場所は、OS X と Linux の場合は <code>~/.android/avd</code>、Windows XP の場合は <code>C:\Documents and Settings\<user>\.android\</code>、Windows Vista の場合は <code>C:\Users\<user>\.android\</code> です。</p> + + +<p>次にビルドを行うと、ビルド ツールは新しいキーストアとデバッグ キーを再度生成します。</p> + +<p>開発コンピュータがグレゴリオ暦以外のロケールを使用している場合、ビルド ツールが誤って期限切れのデバッグ証明書を生成することがあります。このため、アプリケーションをコンパイルしようとするとエラーが発生します。解決策については、トラブルシューティング トピックの <a href="{@docRoot}resources/faq/troubleshooting.html#signingcalendar">ビルド ツールが期限切れのデバッグ証明書を生成するため、アプリケーションがコンパイルできない</a> をご覧ください。 </p> + + +<h2 id="releasemode">公開リリースへの署名</h2> + +<p>アプリケーションを他のユーザーに公開する準備ができたら、次のことを行う必要があります:</p> +<ol> + <li>アプリケーションをリリース モードでコンパイルする</li> + <li>適切な秘密鍵を取得する</li> + <li>アプリケーションに秘密鍵で署名する</li> +</ol> + +<p>以下のセクションでは、これらの手順を実行する方法について説明します。</p> + +<p>ADT プラグイン搭載の Eclipse を使用している場合、これらの手順を実行する代わりに Export Wizard を使用して .apk をコンパイルして秘密鍵で署名できます。Export Wizard では、処理過程で新しいキーストアと秘密鍵の生成も可能です。<a href="#ExportWizard">Eclipse ADT によるコンパイルと署名</a>を参考にコンパイルを行ってください。</p> + + +<h3 id="releasecompile">リリース向けのコンパイル</h3> + +<p>アプリケーションのリリースを準備するには、リリース モードでコンパイルする必要があります。リリース モードでは、Android ビルド ツールはアプリケーションを通常どおりにコンパイルしますが、デバッグ キーで署名しません。</p> + +<p class="warning"><strong>注:</strong> 署名されていないアプリケーション、またはデバッグ キーで署名されたアプリケーションはリリースできません。</p> + +<h4>Eclipse ユーザー</h4> + +<p><em>署名されていない</em> .apk ファイルを Eclipse からエクスポートするには、パッケージ エクスプローラー(Package Explorer)でプロジェクトを右クリックして、[[]<strong>Android ツール(Android Tools)</strong>] > [[]<strong>署名されていないアプリケーション パッケージのエクスポート(Export Unsigned Application Package)</strong>] を選択します。次に、署名されていない .apk ファイルの場所を指定します(または、<code>AndroidManifest.xml</code> ファイルを Eclipse で開き、[[]<em>概要(Overview)</em>] タブを開いて [[]<strong>署名されていない .apk のエクスポート(Export an unsigned .apk)</strong>] をクリックします)。</p> + +<p>Export Wizard では、コンパイルと署名の手順を一緒に処理できます。<a href="#ExportWizard">Eclipse ADT によるコンパイルと署名</a>をご覧ください。</p> + +<h4>Ant ユーザー</h4> + +<p>Ant を使用している場合は、必要な作業は Ant コマンドでビルド ターゲットとして「release」を指定するだけです。たとえば、Ant を build.xml ファイルがあるディレクトリから実行している場合、コマンドは次のようになります:</p> + +<pre>$ ant release</pre> + +<p>ビルド スクリプトは、アプリケーション .apk を署名せずにコンパイルします。</p> + + +<h3 id="cert">適切な秘密鍵の取得</h3> + +<p>アプリケーションの署名を準備するには、まず署名に使用する適切な秘密鍵があることを確認することが必要です。適切な秘密鍵とは、次の条件を満たすものです:</p> + +<ul> +<li>自分が所有している。</li> +<li>アプリケーションで識別される、個人、法人、または組織の実体を表す。</li> +<li>アプリケーションまたはアプリケーション スイートの予期される使用期間を超える有効期間を持っている。有効期間として、25 年以上を推奨します。 +<p>アプリケーションを Android マーケットに公開する予定の場合、2033 年 10 月 22 日までの有効期間が必要です。有効期間がこの日付以前に期限切れになるキーで署名されたアプリケーションは、アップロードできません。 +</p></li> +<li>Android SDK ツールで生成されたデバッグ キーではない。 </li> +</ul> + +<p>自己署名されたキーを使用できます。適切なキーがない場合、Keytool を使用して生成する必要があります。<a href="#setup">基本設定</a>で説明した手順に従って、Keytool を使用できるようにしてください。</p> + +<p>Keytool で自己署名キーを生成するには、<code>keytool</code> コマンドを使用して以下に示すオプション(および、必要に応じてその他のオプション)を渡します。 </p> + +<p class="warning"><strong>注:</strong> Keytool を実行する前に、<a href="#secure-key">秘密鍵のセキュリティ設定</a>を読んで、キーのセキュリティを確保する方法と、自分とユーザーにとってセキュリティ確保が重要な理由を理解してください。特に、自分のキーを生成する場合、キーストアとキーの両方に強力なパスワードを選択する必要があります。</p> + +<table> +<tr> +<th>Keytool のオプション</th> +<th>説明</th> +</tr> +<tr> +<td><code>-genkey</code></td><td>キー ペアを生成します(公開キーと秘密鍵)。</td> +</tr> +<tr> +<td><code>-v</code></td><td>詳しいメッセージを出力する。</td> +</tr> +<tr> +<td><code>-keystore <keystore-name>.keystore</code></td><td>秘密鍵を含むキーストアの名前。</td> +</tr> +<tr> +<td><code>-storepass <password></code></td><td><p>キーストアのパスワード。</p><p>セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Keytool からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。</p></td> +</tr> +<tr> +<td><code>-alias <alias_name></code></td><td>キーのエイリアス。</td> +</tr> +<tr> +<td><code>-keyalg <alg></code></td><td>キーの生成時に使用する暗号化アルゴリズム。DSA と RSA の 2 つをサポートしています。</td> +</tr> +<tr> +<td><code>-dname <name></code></td><td><p>キーの作成者を識別する、識別名。値は、自己署名証明書の発行者およびサブジェクト フィールドとして使用されます。 </p><p>このオプションはコマンド ラインで指定する必要はありません。指定しなかった場合、Jarsigner からそれぞれの識別名フィールド(CN、OU など)の入力が求められます。</p></td> +</tr> +<tr> +<td><code>-validity <valdays></code></td><td><p>キーの有効期間(日数)。 </p><p><strong>注:</strong> 10000 以上の値を推奨します。</p></td> +</tr> +<tr> +<td><code>-keypass <password></code></td><td><p>キーのパスワード。</p> +<p>セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Keytool からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。</p></td> +</tr> +</table> + + +<p>秘密鍵を生成する Keytool コマンドの例を示します。</p> + +<pre>$ keytool -genkey -v -keystore my-release-key.keystore +-alias alias_name -keyalg RSA -validity 10000</pre> + +<p>上記のコマンド例を実行すると、Keytool からキーストアとキーのパスワードと、キーの識別名フィールドの指定が求められます。キーストアが <code>my-release-key.keystore</code> というファイルとして生成されます。キーストアとキーは、入力したパスワードで保護されます。キーストアには 1 つのキーが含まれ、10000 日間有効です。エイリアスは、後で使用する名前で、アプリケーションに署名するときにこのキーストアを参照する名前です。 </p> + +<p>Keytool の詳細は <a +href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security">http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security</a> のドキュメント(英語のみ)をご覧ください。</p> + + +<h3 id="signapp">アプリケーションの署名</h3> + +<p>リリースする .apk に実際に署名する準備ができたら、Jarsigner ツールを使用して署名できます。<a href="#setup">基本設定</a>で説明したように、Jarsigner をコンピュータで使用できることを確認してください。また、秘密鍵を含むキーストアがあることも確認してください。</p> + +<p>アプリケーションに署名するには、Jarsigner を実行して、アプリケーションの .apk と、.apk の署名に使用する秘密鍵を含むキーストアの両方を参照します。以下の表では、使用できるオプションを示します。 <p> + +<table> +<tr> +<th>Jarsigner のオプション</th> +<th>説明</th> +</tr> +<tr> +<td><code>-keystore <keystore-name>.keystore</code></td><td>秘密鍵を含むキーストアの名前。</td> +</tr> +<tr> +<td><code>-verbose</code></td><td>詳しいメッセージを出力する。</td> +</tr> +<tr> +<td><code>-storepass <password></code></td><td><p>キーストアのパスワード。 </p><p>セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Jarsigner からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。</p></td> +</tr> +<tr> +<td><code>-keypass <password></code></td><td><p>秘密鍵のパスワード。 </p><p>セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Jarsigner からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。</p></td> +</tr> +</table> + +<p>Jarsigner を使用して <code>my_application.apk</code> というアプリケーション パッケージに署名する例を、上記で作成したキーストアを使用して示します。 +</p> + +<pre>$ jarsigner -verbose -keystore my-release-key.keystore +my_application.apk alias_name</pre> + +<p>上記のコマンドを実行すると、Jarsigner からキーストアとキーのパスワードの入力が求められます。.apk がその場で変更され、.apk は署名されます。.apk に別のキーで複数回署名できます。</p> + +<p>.apk が署名されたことを確認するには、次のようなコマンドを使用できます:</p> + +<pre>$ jarsigner -verify my_signed.apk</pre> + +<p>.apk が適切に署名されると、Jarsigner から「jar verified」と出力されます。詳細情報が必要な場合は、次のコマンドを使用できます。</p> + +<pre>$ jarsigner -verify -verbose my_application.apk</pre> + +<p>または、次のコマンドを使用します。</p> + +<pre>$ jarsigner -verify -verbose -certs my_application.apk</pre> + +<p>上記の <code>-certs</code> オプションが付加されたコマンドでは、「CN=」行が出力され、キーの作成者が示されます。</p> + +<p class="note"><strong>注:</strong> 「CN=Android Debug」と出力される場合、.apk が Android SDK によって生成されたデバッグ キーで署名されたことを示しています。アプリケーションをリリースする予定の場合は、デバッグ キーではなく秘密鍵で署名する必要があります。</p> + +<p>Jarsigner の詳細は <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security">http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security</a> のドキュメント(英語のみ)をご覧ください。</p> + + +<h3 id="ExportWizard">Eclipse ADT によるコンパイルと署名</h3> + +<p>ADT 搭載 Eclipse を使用している場合、Export Wizard を使用して<em>署名済み</em> .apk をエクスポートできます(必要に応じて、新しいキーストアを作成することもできます)。Export Wizard は、Keytool と Jarsigner のすべての処理を、コマンド ラインを使用せず、グラフィカル ユーザー インターフェースで署名を実行できます。Export Wizard は Keytool と Jarsigner の両方を使用するため、上記の<a href=#setup">署名の基本設定</a>の条件を満たすコンピュータで使用できます。</p> + +<p>署名された .apk を作成するには、パッケージ エクスプローラー(Package Explorer)でプロジェクトを右クリックして、<strong>[[]Android ツール(Android Tools)] > [[]署名済みアプリケーション パッケージのエクスポート(Export Signed Application Package)]</strong> を選択します(または、<code>AndroidManifest.xml</code> ファイルを Eclipse で開き、[[]<em>概要(Overview)</em>] タブを開いて [[]<strong>Export Wizard を使用する(Use the Export Wizard)</strong>] をクリックします)。表示されたウィンドウには、アプリケーションのエクスポート中に見つかったエラーが表示されます。エラーが見つからなかった場合は Export Wizard で処理を続行します。.apk に署名する秘密鍵の選択や、新しいキーストアと秘密鍵の作成など、アプリケーション署名のプロセスを手順を追って実行できます。</p> + +<p>Export Wizard が完了すると、配布可能な署名済み .apk が作成されています。</p> + + +<h2 id="secure-key">秘密鍵のセキュリティ設定</h2> + +<p>秘密鍵のセキュリティ設定は、作成者とユーザーの両者にとって重要です。他人にキーを使用させたり、第三者が見つけて使用できるような安全ではない場所にキーストアとキーを放置したりすると、作成者とユーザー間の信頼が損なわれます。 </p> + +<p>他者が許可を得ずにキーを取得した場合、その人物はアプリケーションに署名して配布し、本物のアプリケーションを故意に置き換えたり破損させたりすることができます。このような人物は、身元を詐称してアプリケーションに署名して配布し、その他のアプリケーションまたはシステム自体を攻撃したり、ユーザー データを破損させたり盗み出したりすることもあります。 </p> + +<p>キーの有効期限が切れるまで、秘密鍵のセキュリティを常に適切に維持できるかは、デベロッパーとしての評価を左右します。キーを安全に保つためのヒントをいくつか紹介します。 </p> + +<ul> +<li>キーストアとキーに強力なパスワードを選択します。</li> +<li>Keytool でキーを生成するとき、<em></em>コマンド ラインで <code>-storepass</code> および <code>-keypass</code> オプションを指定しないようにします。指定すると、パスワードがシェル履歴に記録され、コンピュータのすべてのユーザーがアクセスできるようになります。</li> +<li>同様に、Jarsigner でアプリケーションに署名するとき、<em></em>コマンド ラインで <code>-storepass</code> と <code>-keypass</code> オプションを指定しないようにします。 </li> +<li>秘密鍵を誰にも与えたり貸したりせず、不正なユーザーにキーストアとキーのパスワードを知られないようにします。</li> +</ul> + +<p>一般的には、キーの生成、使用、保管に関して常識的な注意を払っていれば、セキュリティを確保することができます。 </p>
\ No newline at end of file diff --git a/docs/html-intl/ja/guide/publishing/preparing.jd b/docs/html-intl/ja/guide/publishing/preparing.jd new file mode 100644 index 0000000..c7a2950 --- /dev/null +++ b/docs/html-intl/ja/guide/publishing/preparing.jd @@ -0,0 +1,158 @@ +page.title=公開の準備 +@jd:body + +<!-- +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> + +<ol> +<li><a href=""></a></li> +</ol> + +</div> +</div> +--> + +<p>アプリケーションの公開とは、アプリケーションをテストして適切にパッケージし、Android 搭載の携帯端末のユーザーが利用できる状態にすることです。</p> + +<p>アプリケーションを公開して Android 搭載デバイスにインストールするには、いくつかの作業を行ってアプリケーションの準備を整える必要があります。このドキュメントでは、アプリケーションのリリースを成功させるための準備における、重要なチェックポイントを説明しています。 +</p> + +<p>アプリケーションを Android マーケットに公開する場合は、アプリケーションの具体的な準備要件について <a +href="{@docRoot}tools/publishing/publishing.html#market">Android マーケットでの公開</a> もご覧ください。 </p> + +<p>アプリケーションを公開する方法の一般的な情報については、<a href="{@docRoot}tools/publishing/publishing.html">Publishing Your Applications</a> のドキュメントをご覧ください。 </p> + +<div class="special"> + +<p>アプリケーションのリリースを準備する前の作業:</p> + +<ol> +<li>アプリケーションを実際のデバイスで徹底的にテストする </li> +<li>アプリケーションへのエンド ユーザー ライセンス契約の追加を検討する</li> +<li>アプリケーションのマニフェストにアイコンとラベルを指定する</li> +<li>ロギングとデバッグを無効にして、データとファイルをクリーンアップする</li> +</ol> + +<p>アプリケーションの最終コンパイルを実行する前の作業:</p> + +<ol start="5"> +<li>アプリケーションでバージョン管理を行う</li> +<li>適切な暗号化キーを取得する</li> +<li>アプリケーションが MapView 要素を使用している場合は、Maps API キーに登録する</li> +</ol> + +<p><em>アプリケーションのコンパイル</em></p> +<p>アプリケーションをコンパイルした後の作業:</p> +<ol start="8"> +<li>アプリケーションに署名する</li> +<li>コンパイルしたアプリケーションをテストする</li> +</ol> +</div> + +<h2 id="releaseready">アプリケーションのリリースを準備する前の作業</h2> + +<h3 id="test">1. アプリケーションを実際のデバイスで徹底的にテストする</h3> + +<p>アプリケーションをできる限り広範に徹底的にテストすることが重要です。この作業を支援するため、Android では多数のテスト用クラスとツールを用意しています。{@link android.app.Instrumentation Instrumentation} を使用して JUnit およびその他のテスト ケースを実行できます。また、<a href="{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a> などのテスティング ツールを使用できます。 </p> + +<ul> +<li>ユーザーがアプリケーションを正常に実行できるようにするため、アプリケーションが実行されると予想されるタイプの携帯端末の実機を入手してください。実際のデバイスで、実際のネットワーク条件の下でアプリケーションをテストします。アプリケーションを実際のデバイスでテストすることは非常に重要です。これによって、作成したユーザー インターフェース要素のサイズが正しく(特にタッチスクリーン UI の場合)、アプリケーションのパフォーマンスと電池効率が適正であることを確認できるからです。</li> + +<li>アプリケーションの対象とするタイプの携帯端末が手に入らない場合は、<code>-dpi</code>、<code>-device</code>、<code>-scale</code>、<code>-netspeed</code>、<code>-netdelay</code>、<code>-cpu-delay</code> などのエミュレータ オプションを使用して、エミュレータの画面、ネットワーク パフォーマンス、その他の属性をモデル化して可能な限り対象デバイスに適応させることができます。このようにして、アプリケーションの UI とパフォーマンスをテストできます。ただし、公開する前にアプリケーションを実際の対象デバイスでテストすることを強く推奨します。 </li> + +<li>アプリケーションが <a href="http://www.t-mobileg1.com/">T-Mobile G1</a> デバイスを対象としている場合、UI が画面の向き変更に対応しているか確認してください。 </li> +</ul> + +<h3 id="eula">2. アプリケーションへのエンドユーザー ライセンス契約の追加を検討する</h3> + +<p>個人、組織、知的財産を保護するため、アプリケーションのエンドユーザー ライセンス契約(EULA)を付加することを推奨します。 + +<h3 id="iconlabel">3. アプリケーションのマニフェストにアイコンとラベルを指定する</h3> + +<p>アプリケーションのマニフェストに指定するアイコンとラベルは、アプリケーションのアイコンと名前としてユーザーに表示されるため、重要な要素です。アイコンとラベルは、デバイスの [[]ホーム] 画面や、[[]アプリケーションの管理]、[[]マイダウンロード] などに表示されます。また、公開サービスによってアイコンとラベルがユーザーに表示される可能性もあります。 </p> + +<p>アイコンとラベルを指定するには、<code>android:icon</code> と <code>android:label</code> 属性をマニフェストの <code><application></code> 要素に定義します。 </p> + +<p>アイコンのデザインについては、組み込みの Android アプリケーションのスタイルとできるだけ統一感を持たせてください。</p> + +<h3 id="logging">4. ロギングとデバッグを無効にして、データとファイルをクリーンアップする</h3> + +<p>リリース時にはデバッグ機能を無効にし、デバッグおよびその他の不要なデータ/ファイルをアプリケーション プロジェクトから削除してください。</p> +<ul> +<li><code>android:debuggable="true"</code> 属性をマニフェストの <code><application></code> 要素から削除します。</li> +<li>ログ ファイル、バックアップ ファイル、およびその他の不要なファイルをアプリケーション プロジェクトから削除します。</li> +<li>個人的または自分専用のデータがないか確認し、必要に応じて削除します。</li> +<li>ソース コード内に {@link android.util.Log} メソッドへの呼び出しがある場合は、無効にします。</li> +</ul> + +<h2 id="finalcompile">アプリケーションの最終コンパイルを実行する前の作業</h2> + +<h3 id="versionapp">5. アプリケーションでバージョン管理を行う</h3> + +<p>アプリケーションをコンパイルする前に、アプリケーションにバージョン番号を定義しておく必要があります。定義するには、アプリケーションのマニフェスト ファイルの <code><manifest></code> 要素の <code>android:versionCode</code> と <code>android:versionName</code> 属性の両方に適切な値を指定します。バージョン番号の設定は、全体的なアプリケーションアップグレードの計画を考慮して、慎重に検討してください。 </p> + +<p>これまでにリリースしたバージョンがある場合、最新のアプリケーションのバージョン番号を旧バージョンから増加させる必要があります。アプリケーションのマニフェスト ファイルの <code><manifest></code> 要素の <code>android:versionCode</code> と <code>android:versionName</code> 属性の両方を適切な値を使用して増加する必要があります。 </p> + +<p>アプリケーションのバージョン情報を定義する方法は、<a href="{@docRoot}tools/publishing/versioning.html">Versioning Your Applications</a>をご覧ください。</p> + +<h3 id="cryptokey">6. 適切な暗号化キーを取得する</h3> + +<p>ここまで準備作業をすべて読んで実行していれば、アプリケーションはコンパイルされ、署名の準備ができています。.apk の内部では、アプリケーションは適切にバージョン管理されており、上記のように余分なファイルや非公開データは削除されています。 </p> + +<p>アプリケーションに署名する前に、適切な非公開キーがあることを確認する必要があります。非公開キーを取得(または生成)する方法については、<a href="{@docRoot}tools/publishing/app-signing.html#cert">適切な非公開キーの取得</a>をご覧ください。</p> + +<p>適切な非公開キーを取得(または生成)したら、キーを使用して次の手順を実行します:</p> + +<ul> +<li>アプリケーションが MapView 要素を使用している場合は、Maps API キー(以下をご覧ください)に登録します。</li> +<li>以降の準備プロセスで、リリースするアプリケーションに署名します。</li> +</ul> + +<h3 id="mapsApiKey">7. アプリケーションが MapView 要素を使用している場合は、Maps API キーに登録する</h3> + +<div class="sidebox-wrapper"> +<div class="sidebox"><p> +Maps API キーを取得する方法は、<a +href="http://code.google.com/android/add-ons/google-apis/mapkey.html">Maps API キーの取得(英語のみ)</a> +をご覧ください。</p> +</div> +</div> + +<p>アプリケーションが Mapview 要素を使用する場合、アプリケーションを Google Maps サービスで登録し、Maps API キーを取得する必要があります。その後、MapView で Google Maps からデータを取得できるようになります。この処理を行うため、Maps サービスに署名証明書の MD5 フィンガープリントを提出します。 </p> + +<p>開発中は、SDK ツールが生成したデバッグ キーを登録して一時的な Maps API キーを取得できます。ただし、アプリケーションを公開する前には、非公開キーに基づく新しい Maps API キーで登録する必要があります。 </p> + +<p>アプリケーションが MapView 要素を使用する場合、次の点を理解することが重要です:</p> + +<ol> +<li>アプリケーションをリリース用にコンパイルする前に、Maps API キーを取得する必要があります。<em></em>このキーを、アプリケーションのレイアウト ファイルにある各 MapView 要素の、<code>android:apiKey</code> という特殊な属性に追加する必要があるからです。MapView オブジェクトをコードから直接インスタンス化している場合は、Maps API キーをコンストラクタのパラメータとして渡す必要があります。 +</li> +<li>アプリケーションの MapView 要素が参照する Maps API キーは Google Maps 内で登録され、アプリケーションの署名に使用される証明書に登録される必要があります。これはアプリケーションを公開する際に特に重要です。MapView 要素は、アプリケーションの署名に使用されるリリース証明書に登録されるキーを参照する必要があります。 </li> +<li>SDK ツールが生成したデバッグ証明書を登録して一時的な Maps API キーを取得している場合、リリース証明書を登録して新しい Maps API キーを取得する<em>必要があります</em>。また、MapView 要素を変更して、デバッグ証明書と関連付けられたキーではなく、新しいキーを参照させることも忘れないでください。このようにしないと、MapView 要素には Maps データをダウンロードする許可が与えられません。 </li> +<li>アプリケーションの署名に使用する非公開キーを変更するには、Google Maps サービスから新しい Maps API キーを取得する<em>必要があります</em>。新しい Maps API キーを取得してすべての MapView 要素に適用してください。以前のキーを参照する MapView 要素には、Maps データをダウンロードする許可が与えられません。 </li> +</ol> + +<p>署名と非公開キーについては、<a +href="{@docRoot}tools/publishing/app-signing.html">アプリケーションへの署名</a>をご覧ください。</p> + + +<h2 id="compile">アプリケーションのコンパイル</h2> + +<p>前述のセクションで説明したアプリケーションの準備ができたら、アプリケーションをリリース用にコンパイルできます。 </p> + +<h2 id="post-compile">アプリケーションをコンパイルした後の作業</h2> + +<h3 id="signapp">8. アプリケーションに署名する</h3> + +<p>非公開キーを使用してアプリケーションに署名します。アプリケーションに正しく署名することは、非常に重要です。詳細は、<a href="{@docRoot}tools/publishing/app-signing.html">アプリケーションへの署名</a>をご覧ください。 </p> + +<h3 id="testapp">9. コンパイルして署名したアプリケーションのテスト</h3> + +<p>コンパイルしたアプリケーションをリリースする前に、対象とする携帯端末(および可能ならば対象ネットワーク)上で徹底的にテストする必要があります。特に、UI 部分の MapView 要素がマップ データを正常に受信していることを確認してください。正常に受信していない場合、<a href="#mapsApiKey">Maps API キーに登録する</a>に戻って問題を解決してください。アプリケーションがサーバー側サービスを正しく利用できること、指定データまたは使用データを正しく処理できること、そして認証要件を正常に処理できることも確認してください。 </p> + +<p>これらのテストが完了したら、アプリケーションを携帯端末ユーザーに公開する準備が整ったと言えるでしょう。</p> + + diff --git a/docs/html-intl/ja/guide/publishing/versioning.jd b/docs/html-intl/ja/guide/publishing/versioning.jd new file mode 100644 index 0000000..1928610 --- /dev/null +++ b/docs/html-intl/ja/guide/publishing/versioning.jd @@ -0,0 +1,100 @@ +page.title=アプリケーションのバージョニング +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>バージョン管理の概略</h2> + +<ul> +<li>アプリケーションにはバージョンを設定する必要がある<em></em></a></li> +<li>バージョンは、アプリケーションのマニフェスト ファイルで設定する</li> +<li>アプリケーションのバージョン管理方法は、ユーザーのアップグレード方法に影響 </li> +<li>開発プロセスの初期段階で、今後のリリースの検討事項を含めて、バージョン管理戦略を決定します</li> +</ul> + +<h2>このドキュメントの内容</h2> + +<ol> +<li><a href="#appversion">アプリケーションのバージョンの設定</a></li> +<li><a href="#minsdkversion">最小システム API バージョンの指定</a> +</ol> + + +<h2>関連項目</h2> + +<ol> +<li><a href="{@docRoot}tools/publishing/preparing.html">公開の準備</a></li> +<li><a href="{@docRoot}tools/publishing/publishing.html#market">Android マーケットでの公開</a></li> +<li><a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></li> +</ol> + +</div> +</div> + +<p>バージョン管理のコンポーネントは、アプリケーションのアップグレード及びメンテナンスの計画を立てるのに重要です。 </p> + +<ul> +<li>ユーザーは、デバイスにインストールされたアプリケーション バージョンと、インストールが可能なアップグレード バージョンについて、特定の情報が必要です。 </li> +<li>スイートとして公開されたその他のアプリケーションなどでは、アプリケーションのバージョンをシステムに問い合わせて、互換性と依存関係を確認する必要があります。</li> +<li>アプリケーションを公開するサービスでは、アプリケーションにバージョンを問い合わせて、バージョンをユーザーに表示できるようにする必要があります。公開サービスでは、互換性を確認してアップグレードとダウングレードの関係を確立するために、アプリケーション バージョンを確認する必要があります。</li> +</ul> + +<p>Android システム自体は、アップグレードや互換性の制約の実施などのために、アプリケーション バージョン情報をアプリケーションに対して<em>確認することはありません</em>。代わりに、アプリケーションにおけるバージョン制約はユーザーまたはアプリケーション自体によって完全に実施されます。 </p> + +<p>Android システムが確認を行うのは、アプリケーションによってマニフェストの <code>minSdkVersion</code> 属性に指定されたシステム バージョン互換性です。<em></em>この属性によりアプリケーションは互換性を持つ最小システム API を指定できます。詳細は、<a href="#minsdkversion">最小システム API バージョンの指定</a>をご覧ください。 + +<h2 id="appversioning">アプリケーションのバージョンの設定</h2> +<p>アプリケーションのバージョン情報を定義するには、アプリケーションのマニフェスト ファイルで属性を設定します。2 つの属性を使用でき、常にこの両方に値を定義することが推奨されています: </p> + +<ul> +<li><code>android:versionCode</code> - アプリケーション コードのバージョンを他のバージョンと相対的に示す整数値。 + +<p>この値は整数なので、その他のアプリケーションはプログラムでバージョンの値を評価して関係を確認できます(たとえば、このバージョンがアップグレードかダウングレードなのか、など)。任意の整数値を設定できますが、アプリケーションの後続のリリースでは、現在より大きな値を使用するようにしてください。システムではこのバージョン管理の基準を強制しませんが、後継リリースの値を増加させることは標準的です。 </p> + +<p>通常、アプリケーションの最初のバージョンの versionCode を 1 に設定してリリースし、その後は各リリースについて、リリースがメジャー リリースであってもマイナー リリースであっても、値を単調増加させます。これは、<code>android:versionCode</code> の値は、ユーザーに表示されるアプリケーション リリース バージョンと類似している必要性はないことを意味します。以下の <code>android:versionName</code> をご覧ください。アプリケーションと公開サービスでは、このバージョンの値はユーザーには表示されません。</p> +</li> +<li><code>android:versionName</code> - アプリケーション コードのリリース バージョンを表す文字列値で、ユーザーに表示される値です。 +<p>値は文字列なので、アプリケーション バージョンを「<major>.<minor>.<point>」といった文字列や、その他のタイプの絶対的または相対的バージョン ID として記述できます。 </p> + +<p><code>android:versionCode</code> の場合と同様に、システムではこの値をアプリケーションでユーザーに表示する以外の目的で内部的に利用することはありません。公開サービスでは、ユーザーに表示するために <code>android:versionName</code> 値を取り出す可能性もあります。</p> +</li> +</ul> + +<p>これらのバージョン属性の両方をマニフェスト ファイルの <code><manifest></code> 要素で定義します。 </p> + +<p>ここに、<code><manifest></code> 要素の <code>android:versionCode</code> と <code>android:versionName</code> 属性を示すマニフェストの例を示します。 </p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.package.name" + android:versionCode="2" + android:versionName="1.1"> + <application android:icon="@drawable/icon" android:label="@string/app_name"> + ... + </application> +</manifest> +</pre> + +<p>この例では、<code>android:versionCode</code> 値は現在の .apk がこのアプリケーション コードの 2 番目のリリースを含んでいることを表し、これは <code>android:codeName</code> 文字列が示すようにマイナー後継リリースであることを示します。 </p> + +<p>Android フレームワークには、アプリケーションがシステムに別のアプリケーションのバージョン情報を問い合わせる API が用意されています。バージョン情報を取得するため、アプリケーションは {@link android.content.pm.PackageManager#getPackageInfo(java.lang.String, int)} +method of {@link android.content.pm.PackageManager PackageManager}. </p> を使用します。 + +<h2 id="minsdkversion">最小システム API バージョンの指定</h2> + +<p>アプリケーションが最低でも Android プラットフォームの特定のバージョンを必要とする場合、このバージョンを API レベルの ID としてアプリケーションのマニフェスト ファイルに指定できます。このようにすると、互換性のあるバージョンの Android システムを実行しているデバイスにのみアプリケーションをインストールできるようになります。 </p> + +<p>最小システム バージョンをマニフェストに指定するには、次の属性を使用します: </p> + +<ul> +<li><code>android:minSdkVersion</code> - Android プラットフォームのコード バージョンに対応する整数値。 +<p>アプリケーションのインストールを準備する際に、システムはこの属性の値を確認して、システム バージョンと比較します。<code>android:minSdkVersion</code> 値がシステム バージョンよりも大きい場合、システムはアプリケーションのインストールを中止します。 </p> + +<p>この属性をマニフェストに指定しない場合、システムではアプリケーションがすべてのプラットフォーム バージョンと互換性があると仮定します。</p></li> +</ul> + +<p>アプリケーションに最小プラットフォーム バージョンを指定するには、<code><uses-sdk></code> 要素を <code><manifest></code> の子として追加し、<code>android:minSdkVersion</code> を属性として定義します。 </p> + +<p>詳細は、<a href="{@docRoot}about/versions/android-1.1.html">Android System Image 1.1 Version Notes</a> もご覧ください。</p> diff --git a/docs/html-intl/ja/guide/topics/fundamentals.jd b/docs/html-intl/ja/guide/topics/fundamentals.jd new file mode 100644 index 0000000..cf9f7dd --- /dev/null +++ b/docs/html-intl/ja/guide/topics/fundamentals.jd @@ -0,0 +1,922 @@ +page.title=開発の基礎 +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>主なクラス</h2> +<ol> +<li>{@link android.app.Activity}</li> +<li>{@link android.app.Service}</li> +<li>{@link android.content.BroadcastReceiver}</li> +<li>{@link android.content.ContentProvider}</li> +<li>{@link android.content.Intent}</li> +</ol> + +<h2>このドキュメントの内容</h2> +<ol> +<li><a href="#appcomp">アプリケーションのコンポーネント</a> + <ol> + <li><a href="#actcomp">コンポーネントのアクティブ化: インテント</a></li> + <li><a href="#endcomp">コンポーネントの終了</a></li> + <li><a href="#manfile">マニフェスト ファイル</a></li> + <li><a href="#ifilters">インテント フィルタ</a></li> + </ol></li> +<li><a href="#acttask">アクティビティとタスク</a> + <ol> + <li><a href="#afftask">親和性と新しいタスク</a></li> + <li><a href="#lmodes">起動モード</a></li> + <li><a href="#clearstack">スタックのクリア</a></li> + <li><a href="#starttask">タスクの開始</a></li> + </ol></li> +<li><a href="#procthread">プロセスとスレッド</a> + <ol> + <li><a href="#procs">プロセス</a></li> + <li><a href="#threads">スレッド</a></li> + <li><a href="#rpc">リモート プロシージャ コール</a></li> + <li><a href="#tsafe">スレッドセーフなメソッド</a></li> + </ol></li> +<li><a href="#lcycles">コンポーネントのライフサイクル</a> + <ol> + <li><a href="#actlife">アクティビティのライフサイクル</a></li> + <li><a href="#servlife">サービスのライフサイクル</a></li> + <li><a href="#broadlife">ブロードキャスト レシーバのライフサイクル</a></li> + <li><a href="#proclife">プロセスとライフサイクル</a></li> + </ol></li> +</ol> +</div> +</div> + +<p> +Android アプリケーションはすべて Java プログラミング言語で記述します。コンパイル済みの Java コード(およびそのアプリケーションに必要なすべてのデータやリソース ファイル)は、<a href="{@docRoot}tools/aapt.html"><code>aapt</code> ツール</a>を使用して Android パッケージにバンドルします。Android パッケージは、拡張子が {@code .apk} のアーカイブ ファイルです。<i></i>ユーザーは、このファイルをデバイスにダウンロードして利用します。つまり、Android パッケージは、アプリケーションをモバイル デバイスに配布およびインストールするための媒体として機能します。1 つの {@code .apk} ファイルに含まれているすべてのコードが、1 つのアプリケーションと見なされます。<i></i> +</p> + +<p> +各 Android アプリケーションは、以下に示すさまざまな方法で他のアプリケーションから隔離されています: +</p> + +<ul> +<li>すべてのアプリケーションは、デフォルトではそのアプリケーション個別の Linux プロセスで実行されます。Android は、アプリケーション コードの実行が必要になったときにプロセスを開始し、その必要がなくなって他のアプリケーションからシステム リソースを要求されたときにプロセスを終了します。</li> + +<li>プロセスごとに専用の Java 仮想マシン(VM)が割り当てられるため、アプリケーション コードは他のアプリケーションから隔離された状態で実行されます。</li> + +<li>デフォルトでは、アプリケーションごとに固有の Linux ユーザー ID が割り当てられます。権限が設定されているため、アプリケーションのファイルはそのユーザーからしか認識できず、そのアプリケーション自体からのみ利用できます。ただし、ファイルを他のアプリケーションにエクスポートすることは可能です。</li> +</ul> + +<p> +2 つのアプリケーションで同じユーザー ID を共有することもできます。その場合は、それぞれのアプリケーションのファイルを相互に認識できます。システム リソースを節約するため、同じ ID のアプリケーションで同じ VM を共有し、同じ Linux プロセスで実行することも可能です。 +</p> + + +<h2 id="appcomp">アプリケーションのコンポーネント</h2> + +<p> +Android の大きな特長の 1 つは、許可されていれば、あるアプリケーションから別のアプリケーションの要素を利用できる点です。たとえば、開発中のアプリケーションで画像の一覧をスクロール表示したい場合、他のアプリケーションで開発済みの適切なスクローラがあり、その利用が許可されていれば、独自に開発しなくてもそのスクローラを利用できます。アプリケーションに他のアプリケーションのコードを組み込んだり、リンクを設定したりする必要はありません。必要になった時点で、他のアプリケーションの一部分を開始するだけです。 +</p> + +<p> +この仕組みが機能するには、アプリケーション プロセスの一部分を必要に応じて開始でき、その部分の Java オブジェクトをインスタンス化できなくてはなりません。そのため、Android アプリケーションには、他のシステムで動作するアプリケーションでよく使用されるような、アプリケーション全体にアクセスするための単一のエントリ ポイント(たとえば {@code main()} 関数)はありません。代わりに、システムが必要に応じてインスタンス化して実行できるコンポーネントで構成されます。<i></i>コンポーネントには以下の 4 つのタイプがあります: +</p> + +<dl> + +<dt><b>アクティビティ</b></dt> +<dd>アクティビティは、ユーザーが 1 つの操作を集中的に行うための視覚的なユーザー インターフェースを表します。<i></i>たとえば、ユーザーが選択できるメニュー アイテムの一覧を表示するアクティビティや、写真をキャプション付きで表示するアクティビティなどが考えられます。SMS アプリケーションなら、あるアクティビティでメッセージを送信する連絡先の一覧を表示し、別のアクティビティで選択した連絡先へのメッセージを入力し、その他のアクティビティで古いメッセージを参照したり設定を変更したりできます。これらのアクティビティを組み合わせて全体としてのユーザー インターフェースを形成しますが、それぞれのアクティビティは相互に独立しています。各アクティビティは、{@link android.app.Activity} 基本クラスのサブクラスとして実装されます。 + +<p> +アプリケーションは、1 つのアクティビティで構成することも、上記のSMS アプリケーションのように複数のアクティビティで構成することもできます。どのようなアクティビティがいくつ必要になるかは、アプリケーションやその設計に応じて異なります。通常は、アクティビティのうちのいずれかを最初のアクティビティとして指定し、ユーザーがアプリケーションを起動したときに表示します。あるアクティビティから別のアクティビティに移動するには、現在のアクティビティから次のアクティビティを開始します。 +</p> + +<p> +各アクティビティには、それを表示するためのデフォルトのウィンドウが割り当てられます。通常はウィンドウを画面全体に表示しますが、画面より小さいウィンドウを他のウィンドウの前面に表示することもできます。アクティビティに、新たなウィンドウを追加することも可能です。たとえば、アクティビティの途中でユーザーの応答を要求するポップアップ ダイアログを表示したり、ユーザーが画面上の特定のアイテムを選択したときに別ウィンドウで重要な情報を表示したりできます。 +</p> + +<p> +ウィンドウの視覚的なコンテンツは、ビュー({@link android.view.View} 基本クラスの派生オブジェクト)の階層として提供されます。各ビューは、ウィンドウ内の特定の矩形領域を制御します。親ビューは、その子となるビューで構成され、それらの子ビューのレイアウトを決定します。リーフ ビュー(階層の最下位に位置するビュー)は、そのビューが制御する矩形領域に表示され、その領域でのユーザーのアクションに対して応答します。つまり、ビューはアクティビティとユーザーが対話する場所です。たとえば、ビューに小さな画像を表示し、ユーザーがその画像をタップしたら何らかのアクションを開始することもできます。Android には、ボタン、テキスト フィールド、スクロール バー、メニュー アイテム、チェックボックスなど、さまざまなビューがあらかじめ用意されています。 +</p> + +<p> +ビューの階層は、<code>{@link android.app.Activity#setContentView Activity.setContentView()}</code> メソッドを使用してアクティビティのウィンドウ内に配置します。コンテンツ ビューは、階層のルートとなる View オブジェクトです<i></i>(ビューおよびその階層について詳しくは<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> のドキュメントをご覧ください)。 +</p> + +<p><dt><b>サービス</b></dt> +<dd>サービスは、視覚的なユーザー インターフェースを持たず、バックグラウンドにおいて明確な終了期限がなくで実行されます。<i></i>たとえば、ユーザーが他の操作をしている間 BGM を再生するサービス、ネットワーク経由でデータをフェッチするサービス、何かを計算してその結果をアクティビティに提供するサービスなどが考えられます。各サービスは、{@link android.app.Service} 基本クラスの拡張です。 + +<p> +典型的な例としては、プレイリストの曲を再生するメディア プレーヤーが挙げられます。プレーヤー アプリケーションは、ユーザーが曲を選んで再生するための 1 つ以上のアクティビティで構成することが予想されますが、ユーザーはプレーヤーを離れて別の操作に移った後も曲を聞いていたいと考えられることから、曲の再生自体をアクティビティで処理するわけにはいきません。音楽の再生を続けるには、メディア プレーヤー アクティビティから、バックグラウンドで実行するサービスを開始します。音楽再生サービスは、それを開始したアクティビティが画面上に見えなくなった後もそのまま実行されます。 +</p> + +<p> +また、実行中のサービスに接続(バインド)することもできます(実行されていない場合はそのサービスを開始することも可能です)。接続中は、サービスが公開しているインターフェースを使ってサービスと対話できます。音楽再生サービスであれは、このインターフェースを使って一時停止、巻き戻し、停止、再生の再開などの操作を実行できるようにします。 +</p> + +<p> +アクティビティや他のコンポーネントと同様に、サービスもアプリケーション プロセスのメイン スレッドで実行します。したがって、サービスによって他のコンポーネントやユーザー インターフェースの実行を妨げられることはなく、時間がかかるタスク(たとえば曲の再生)については、通常は別のスレッドを生成して処理します。詳しくは、<a href="#procthread">プロセスとスレッド</a>をご覧ください。 +</p></dd> + +<dt><b>ブロードキャスト レシーバ</b></dt> +<dd>ブロードキャスト レシーバは、ブロードキャストの連絡を受信してそれに対処するだけのコンポーネントです。<i></i>ブロードキャストの多くが元々はシステム コードで、たとえばタイム ゾーンが変更されたこと、電池の残量が少なくなったこと、写真が撮影されたこと、ユーザーが言語設定を変更したことなどを連絡するために使用します。アプリケーションでも、たとえば何らかのデータがデバイスにダウンロードされて利用できるようになったことを、他のアプリケーションにブロードキャストで知らせることができます。 + +<p> +アプリケーションでは、重要と思われるすべての連絡に応答できるよう、ブロードキャスト レシーバをいくつでも設定できます。すべてのレシーバは、{@link android.content.BroadcastReceiver} 基本クラスの拡張です。 +</p> + +<p> +ブロードキャスト レシーバがユーザー インターフェースを表示することはありません。ただし、受信した情報への応答としてアクティビティを開始したり、{@link android.app.NotificationManager} を使用してユーザーにアラートを送信したりすることはあります。通知の際には、バックライトを点滅させる、バイブレーションを起動する、音を鳴らすなど、さまざまな方法でユーザーの注意を喚起できます。通常は、ステータス バーに永続アイコンを表示し、ユーザーがこれを開いてメッセージを取得できるようにします。 +</p></dd> + +<dt><b>コンテンツ プロバイダ</b></dt> +<dd>コンテンツ プロバイダは、アプリケーションのデータを他のアプリケーションでも利用できるようにします。<i></i>データは、ファイル システムや SQLite データベースなど、一般に利用できる方法で格納されていれば使用できます。コンテンツ プロバイダは、{@link android.content.ContentProvider} 基本クラスの拡張です。プロバイダが制御する型のデータを、他のアプリケーションから取得および格納するための標準メソッド セットを実装しています。ただし、これらのメソッドをアプリケーションから直接呼び出すことはできません。代わりに、{@link android.content.ContentResolver} オブジェクトのメソッドを呼び出します。ContentResolver は、すべてのプロバイダと通信でき、プロバイダと連携して関係のあるすべてのプロセス間通信を管理します。 + +<p> +コンテンツ プロバイダの使用方法について詳しくは、<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>のドキュメントをご覧ください。 +</p></dd> + +</dl> + +<p> +Android では、特定のコンポーネントで処理すべきリクエストがあると、そのコンポーネントのアプリケーション プロセスが実行中かどうかを確認(必要に応じてプロセスを開始)し、そのコンポーネントの適切なインスタンスが利用可能かどうかを確認(必要に応じてインスタンスを作成)します。 +</p> + + +<h3 id="actcomp">コンポーネントのアクティブ化: インテント</h3> + +<p> +コンテンツ プロバイダは、ContentResolver からのリクエストの対象になるとアクティブ化されます。それ以外の 3 つのコンポーネント(アクティビティ、サービス、ブロードキャスト レシーバ)は、インテントと呼ばれる非同期メッセージによってアクティブ化されます。<i></i>インテントは、メッセージのコンテンツを保持する {@link android.content.Intent} オブジェクトです。アクティビティやサービスの場合の Intent オブジェクトの主な役割は、リクエストされているアクションを指名し、その対象となるデータの URI を指定することです。たとえば、ユーザーに画像を表示するためのリクエストや、ユーザーにテキストを編集させるリクエストをアクティビティに伝達できます。ブロードキャスト レシーバの場合は、Intent オブジェクトがこれから通知を行うアクションを指名します。たとえば、カメラのボタンが押されたことを、関係のあるブロードキャスト レシーバに通知できます。 +</p> + +<p> +以下に示すように、コンポーネントのタイプごとに別々のアクティブ化メソッドが用意されています: +</p> + +<ul> + +<li>アクティビティを起動する(または何か新しい処理を実行させる)には、Intent オブジェクトを <code>{@link android.content.Context#startActivity +Context.startActivity()}</code> または <code>{@link +android.app.Activity#startActivityForResult +Activity.startActivityForResult()}</code> に渡します。応答アクティビティで <code>{@link android.app.Activity#getIntent getIntent()}</code> メソッドを呼び出すと、最初にそのアクティビティが起動されたときのインテントの内容を確認できます。Android によってアクティビティの <code>{@link +android.app.Activity#onNewIntent onNewIntent()}</code> メソッドが呼び出され、アクティビティが後続のインテントに渡されます。 + +<p> +多くの場合、アクティビティから次のアクティビティを開始します。開始するアクティビティから結果が返される場合は、{@code startActivity()} ではなく {@code startActivityForResult()} を呼び出します。たとえば、ユーザーに写真を選択させるアクティビティを開始する場合は、ユーザーによって選択された写真が返されるかもしれません。結果は、呼び出し側のアクティビティの <code>{@link android.app.Activity#onActivityResult +onActivityResult()}</code> メソッドに渡した Intent オブジェクトで返されます。 +</p> +</li> + +<li><p>サービスを開始する(または実行中のサービスに新しい指示を与える)には、<code>{@link +android.content.Context#startService Context.startService()}</code> に Intent オブジェクトを渡します。Android により、サービスの <code>{@link android.app.Service#onStart +onStart()}</code> メソッドが呼び出されて Intent オブジェクトが渡されます。</p> + +<p> +同様に、インテントを <code>{@link +android.content.Context#bindService Context.bindService()}</code> に渡すと、呼び出し側のコンポーネントと対象となるサービスの間の継続中の接続を確立できます。サービスは、<code>{@link android.app.Service#onBind onBind()}</code> 呼び出しで Intent オブジェクトを受け取ります(サービスがまだ開始されていない場合は、必要に応じて {@code bindService()} で開始できます)。たとえば、上で例に挙げた音楽再生サービスとの接続を確立するアクティビティを使用して、ユーザーが再生を操作するための手段(ユーザー インターフェース)を提供できます。アクティビティで {@code bindService()} を呼び出して接続を確立してから、サービスに定義されているメソッドを呼び出して再生を操作します。 +</p> + +<p> +サービスのバインドについては、後ほど<a href="#rpc">リモート プロシージャ コール</a>のセクションで詳しく説明します。 +</p> +</li> + +<li><p>アプリケーションでブロードキャストを開始するには、<code>{@link +android.content.Context#sendBroadcast(Intent) Context.sendBroadcast()}</code>、<code>{@link android.content.Context#sendOrderedBroadcast(Intent, String) +Context.sendOrderedBroadcast()}</code>、<code>{@link +android.content.Context#sendStickyBroadcast Context.sendStickyBroadcast()}</code> などのメソッドのいずれかのバリエーションに Intent オブジェクトを渡します。Android によって <code>{@link +android.content.BroadcastReceiver#onReceive onReceive()}</code> メソッドが呼び出され、関係のあるすべてのブロードキャスト レシーバにインテントが配信されます。</p></li> + +</ul> + +<p> +インテント メッセージについて詳しくは、<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> をご覧ください。 +</p> + + +<h3 id="endcomp">コンポーネントの終了</h3> + +<p> +コンテンツ プロバイダは、ContentResolver からのリクエストに応答している間のみアクティブになります。ブロードキャスト レシーバは、ブロードキャスト メッセージに応答している間のみアクティブになります。つまり、これらのコンポーネントを明示的に終了させる必要はありません。 +</p> + +<p> +一方、アクティビティはユーザー インターフェースを提供します。長い時間をかけてユーザーと会話するためのものであり、待機状態の間も、会話が続いてきる限りはアクティブなままになっている可能性があります。同様に、サービスも長い間実行されたままになる可能性があります。Android には、アクティビティとサービスを以下のような規則的な方法で終了させるためのメソッドが用意されています: +</p> + +<ul> +<li>アクティビティを終了させるには、その <code>{@link android.app.Activity#finish finish()}</code> メソッドを呼び出します。あるアクティビティから {@code startActivityForResult()} で開始した別のアクティビティは、<code>{@link android.app.Activity#finishActivity finishActivity()}</code> を呼び出して終了させることができます。</li> + +<li>サービスは、その <code>{@link android.app.Service#stopSelf stopSelf()}</code> メソッドを呼び出すか、<code>{@link android.content.Context#stopService Context.stopService()}</code> を呼び出すことで停止できます。</li> +</ul> + +<p> +コンポーネントが、既に利用されていない場合や、Android がよりアクティブな他のコンポーネントにメモリを割り当てる必要がある場合は、システムがコンポーネントを終了させることもあります。このような状況およびその影響については、<a href="#lcycles">コンポーネントのライフサイクル</a>で詳しく説明します。 +</p> + + +<h3 id="manfile">マニフェスト ファイル</h3> + +<p> +アプリケーション コンポーネントを開始するには、Android がそのコンポーネントの存在を認識している必要があります。アプリケーションのコンポーネントは、マニフェスト ファイルで宣言します。このファイルは、アプリケーションのコード、ファイル、リソースなどとともに Android パッケージ({@code .apk} ファイル)にバンドルされます。 +</p> + +<p> +マニフェストは構造化された XML ファイルで、どのアプリケーションでも常に AndroidManifest.xml という名前になります。アプリケーション コンポーネントの宣言以外にも、アプリケーションをリンクさせる必要のあるライブラリ(デフォルトの Android ライブラリを除く)の指定や、アプリケーションに付与されるべき権限の指定などにも使用します。 +</p> + +<p> +しかし、マニフェストの最も重要な役割は、アプリケーションのコンポーネントに関する情報を Android に提供することです。たとえば、アクティビティを次のように宣言できます: +</p> + +<pre><?xml version="1.0" encoding="utf-8"?> +<manifest . . . > + <application . . . > + <activity android:name="com.example.project.FreneticActivity" + android:icon="@drawable/small_pic.png" + android:label="@string/freneticLabel" + . . . > + </activity> + . . . + </application> +</manifest></pre> + +<p> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の {@code name} 属性は、そのアクティビティを実装する {@link android.app.Activity} サブクラスを指名します。{@code icon} および {@code label} 属性には、ユーザーに対して表示するアイコンやラベルが保持されているリソース ファイルを指定します。 +</p> + +<p> +その他のコンポーネントも、サービスは <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> 要素、ブロードキャスト レシーバは <code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code> 要素、コンテンツ プロバイダは <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> 要素を使用して同じような方法で宣言します。マニフェストに宣言されていないアクティビティ、サービス、およびコンテンツ プロバイダは、システムから認識できないため実行されることはありません。ただし、ブロードキャスト レシーバの場合は、マニフェストで宣言する方法と、コード内で {@link android.content.BroadcastReceiver} オブジェクトとして動的に作成し、<code>{@link android.content.Context#registerReceiver Context.registerReceiver()}</code> を呼び出してシステムに登録する方法があります。 +</p> + +<p> +マニフェスト ファイルの作成方法について詳しくは、<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>をご覧ください。 +</p> + + +<h3 id="ifilters">インテント フィルタ</h3> + +<p> +Intent オブジェクトでは、対象とするコンポーネントを明示的に指名できます。明示的に指名されている場合、Android はマニフェスト ファイル内の宣言に基づいてコンポーネントを特定してアクティブにします。一方、明示的に指名されていない場合は、そのインテントに応答する上で最適なコンポーネントが選択されます。方法としては、Intent オブジェクトを、その対象となりうるコンポーネントのインテント フィルタと照合します。<i></i>コンポーネントのインテント フィルタは、そのコンポーネントで処理できるインテントの種類を示します。これもコンポーネントに関する重要な情報の 1 つなので、マニフェスト ファイルで宣言します。次に、上に示した例を拡張して 2 つのインテント フィルタを追加したアクティビティを示します: +</p> + +<pre><?xml version="1.0" encoding="utf-8"?> +<manifest . . . > + <application . . . > + <activity android:name="com.example.project.FreneticActivity" + android:icon="@drawable/small_pic.png" + android:label="@string/freneticLabel" + . . . > + <intent-filter . . . > + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + <intent-filter . . . > + <action android:name="com.example.project.BOUNCE" /> + <data android:mimeType="image/jpeg" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + . . . + </application> +</manifest></pre> + +<p> +この例の 1 つ目のフィルタは、アクション「{@code android.intent.action.MAIN}」とカテゴリ「{@code android.intent.category.LAUNCHER}」を組み合わせた一般的なフィルタです。このフィルタは、アプリケーション ランチャ(ユーザーがデバイス上で起動できるアプリケーションを一覧表示した画面)に、このアクティビティを表示する必要があることを示しています。つまり、このアクティビティはアプリケーションへのエントリ ポイントとして機能し、ユーザーがランチャでそのアプリケーションを選択したときに最初に表示されるということです。 +</p> + +<p> +2 つ目のフィルタでは、アクティビティが特定のタイプのデータに対して実行できるアクションを宣言しています。 +</p> + +<p> +コンポーネントにはインテント フィルタをいくつでも指定でき、それぞれのフィルタで別々の機能を宣言できます。フィルタが 1 つも指定されていないコンポーネントは、そのコンポーネントが対象として明示的に指名されているインテントでのみアクティブにできます。 +</p> + +<p> +コード内で作成して登録したブロードキャスト レシーバの場合、インテント フィルタは {@link android.content.IntentFilter} オブジェクトとして直接インスタンス化されます。それ以外の全てのフィルタは、マニフェストで設定します。 +</p> + +<p> +インテント フィルタについて詳しくは、<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> をご覧ください。 +</p> + + +<h2 id="acttask">アクティビティとタスク</h2> + +<p> +既に説明したように、あるアクティビティから別のアクティビティを開始することができます。これには、別のアプリケーションで定義されているアクティビティも含まれます。たとえば、ユーザーに特定の場所の地図を表示するとします。そのためのアクティビティは既に存在しているので、現在のアクティビティで必要な情報を Intent オブジェクトに格納して {@code startActivity()} に渡すだけで、マップ ビューアに地図を表示できます。ユーザーが [戻る] キーを押すと、画面に元のアクティビティが再表示されます。 +</p> + +<p> +この場合、マップ ビューアは別のアプリケーションで定義されており、そのアプリケーションのプロセスで実行されていますが、ユーザーにとってはマップ ビューアが元のアプリケーションの一部であるかのように感じられます。Android では、両方のアクティビティを同じタスクに組み込むことで、このようなユーザー エクスペリエンスを実現できます。<i></i>簡単に言えば、ユーザーが 1 つの「アプリケーション」と感じるものがタスクです。関連するアクティビティをスタックにまとめたものがタスクです。スタック内のルート アクティビティは、タスクを開始するアクティビティです。通常であれば、ユーザーがアプリケーション ランチャで選択するアクティビティがこれに相当します。スタックの最上位にあるアクティビティは、ユーザーのアクションの焦点となっている実行中のアクティビティです。あるアクティビティから別のアクティビティを開始すると、そのアクティビティが新たにスタックにプッシュされて実行中のアクティビティになります。1 つ前のアクティビティはスタック内に残されています。ユーザーが [[]戻る] キーを押すと、現在のアクティビティがスタックからポップされ、1 つ前のアクティビティが実行中のアクティビティとして再開されます。 +</p> + +<p> +スタックはオブジェクトを保持します。したがって、同じ Activity サブクラスのインスタンス(たとえばマップ インスタンス)を複数開くと、それぞれのインスタンスが別々のエントリになります。スタック内のアクティビティは、プッシュまたはポップされるのみで再配置されることはありません。 +</p> + +<p> +タスクはアクティビティのスタックであり、マニフェスト ファイル内のクラスや要素ではありません。したがって、アクティビティと無関係にタスクの値を設定することはできません。タスクの値は、ルート アクティビティでまとめて設定します。たとえば、次のセクションでは「タスクの親和性」について説明しますが、値はタスクのルート アクティビティの親和性のセットから読み込まれます。 +</p> + +<p> +タスク内のアクティビティは、1 つのユニットとして一緒に移動します。タスク全体(アクティビティ スタック全体)をフォアグラウンドに移動したり、バックグラウンドに移動したりできます。たとえば、現在のタスクは 4 つのアクティビティからなるスタックで、現在のアクティビティの下にアクティビティが 3 つあるとします。ここで、ユーザーが [ホーム] キーを押してアプリケーション ランチャに移動し、新しいアプリケーション(実際には新しいタスク)を選択したとします。<i></i>すると、現在のタスクはバックグラウンドに移動し、新しいタスクのルート アクティビティが表示されます。しばらくして、ユーザーがホーム画面に戻り 1 つ前のアプリケーション(タスク)を選択すると、そのタスクがスタック内の 4 つのアクティビティとともにフォアグラウンドに移動します。ここでユーザーが [戻る] キーを押しても、中断したばかりのアプリケーション(1 つ前のタスクのルート アクティビティ)は表示されません。代わりに、スタックの最上位のアクティビティがポップされ、同じタスクの 1 つ前のアクティビティが表示されます。 +</p> + +<p> +アクティビティとタスクの動作としては、ここで説明した動作がデフォルトです。ただし、この動作のほとんどの要素は変更可能です。タスクとアクティビティの関連付けやタスク内でのアクティビティの動作は、アクティビティを開始した Intent オブジェクトのフラグ セットと、マニフェストに指定されているアクティビティの <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の属性セットとの相互作用によって決まります。リクエスト側と応答側の両方が動作に影響を及ぼします。 +</p> + +<p> +この点において、主に使用する Intent フラグは以下のとおりです: + +<p style="margin-left: 2em">{@code FLAG_ACTIVITY_NEW_TASK} <br/>{@code FLAG_ACTIVITY_CLEAR_TOP} <br/>{@code FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} <br/>{@code FLAG_ACTIVITY_SINGLE_TOP}</p> + +<p> +また、主に使用する {@code <activity>} 属性は以下のとおりです: + +<p style="margin-left: 2em">{@code taskAffinity} <br/>{@code launchMode} <br/>{@code allowTaskReparenting} <br/>{@code clearTaskOnLaunch} <br/>{@code alwaysRetainTaskState} <br/>{@code finishOnTaskLaunch}</p> + +<p> +以降のセクションでは、これらのフラグや属性の役割、相互作用の仕組み、使用する際の留意事項などについて説明します。 +</p> + + +<h3 id="afftask">親和性と新しいタスク</h3> + +<p> +デフォルトでは、アプリケーション内のすべてのアクティビティは相互に親和性があり、すべてのアクティビティができる限り同じタスクに属そうとします。<i></i>ただし、{@code <activity>} 要素の {@code taskAffinity} 属性を使用して、アクティビティごとに個別の親和性を設定することもできます。つまり、別々のアプリケーションで定義されているアクティビティで親和性を共有したり、同じアプリケーションで定義されているアクティビティに別々の親和性を割り当てたりできるということです。親和性が作用する状況は 2 つあります。1 つはアクティビティを起動する Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、もう 1 つはアクティビティの {@code allowTaskReparenting} 属性が "{@code true}" に設定されている場合です。 +</p> + +<dl> +<dt><code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> フラグ</dt> +<dd>既に説明したとおり、新しいアクティビティは、デフォルトでは {@code startActivity()} を呼び出したアクティビティのタスクの一部として起動します。つまり、呼び出し側のアクティビティと同じスタックにプッシュされるということです。しかし、{@code startActivity()} に渡された Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、システムはその新しいアクティビティを別のタスクに収容しようとします。フラグの名前からも判断できますが、ほとんどの場合は新しいタスクが開始されます。ただし常にそうなるとは限りません。既存のタスクに新しいアクティビティと同じ親和性が割り当てられている場合、そのアクティビティはそのタスクの一部として起動します。そうでない場合には、新しいタスクが開始されます。</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code> 属性</dt> +<dd>{@code allowTaskReparenting} 属性が "{@code true}" に設定されているアクティビティは、そのアクティビティと親和性のあるタスクがフォアグラウンドに移ったときに、アクティビティを開始したタスクから親和性のあるタスクに移動できます。たとえば、旅行アプリケーションの一部として、選択された都市の天気予報を表示するアクティビティが定義されているとします。このアクティビティには、同じアプリケーション内の他のアクティビティと同じ親和性(デフォルトの親和性)が割り当てられていますが、その親の割り当てを変更することも可能です。あるアクティビティが天気予報アクティビティを開始すると、その時点では開始側のアクティビティと同じタスクに属した状態になります。しかし、次に旅行アプリケーションがフォアグラウンドに移ると、天気予報アクティビティの割り当てが変更され、旅行アプリケーションのタスクの一部として表示されます。</dd> +</dl> + +<p> +ユーザーから見て複数の「アプリケーション」が 1 つの {@code .apk} ファイルに含まれている場合は、それぞれのアプリケーションに関連付けられているアクティビティに別々の親和性を割り当てることをおすすめします。 +</p> + + +<h3 id="lmodes">起動モード</h3> + +<p> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code> 属性の {@code <activity>} 要素には、以下の 4 種類の起動モードを割り当てることができます: +</p> + +<p style="margin-left: 2em">"{@code standard}"(デフォルト モード)<br>"{@code singleTop}"<br>"{@code singleTask}"<br>"{@code singleInstance}"</p> + +<p> +これらのモードは、それぞれが以下の 4 つの点で異なります: +</p> + +<ul> + +<li><b>インテントに応答するアクティビティをどのタスクに保持するか</b>。"{@code standard}" および "{@code singleTop}" モードの場合は、そのインテントを開始した(つまり <code>{@link android.content.Context#startActivity startActivity()}</code> を呼び出した)タスクに保持されます。ただし、Intent オブジェクトに <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> フラグが含まれている場合は、前のセクション<a href="#afftask">親和性と新しいタスク</a>で説明したとおり、別のタスクが選択されます。 + +<p> +一方、"{@code singleTask}" および "{@code singleInstance}" モードの場合は、アクティビティが常にタスクのルート アクティビティになります。タスクは定義されており、他のタスクの一部として起動されることはありません。 +</p> + +<li><p><b>アクティビティのインスタンスを複数生成できるか</b>。"{@code standard}" または "{@code singleTop}" アクティビティは複数回インスタンス化できます。それらのインスタンスを複数のタスクに割り当てることも、特定のタスクに同じアクティビティの複数のインスタンスを割り当てることも可能です。 +</p> + +<p> +一方、"{@code singleTask}" および "{@code singleInstance}" アクティビティのインスタンスは 1 つに制限されます。これらのアクティビティはタスクのルートに当たります。したがって、これらのタスクの複数のインスタンスがデバイス上に同時に存在することはないということになります。 +</p> + +<li><p><b>インスタンスのタスクに他のアクティビティを含めることができるか</b>。"{@code singleInstance}" アクティビティは、そのタスク内の唯一のアクティビティとして単独で動作します。ここから別のアクティビティを開始した場合、そのアクティビティは起動モードに関係なく、あたかもインテントに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれているかのように別のタスクで起動します。"{@code singleInstance}" モードと "{@code singleTask}" モードは、これ以外の点ではまったく同じです。</p> + +<p> +他の 3 つのモードでは、タスクに複数のアクティビティを割り当てることができます。"{@code singleTask}" アクティビティは、常にタスクのルート アクティビティになりますが、同じタスクに割り当てることになる別のアクティビティを開始することができます。"{@code standard}" および "{@code singleTop}" アクティビティのインスタンスは、スタック内のどの位置にでも配置できます。 +</p></li> + +<li><b>クラスの新しいインスタンスを起動して新しいインテントを処理するかどうか</b>。デフォルトの "{@code standard}" モードの場合は、新しいインテントに応答するときには必ず新しいインスタンスが作成されます。それぞれのインスタンスで処理するインテントは 1 つのみです。"{@code singleTop}" モードの場合は、クラスの既存のインスタンスが対象タスクのアクティビティ スタックの最上位にあれば、それを再利用して新しいインテントを処理します。スタックの最上位にない場合は再利用されません。代わりに、新しいインスタンスが作成されてスタックにプッシュされ、新しいインテントの処理に使用されます。 + +<p> +たとえば、タスクのアクティビティ スタックに、ルート アクティビティ A とアクティビティ B、C、D が含まれているとします。スタック内のアクティビティの順序は A-B-C-D で D が最上位です。ここに、アクティビティのタイプが D のインテントが届きます。D の起動モードがデフォルトの "{@code standard}" である場合は、そのクラスの新しいインスタンスが起動し、スタックは A-B-C-D-D となります。しかし、D の起動モードが "{@code singleTop}" であれば、スタックの最上位は D なので、新しいインテントは既存のインスタンスによって処理されるはずです。したがって、スタックは A-B-C-D のままとなります。 +</p> + +<p> +一方、届いたインテントのアクティビティ タイプが B だった場合は、B のモードが "{@code standard}" であっても "{@code singleTop}"であっても B の新しいインスタンスが起動します。これは B がスタックの最上位ではないためで、結果としてスタックは A-B-C-D-B となります。 +</p> + +<p> +"{@code singleTask}" または "{@code singleInstance}" アクティビティの場合は、既に説明したとおり同時に複数のインスタンスが存在することはないため、インスタンスは常に新しいインテントを処理することになります。"{@code singleInstance}" アクティビティはスタック内の唯一のアクティビティであるため、常にスタックの最上位、つまりインテントを処理する位置にあります。一方、"{@code singleTask}" アクティビティは、スタック内の上位に他のアクティビティがある場合とない場合があります。上位にアクティビティがある場合、インテントを処理する位置にはないため、そのインテントはドロップされます(インテントがドロップされたとしても、そのインテントが届いたことによって、タスクがフォアグラウンドに移ったままの状態になります)。 +</p> +</li> + +</ul> + +<p> +既存のアクティビティで新しいインテントを処理することになった場合は、<code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> の呼び出しによって Intent オブジェクトがアクティビティに渡されます(最初にアクティビティを開始したインテント オブジェクトは <code>{@link android.app.Activity#getIntent getIntent()}</code> を呼び出して取得できます)。 +</p> + +<p> +なお、新しいインテントを処理するためにアクティビティの新しいインスタンスが作成された場合、ユーザーは [[]戻る] キーを押して 1 つ前の状態(1 つ前のアクティビティ)に戻ることができます。しかし、アクティビティの既存のインスタンスで新しいインテントを処理する場合は、[[]戻る] キーを押しても、新しいインテントが届く前にそのインスタンスで処理していた作業に戻ることはできません。 +</p> + +<p> +起動モードについて詳しくは、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の説明をご覧ください。 +</p> + + +<h3 id="clearstack">スタックのクリア</h3> + +<p> +ユーザーがタスクを長時間放置すると、タスクのルート アクティビティを除くすべてのアクティビティがクリアされます。ユーザーがタスクに戻ると、タスクは以前のように表示されますが、残っているのは最初のアクティビティだけです。つまり、一定の時間が経過していればユーザーは以前の作業を放棄していて、新しい作業をするためにそのタスクに戻ってきたと考えるわけです。 +</p> + +<p> +これがデフォルトです。この動作を変更したい場合は、以下のアクティビティ属性を使用します: +</p> + +<dl> +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code> 属性</dt> +<dd>タスクのルート アクティビティでこの属性を "{@code true}" に設定すると、上で説明したデフォルトの動作は発生しません。長時間経過しても、タスク内のすべてのアクティビティはそのまま残されます。</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code> 属性</dt> +<dd>タスクのルート アクティビティでこの属性を "{@code true}" に設定した場合、ユーザーがいったんタスクを離れると、戻ったときにはルートを含むすべてのアクティビティがクリアされています。つまり、{@code alwaysRetainTaskState} の正反対の動作になります。ユーザーが一瞬でもタスクを離れると、最初の状態からやり直すことになります。</dd> + +<dt><code><a +href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code> 属性</dt> +<dd>この属性は {@code clearTaskOnLaunch} に似ていますが、タスク全体ではなく単一のアクティビティに作用します。また、ルート アクティビティを含むどのアクティビティもクリアの対象となりえます。この属性が "{@code true}" に設定されたアクティビティは、現在のセッションの間のみタスクの一部を形成します。ユーザーがいったんそのタスクから離れてから、再度タスクに戻ると、このアクティビティはクリアされています</dd> +</dl> + +<p> +アクティビティをスタックから削除する方法は他にもあります。Intent オブジェクトに <code>{@link +android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_CLEAR_TOP}</code> フラグが含まれており、そのインテントを処理すべきタイプのアクティビティのインスタンスが対象タスクのスタック内に存在する場合は、そのインスタンスがスタックの最上位になってインテントに応答できるよう、それより上位のアクティビティはすべてクリアされます。指定されたアクティビティの起動モードが "{@code standard}" である場合は、そのアクティビティもスタックから削除され、新しいインスタンスが起動してインテントを処理します。起動モード "{@code standard}" では、新しいインテントを処理する際、常に新しいインスタンスが作成されるためです。 +</p> + +<p> +{@code FLAG_ACTIVITY_CLEAR_TOP} は、ほとんどの場合 {@code FLAG_ACTIVITY_NEW_TASK} と組み合わせて使用します。これらのフラグを組み合わせると、別のタスクに既に存在しているアクティビティを探し、それをインテントに応答できる位置に配置できます。 +</p> + + +<h3 id="starttask">タスクの開始</h3> + +<p> +アクティビティをタスクのエントリ ポイントとして設定するには、アクションとして "{@code android.intent.action.MAIN}"、カテゴリとして "{@code android.intent.category.LAUNCHER}" を指定したインテント フィルタをアクティビティに追加します(このタイプのフィルタの例については、<a href="#ifilters">インテント フィルタ</a>をご覧ください)。このタイプのフィルタを追加すると、アクティビティのアイコンとラベルがアプリケーション ランチャに表示されます。これにより、ユーザーがタスクを起動するための手段を提供できるだけでなく、起動後はいつでもそのタスクに戻れるようにすることができます。 +</p> + +<p> +この 2 番目の機能、つまりユーザーがいったんタスクを離れても後で戻ることができるようにする点が重要です。この理由から、アクティビティに {@code MAIN} と {@code LAUNCHER} フィルタが指定されている場合は、必ずタスクが開始される起動モード("{@code singleTask}" または "{@code singleInstance}")を使用する必要があります。たとえば、このフィルタを指定しなかった場合を考えてみましょう。インテントが "{@code singleTask}" アクティビティを起動し、新しいタスクが開始され、ユーザーがしばらくの間このタスクで作業を行います。その後、ユーザーが [ホーム] キーを押したとします。ホーム画面が表示され、先ほどのタスクはバックグラウンドに移動します。しかし、このタスクはアプリケーション ランチャには表示されていないため、ユーザーがタスクに戻るための手段がありません。 +</p> + +<p> +{@code FLAG_ACTIVITY_NEW_TASK} フラグにも、これと同じような難しさがあります。このフラグを指定したアクティビティでは、新しいタスクを開始した後にユーザーが [ホーム] キーを押してそのタスクを離れた場合に備え、タスクに戻るための手段を用意しておく必要があります。一部のエンティティ(たとえば通知マネージャ)は、アクティビティを常に外部タスクとして開始します。エンティティの一部として開始することはないため、{@code startActivity()} に渡すインテントには必ず {@code FLAG_ACTIVITY_NEW_TASK} を指定します。外部エンティティから呼び出すことのできるアクティビティでこのフラグが使用されている可能性がある場合は、開始されたタスクにユーザーが戻るための手段を別途提供するようにしてください。 +</p> + +<p> +ユーザーがアクティビティに戻ることができるようにしない場合は、{@code <activity>} 要素の {@code finishOnTaskLaunch} を "{@code true}" に設定します。詳しくは、<a href="#clearstack">スタックのクリア</a>をご覧ください。 +</p> + + +<h2 id="procthread">プロセスとスレッド</h2> + +<p> +Android では、最初のアプリケーション コンポーネントを実行する必要が生じると、そのための Linux プロセスを単一の実行スレッドで開始します。デフォルトでは、アプリケーションのすべてのコンポーネントがそのプロセスとスレッドで実行されます。 +</p> + +<p> +ただし、コンポーネントが他のプロセスで実行されるようにしたり、特定のプロセスに使用する追加スレッドを生成したりすることも可能です。 +</p> + + +<h3 id="procs">プロセス</h3> + +<p> +コンポーネントを実行するプロセスは、マニフェスト ファイルで管理します。コンポーネントの各要素({@code <activity>}、{@code <service>}、{@code <receiver>}、および {@code <provider>})には {@code process} 属性があり、そのコンポーネントをどのプロセスで実行すべきかを指定できるようになっています。これらの属性の設定によって、それぞれのコンポーネントを専用のプロセスで実行したり、一部のコンポーネントだけでプロセスを共有したりできます。また、別々のアプリケーションのコンポーネントが、同じプロセスで実行されるように設定することもできます。この場合は、それらのアプリケーションが同じ Linux ユーザー ID を共有し、同じ認証機関によって署名されている必要があります。{@code <application>} 要素にも {@code process} 属性があり、すべてのコンポーネントに適用されるデフォルト値を設定できます。 +</p> + +<p> +すべてのコンポーネントは指定されたプロセスのメイン スレッドでインスタンス化され、コンポーネントに対するシステム コールはそのスレッドからディスパッチされます。1 つのインスタンスに対して、複数のスレッドが作成されることはありません。したがって、システム コールに応答するメソッド(たとえば、後ほど<a href="#lcycles">コンポーネント ライフサイクル</a>で説明するライフサイクル通知や、ユーザーのアクションを報告する <code>{@link android.view.View#onKeyDown View.onKeyDown()}</code> のようなメソッド)は、常にそのプロセスのメイン スレッドで実行されます。つまり、コンポーネントがシステムから呼び出されたときに、プロセス内の他のコンポーネントの実行を妨げないよう、実行に時間がかかる処理や他の妨げになることの多い処理(ネットワーク処理、ループ計算など)をできる限り避ける必要があるということです。時間がかかる処理には別のスレッドを生成できます。詳しくは、次の<a href="#threads">スレッド</a> セクションをご覧ください。 +</p> + +<p> +状況によっては、Android がプロセスを終了させるべきと判断する場合があります。たとえば、メモリが不足してきた場合や、他のプロセスでユーザーにすばやく応答する必要がある場合です。プロセスが終了すると、そのプロセス内で実行されているアプリケーション コンポーネントは破棄されます。それらのコンポーネントで処理する作業がもう一度発生すると、そのためのプロセスが再び開始されます。 +</p> + +<p> +Android では、どのプロセスを終了させるかを判断するため、ユーザーにとっての相対的な重要度を重み付けして管理します。たとえば、アクティビティがまだ画面に表示されているプロセスを終了させるよりも、アクティビティが画面に表示されていないプロセスを終了させる方が合理的です。したがって、プロセスを終了させるかどうかは、そのプロセスで実行されているコンポーネントの状態に応じて判断されるということです。コンポーネントの状態については、後ほど<a href="#lcycles">コンポーネントのライフサイクル</a>で詳しく説明します。 +</p> + + +<h3 id="threads">スレッド</h3> + +<p> +アプリケーションを単一のプロセスに限定したとしても、バックグラウンドでの処理にスレッドが必要になることはよくあります。ユーザー インターフェースはユーザーのアクションに対して常にすばやく応答できなければならないため、アクティビティをホストするスレッドで、ネットワーク ダウンロードのような時間のかかる処理を一緒にホストしないようにする必要があります。すぐに完了しない可能性のあるすべての処理は、別のスレッドに割り当てるようにしてください。 +</p> + +<p> +スレッドは、標準の Java {@link java.lang.Thread} オブジェクトを使用してコード内で作成します。Android には、スレッドを管理するための便利なクラスが数多く用意されています。たとえば、スレッド内でメッセージ ループを実行するための {@link android.os.Looper}、メッセージを処理するための {@link android.os.Handler}、メッセージ ループでスレッドを設定するための {@link android.os.HandlerThread} などがあります。 +</p> + + +<h3 id="rpc">リモート プロシージャ コール</h3> + +<p> +Androidは軽量な仕組みのリモート・プロシージャ・コール (RPC) を採用しています。RPC とは、メソッドをローカルで呼び出しますが、実行はリモート(別のプロセス)で行い、その結果を呼び出し側に返します。そのためには、メソッド呼び出しとそれに付随するデータをオペレーティングシステムが解釈できるレベルまで分解してから、それらをローカルのプロセスとアドレス空間からリモートのプロセスとアドレス空間に転送し、リモートで呼び出しを再構築する必要があります。戻り値は、反対方向に転送しなければなりません。Android にはこの処理を行うためのコードがすべて用意されているため、RPC インターフェースを定義して実装するだけで RPC を利用できます。 +</p> + +<p> +RPC インターフェースに含めることができるのはメソッドのみです。すべてのメソッドは、戻り値がない場合でも同期的に実行されます(つまり、リモート メソッドが完了するまでローカル メソッドがブロックされます)。 +</p> + +<p> +このメカニズムを簡単に説明すると次のようになります。まず、シンプルなインターフェース定義言語(IDL)を使用して、実装したい RPC インターフェースを宣言します。<code><a href="{@docRoot}guide/components/aidl.html">aidl</a></code> ツールにより、RPC インターフェースの宣言から Java インターフェース定義が生成されます。この定義は、ローカルとリモートの両方のプロセスで使用する必要があります。定義には、次の図に示すように 2 つの内部クラスが含まれています: +</p> + +<p style="margin-left: 2em"> +<img src="{@docRoot}images/binder_rpc.png" alt="RPC のメカニズム" /> +</p> + +<p> +これらの内部クラスには、IDL で宣言したインターフェースのリモート プロシージャ コールを管理するために必要なコードがすべて含まれています。どちらの内部クラスも {@link android.os.IBinder} インターフェースを実装します。一方の内部クラスは、ローカルのシステムで内部的に使用しますが、記述するコードでは無視しても構いません。もう一方の内部クラスはスタブと呼ばれ、{@link android.os.Binder} クラスを拡張します。スタブには、IPC(プロセス間通信)呼び出しを発生させるための内部コードに加え、IDL で宣言した RPC インターフェース内のメソッドの宣言が含まれます。これらのメソッドを実装するには、図に示すようにスタブをサブクラス化します。2つの内部クラスのうちの一方は、システムがローカルかつ内部的に使用するので、開発者が記述するコードでは無視してかまいません。... リモート側では、図のようにスタブをサブクラス化して、これらのメソッドを実装する必要があります。 +</p> + +<p> + 通常、リモート プロセスはサービスで管理します。サービスなら、プロセスや他のプロセスへの接続に関する情報をシステムに伝えることができるからです。サービスには、{@code aidl} ツールで生成されたインターフェース ファイルと、RPC メソッドを実装するスタブ サブクラスの両方を持たせることになります。サービスのクライアントには、{@code aidl} ツールで生成されたインターフェース ファイルのみを持たせます。 +</p> + +<p> +以下に、サービスとそのクライアントの間の接続がどのように設定されるかを示します: +</p> + +<ul> +<li>サービスのクライアント(ローカル側)には <code>{@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()}</code> および<code>{@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()}</code> メソッドが実装されているため、リモート サービスとの接続が確立されたときや切断されたときには通知を受けることができます。通知があり次第、<code>{@link android.content.Context#bindService bindService()}</code> を呼び出して接続を設定します。 +</li> + +<li> +サービスの <code>{@link android.app.Service#onBind onBind()}</code> メソッドは、受け取ったインテント({@code bindService()} に渡されたインテント)に応じて、接続を承認または拒否するために実装します。接続が承認されると、接続を承認するのであれば、スタブ サブクラスのインスタンスを返します。 +</li> + +<li>サービスが接続を承認すると、Android がクライアントの {@code onServiceConnected()} メソッドを呼び出し、IBinder オブジェクト(サービスが管理するスタブ サブクラスのプロキシ)を渡します。クライアントは、このプロキシを介してリモートサービスを呼び出すことができます。 +</li> +</ul> + +<p> +ここでは、説明を簡単にするため、RPC メカニズムの細かい点は省略しています。詳しくは、<a href="{@docRoot}guide/components/aidl.html">Designing a Remote Interface Using AIDL</a>、および {@link android.os.IBinder IBinder} クラスの説明をご覧ください。 +</p> + + +<h3 id="tsafe">スレッドセーフなメソッド</h3> + +<p> +状況によっては実装したメソッドが複数のスレッドから呼び出されることもあるため、スレッドセーフな記述を心掛ける必要があります。 +</p> + +<p> +前のセクションで説明した RPC のようにメソッドをリモートで呼び出すことができる場合は、このような状況が特に発生しやすくなります。IBinder オブジェクトに実装されているメソッドを IBinder と同じプロセスから呼び出すと、そのメソッドは呼び出し側のスレッドで実行されます。一方、別のプロセスからメソッドを呼び出した場合は、プロセスのメイン スレッドではなく、IBinder と同じプロセス内に保持されているスレッドのプールから選択されたスレッドで実行されます。たとえば、サービスの {@code onBind()} メソッドはそのサービスのプロセスのメイン スレッドから呼び出されるのに対し、{@code onBind()} から返されたオブジェクトに実装されているメソッド(たとえば RPC メソッドを実装するスタブ サブクラス)はプール内のスレッドから呼び出されます。サービスには複数のクライアントを割り当てることができるため、複数のプール スレッドを同じ IBinder に同時に割り当てることも可能です。したがって、IBinder メソッドはスレッドセーフになるように実装する必要があります。 +</p> + +<p> +同様に、コンテンツ プロバイダも別のプロセスからのデータ リクエストを受け取ることができます。ContentResolver および ContentProvider クラスはプロセス間通信の管理の詳細を隠蔽しますが、それらのリクエストに応答する ContentProvider メソッド(<code>{@link android.content.ContentProvider#query query()}</code>、<code>{@link android.content.ContentProvider#insert insert()}</code>、<code>{@link android.content.ContentProvider#delete delete()}</code>、<code>{@link android.content.ContentProvider#update update()}</code>、および <code>{@link android.content.ContentProvider#getType getType()}</code> メソッド)は、プロセスのメイン スレッドではなく、コンテンツ プロバイダのプロセス内のスレッドのプールから呼び出されます。これらのメソッドを同時に呼び出すことのできるメソッドの数に制限はありません。したがって、これらのメソッドもスレッドセーフになるように実装する必要があります。 +</p> + + +<h2 id="lcycles">コンポーネントのライフサイクル</h2> + +<p> +アプリケーション コンポーネントにはライフサイクルがあります。ライフサイクルは、インテントへ応答することでのインスタンス化で始まり、そのインスタンスの破棄で終わります。この間、コンポーネントがアクティブなときとアクティブでないときがあり、アクティビティであればユーザーから見えるときと見えないときがあります。このセクションでは、アクティビティ、サービス、およびブロードキャスト レシーバのライフサイクルについて説明します。具体的には、それぞれがライフタイムの間に取ることのできる状態、状態の遷移を通知する方法、およびそれらの状態が、コンポーネントを実行しているプロセスが終了させられたり、インスタンスが破棄されたりする可能性への影響などについて説明します。 +</p> + + +<h3 id="actlife">アクティビティのライフサイクル</h3> + +<p>アクティビティは、基本的に以下の 3 つの状態を取ります:</p> + +<ul> +<li> 状態がアクティブまたは実行中のアクティビティは、画面のフォアグラウンドに表示されている(つまり現在のタスクのアクティビティ スタックの最上位にある)アクティビティです。<em></em><em></em>これが、ユーザーのアクションの焦点となっているアクティビティです。</li> + +<li><p>状態が一時停止のアクティビティは、ユーザーのアクションの焦点から外れていますが、まだユーザーから見ることのできるアクティビティです。<em></em>つまり、それよりも前面に他のアクティビティが表示されていますが、そのアクティビティが透明か全画面表示でないかのどちらかで、一時停止しているアクティビティの一部が見えている状態です。一時停止しているアクティビティは、完全に動作しています(すべての状態やメンバー情報は保持されており、ウィンドウ マネージャにアタッチされたままになっています)。ただし、メモリが極端に不足した場合は、システムによって強制終了させられる可能性があります。</p></li> + +<li><p>状態が停止のアクティビティは、別のアクティビティに隠されて完全に見えなくなったアクティビティです。<em></em>すべての状態とメンバー情報はまだ保持しています。しかし、もうユーザーに対して表示されていないため、他でメモリが必要な場合は強制終了させられる可能性が高いアクティビティです。</p></li> +</ul> + +<p> +システムが一時停止または停止しているアクティビティをメモリから削除する場合は、アクティビティの {@link android.app.Activity#finish finish()} メソッドを呼び出して終了を要求するか、単純のそのプロセスを強制終了します。そのアクティビティをもう一度ユーザーに表示する際は、完全に再起動して以前の状態に復元する必要があります。 +</p> + +<p> +アクティビティがある状態から別の状態に遷移すると、以下の protected メソッドに対する呼び出しによって変更が通知されます: +</p> + +<p style="margin-left: 2em">{@code void onCreate(Bundle <i>savedInstanceState</i>)} <br/>{@code void onStart()} <br/>{@code void onRestart()} <br/>{@code void onResume()} <br/>{@code void onPause()} <br/>{@code void onStop()} <br/>{@code void onDestroy()}</p> + +<p> +これらのメソッドはすべて、状態が変化したときに適切な処理を行うためにオーバーライドできるフックです。オブジェクトが初めてインスタンス化されたときに初期設定を行うため、すべてのアクティビティには <code>{@link android.app.Activity#onCreate onCreate()}</code> を実装する必要があります。多くのアクティビティには、データの変更をコミットするための <code>{@link android.app.Activity#onPause onPause()}</code> も実装します。これを実装しない場合は、何らかの方法でユーザーとの対話を停止できるようにしておく必要があります。 +</p> + +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h2>スーパークラスの呼び出し</h2> +<p> +どのアクティビティ ライフサイクル メソッドの実装でも、必ず最初にスーパークラス バージョンを呼び出す必要があります。次に例を示します: +</p> + +<pre>protected void onPause() { + super.onPause(); + . . . +}</pre> +</div> +</div> + + +<p> +これら 7 つのメソッドを使用すると、アクティビティのライフサイクル全体を定義できます。これらを実装することで、ネストされた 3 つのループからなるアクティビティのライフサイクルを監視できます: +</p> + +<ul> +<li>アクティビティの<b>ライフタイム全体</b>は、<code>{@link android.app.Activity#onCreate onCreate()}</code> が初めて呼び出されたときに始まり、最後に <code>{@link android.app.Activity#onDestroy}</code> が呼び出されたときに終了します。アクティビティは、{@code onCreate()} で「全体的」な状態のすべての初期設定を行い、{@code onDestroy()} 残っていたリソースをすべて解放します。たとえば、ネットワークからのデータのダウンロードをバックグラウンドで実行するスレッドは、{@code onCreate()} で作成され、{@code onDestroy()} で停止します。</li> + +<li><p>アクティビティの<b>可視ライフタイム</b>は、<code>{@link android.app.Activity#onStart onStart()}</code> の呼び出しで始まり、対応する <code>{@link android.app.Activity#onStop onStop()}</code> の呼び出しで終了します。このライフタイムの間は、ユーザーが画面上でそのアクティビティを見ることができます。ただし、アクティビティがフォアグラウンドにない場合や、ユーザーと対話していない場合もあります。これらの 2 つのメソッドの間は、ユーザーに対してアクティビティを表示するために必要なリソースを確保できます。たとえば、{@code onStart()} で {@link android.content.BroadcastReceiver} を登録して UI に影響する変化を監視し、表示しているアクティビティがユーザーから見えなくなったら {@code onStop()} で登録を解除できます。{@code onStart()} および {@code onStop()} メソッドは、アクティビティがユーザーから見え隠れするたびに繰り返し呼び出すことができます。</p></li> + +<li><p>アクティビティの<b>フォアグラウンド ライフタイム</b>は、<code>{@link android.app.Activity#onResume onResume()}</code> の呼び出しで始まり、対応する <code>{@link android.app.Activity#onPause onPause()}</code> の呼び出しで終了します。フォアグラウンド ランタイムの間は、このアクティビティが他のどのアクティビティよりも前面に表示され、ユーザーと対話しています。アクティビティは、一時停止状態と再開状態の間を頻繁に遷移します。たとえば、デバイスがスリープ状態になるときや新しいアクティビティを開始するときには {@code onPause()} が呼び出され、アクティビティの結果や新しいインテントが届いたときには {@code onResume()} が呼び出されます。したがって、これらのメソッドを記述する際は、できるだけ軽量化しておく必要があります。</p></li> +</ul> + +<p> +次の図に、これらのループとアクティビティの遷移経路を示します。色の付いた楕円は、アクティビティが取ることのできる主な状態です。長方形は、アクティビティが状態間を遷移するときに処理を実行するために実装できるコールバック メソッドを表します。 +<p> + +<p style="margin-left: 2em"><img src="{@docRoot}images/activity_lifecycle.png" +alt="Android のアクティビティ ライフサイクルの状態遷移図" /></p> + +<p> +次の表では、各メソッドについて詳しく説明し、ライフサイクル全体における位置付けを示します: +</p> + +<table border="2" width="85%" frame="hsides" rules="rows"> +<colgroup align="left" span="3"></colgroup> +<colgroup align="left"></colgroup> +<colgroup align="center"></colgroup> +<colgroup align="center"></colgroup> + +<thead> +<tr><th colspan="3">メソッド</th> <th>説明</th> <th>強制終了</th> <th>次</th></tr> +</thead> + +<tbody> +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td> + <td>アクティビティが初めて作成されるときに呼び出されます。通常の静的な設定(ビューの作成、リストへのデータのバインドなど)は、すべてのこのメソッドで行う必要があります。このアクティビティの 以前の状態が保存されていた場合、このメソッドにはその状態を保持している Bundle オブジェクトが引数として(詳しくは、後述の<a href="#actstate">アクティビティの状態の保存</a>をご覧ください)。 + <p>この後には、必ず {@code onStart()} が呼び出されます。</p></td> + <td align="center">不可</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td rowspan="5" style="border-left: none; border-right: none;"> </td> + <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart +onRestart()}</code></td> + <td>アクティビティが停止した後、それをもう一度開始する直前に呼び出されます。 + <p>この後には、必ず {@code onStart()} が呼び出されます。</p></td> + <td align="center">不可</td> + <td align="center">{@code onStart()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td> + <td>アクティビティがユーザーから見えるようになる直前に呼び出されます。 + <p>その後、アクティビティがフォアグラウンドに表示された場合は {@code onResume()} が、他のアクティビティの後ろに隠れた場合は {@code onStop()} が呼び出されます。</p></td> + <td align="center">不可</td> + <td align="center">{@code onResume()} <br/>または<br/>{@code onStop()}</td> +</tr> + +<tr> + <td rowspan="2" style="border-left: none;"> </td> + <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td> + <td>アクティビティがユーザーとの対話を開始する直前に呼び出されます。この時点で、アクティビティはアクティビティ スタックの最上位にあり、ユーザーからの入力はこのアクティビティに対して行われます。 + <p>この後には、必ず {@code onPause()} が呼び出されます。</p></td> + <td align="center">不可</td> + <td align="center">{@code onPause()}</td> +</tr> + +<tr> + <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td> + <td>システムが別のアクティビティを開始しようとしているときに呼び出されます。このメソッドは、保存されていない変更を永続データにコミットする場合や、アニメーションのように CPU を大量に消費する処理を停止する場合に使用するのが一般的です。このメソッドが終了するまでは次のアクティビティが開始されたないため、できる限り短時間で実行できるようにしておく必要があります。 + <p>その後、アクティビティがフォアグラウンドに戻った場合は {@code onResume()} が、ユーザーから見えなくなった場合は {@code onStop()} が呼び出されます。</td> + <td align="center"><strong style="color:#800000">可能</strong></td> + <td align="center">{@code onResume()} <br/>または<br/>{@code onStop()}</td> +</tr> + +<tr> + <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td> + <td>アクティビティがユーザーから見えなくなったときに呼び出されます。見えなくなる状況としては、アクティビティが破棄された場合や、再開された別のアクティビティ(既存か新規かを問わず)によって隠された場合が考えられます。 + <p>その後、アクティビティがユーザーとの対話に戻った場合は {@code onRestart()} が、アクティビティが完全に終了する場合は {@code onDestroy()} が呼び出されます。</p></td> + <td align="center"><strong style="color:#800000">可能</strong></td> + <td align="center">{@code onRestart()} <br/>または<br/>{@code onDestroy()}</td> +</tr> + +<tr> + <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy +onDestroy()}</code></td> + <td>アクティビティが破棄される前に呼び出されます。これが、アクティビティが受け取る最後の呼び出しとなります。このメソッドが呼び出される状況としては、アクティビティが完了する場合(<code>{@link android.app.Activity#finish + finish()}</code> が呼び出されたとき)や、システムが領域を確保するために一時的にそのアクティビティのインスタンスを破棄する場合が考えられます。これらの 2 つの状況は、<code>{@link + android.app.Activity#isFinishing isFinishing()}</code> メソッドを使用して識別できます。</td> + <td align="center"><strong style="color:#800000">可能</strong></td> + <td align="center"><em>なし</em></td> +</tr> +</tbody> +</table> + +<p> +表の<b>強制終了</b>列に注目してください。この列は、メソッドが終了した後であれば、システムがアクティビティのコードの別の行を実行することなくいつでもアクティビティを実行しているプロセスを強制終了できるかどうかを示しています。<em></em>{@code onPause()}、{@code onStop()}、および {@code onDestroy()} メソッドの 3 つは「可能」となっています。1 番目に挙げた {@code onPause()} だけは、プロセスが強制終了する前に必ず呼び出されます。{@code onStop()} と {@code onDestroy()} は、必ず呼び出されるとは限りません。したがって、永続データ(たとえばユーザーによる編集)をストレージに書き込む際は {@code onPause()} を使用する必要があります。 +</p> + +<p> +<b>強制終了</b>列が「不可」になっているメソッドは、それらが呼び出された瞬間から、アクティビティを実行しているプロセスを保護して強制終了されないようにします。したがって、アクティビティが強制終了可能な状態にあるのは、たとえば {@code onPause()} が返されてから {@code onResume()} が呼び出されるまでの間ということです。その後は、もう一度 {@code onPause()} が返されるまで、強制終了できる状態には戻りません。 +</p> + +<p> +後述の<a href="#proclife">プロセスとライフサイクル</a>のセクションで詳しく説明しますが、ここでの定義で技術的には「強制終了可能」でないアクティビティでも、システムによって強制終了させられる可能性はありますが、他に利用できるリソースがないなど、極端に急を要する場合に限られます。 +</p> + + +<h4 id="actstate">アクティビティの状態の保存</h4> + +<p> +メモリ不足を補うためにユーザーではなくシステムがアクティビティを終了させた場合には,ユーザがそのアクティビティに戻ったときに、以前の状態のままであることを期待するでしょう。 +</p> + +<p> +アクティビティが強制終了させられる前の状態を保存しておきたい場合は、アクティビティに <code>{@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()}</code> メソッドを実装します。このメソッドは、アクティビティが破棄されやすい状態になる前(つまり {@code onPause()} が呼び出される前)に呼び出されます。その際、アクティビティの動的な状態を名前/値ペアとして記録できる {@link android.os.Bundle} オブジェクトが渡されます。アクティビティがもう一度開始されると、Bundle は {@code onCreate()} だけでなく、{@code onStart()} の後に呼び出される <code>{@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}</code> メソッドにも渡され、保存されている状態をそのどちらかまたは両方で復元できます。 +</p> + +<p> +{@code onSaveInstanceState()} および {@code onRestoreInstanceState()} メソッドは、これまでに説明した {@code onPause()} などとは異なり、ライフサイクル メソッドではありません。これらのメソッドは、常に呼び出されるわけではありません。たとえば、{@code onSaveInstanceState()} は、システムによってアクティビティが破棄しやすい状態にされる前には呼び出されますが、ユーザーのアクション(たとえば [[]戻る] キー)によってインスタンスが実際に破棄されるときには呼び出されません。そのような場合は、ユーザーがそのアクティビティに戻ることを想定する必要はないため、状態を保存する理由がないのです。 +</p> + +<p> +{@code onSaveInstanceState()} は常に呼び出されるとは限らないため、アクティビティの一時的な状態を記録する目的のみに使用し、永続データの格納には使用しないようにしてください。この目的には {@code onPause()} を使用します。 +</p> + + +<h4 id="coordact">アクティビティの協調</h4> + +<p> +あるアクティビティが別のアクティビティを開始すると、両方のアクティビティのライフサイクル状態が遷移します。一方が一時停止または停止し、もう一方が開始されます。場合によっては、これらの協調させる必要があります。 +</p> + +<p> +ライフサイクルのコールバックの順序は明確に定義されており、特に 2 つのアクティビティが同じプロセス内に存在する場合は次のようになります: +</p> + +<ol> +<li>現在のアクティビティの {@code onPause()} メソッドが呼び出されます。</li> + +<li>続いて、開始されるアクティビティの {@code onCreate()}、{@code onStart()}、および {@code onResume()} メソッドが順番に呼び出されます。</li> + +<li>その後、開始されたアクティビティが画面上で見えなくなると、その {@code onStop()} メソッドが呼び出されます。</li> +</ol> + + +<h3 id="servlife">サービスのライフサイクル</h3> + +<p> +サービスは、以下の 2 つの方法で使用できます: +</p> + +<ul> +<li>いったん開始したら、停止させられる(または自ら停止する)まで実行し続けることができます。このモードでは、<code>{@link android.content.Context#startService Context.startService()}</code> が呼び出されて開始し、<code>{@link android.content.Context#stopService Context.stopService()}</code> 呼び出されて停止します。サービス自体が <code>{@link android.app.Service#stopSelf() Service.stopSelf()}</code> または <code>{@link android.app.Service#stopSelfResult Service.stopSelfResult()}</code> を呼び出して停止することもできます。サービスの開始時に {@code startService()} が何度呼び出されたとしても、{@code stopService()} を一度呼び出せばサービスは停止します。</li> + +<li><p>サービスで定義されているインターフェースをエクスポートし、これを介してプログラム的に操作できます。クライアントから Service オブジェクトへの接続を確立し、その接続を使用してサービスにアクセスします。接続は、<code>{@link android.content.Context#bindService Context.bindService()}</code> を呼び出して確立し、<code>{@link android.content.Context#unbindService Context.unbindService()}</code> でサービスを開始します。複数のクライアントが同じサービスにバインドすることも可能です。サービスがまだ開始されていなかった場合は,必要に応じて {@code bindService()} で開始できます。 +</p></li> +</ul> + +<p> +これら 2 つのモードは、完全に分離されているわけではありません。{@code startService()} で開始されたサービスにバインドすることも可能です。たとえば、再生する曲を指定した Intent オブジェクトで {@code startService()} を呼び出して音楽再生サービスを開始したとします。その後、たとえばユーザーがプレーヤーを操作したい場合や再生中の曲に関する情報を入手したい場合には、アクティビティから {@code bindService()} を呼び出してサービスとの接続を確立できます。このような場合、最後のバインドが閉じられるまでは、{@code stopService()} を呼び出してもサービスは停止しません。 +</p> + +<p> +アクティビティと同様、サービスにもライフサイクル メソッドがあり、これらを実装することでサービスの状態の変化を監視できます。ただし、protected ではなく public で、以下の 3 つしかありません: +</p> + +<p style="margin-left: 2em">{@code void onCreate()} <br/>{@code void onStart(Intent <i>intent</i>)} <br/>{@code void onDestroy()}</p> + +<p> +これらのメソッドを実装することで、ネストされた 2 つのループからなるサービスのライフサイクルを監視できます: +</p> + +<ul> +<li>サービスの<b>ライフタイム全体</b>は、<code>{@link android.app.Service#onCreate onCreate()}</code> が呼び出されたときに始まり、<code>{@link android.app.Service#onDestroy}</code> 終了したときに終わります。アクティビティと同じく、サービスも {@code onCreate()} で初期設定を行い、{@code onDestroy()} で残っていたリソースをすべて解放します。たとえば、音楽再生サービスであれば、{@code onCreate()} で音楽を再生するスレッドを作成し、{@code onDestroy()} でそのスレッドを停止できます。</li> + +<li><p>サービスの<b>アクティブ ライフタイム</b>は、<code>{@link android.app.Service#onStart onStart()}</code> を呼び出したときに始まります。このメソッドには、{@code startService()} に渡された Intent オブジェクトが渡されます。音楽再生サービスは、この Intent オブジェクトをみて曲を見つけ、その再生を開始します。</p> + +<p> +サービスの停止に相当するコールバック、つまり {@code onStop()} メソッドはありません。 +</p></li> +</ul> + +<p> +{@code onCreate()} および {@code onDestroy()} メソッドは、サービスを <code>{@link android.content.Context#startService Context.startService()}</code> または <code>{@link android.content.Context#bindService Context.bindService()}</code> のどちらで開始したかに関係なく、すべてのサービスで呼び出されます。一方、{@code onStart()} は、サービスを {@code startService()} で開始した場合のみ呼び出されます。 +</p> + +<p> +サービスが他からのバインドを許可している場合は、以下のコールバック メソッドを追加で実装できます: +</p> + +<p style="margin-left: 2em">{@code IBinder onBind(Intent <i>intent</i>)} <br/>{@code boolean onUnbind(Intent <i>intent</i>)} <br/>{@code void onRebind(Intent <i>intent</i>)}</p> + +<p> +<code>{@link android.app.Service#onBind onBind()}</code> コールバックには {@code bindService()} に渡された Intent オブジェクトが渡され、<code>{@link android.app.Service#onUnbind onUnbind()}</code> には {@code unbindService()} 渡された Intent オブジェクトが渡されます。サービスがバインドを許可している場合は、クライアントがサービスと対話する通信チャネルを {@code onBind()} で返します。{@code onUnbind()} メソッドは、サービスに新しいクライアントが接続した場合に <code>{@link android.app.Service#onRebind onRebind()}</code> の呼び出しを要求できます。 +</p> + +<p> +次の図に、サービスのコールバック メソッドを示します。なお、{@code startService()} で作成されたサービスと、{@code bindService()} で作成されたサービスを分けて記述していますが、作成された方法に関係なく,すべてのサービスはクライアントからのバインドを許可できます。したがって、どのサービスも {@code onBind()} および{@code onUnbind()} メソッドの呼び出しを受け取る可能性はあります。 +</p> + +<p style="margin-left: 2em"><img src="{@docRoot}images/service_lifecycle.png" +alt="サービス コールバックの状態遷移図" /></p> + + +<h3 id="broadlife">ブロードキャスト レシーバのライフサイクル</h3> + +<p> +ブロードキャスト レシーバのコールバック メソッドは次の 1 つのみです: +</p> + +<p style="margin-left: 2em">{@code void onReceive(Context <i>curContext</i>, Intent <i>broadcastMsg</i>)}</p> + +<p> +レシーバにブロードキャスト メッセージが届くと、<code>{@link android.content.BroadcastReceiver#onReceive onReceive()}</code> メソッドが呼び出され、メッセージを保持する Intent オブジェクトが渡されます。ブロードキャスト レシーバは、このメソッドの実行中のみアクティブと見なされます。{@code onReceive()} 終了すると、ブロードキャスト レシーバはアクティブでなくなります。 +</p> + +<p> +ブロードキャスト レシーバがアクティブになっているプロセスは、強制終了しないよう保護されます。一方、アクティブでないコンポーネントのみからなるプロセスは、それが消費しているメモリが他のプロセスで必要になった場合は、いつでも強制終了される可能性があります。 +</p> + +<p> +この点は、ブロードキャスト メッセージへの応答に時間がかかるため、ユーザー インターフェースの他のコンポーネントを実行しているメイン スレッドとは別のスレッドで何らかの処理を行う必要がある場合に問題になります。{@code onReceive()} が新しいスレッドを生成して終了した場合、プロセス内に他にアクティブなアプリケーション コンポーネントがなければ、そのスレッドを含めたプロセス全体がアクティブでないと判断されて強制終了させられるおそれがあります。この問題を回避するには、{@code onReceive()} でサービスを開始し、そのサービスにジョブを実行させます。これにより、プロセス内にまだアクティブなコンポーネントがあると見なされます。 +</p> + +<p> +次のセクションでは、プロセスが強制終了される可能性が高くなる状況についてさらに詳しく説明します。 +</p> + + +<h3 id="proclife">プロセスとライフサイクル</h3> + +<p>Android は、プロセスをできるだけ長い間維持しようとします。しかし、最終的にメモリが不足したときには、古いプロセスを削除しなければならなくなります。Android では、どのプロセスを維持し、どのプロセスを強制終了させるかを判断するため、プロセス内で実行されているコンポーネントと各コンポーネントの状態に基づいて、各プロセスを「重要度の階層」の位置づけます。まず最も重要度の低いプロセスが削除され、次は 2 番目に重要度の低いプロセス、その次に 3 番目、というように判断されます。階層は 5 つのレベルで構成されます。以下では、重要度の高いものから順に説明します: +</p> + +<ol> + +<li><b>フォアグラウンド プロセス</b>は、ユーザーがその時点で行っている作業に必要なプロセスです。以下のいずれかの条件を満たしているプロセスは、フォアグラウンド プロセスと見なされます: + +<ul> +<li>ユーザーと対話中のアクティビティを実行している(Activity オブジェクトの <code>{@link android.app.Activity#onResume +onResume()}</code> メソッドが呼び出されている)。</li> + +<li><p>ユーザーと対話中のアクティビティにバインドされているサービスを実行している。</p></li> + +<li><p>いずれかのライフサイクル コールバック(<code>{@link android.app.Service#onCreate +onCreate()}</code>、<code>{@link android.app.Service#onStart onStart()}</code>、または <code>{@link android.app.Service#onDestroy onDestroy()}</code>)を実行している {@link android.app.Service} オブジェクトを保持している。</p></li> + +<li><p><code>{@link android.content.BroadcastReceiver#onReceive +onReceive()}</code> メソッドを実行している {@link android.content.BroadcastReceiver} オブジェクトを保持している。</p></li> +</ul> + +<p> +同時に存在するフォアグラウンド プロセスは少数に限られています。フォアグラウンド プロセスは、メモリが極端に不足し、すべてのフォアグラウンド プロセスの実行を継続できない場合の最終手段として強制終了させられます。通常、その時点でデバイスはメモリ ページングの状態に達しており、ユーザー インターフェースを応答可能な状態に維持するためには、フォアグラウンド プロセスの一部を強制終了させなければならない状況に陥っています。 +</p></li> + +<li><p><b>可視プロセス</b>は、フォアグラウンド コンポーネントではないものの、ユーザーが見ている画面に影響を及ぼすことのできるプロセスです。以下のいずれかの条件を満たしているプロセスは、可視プロセスと見なされます:</p> + +<ul> +<li>フォアグラウンドではないがユーザーから見ることができるアクティビティを実行している(その <code>{@link android.app.Activity#onPause onPause()}</code> メソッドが呼び出されている)。これは、たとえばフォアグラウンド アクティビティがダイアログで、その背後に直前のアクティビティが見えるような状況です。</li> + +<li><p>ユーザーから見ることのできるアクティビティにバインドされているサービスを実行している。</p></li> +</ul> + +<p> +可視プロセスは、非常に重要なプロセスと見なされ、すべてのフォアグラウンド プロセスの実行を維持するために必要でない限り、強制終了させられることはありません。 +</p></li> + +<li><p><b>サービス プロセス</b>は、<code>{@link android.content.Context#startService startService()}</code> メソッドで開始されたサービスを実行しているプロセスのうち、より重要度の高い 2 つのレベルのどちらにも該当しないプロセスです。サービス プロセスは、ユーザーに見えるものとの直接的な関係はありませんが、たとえばバックグラウンドでの MP3 の再生、ネットワークからのデータのダウンロードなど、ユーザーが気にかけている処理であることが一般的です。したがって、すべてのフォアグラウンド プロセスと可視プロセスに加え、これらのサービス プロセスの実行を維持するだけのメモリが確保できる限り、強制終了させられることはありません。 +</p></li> + +<li><p><b>バックグラウンド プロセス</b>は、その時点でユーザーから見えないアクティビティを保持している(Activity オブジェクトの <code>{@link android.app.Activity#onStop onStop()}</code> メソッドが呼び出されている)プロセスです。これらのプロセスは、ユーザー エクスペリエンスに直接的には影響しておらず、フォアグラウンド、可視、サービス プロセスからメモリが要求された場合はいつでも強制終了する可能性があります。通常は数多くのバックグラウンド プロセスが実行されているため、それらを LRU(least recently used)リストに登録し、ユーザーが一番最近見たアクティビティのプロセスが最後に強制終了するような仕組みになっています。アクティビティにライフサイクル メソッドが正しく実装されており、現在の状態が正しく保存されていれば、プロセスを強制終了してもユーザー エクスペリエンスに悪影響が及ぶことはありません。 +</p></li> + +<li><p><b>空のプロセス</b>は、アクティブなアプリケーション コンポーネントを保持していないプロセスです。このようなプロセスを維持しておく唯一の理由は、これをキャッシュとして使用し、次回コンポーネントを実行するときの起動時間を短くするためです。多くの場合、システムはこれらのプロセスを強制終了させて、プロセス キャッシュとその基礎となるカーネル キャッシュの間でシステム リソース全体のバランスを取ります。</p></li> + +</ol> + +<p> +各プロセスは、その時点でアクティブなコンポーネントの重要度に基づいて、そのプロセスが取りうる最も高いレベルにランク付けされます。たとえば、あるプロセスがサービスと可視アクティビティをホストしている場合、そのプロセスはサービス プロセスではなく可視プロセスとしてランク付けされます。 +</p> + +<p> +また、あるプロセスに他のプロセスが依存しているために、そのプロセスのランクが引き上げられる可能性もあります。他のプロセスから依存されているプロセスが、依存しているプロセスよりも低いレベルにランク付けされることはありません。たとえば、プロセス A 内のコンテンツ プロバイダにプロセス B 内のクライアントが依存している場合や、プロセス A 内のサービスがプロセス B 内のコンポーネントにバインドされている場合、プロセス A は常にプロセス B よりは重要度が高いと見なされます。 +</p> + +<p> +サービスを実行しているプロセスは、バックグラウンド アクティビティを実行しているプロセスよりも高くランク付けされます。したがって、時間のかかる処理を実行する場合、特にその処理がアクティビティよりも長く続くような場合は、単にスレッドを生成するのではなく、その処理用のサービスを開始することをおすすめします。たとえば、バックグラウンドで音楽を再生する場合や、カメラで撮影した写真を Web サイトにアップロードする場合などはこれに当たります。サービスを使用することで、アクティビティがどのような状況にあっても、処理の重要度として「サービス プロセス」レベル以上を維持できます。<a href="#broadlife">ブロードキャスト レシーバのライフサイクル</a>のセクションでも説明しましたが、ブロードキャスト レシーバにおいてもこれと同じ理由で、処理に時間がかかる場合はスレッドではなくサービスを使用することをおすすめします。 +</p> diff --git a/docs/html-intl/ja/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/ja/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..c4aafe4 --- /dev/null +++ b/docs/html-intl/ja/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=電池残量と充電状態の監視 +parent.title=電池消費量の最適化 +parent.link=index.html + +trainingnavtop=true +next.title=ホルダーの装着状態とタイプの特定と監視 +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンの内容</h2> +<ol> + <li><a href="#DetermineChargeState">現在の充電状態を特定する</a></li> + <li><a href="#MonitorChargeState">充電状態の変化を監視する</a></li> + <li><a href="#CurrentLevel">現在の電池残量を特定する</a></li> + <li><a href="#MonitorLevel">電池残量の大きな変化を監視する</a></li> +</ol> + +<h2>関連項目</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> +</ul> + +</div> +</div> + +<p>バックグラウンド更新が電池消費量に及ぼす影響を抑えるために更新の頻度を変更するには、初めに現在の電池残量と充電状態を調べることをおすすめします。</p> + +<p>アプリの更新が電池消費量に及ぼす影響の度合いは、端末の電池残量と充電状態によって異なります。AC 電源から端末を充電しているときは、更新の実行による影響はごくわずかなので、ほとんどの場合は、端末が AC 電源に接続されている限り、更新頻度を最大にして差し支えありません。逆に、端末が電池で駆動しているときは、更新頻度を下げると電池消費量を抑えることができます。</p> + +<p>同様に、電池残量を調べると、残量がごくわずかであるときに更新頻度を下げたり、場合によっては停止させたりすることができます。</p> + + +<h2 id="DetermineChargeState">現在の充電状態を特定する</h2> + +<p>初めに、現在の充電状態を特定します。{@link android.os.BatteryManager} によって電池と充電状態に関するすべての詳細情報が sticky {@link android.content.Intent} としてブロードキャストされますが、この中に充電状態が格納されています。</p> + +<p>これは sticky インテントであるため、{@link android.content.BroadcastReceiver} を登録する必要はありません。{@code registerReceiver} を呼び出し、{@code null} をレシーバとして渡すだけで(次のコード例を参照)、現在の電池状態のインテントが返されます。ここで実際の {@link android.content.BroadcastReceiver} オブジェクトを渡すこともできますが、このレッスンでは後で更新についての処理を行うので、これは必要ありません。</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>現在の充電状態に加えて、充電中の場合は USB 経由か AC 充電器経由かを調べることもできます。<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>一般的には、端末が AC 充電器に接続されているときはバックグラウンド更新の頻度を最大にし、USB 経由で充電中のときは頻度を下げ、電池で駆動中のときはさらに頻度を下げます。</p> + + +<h2 id="MonitorChargeState">充電状態の変化を監視する</h2> + +<p>充電状態は、端末が充電器に接続されたときにすぐに変化するので、充電状態の変化を監視し、その変化に応じて更新の頻度を変更することが重要です。</p> + +<p>{@link android.os.BatteryManager} は、端末が電源に接続されたときや接続が解除されたときに、アクションをブロードキャストします。このようなイベントは、アプリが実行中でないときでも受信することが重要です。特にそのイベントが、アプリのバックグラウンド更新を開始するためにアプリを起動させる頻度に影響するものである場合です。したがって、{@link android.content.BroadcastReceiver} をアプリのマニフェスト内で登録し、両方のイベントを受信するために {@link android.content.Intent#ACTION_POWER_CONNECTED} と {@link android.content.Intent#ACTION_POWER_DISCONNECTED} をインテント フィルタ内で定義します。</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>関連付けられている {@link android.content.BroadcastReceiver} 実装の中で、前のステップで説明したように、現在の充電状態と充電方法を抽出します。</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">現在の電池残量を特定する</h2> + +<p>状況によっては、現在の電池残量がわかると便利なことがあります。たとえば、電池残量が所定のレベルを下回った場合にアプリのバックグラウンド更新の頻度を下げることができます。</p> + +<p>現在の電池残量を調べるには、次に示すように、電池状態のインテントから現在の電池残量と最大量を抽出します。</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">電池残量の大きな変化を監視する</h2> + +<p>電池状態を継続的に監視することは簡単ではありませんが、その必要もありません。</p> + +<p>一般的に、電池残量を継続的に監視するほうが、電池への影響はアプリの通常の動作によるものよりも大きくなるため、電池残量の大きな変化のみを監視することをおすすめします。特に、端末が電池残量低下状態に入ったときや、その状態が解消されたときです。</p> + +<p>次に示すマニフェストの断片は、ブロードキャスト レシーバの中にあるインテント フィルタ要素からの抜粋です。このレシーバは、端末が電池残量低下状態に入ったときや、その状態が解消されたときに呼び出されます。そのために、{@link android.content.Intent#ACTION_BATTERY_LOW} と {@link android.content.Intent#ACTION_BATTERY_OKAY} を受信します。</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>一般的に、電池残量がごくわずかになったときはアプリのバックグラウンド更新をすべて停止することをおすすめします。データがいくら新しくても、端末自体の電源が切れてしまったのではデータを活用できません。</p> + +<p>多くの場合、端末の充電という動作が開始するのは、端末がホルダーにセットされるのと同時です。次のレッスンでは、現在のホルダーの状態を特定し、端末のホルダー装着状態の変化を監視する方法を紹介します。</p> + diff --git a/docs/html-intl/ja/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/ja/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..82b0c6b --- /dev/null +++ b/docs/html-intl/ja/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=接続状態の特定と監視 +parent.title=電池消費量の最適化 +parent.link=index.html + +trainingnavtop=true + +previous.title=ホルダーの装着状態とタイプの特定と監視 +previous.link=docking-monitoring.html +next.title=オンデマンドでのブロードキャスト レシーバ操作 +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンの内容</h2> +<ol> + <li><a href="#DetermineConnection">インターネット接続の有無を特定する</a></li> + <li><a href="#DetermineType">インターネット接続のタイプを特定する</a></li> + <li><a href="#MonitorChanges">接続状態の変化を監視する</a></li> +</ol> + + +<h2>関連項目</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> +</ul> + +</div> +</div> + +<p>反復アラームとバックグラウンド サービスの用途のうち代表的なものとしては、インターネット リソースからアプリのデータを定期的に更新するためのスケジュール設定や、データのキャッシュへの格納、長時間に及ぶダウンロードの実行などがあります。しかし、インターネットに接続されていないときや、速度が低すぎるためにダウンロードを完了できない場合にまで、更新をスケジューリングするために端末をスリープ状態から復帰させる必要があるでしょうか。</p> + +<p>{@link android.net.ConnectivityManager} を使用すると、端末が実際にインターネットに接続されているかどうかと、接続されている場合の接続タイプを調べることができます。</p> + + +<h2 id="DetermineConnection">インターネット接続の有無を特定する</h2> + +<p>端末がインターネットに接続されていない場合は、インターネット リソースに基づく更新をスケジューリングする必要性はありません。次のスニペットは、{@link android.net.ConnectivityManager} を使用してアクティブなネットワークを問い合わせて、インターネットに接続しているかどうかを特定する方法を示すものです。</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">インターネット接続のタイプを特定する</h2> + +<p>現在使用可能なインターネット接続のタイプも調べることができます。</p> + +<p>端末の接続のタイプとしては、モバイル データ、WiMAX、Wi-Fi、イーサネットがあります。次に示すように、アクティブなネットワークのタイプを問い合わせると、使用可能な帯域幅に合わせて更新頻度を変更することができます。</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>モバイル データ接続のコストは Wi-Fi 接続を大きく上回る傾向があるため、端末がモバイル接続しているときはアプリの更新頻度を下げるのが一般的です。同様に、大量のデータをダウンロードするときは、Wi-Fi 接続されるまで停止するとよいでしょう。</p> + +<p>更新を停止した場合は、接続状態の変化を受信することが重要です。インターネット接続が確立されたら更新を再開できるようにするためです。</p> + + +<h2 id="MonitorChanges">接続状態の変化を監視する</h2> + +<p>接続状態の詳細が変化すると、{@link android.net.ConnectivityManager} によって {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}({@code "android.net.conn.CONNECTIVITY_CHANGE"})アクションがブロードキャストされます。アプリのマニフェスト内でブロードキャスト レシーバを登録し、このような変化を検出することで、それに応じてアプリのバックグラウンド更新を再開(または停止)することができます。</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>端末の接続状態の変化は、きわめて頻繁になることもあります。このブロードキャストは、モバイル データ接続と Wi-Fi 接続とが切り替わるたびに発行されるからです。したがって、このブロードキャストの監視は、更新やダウンロードを停止した後に再開すべきかどうかを判断するために限って行うことをおすすめします。一般的には、更新を開始する前にインターネット接続の有無を調べれば十分です。インターネットに接続していない場合は、再び接続されるまでの間、更新を停止します。</p> + +<p>このようにするには、マニフェスト内で宣言したブロードキャスト レシーバのオンとオフを切り替える必要があります。これについて、次のレッスンで説明します。</p> diff --git a/docs/html-intl/ja/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/ja/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..9c0e054 --- /dev/null +++ b/docs/html-intl/ja/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=ホルダーの装着状態とタイプの特定と監視 +parent.title=電池消費量の最適化 +parent.link=index.html + +trainingnavtop=true +previous.title= 電池残量と充電状態の監視 +previous.link=battery-monitoring.html +next.title= 接続状態の特定と監視 +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンの内容</h2> +<ol> + <li><a href="#CurrentDockState">オーディオ フォーカスをリクエストする</a></li> + <li><a href="#DockType">現在のホルダーのタイプを特定する</a></li> + <li><a href="#MonitorDockState">ホルダーの装着状態またはタイプの変化を監視する</a></li> +</ol> + + +<h2>関連項目</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> +</ul> + +</div> +</div> + +<p>Android 搭載端末を装着できるホルダーの種類には、さまざまなものがあります。たとえば、車載用や家庭用のホルダーがあり、デジタルかアナログかという区別もあります。ホルダー装着状態は一般的に、充電状態と密接にリンクしています。多くのホルダーは、装着されている端末に電力を供給しているからです。</p> + +<p>端末のホルダー装着状態が更新の頻度にどのように影響するかは、アプリによって異なります。たとえば、スポーツ センター アプリなら、卓上ホルダー装着時には更新頻度を上げ、カー ホルダー装着時には更新を完全に停止するとよいでしょう。逆に、カー ホルダー装着時に更新頻度を最大にするケースとしては、バックグラウンド サービスによって道路交通状況を更新する場合が考えられます。</p> + +<p>ホルダー装着状態も sticky {@link android.content.Intent} としてブロードキャストされるので、端末がホルダーに装着されているかどうかと、装着されている場合のホルダーのタイプを問い合わせることができます。</p> + + +<h2 id="CurrentDockState">現在のホルダー装着状態を特定する</h2> + +<p>ホルダー装着状態の詳細は、{@link android.content.Intent#ACTION_DOCK_EVENT} アクションの sticky ブロードキャストにエクストラとして含まれています。これは sticky であるため、{@link android.content.BroadcastReceiver} を登録する必要はありません。次のコード例に示すように、{@link android.content.Context#registerReceiver registerReceiver()} を呼び出し、{@code null} をブロードキャスト レシーバとして渡します。</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>現在のホルダー装着状態は、次のように {@code EXTRA_DOCK_STATE} エクストラから抽出します。<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">現在のホルダーのタイプを特定する</h2> + +<p>端末がホルダーに装着されている場合のホルダーのタイプは、次の 4 つのいずれかです。 +<ul><li>カー</li> +<li>卓上</li> +<li>ローエンド(アナログ)卓上</li> +<li>ハイエンド(デジタル)卓上</li></ul></p> + +<p>最後の 2 つは、Android API レベル 11 で追加されたものです。したがって、ホルダーのタイプだけがわかればよく、デジタルとアナログの区別は問わないという場合は、次のように 3 つすべてについて調べるとよいでしょう。</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">ホルダーの装着状態またはタイプの変化を監視する</h2> + +<p>端末がホルダーに装着されたり、装着が解除されたりするたびに、{@link android.content.Intent#ACTION_DOCK_EVENT} アクションがブロードキャストされます。端末のホルダー装着状態の変化を監視するには、次のコード例に示すように、アプリのマニフェスト内でブロードキャスト レシーバを登録します。</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>レシーバ実装の中でホルダーのタイプと状態を抽出する方法は、前のステップで使用したものと同じです。</p> diff --git a/docs/html-intl/ja/training/monitoring-device-state/index.jd b/docs/html-intl/ja/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..07897b1 --- /dev/null +++ b/docs/html-intl/ja/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=電池消費量の最適化 + +trainingnavtop=true +startpage=true +next.title=電池残量と充電状態の監視 +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>依存関係と前提条件</h2> +<ul> + <li>Android 2.0(API レベル 5)以上</li> + <li>「<a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a>」を読み終えていること</li> +</ul> + +<h2>関連項目</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">サービス</a> +</ul> + +</div> +</div> + +<p>アプリを開発するときは、ホスト端末の電池消費量への影響を抑えるよう心がける必要があります。このクラスを修了すると、開発するアプリの中でホスト端末の状態を監視し、それに基づいて機能や動作を変更することができるようになります。</p> + +<p>接続が失われたときはバックグラウンド サービスの更新を停止する、電池残量が低下したときは更新の頻度を下げるといった対策を講じることにより、ユーザー エクスペリエンスを損なうことなく、アプリが電池消費量に及ぼす影響を最小限に抑えることができます。</p> + +<h2>レッスン</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">電池残量と充電状態の監視</a></b></dt> + <dd>アプリの更新頻度を変更するために現在の電池残量や充電状態の変化を特定および監視する方法を学習します。</dd> + + <dt><b><a href="docking-monitoring.html">ホルダーの装着状態とタイプの特定と監視</a></b></dt> + <dd>最適な更新頻度は、ホスト端末がどのように使用されているかによって異なります。ホルダーの装着状態とタイプに応じてアプリの動作を変更するために、これらを特定および監視する方法を学習します。</dd> + + <dt><b><a href="connectivity-monitoring.html">接続状態の特定と監視</a></b></dt> + <dd>インターネットに接続していないときは、オンライン ソースからアプリを更新することはできません。接続状態を調べ、それに応じてバックグラウンド更新の頻度を変更する方法を学習します。また、大量の帯域幅を消費する処理を開始する前に接続が Wi-Fi かモバイル データかを調べる方法も学習します。</dd> + + <dt><b><a href="manifest-receivers.html">オンデマンドでのブロードキャスト レシーバ操作</a></b></dt> + <dd>マニフェスト内で宣言したブロードキャスト レシーバのオンとオフを実行時に切り替えます。端末の状態に応じて、不要なレシーバを無効にすることができます。効率を上げるために、状態変化レシーバのオンとオフを切り替える方法や、端末が特定の状態になるまでアクションを延期する方法を学習します。</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/ja/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/ja/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..7635d9f --- /dev/null +++ b/docs/html-intl/ja/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=オンデマンドでのブロードキャスト レシーバ操作 +parent.title=電池消費量の最適化 +parent.link=index.html + +trainingnavtop=true + +previous.title=接続状態の特定と監視 +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンの内容</h2> +<ol> + <li><a href="#ToggleReceivers">効率を上げるために状態変化レシーバのオンとオフを切り替える</a></li> +</ol> + + +<h2>関連項目</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">インテントとインテント フィルタ</a> +</ul> + +</div> +</div> + +<p>端末の状態変化を監視する最も単純な方法は、監視対象とする状態ごとに {@link android.content.BroadcastReceiver} を作成し、それぞれをアプリのマニフェスト内で登録するというものです。これらの各レシーバ内で、端末の現在の状態に基づいて反復アラームのスケジュールを再設定します。</p> + +<p>この方法のデメリットは、これらのレシーバのいずれかがトリガされるたびに端末がスリープから復帰することですが、このことは必要以上に頻繁に発生する可能性があります。</p> + +<p>これよりも良い方法は、実行時にブロードキャスト レシーバをオンまたはオフにするというものです。このようにすれば、マニフェスト内で宣言したレシーバを受動的アラームとして使用できます。つまり、このアラームは、必要なときにだけシステム イベントによって呼び出されます。</p> + + +<h2 id="ToggleReceivers">効率を上げるために状態変化レシーバのオンとオフを切り替える </h2> + +<p>{@link android.content.pm.PackageManager} を使用すると、マニフェスト内で定義されているコンポーネントの有効化状態を切り替えることができます。このコンポーネントにはブロードキャスト レシーバも該当するので、次に示すようにオンとオフを切り替えることができます。</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>この手法を使用すれば、接続が失われたことが判明した場合に、接続状態変化レシーバ以外のレシーバをすべて無効にすることができます。逆に、接続が確立された後は、接続状態変化の受信を停止します。オンラインかどうかを調べるのは、更新を実行する直前や、反復更新アラームのスケジュール再設定の直前だけで十分です。</p> + +<p>同じ手法を使用して、大量の帯域幅を必要とするダウンロードを延期することもできます。それには、接続状態の変化をリッスンするブロードキャスト レシーバを有効にしておき、端末が Wi-Fi に接続されたらダウンロードを開始します。</p> diff --git a/docs/html-intl/ja/training/multiscreen/adaptui.jd b/docs/html-intl/ja/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..8b1e6ac --- /dev/null +++ b/docs/html-intl/ja/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=順応性のある UI フローの実装 +parent.title=複数画面のデザイン +parent.link=index.html + +trainingnavtop=true +previous.title=さまざまな画面密度のサポート +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンでの学習内容</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">現在のレイアウトを判別する</a></li> + <li><a href="#TaskReactToLayout">現在のレイアウトに合わせて応答する</a></li> + <li><a href="#TaskReuseFrag">他のアクティビティのフラグメントを再利用する</a></li> + <li><a href="#TaskHandleConfigChanges">画面設定の変更を処理する</a></li> +</ol> + +<h2>関連ドキュメント</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">タブレットと携帯端末のサポート</a></li> +</ul> + +<h2>試してみる</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">サンプル アプリのダウンロード</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>アプリが現在表示しているレイアウトによって、UI フローが異なる可能性があります。たとえば、アプリがデュアルペイン モードであれば、左ペインのアイテムをクリックすると、単に右ペインにコンテンツが表示されるだけですが、シングルペイン モードであれば、コンテンツは(別のアクティビティ内の)コンテンツ専用のペインに表示される必要があります。</p> + + +<h2 id="TaskDetermineCurLayout">現在のレイアウトを判別する</h2> + +<p>レイアウトによって実装が多少異なるので、まず、ユーザーが現在どのようなレイアウトを表示しているかを判別する必要があります。たとえば、ユーザーが表示しているレイアウトが「シングルペイン」モードなのか、「デュアルペイン」モードなのかを確認する必要があります。それは、以下のようなコードで、ある特定のビューが存在し、かつ可視になっているかを照会することで可能です:</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>このコードにおいて「article」ペインが使用可能かどうかを照会している点に注目してください。特定のレイアウトの照会をハードコーディングするよりもはるかに柔軟性があります。</p> + +<p>その他にも、さまざまなコンポーネントでも対応できる方法として、コンポーネントを操作する前に使用可能かどうかを確認する方法もあります。たとえば、News Reader サンプル アプリでは、メニューを開くボタンがありますが、このボタンは Android 3.0 よりも古いバージョンで動作しているときにしか表示されません(この機能は、API レベル 11 以上の <PH>{@link android.app.ActionBar}</PH> で提供されるため)。そこで、以下のようなコードを追加して、このボタンのイベント リスナーを追加します:</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">現在のレイアウトに合わせて応答する</h2> + +<p>現在のレイアウトによって、一部のアクションの結果が異なる可能性があります。たとえば、News Reader サンプルでは、見出しリストで見出しをクリックしたとき、デュアルペイン モードの UI の場合は右ペインに記事が表示されますが、シングルペインの UI の場合は別のアクティビティが起動します:</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>同様に、アプリがデュアルペイン モードの場合は、ナビ用タブでアクション バーを設定し、一方、シングルペイン モードの場合は、スピナー ウィジェットでナビを設定することになります。したがって、コードでは以下のようにどちらのケースが適切かを調べることも必要です:</p> + +<pre> +final String CATEGORIES[] = { "トップ ニュース 政治", "政治", "経済", "Technology" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">他のアクティビティのフラグメントを再利用する</h2> + +<p>複数の画面に対応するように設計する場合、あるパターンが繰り返されますが、そうしたパターンは、ある画面設定ではペインとして、別の画面設定では別のアクティビティとして実装されるインターフェースの一部に存在します。たとえば、News Reader サンプルでは、ラージ画面の場合はニュース記事のテキストが右ペインに表示されますが、それよりも小さい画面の場合は別のアクティビティになります。</p> + +<p>このような場合、通常、複数のアクティビティで同じ <PH>{@link android.app.Fragment}</PH> サブクラスを再利用することでコードの重複を回避できます。たとえば、<code>ArticleFragment</code> は以下のようにデュアルペイン レイアウトで使用されます:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>また、より小さな画面向けのアクティビティ レイアウト内では(レイアウトを使用せずに)再利用されます(<code>ArticleActivity</code>):</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>当然、これは XML レイアウトでフラグメントを宣言するのと同じ効果がありますが、この場合は、XML レイアウトは必要ありません。このアクティビティのコンポーネントは記事フラグメントしかないからです。</p> + +<p>フラグメントを設計する際に注意すべき非常に重要なポイントの 1 つとして、特定のアクティビティに対して強い結合を作成しないことがあります。通常、これは、フラグメントが自分のホスト アクティビティとやり取りするのに必要なあらゆる手段を抽象化したインターフェースを定義し、さらに、そのインターフェースをホスト アクティビティに実装することで可能になります:</p> + +<p>たとえば、News Reader アプリの <code>HeadlinesFragment</code> は、まさにそのようになっています:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>これにより、ユーザーが見出しを選択すると、フラグメントは以下のように(特定のハードコーディングされたアクティビティに通知するのではなく)ホスト アクティビティが指定したリスナーに通知します:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p>このテクニックについては、<a +href="{@docRoot}guide/practices/tablets-and-handsets.html">タブレットと携帯端末のサポート</a>で詳しく説明されています。</p> + + +<h2 id="TaskHandleConfigChanges">画面設定の変更を処理する</h2> + +<p>インターフェースの各パーツを実装するのに個別のアクティビティを使用している場合、インターフェースの一貫性を維持するために、(向きの変更などの)特定の設定変更に対応できるように注意する必要があります。</p> + +<p>たとえば、Android 3.0 以上が動作する一般的な 7 インチ タブレットでは、News Reader サンプルがニュース記事を表示する場合、縦表示では個別のアクティビティを使用しますが、横表示では 2 ペイン レイアウトを使用します。</p> + +<p>つまり、縦表示のときに記事閲覧用アクティビティが画面上にある場合、画面の向きが横方向に変わったことを検出したら、コンテンツを 2 ペイン レイアウトで表示するために、そのアクティビティを終了してメインのアクティビティに戻り、適切に応答しなければなりません:</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/ja/training/multiscreen/index.jd b/docs/html-intl/ja/training/multiscreen/index.jd new file mode 100644 index 0000000..ff84f8a --- /dev/null +++ b/docs/html-intl/ja/training/multiscreen/index.jd @@ -0,0 +1,64 @@ +page.title=複数画面のデザイン + +trainingnavtop=true +startpage=true +next.title=さまざまな画面サイズのサポート +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>必要な知識と前提条件</h2> + +<ul> + <li>Android 1.6 以上(サンプル アプリを使用するには 2.1 以上)</li> + <li><a +href="http://developer.android.com/guide/components/activities.html">アクティビティ</a>と<a href="http://developer.android.com/guide/components/fragments.html">フラグメント</a>の基礎知識</li> + <li>Android <a +href="http://developer.android.com/guide/topics/ui/index.html">ユーザー インターフェース</a>の開発経験</li> + <li><a +href="{@docRoot}tools/extras/support-library.html">サポート ライブラリ</a>の利用(一部の機能で必要)</li> +</ul> + +<h2>関連ドキュメント</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">複数画面のサポート</a></li> +</ul> + +<h2>試してみる</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">サンプル アプリのダウンロード</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>Android は、小さな携帯電話から大きなテレビまで、画面サイズも種類もさまざまなデバイスに搭載できます。そのため、できる限り多くのユーザーが使用できるように、すべての画面サイズに対応できるようアプリを設計することが重要になります。</p> + +<p>しかし、さまざまな種類のデバイスに対応できるだけでは十分ではありません。画面サイズによって、ユーザーが操作できることが決まってくるため、本当にユーザーを満足させてよい印象を持ってもらうためには、アプリが単に複数の画面をサポートするだけでは不十分です: 画面設定ごとにユーザー エクスペリエンスを最適化する必要があります。<em></em><em></em></p> + +<p>このクラスは、いくつかの画面設定に合わせて最適化されたユーザー インターフェースを実装する方法を提供します。</p> + +<p>各レッスンで紹介されているコードは、複数の画面に合わせて最適化する際、ベスト プラクティスとなるサンプル アプリから抜粋したものです。このサンプルを(右側から)ダウンロードして、再利用可能なコードのソースとしてご自分のアプリに使用することができます。</p> + +<p class="note"><strong>注:</strong> このクラスと関連サンプルでは、<a +href="{@docRoot}tools/extras/support-library.html">サポート ライブラリ</a>を使用します。理由は、Android 3.0 未満のバージョンで <PH>{@link android.app.Fragment}</PH> API を使用するためです。このクラスのすべての API を使用するには、ライブラリをダウンロードして、アプリに追加する必要があります。</p> + + +<h2>レッスン</h2> + +<dl> + <dt><b><a href="screensizes.html">さまざまな画面サイズのサポート</a></b></dt> + <dd>このレッスンでは、さまざまな画面サイズに適したレイアウトを(柔軟なビュー サイズ、 <PH>{@link android.widget.RelativeLayout}</PH>、画面サイズと画面の向きの修飾子、エイリアス フィルタ、ナインパッチ ビットマップを使用して)設計する方法について学習します。</dd> + + <dt><b><a href="screendensities.html">さまざまな画面密度のサポート</a></b></dt> + <dd>このレッスンでは、(密度非依存ピクセルを使用し、各密度に適したビットマップを提供して)ピクセル密度が異なる画面をサポートする方法について学習します。</dd> + + <dt><b><a href="adaptui.html">順応性のある UI フローの実装</a></b></dt> + <dd>このレッスンでは、いくつかの画面サイズ/密度の組み合わせに適した方法(実行時にアクティブなレイアウトを検出する方法、現在のレイアウトに合わせて応答する方法、画面設定の変更を処理する方法)で UI を実装する方法について学習します。</dd> +</dl> diff --git a/docs/html-intl/ja/training/multiscreen/screendensities.jd b/docs/html-intl/ja/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..3482d5c --- /dev/null +++ b/docs/html-intl/ja/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=さまざまな画面密度のサポート +parent.title=複数画面のデザイン +parent.link=index.html + +trainingnavtop=true +previous.title=さまざまな画面サイズのサポート +previous.link=screensizes.html +next.title=順応性のある UI フローの実装 +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンでの学習内容</h2> +<ol> + <li><a href="#TaskUseDP">密度非依存ピクセルを使用する</a></li> + <li><a href="#TaskProvideAltBmp">代替ビットマップを生成する</a></li> +</ol> + +<h2>関連ドキュメント</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">複数画面のサポート</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">アイコン設計のガイドライン</a></li> +</ul> + +<h2>試してみる</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">サンプル アプリのダウンロード</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>このレッスンでは、異なるリソースを生成し、かつ解像度非依存単位を使用して、異なる画面密度をサポートする方法について学習します。</p> + +<h2 id="TaskUseDP">密度非依存ピクセルを使用する</h2> + +<p>レイアウトを設計する際に回避すべきよくある落とし穴の 1 つとして、絶対ピクセルを使用して距離やサイズを定義することがあります。ピクセルを使用してレイアウトのサイズを定義すると、画面によってピクセル密度が異なるため、問題が起こります。したがって、同じピクセル数では、デバイスが異なる場合に物理サイズが異なる可能性があります。そのため、サイズを指定する場合は、常に <code>dp</code> 単位や <code>sp</code> 単位を使用します。<code>dp</code> とは、1 ピクセルの物理サイズが 160 dpi に相当する密度非依存ピクセルです。<code>sp</code> も基本単位は同じですが、ユーザーの優先テキスト サイズによってサイズが決まるので(スケール非依存ピクセル)、テキスト サイズを定義する際にはこの単位を使用する必要があります(ただし、レイアウト サイズには絶対に使用しないこと)。</p> + +<p>たとえば、2 つのビューの間にスペースを挿入する場合は、<code>px</code> ではなくて <code>dp</code> を使用します:</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>テキスト サイズを指定する場合は、常に <code>sp</code> を使用します:</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">代替ビットマップを生成する</h2> + +<p>Android は、画面密度がさまざまなデバイスで動作するため、それぞれの汎用密度バケット(低密度、中密度、高密度、超高密度)に合わせてビットマップ リソースを生成する必要があります。そうすることで、すべての画面密度で画質とパフォーマンスが向上します。</p> + +<p>これらの画像を生成するには、ベクター形式の未加工リソースから、次のサイズ スケールを使用して密度別に画像を生成する必要があります:</p> + +<p><ul> + <li><code>xhdpi</code>: 2.0 + <li><code>hdpi</code>: 1.5 + <li><code>mdpi</code>: 1.0(基準) + <li><code>ldpi</code>: 0.75 +</ul></p> + +<p>つまり、200×200 画像(<code>xhdpi</code> デバイス用)を生成する場合、同じリソースを 150×150 画像(<code>hdpi</code> デバイス用)、100×100 画像(<code>mdpi</code> デバイス用)、75×75(<code>ldpi</code> デバイス用)でも生成する必要があります。</p> + +<p>さらに、生成した画像を <code>res/</code> 下の適切なサブディレクトリに配置することで、アプリが動作するデバイスの画面密度に基づいて、自動的に適切な画像が表示されます:</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>また、<code>@drawable/awesomeimage</code> を参照する場合は常に画面の dpi に基づいて、適切なビットマップが選択されます。</p> + +<p>アプリ用のアイコン アセットを作成するためのヒントとガイドラインについては、<a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">アイコン設計のガイドライン</a>をご覧ください。</p> + diff --git a/docs/html-intl/ja/training/multiscreen/screensizes.jd b/docs/html-intl/ja/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..3655a33 --- /dev/null +++ b/docs/html-intl/ja/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=さまざまな画面サイズのサポート +parent.title=複数画面のデザイン +parent.link=index.html + +trainingnavtop=true +next.title=さまざまな画面密度のサポート +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>このレッスンでの学習内容</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">「wrap_content」と「match_parent」を使用する</a></li> + <li><a href="#TaskUseRelativeLayout">RelativeLayout を使用する</a></li> + <li><a href="#TaskUseSizeQuali">サイズ修飾子を使用する</a></li> + <li><a href="#TaskUseSWQuali">最小幅修飾子を使用する</a></li> + <li><a href="#TaskUseAliasFilters">レイアウト エイリアスを使用する</a></li> + <li><a href="#TaskUseOriQuali">画面の向きの修飾子を使用する</a></li> + <li><a href="#TaskUse9Patch">ナインパッチ ビットマップを使用する</a></li> +</ol> + +<h2>関連ドキュメント</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">複数画面のサポート</a></li> +</ul> + +<h2>試してみる</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">サンプル アプリのダウンロード</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>このレッスンでは、異なる画面サイズを以下のような方法でサポートする方法について学習します:</p> +<ul> + <li>画面に収まるようにレイアウト サイズを適切に変更する</li> + <li>画面設定に基づいて適切な UI レイアウトを表示する</li> + <li>適切な画面に適切なレイアウトを適用する</li> + <li>適切にサイズ調整したビットマップを表示する</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">「wrap_content」と「match_parent」を使用する</h2> + +<p>レイアウトをさまざまな画面サイズに柔軟に対応させるには、一部のビュー コンポーネントの幅と高さに <code>"wrap_content"</code> と <code>"match_parent"</code> を使用する必要があります。<code>"wrap_content"</code> を使用すると、ビューの幅や高さがそのビュー内にコンテンツが収まるのに必要な最小サイズに設定されます。一方、<code>"match_parent"</code>(API レベル 8 より前の名称は <code>"fill_parent"</code>)を使用すると、コンポーネントがその親ビューのサイズに一致するまで拡大されます。</p> + +<p>ハードコーディングされたサイズの代わりに <code>"wrap_content"</code> と <code>"match_parent"</code> を使用することで、ビューはそれぞれ、そのビューに必要なスペースだけを使用したり、空きスペースを埋めるまで拡大したりします。次に例を示します:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>このサンプルでは、特定のサイズではない <code>"wrap_content"</code> と <code>"match_parent"</code> をコンポーネント サイズにどのように使用しているかに注目してください。こうすることで、異なる画面のサイズと向きにレイアウトを正しく対応させることができます。</p> + +<p>たとえば、このレイアウトを縦表示と横表示で表示したときの見え方を以下に示します。コンポーネントのサイズが幅と高さに自動的に適合している点に注目してください:</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>図 1.</strong> News Reader サンプル アプリの縦表示(左)と横表示(右)</p> + + +<h2 id="TaskUseRelativeLayout">RelativeLayout を使用する</h2> + +<p>ネストされた <PH>{@link android.widget.LinearLayout} インスタンスや、</PH> <code>"wrap_content"</code> と <code>"match_parent"</code> のサイズの組み合わせを使用すると、かなり複雑なレイアウトを作成できます。しかし、 <PH>{@link android.widget.LinearLayout}</PH> では、子ビューの空間的な位置関係を正確に制御することはできません。 <PH>{@link android.widget.LinearLayout} のビューは、</PH> 単に一列に並ぶだけです。子ビューに対して直線以外のさまざまな配置を実現する必要がある場合は、 <PH>{@link android.widget.RelativeLayout}</PH>を使用することでうまくいくことがよくあります。たとえば、1 つの子ビューを画面の左側に配置し、もう 1 つの子ビューを右側に配置できます。</p> + +<p>次に例を示します:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>図 2 は、このレイアウトの QVGA 画面での見え方を示しています。</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>図 2.</strong> QVGA 画面(スモール画面)のスクリーンショット</p> + +<p>図 3 は、このレイアウトのラージ画面での見え方を示しています。</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>図 3.</strong> WSVGA 画面(ラージ画面)のスクリーンショット</p> + +<p>コンポーネントのサイズが変更されても、 <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH>で指定されたとおりに空間的な位置関係が維持されていることがわかります。</p> + + +<h2 id="TaskUseSizeQuali">サイズ修飾子を使用する</h2> + +<p>柔軟なレイアウトや相対的なレイアウトから得られる恩恵は、前のセクションで説明したことくらいです。これらのレイアウトはコンポーネントの内部や周囲のスペースを引き延ばすことでさまざまな画面に対応しますが、それぞれの画面サイズに合った最高のユーザー エクスペリエンスを実現していない可能性があります。したがって、アプリでは、柔軟なレイアウトの実装だけではなく、さまざまな画面設定に合わせた複数の代替レイアウトも必要になります。これは、<a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">設定修飾子</a>を使用することで実現可能です。設定修飾子により、ランタイムが現在のデバイスの設定に基づいて適切なリソース(画面サイズ別のレイアウト デザインなど)を自動的に選択できます。</p> + +<p>たとえば、多くのアプリでは、ラージ画面用に「2 ペイン」パターンを実装しています(一方のペインに項目リスト、もう一方のペインにそのコンテンツを表示することが可能です)。タブレットやテレビは両方のペインを同時に表示できるほど十分に大きい画面ですが、携帯端末の画面では 2 つのペインを別々に表示する必要があります。そのようなレイアウトを実装するには、次のようなファイルが必要になります:</p> + +<ul> + <li><code>res/layout/main.xml</code>、シングルペイン(デフォルト)レイアウト: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>、2 ペイン レイアウト: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>2 番目のレイアウトのディレクトリ名の <code>large</code> 修飾子に注目してください。このレイアウトは、ラージ(7 インチ以上のタブレットなど)と分類された画面のデバイスで選択されます。それよりも小さいデバイスでは、その他のレイアウト(修飾子なし)が選択されます。</p> + + +<h2 id="TaskUseSWQuali">最小幅修飾子を使用する</h2> + +<p>Android 3.2 未満のデバイスでデベロッパーが抱えていた問題の 1 つに、Dell Streak、初代 Galaxy Tab、7 インチ タブレット全般を含む、「ラージ」画面サイズの分類があります。しかし、多くのアプリでは、すべて「ラージ」画面と見なされたとしても、このカテゴリ内のデバイスのサイズに合わせて異なるレイアウト(5 インチと 7 インチのデバイス用など)を表示したい場合があります。そこで、Android 3.2 では「最小幅」修飾子などが導入されました。</p> + +<p>最小幅修飾子を使用すると、dp で指定した特定の最小幅の画面を対象とすることができます。たとえば、一般的な 7 インチ タブレットは最小幅が 600 dp なので、これらの画面の UI で 2 つのペイン(ただし、それよりも小さい画面ではシングル リスト)を表示したい場合は、前のセクションで説明した 2 つのレイアウトをシングルペイン レイアウト用と 2 ペイン レイアウト用としてそのまま利用できます。ただし、<code>large</code> サイズ修飾子の代わりに、<code>sw600dp</code> を使用して、最小幅が 600 dp の画面では 2 ペイン レイアウトになるよう指定します:</p> + +<ul> + <li><code>res/layout/main.xml</code>、シングルペイン(デフォルト)レイアウト: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>、2 ペイン レイアウト: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>つまり、最小幅が 600dp 以上のデバイスでは <code>layout-sw600dp/main.xml</code>(2 ペイン)レイアウトが選択され、それよりも小さい画面では <code>layout/main.xml</code>(シングルペイン)レイアウトが選択されるということです。</p> + +<p>ただし、Android 3.2 未満のデバイスではこの修飾子は機能しません。これは <code>sw600dp</code> をサイズ修飾子として認識できないためです。したがって、引き続き <code>large</code> 修飾子も使用する必要があります。そこで、<code>res/layout-sw600dp/main.xml</code> と同じ内容の <code>res/layout-large/main.xml</code> という名前のファイルも必要になります。次のセクションでは、このようにレイアウト ファイルの重複を避けるためのテクニックについて学習します。</p> + + +<h2 id="TaskUseAliasFilters">レイアウト エイリアスを使用する</h2> + +<p>最小幅修飾子は、Android 3.2 以上でしか利用できません。したがって、旧バージョンとの互換性を維持するために、あいまいなサイズ分類(small、normal、large、xlarge)も併用することが必要です。たとえば、携帯端末ではシングルペイン UI、7 インチ タブレットやテレビなどの大きなデバイスではマルチペイン UI を表示するよう UI を設計する場合、以下のようなファイルが必要になります:</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> シングルペイン レイアウト</li> +<li><code>res/layout-large:</code> マルチペイン レイアウト</li> +<li><code>res/layout-sw600dp:</code> マルチペイン レイアウト</li> +</ul></p> + +<p>最後の 2 つのファイルは同じものです。一方は Android 3.2 デバイス用で、もう一方は旧バージョンの Android を搭載したタブレットとテレビ用です。</p> + +<p>このようにタブレット/テレビ用として同じファイルを使用することで起こる重複(さらに、その結果メンテナンスが困難になる状況)を避けるために、エイリアス ファイルを使用できます。たとえば、次のようなレイアウトを定義できます:</p> + +<ul> +<li><code>res/layout/main.xml</code>、シングルペイン レイアウト</li> +<li><code>res/layout/main_twopanes.xml</code>、2 ペイン レイアウト</li> +</ul> + +<p>さらに、次の 2 つのファイルを追加します:</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>最後の 2 つのファイルの内容は同じですが、実際のレイアウトは定義していません。これらのファイルは、単に <PH>{@code main}</PH> を <PH>{@code main_twopanes}</PH>へのエイリアスになるように設定しただけです。これらのファイルには <code>large</code> と <code>sw600dp</code> セレクタが含まれているので、Android のバージョンに関係なく( +<PH>Android 3.2 未満のタブレット/テレビは {@code large} に一致し、</PH>Android 3.2 以上のタブレット/テレビは <code>sw600dp</code> に一致します)タブレット/テレビに適用されます。</p> + + +<h2 id="TaskUseOriQuali">画面の向きの修飾子を使用する</h2> + +<p>横表示と縦表示が両方とも正しく表示されるレイアウトもありますが、ほとんどのレイアウトは調整が必要になります。以下に、News Reader サンプル アプリの各画面のサイズと向きでレイアウトがどのように表示されるかを示します:</p> + +<p><ul> +<li><b>スモール画面、縦表示:</b> シングル ペイン、ロゴ付き</li> +<li><b>スモール画面、横表示:</b> シングル ペイン、ロゴ付き</li> +<li><b>7 インチ タブレット、縦表示:</b> シングル ペイン、アクション バー付き</li> +<li><b>7 インチ タブレット、横表示:</b> デュアル ペイン、ワイド、アクション バー付き</li> +<li><b>10 インチ タブレット、縦表示:</b> デュアル ペイン、ナロー、アクション バー付き</li> +<li><b>10 インチ タブレット、横表示:</b> デュアル ペイン、ワイド、アクション バー付き</li> +<li><b>テレビ、横表示:</b> デュアル ペイン、ワイド、アクション バー付き</li> +</ul></p> + +<p>これらの各レイアウトは、<code>res/layout/</code> ディレクトリ内の XML ファイルに定義されています。各レイアウトをさまざまな画面設定に割り当てるには、アプリでレイアウト エイリアスを使用して、各設定に対応付けます:</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>これで、考えられるすべてのレイアウトが定義されました。あとは、設定修飾子を使用して、適切なレイアウトを各設定にマッピングするだけです。そのためには、以下のようなレイアウト エイリアス テクニックを使用することができます:</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">ナインパッチ ビットマップを使用する</h2> + +<p>異なる画面サイズをサポートするには、画像リソースも異なるサイズに対応できないといけません。たとえば、ボタンの背景は、適用されるボタンの形状が異なってもサイズが合わなければいけません。</p> + +<p>サイズ変更可能なコンポーネントでシンプルな画像を使用すると、ランタイムによって画像が一様に拡大縮小されるので、いくぶん期待はずれの結果になることがすぐにわかります。これは、ナインパッチ ビットマップを使用することで解決します。ナインパッチ ビットマップとは、拡大可能な領域と拡大不可能な領域が指定された特殊なフォーマットの PNG ファイルです。</p> + +<p>そのため、サイズが変化するコンポーネントで使用するビットマップをデザインする場合は、常にナインパッチを使用してください。ビットマップをナインパッチに変換するには、まず、通常の画像を用意します(図 4: わかりやすく 4 倍に拡大しています)。</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>図 4.</strong> <code>button.png</code></p> + +<p>次に、 <ode +href="{@docRoot}tools/help/draw9patch.html">SDK の <code>draw9patch</code></a> ユーティリティ(<code>tools/</code> ディレクトリにあります)からナインパッチを実行して、左境界線と上境界線上にピクセル(ドット)を描くことで拡大する領域にマークを付けます。また、右境界線と下境界線上にピクセルを描くことで、コンテンツを入れる領域をマークできます(図 5)。</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>図 5.</strong> <code>button.9.png</code></p> + +<p>境界線上に黒いピクセルがあることに注目してください。左境界線と上境界線上のものは画像を拡大できる領域で、右境界線と下境界線上のものはコンテンツを配置する領域を示しています。</p> + +<p>さらに、<code>.9.png</code> という拡張子にも注目してください。この拡張子は必ず使用してください。そうすることで、通常の PNG 画像ではなく、ナインパッチ画像であることがフレームワークによって検出されます。</p> + +<p>この背景を(<code>android:background="@drawable/button"</code> を設定して)コンポーネントに適用すると、ボタンのサイズに合わせて適切に画像が拡大します(図 6 のさまざまなサイズを参照)。</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>図 6</strong><code>button.9.png</code> ナインパッチを使用したさまざまなサイズのボタン</p> + diff --git a/docs/html-intl/ko/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/ko/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..2eacccf --- /dev/null +++ b/docs/html-intl/ko/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=배터리 수준 및 충전 상태 모니터링 +parent.title=배터리 수명 최적화 +parent.link=index.html + +trainingnavtop=true +next.title=도킹 상태와 유형 확인 및 모니터링 +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#DetermineChargeState">현재 충전 상태 확인</a></li> + <li><a href="#MonitorChargeState">충전 상태 변경사항 모니터링</a></li> + <li><a href="#CurrentLevel">현재 배터리 수준 확인</a></li> + <li><a href="#MonitorLevel">배터리 수준 중요 변경사항 모니터링</a></li> +</ol> + +<h2>참고자료</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">인텐트 및 인텐트 필터</a> +</ul> + +</div> +</div> + +<p>백그라운드 업데이트가 배터리 수명에 미치는 영향을 줄이기 위하여 백그라운드 업데이트 빈도수를 변경하는 경우, 현재 배터리 수준과 충전 상태부터 확인하는 것이 좋습니다.</p> + +<p>애플리케이션 업데이트 수행이 배터리 수명에 미치는 영향은 배터리 수준 및 기기의 충전 상태에 따라 다릅니다. 기기를 AC 충전기로 충전하는 동안 업데이트 수행이 미치는 영향은 무시해도 좋습니다. 따라서 기기가 범용 충전기에 연결되어 있을 때는 대부분 새로고침 빈도를 최대화할 수 있습니다. 반대로 기기가 충전 중이 아니라면, 업데이트 빈도를 줄이는 것이 배터리 수명 연장에 도움이 됩니다.</p> + +<p>마찬가지로 배터리가 거의 방전된 경우, 업데이트 빈도를 줄이거나 중단할 수 있습니다.</p> + + +<h2 id="DetermineChargeState">현재 충전 상태 확인</h2> + +<p>먼저 현재 충전 상태를 확인하는 것부터 시작합니다. {@link android.os.BatteryManager}는 배터리 충전 상태 등 충전 정보를 스티키 {@link android.content.Intent}를 통해 브로드캐스트합니다.</p> + +<p>스티키 인텐트이므로 {@link android.content.BroadcastReceiver}를 등록할 필요가 없으며 아래 코드 상의 리시버와 같이 간단히 {@code registerReceiver}을(를) 호출하여 {@code null}에 제출하면 현재 배터리 상태가 담긴 인텐트가 반환됩니다. 여기에 실제 {@link android.content.BroadcastReceiver} 개체 사용할 수 있으나, 이후 섹션에서 업데이트를 다루게 되므로 그럴 필요는 없습니다.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>현재 충전 상태와 어떤 충전기(USB 또는 AC 전원)로 충전하는지 추출할 수 있습니다.<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>일반적으로 기기가 AC 충전기에 연결된 경우 백그라운드 업데이트 빈도를 최대화합니다. USB를 통해 충전하는 경우 업데이트 빈도를 낮춥니다. 배터리가 방전 중이라면 빈도를 더 많이 낮추도록 합니다.</p> + + +<h2 id="MonitorChargeState">충전 상태 변경사항 모니터링</h2> + +<p>충전 상태는 수시로 변하므로 충전 상태의 변경사항을 확인하고 이에 따라 업데이트 주기를 변경하는 것이 중요합니다.</p> + +<p>{@link android.os.BatteryManager}는 기기가 전원에 연결되어 있는지 여부와 관계없이 언제나 액션을 브로드캐스트합니다. 앱이 실행되지 않는 동안에도 이벤트를 수신하는 것이 중요합니다. 특히 백그라운드 업데이트를 실행하기 위해 앱을 시작하는 빈도수에 이벤트가 영향을 주기 때문입니다. 따라서 두 이벤트를 수신하려면 매니페스트에서 {@link android.content.BroadcastReceiver}를 등록하여 인텐트 필터 내에 {@link android.content.Intent#ACTION_POWER_CONNECTED}와 {@link android.content.Intent#ACTION_POWER_DISCONNECTED}를 정의해야 합니다.</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>다음의 {@link android.content.BroadcastReceiver} 구현에서 이전 단계에서 설명한 대로 현재 충전 상태와 방법을 알아낼 수 있습니다.</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">현재 배터리 수준 확인</h2> + +<p>현재 배터리 수준을 확인하는 것이 유용한 경우도 있습니다. 배터리 충전이 수준 이하인 경우 백그라운드 업데이트 빈도를 줄일 수 있습니다.</p> + +<p>다음은 배터리 상태 정보가 담긴 인텐트에서 현재 배터리 수준 및 충전 상태를 추출하는 방법입니다.</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">배터리 수준 중요 변경사항 모니터링</h2> + +<p>배터리 상태를 지속적으로 확인하는 것은 쉽지 않지만, 꼭 그럴 필요도 없습니다.</p> + +<p>배터리 수준을 지속적으로 모니터링하는 것은 앱의 다른 작업보다 배터리에 더 큰 영향을 미칩니다. 따라서 기기가 배터리 전원 부족 상태가 되거나 이를 벗어날 때 등 중요한 변경사항만 확인하는 것이 좋습니다.</p> + +<p>다음 코드는 매니페스트의 브로드캐스트 리시버 내의 인텐트 필터를 보여줍니다. 배터리가 얼마 남지 않거나{@link android.content.Intent#ACTION_BATTERY_LOW} 배터리 상태가 회복되었을 때{@link android.content.Intent#ACTION_BATTERY_OKAY} 전달되는 메시지를 수신할 수 있습니다.</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>배터리 충전 상태가 매우 낮은 경우 백그라운드 업데이트를 사용하지 않는 것이 좋습니다. 전화기가 꺼져버리면 최신 데이터를 제공하는 것이 의미가 없기 때문입니다.</p> + +<p>기기를 충전하는 것은 곧 기기를 도크에 집어넣는 것과 같은 경우가 많습니다. 다음 강의는 현재 도크 상태를 확인하고 기기 도킹의 변경사항을 모니터링하는 방법을 보여줍니다.</p> + diff --git a/docs/html-intl/ko/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/ko/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..5666b98 --- /dev/null +++ b/docs/html-intl/ko/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=연결 상태 확인 및 모니터링 +parent.title=배터리 수명 최적화 +parent.link=index.html + +trainingnavtop=true + +previous.title=도킹 상태와 유형 확인 및 모니터링 +previous.link=docking-monitoring.html +next.title=온디맨드로 브로드캐스트 수신기 조작 +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#DetermineConnection">인터넷에 연결되어 있는지 확인</a></li> + <li><a href="#DetermineType">인터넷 연결 유형 확인</a></li> + <li><a href="#MonitorChanges">연결 변경사항 모니터링</a></li> +</ol> + + +<h2>참고자료</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">인텐트 및 인텐트 필터</a> +</ul> + +</div> +</div> + +<p>반복 알람과 백그라운드 서비스는 일반적으로 인터넷 리소스 및 캐시 데이터로부터 애플리케이션의 업데이트를 예약하거나 긴 시간이 필요한 다운로드를 실행하는 데 사용됩니다. 하지만 인터넷에 연결되어 있지 않거나 연결이 매우 느려 다운로드를 완료하지 못한다면 업데이트 예약을 해도 소용이 없겠죠?</p> + +<p>인터넷에 연결되었는지, 어떤 연결 방식인지를 확인하기 위하여 {@link android.net.ConnectivityManager}를 사용할 수 있습니다.</p> + + +<h2 id="DetermineConnection">인터넷에 연결되어 있는지 확인</h2> + +<p>인터넷에 연결되어 있지 않는 경우 인터넷 리소스를 기반으로 한 업데이트 예약을 할 필요가 없습니다. 다음은 활성 네트워크를 쿼리하고 인터넷이 연결되어 있는지 확인하기 위한 {@link android.net.ConnectivityManager} 사용법을 보여줍니다.</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">인터넷 연결 유형 확인</h2> + +<p>현재 사용할 수 있는 인터넷 연결 유형을 확인할 수도 있습니다.</p> + +<p>연결은 모바일 데이터, WiMAZ, Wi-Fi 및 이더넷 연결을 통해 제공될 수 있습니다. 아래와 같이 활성 네트워크의 유형을 쿼리하면, 사용 가능한 대역폭에 따라 업데이트 빈도를 변경할 수 있습니다.</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>모바일 데이터 비용은 Wi-Fi보다 높은 경향이 있으므로, 모바일 연결인 경우 앱의 업데이트 빈도를 줄여야 합니다. 마찬가지로 Wi-Fi로 연결되기까지 큰 용량의 다운로드는 일시 중지해야 합니다.</p> + +<p>업데이트를 비활성화한 경우, 인터넷 연결이 재개되면 업데이트를 다시 시작하기 위해 연결 변경사항을 알고 있는 것이 중요합니다.</p> + + +<h2 id="MonitorChanges">연결 변경사항 모니터링</h2> + +<p>연결 정보가 변경될 때마다 {@link android.net.ConnectivityManager}는 {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION}({@code "android.net.conn.CONNECTIVITY_CHANGE"}) 액션을 브로드캐스트합니다. 변경사항을 수신하거나 적절히 백그라운드 업데이트를 다시 시작 또는 일시 중지하기 위해 매니페스트에서 브로드캐스트 리시버를 등록할 수 있습니다.</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>연결 정보는 수시로 변경될 수 있습니다. 모바일과 Wi-Fi 간에 이동할 때마다 브로드캐스트가 실행됩니다. 따라서 업데이트나 다운로드를 일시 중지한 경우에만 브로드캐스트를 확인하는 것이 좋습니다. 업데이트를 시작하기 전이나 이전에 업데이트를 일시 중지했던 경우에만 확인하는 것으로 충분합니다.</p> + +<p>이 기술은 다음 강의에서 설명하는 매니페스트에서 선언한 브로드캐스트 리시버의 전환이 필요합니다.</p> diff --git a/docs/html-intl/ko/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/ko/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..0cd61a0 --- /dev/null +++ b/docs/html-intl/ko/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=도킹 상태와 유형 확인 및 모니터링 +parent.title=배터리 수명 최적화 +parent.link=index.html + +trainingnavtop=true +previous.title= 배터리 수준 및 충전 상태 모니터링 +previous.link=battery-monitoring.html +next.title= 연결 상태 확인 및 모니터링 +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#CurrentDockState">오디오 포커스 요청</a></li> + <li><a href="#DockType">현재 도크 유형 확인</a></li> + <li><a href="#MonitorDockState">도크 상태 또는 유형 변경사항 모니터링</a></li> +</ol> + + +<h2>참고자료</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">인텐트 및 인텐트 필터</a> +</ul> + +</div> +</div> + +<p>Android 기기는 여러 종류의 도크로 도킹될 수 있습니다. 여기에는 카폰 또는 홈 도크와 디지털 및 아날로그 도크가 포함됩니다. 많은 도크가 도킹된 기기에 전기를 공급하므로 일반적으로 충전 상태와 도크 상태는 밀접한 관련이 있습니다.</p> + +<p>전화의 도크 상태가 업데이트 빈도에 어떻게 영향을 미치는지는 앱에 따라 다릅니다. 스포츠 센터 앱이라면 데스크톱 도크에서 업데이트 빈도를 높이고 카폰 도크에 연결된 경우 업데이트를 완전히 사용 중지해도 좋습니다. 반대로 교통 상황을 제공하는 앱이라면 카폰 도크에서 업데이트를 최대화해도 좋습니다.</p> + +<p>도크 상태는 스티키 {@link android.content.Intent}로 브로드캐스트되어 기기가 도킹되었는지 여부와 도킹되었다면 어떤 종류의 도크인지 알아낼 수 있습니다. </p> + + +<h2 id="CurrentDockState">현재 도킹 상태 확인</h2> + +<p>도크 상태의 세부사항은 {@link android.content.Intent#ACTION_DOCK_EVENT} 액션의 스티키 브로드캐스트 내에 추가로 포함됩니다. 스티키 브로드캐스트이므로 {@link android.content.BroadcastReceiver}를 등록할 필요가 없습니다. 다음 스니펫에 표시된 브로드캐스트 수신기와 같이 간단히 {@link android.content.Context#registerReceiver registerReceiver()}를 호출하여 {@code null}에 제출할 수 있습니다. </p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>{@code EXTRA_DOCK_STATE} 추가로부터 현재 도킹 상태를 추출할 수 있습니다.<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">현재 도크 유형 확인</h2> + +<p>4가지 유형의 도크가 있습니다. +<ul><li>카폰</li> +<li>데스크</li> +<li>저가형(아날로그) 데스크</li> +<li>고가형(디지털) 데스크</li></ul></p> + +<p>마지막 두 가지 옵션은 API 수준 11의 Android에만 제공되어 있으므로, 디지털 또는 아날로그에 상관하지 않고 관심 있는 세 가지 도크 유형에 대해 확인하는 것이 좋습니다.</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">도크 상태 또는 유형 변경사항 모니터링</h2> + +<p>도킹 상태가 바뀌면 {@link android.content.Intent#ACTION_DOCK_EVENT} 액션이 브로드캐스트됩니다. 기기의 도크 상태 변경사항을 모니터링하려면 아래에 표시된 대로 애플리케이션 매니페스트에서 브로드캐스트 리시버를 등록하세요.</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>이전 단계에서 설명한 기술을 사용하여 리시버 구현에서 도크 유형 및 상태를 추출할 수 있습니다.</p> diff --git a/docs/html-intl/ko/training/monitoring-device-state/index.jd b/docs/html-intl/ko/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..f96e2e1 --- /dev/null +++ b/docs/html-intl/ko/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=배터리 수명 최적화 + +trainingnavtop=true +startpage=true +next.title=배터리 수준 및 충전 상태 모니터링 +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>요구사항과 선행조건</h2> +<ul> + <li>Android 2.0(API 수준 5) 또는 이상</li> + <li> <a href="{@docRoot}guide/components/intents-filters.html">인텐트 및 인텐트 필터</a> 사용 경험</li> +</ul> + +<h2>참고자료</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">서비스</a> +</ul> + +</div> +</div> + +<p>좋은 앱은 호스트 기기의 배터리 수명에 미치는 영향이 미미해야 합니다. 강의를 통해 호스트 기기의 상태에 따라 기능과 동작을 수정하는 것을 모니터링하는 앱을 구축할 수 있게 됩니다.</p> + +<p>연결이 끊겼을 때 백그라운드 서비스 업데이트를 사용 중지하거나, 배터리 수준이 낮을 때 업데이트 빈도를 줄이는 조치를 취하여, 사용자 환경을 손상시키지 않고 배터리 수명에 미치는 영향을 최소화할 수 있습니다.</p> + +<h2>강의</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">배터리 수준 및 충전 상태 모니터링</a></b></dt> + <dd>충전 상태에서 현재 배터리 수준 및 변경사항을 확인 및 모니터링하여 앱의 업데이트 빈도를 변경하는 법을 알아보세요.</dd> + + <dt><b><a href="docking-monitoring.html">도킹 상태와 유형 확인 및 모니터링</a></b></dt> + <dd>최적의 새로고침 빈도는 호스트 기기의 사용 방법에 따라 달라질 수 있습니다. 앱의 동작에 영향을 미치는 도킹 상태와 도크 유형을 확인 및 모니터링하는 방법을 알아보세요.</dd> + + <dt><b><a href="connectivity-monitoring.html">연결 상태 확인 및 모니터링</a></b></dt> + <dd>인터넷 연결 없이 온라인 소스를 통해 앱을 업데이트할 수 없습니다. 연결 상태를 확인하여 백그라운드 업데이트 빈도를 변경하는 방법을 알아보세요. 고대역폭 작업을 시작하기 전에 Wi-Fi 또는 모바일 연결을 확인하는 방법도 알 수 있습니다.</dd> + + <dt><b><a href="manifest-receivers.html">온디맨드로 브로드캐스트 수신기 조작</a></b></dt> + <dd>매니페스트 내에 선언했던 브로드캐스트 리시버는 현재 기기 상태에서 필요 없는 것을 사용 중지하도록 런타임 때 전환될 수 있습니다. 기기가 특정 상태에 도달할 때까지 상태 변화 리시버 및 지연 액션을 전환 및 단계적으로 연결하여 효율성을 향상하는 법을 알아보세요.</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/ko/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/ko/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..c5c311b --- /dev/null +++ b/docs/html-intl/ko/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=온디맨드로 브로드캐스트 수신기 조작 +parent.title=배터리 수명 최적화 +parent.link=index.html + +trainingnavtop=true + +previous.title=연결 상태 확인 및 모니터링 +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#ToggleReceivers">효율성 향상을 위한 상태 변화 리시버의 전환 및 단계적 연결</a></li> +</ol> + + +<h2>참고자료</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">인텐트 및 인텐트 필터</a> +</ul> + +</div> +</div> + +<p>기기 상태 변경을 모니터링하는 가장 간단한 방법은 모니터링하는 각 상태에 대해 {@link android.content.BroadcastReceiver}를 만들어 각각을 애플리케이션 매니페스트에 등록하는 것입니다. 그러면 각 리시버 내에서 현재 기기 상태를 기반으로 반복 알람의 일정을 간단히 변경할 수 있습니다.</p> + +<p>이 방법의 부작용은 리시버 중 하나라도 실행되면 매번 앱이 기기의 절전 모드를 해제시킨다는 것입니다.</p> + +<p>더 나은 방법은 런타임 때 브로드캐스트 리시버를 사용 중지 또는 사용하도록 설정하는 것입니다. 이렇게 하면 매니페스트에 선언한 리시버를 필요할 때만 시스템 이벤트에 의해 실행되는 수동적인 알람으로 사용할 수 있습니다.</p> + + +<h2 id="ToggleReceivers">효율성 향상을 위한 상태 변화 수신기의 전환 및 단계적 연결 </h2> + +<p>{@link android.content.pm.PackageManager}를 사용하여 아래에서 표시된 대로 모든 사용 또는 사용 중지하기 원하는 브로드캐스트 리시버를 포함하여 매니페스트 내에 정의된 모든 요소의 사용 가능 상태를 전환할 수 있습니다.</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>이 방법을 사용하면 연결이 없음을 확인한 경우 연결 변경 리시버를 제외한 모든 리시버를 사용 중지할 수 있습니다. 반대로 한 번 연결되면 연결 변경사항의 수신을 중지할 수 있으며, 업데이트를 수행하고 반복 업데이트 알람의 일정을 변경하기 전에 온라인 상태인지만 간단히 확인할 수 있습니다.</p> + +<p>높은 대역폭을 요구하는 다운로드를 중지시키는 데 동일한 기술을 사용할 수 있습니다. 연결 변경을 수신하는 브로드캐스트 리시버를 사용하도록 설정하고 반드시 Wi-Fi에 연결한 후에 다운로드를 시작하도록 합니다.</p> diff --git a/docs/html-intl/ko/training/multiscreen/adaptui.jd b/docs/html-intl/ko/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..cb7b66c --- /dev/null +++ b/docs/html-intl/ko/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=조정형 UI 플로우 구현 +parent.title=다양한 화면 지원 +parent.link=index.html + +trainingnavtop=true +previous.title=다양한 화면 밀도 지원 +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">현재 레이아웃 확인</a></li> + <li><a href="#TaskReactToLayout">현재 레이아웃에 대한 대응</a></li> + <li><a href="#TaskReuseFrag">다른 액티비티에 프래그먼트 재사용</a></li> + <li><a href="#TaskHandleConfigChanges">화면 구성 변경의 처리</a></li> +</ol> + +<h2>참고자료</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">태블릿 및 휴대전화 지원</a></li> +</ul> + +<h2>다운로드 </h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">샘플 앱 다운로드</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>현재 애플리케이션이 표시하는 레이아웃에 따라 UI 플로가 달라질 수 있습니다. 예를 들어 애플리케이션이 이중 창 모드로 되어 있는 경우에는 왼쪽 창에 있는 항목을 클릭하면 오른쪽 창에 콘텐츠가 표시되고, 단일 창 모드로 되어 있는 경우에는 콘텐츠가 해당 창에 표시됩니다(다른 액티비티에서).</p> + + +<h2 id="TaskDetermineCurLayout">현재 레이아웃 확인</h2> + +<p>각 레이아웃을 구현하는 방식이 약간씩 다르므로 가장 먼저 해야 할 일은 현재 사용자에게 어떤 레이아웃이 표시되는지 확인하는 것입니다. 예를 들어, 사용자가 '단일 창' 모드에 있는지 혹은 '이중 창' 모드에 있는지 파악할 수 있습니다. 이는 특정 뷰가 존재하고 그 뷰가 표시되는지 조회하면 됩니다.</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>이 코드는 'article' 창을 사용할 수 있는지 여부를 조회하며 이러한 방식이 특정 레이아웃에 대한 조회를 하드코딩하는 것보다 훨씬 유연한 방식입니다.</p> + +<p>다른 구성요소의 존재 여부에 맞게 앱을 조정하는 또 다른 방법은 구성요소에 대한 작업을 수행하기 전에 해당 구성요소를 사용할 수 있는지 확인하는 것입니다. 예를 들어 뉴스 리더 샘플 앱의 경우, 메뉴를 여는 버튼이 있긴 하지만 이 버튼은 Android 3.0 이전 버전에서 실행되는 경우에만 존재합니다(API 수준 11 이상에서 <PH>{@link android.app.ActionBar}</PH> 가 그 기능을 대신하기 때문). 따라서 이 버튼에 대한 이벤트 리스너를 추가하기 위해 다음과 같이 할 수 있습니다.</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">현재 레이아웃에 대한 대응</h2> + +<p>현재 레이아웃에 따라 일부 액션의 결과가 달라질 수 있습니다. 예를 들어 뉴스 리더 샘플의 헤드라인 목록에서 헤드라인을 클릭하면 UI가 이중 창 모드인 경우에는 기사가 오른쪽 창에서 열리지만, UI가 단일 창 모드인 경우에는 별도의 액티비티가 실행됩니다.</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>마찬가지로, 앱이 이중 창 모드인 경우에는 탐색용 탭이 포함된 작업 표시줄이 설정되지만, 앱이 단일 창 모드인 경우에는 스피너 위젯이 포함된 탐색 메뉴가 설정됩니다. 따라서 어떤 경우가 적합한지도 코드에서 확인해야 합니다.</p> + +<pre> +final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">다른 액티비티에 프래그먼트 재사용</h2> + +<p>다양한 화면의 디자인에 반복되는 패턴에는 일부 화면 구성에서는 창으로 구현되고 다른 화면 구성에서는 별도의 액티비티로 구현되는 인터페이스가 일부 있습니다. 예를 들어 뉴스 리더 샘플에서 뉴스 기사 텍스트가 큰 화면에서는 오른쪽 창에 표시되지만 작은 화면에서는 별도의 액티비티입니다.</p> + +<p>이러한 경우 일반적으로 동일한 <PH>{@link android.app.Fragment}</PH> 하위 클래스를 여러 액티비티에 재사용하여 코드 중복을 피할 수 있습니다. 예를 들어 <code>ArticleFragment</code>는 이중 창 레이아웃에서 사용되며 </p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>작은 화면의 액티비티 레이아웃에 레이아웃 없이 재사용됩니다(<code>ArticleActivity</code>).</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>당연히 이는 XML 레이아웃에서 프래그먼트(fragment)를 명시하는 것과 같은 효과가 있지만 이 경우에는 아티클 프래그먼트가 이 액티비티의 유일한 구성요소이기 때문에 XML 레이아웃은 불필요한 작업이 됩니다.</p> + +<p>프래그먼트를 디자인할 때 염두에 두어야 할 매우 중요한 점 한 가지는 특정 액티비티에 대한 강한 커플링을 만들지 말아야 한다는 점입니다. 이렇게 하려면 일반적으로 프래그먼트가 호스트 액티비티와 상호작용해야 하는 모든 방식을 추상화하는 인터페이스를 정의하면 됩니다. 그러면 호스트 액티비티가 해당 인터페이스를 구현합니다.</p> + +<p>예를 들어 뉴스 리더 앱의 <code>HeadlinesFragment</code>가 정확하게 그 일을 해 줍니다.</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>그런 다음 사용자가 헤드라인을 선택하면 프래그먼트가 하드코딩된 특정 액티비티를 알리지 않고 호스트 액티비티가 지정한 리스너를 알립니다.</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p>이 기술은 <a +href="{@docRoot}guide/practices/tablets-and-handsets.html">태블릿 및 휴대전화 지원</a> 가이드에서 자세히 설명되어 있습니다.</p> + + +<h2 id="TaskHandleConfigChanges">화면 구성 변경 처리</h2> + +<p>인터페이스 중 일부를 구현하는데 별도의 액티비티를 사용 중인 경우 인터페이스의 일관성을 유지하기 위해 특정 구성의 변경(예: 화면 전환)에 대응해야 합니다.</p> + +<p>예를 들어 Android 3.0 이상을 실행하는 일반적인 7인치 태블릿에서 뉴스 리더 샘플은 세로 모드에서 실행될 때에는 뉴스 기사를 표시하는 데 별도의 액티비티를 사용하지만 가로모드에서는 이중 창(two-pane) 레이아웃을 사용합니다.</p> + +<p>즉 사용자가 세로 모드에 있고 기사를 보기 위한 액티비티가 화면에 있는 경우, 방향이 가로로 바뀌었음을 감지하고, 액티비티를 종료한 다음 주요 액티비티로 돌아감으로써 콘텐츠가 이중 창 레이아웃에서 표시되도록 적절하게 대응해야 합니다.</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/ko/training/multiscreen/index.jd b/docs/html-intl/ko/training/multiscreen/index.jd new file mode 100644 index 0000000..d9e09b0 --- /dev/null +++ b/docs/html-intl/ko/training/multiscreen/index.jd @@ -0,0 +1,64 @@ +page.title=다양한 화면 지원 + +trainingnavtop=true +startpage=true +next.title=다양한 화면 크기 지원 +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>요구사항과 선행조건</h2> + +<ul> + <li>Android 1.6 이상(샘플 앱의 경우 2.1 이상)</li> + <li><a +href="http://developer.android.com/guide/components/activities.html">액티비티</a> 및 <a href="http://developer.android.com/guide/components/fragments.html">프래그먼트</a>에 대한 기본 지식</li> + <li>Android <a +href="http://developer.android.com/guide/topics/ui/index.html"> 사용자 인터페이스</a> 구축 경험</li> + <li><a +href="{@docRoot}tools/extras/support-library.html">호환성 라이브러리</a>를 사용해야 하는 여러 기능</li> +</ul> + +<h2>참고자료</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">다양한 화면 지원</a></li> +</ul> + +<h2>다운로드 </h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">샘플 앱 다운로드</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>Android는 소형 휴대전화에서부터 대형 TV에 이르기까지 다양한 화면 크기의 수많은 기기 유형을 지원합니다. 따라서 애플리케이션이 모든 화면 크기와 호환되어 최대한 많은 사용자가 사용할 수 있도록 디자인하는 것이 중요합니다.</p> + +<p>하지만 다양한 기기 유형과 호환되는 것만으로는 충분하지 않습니다. 각 화면 크기에 따라 사용자 상호작용에 유리한 점과 불리한 점이 다릅니다. 따라서 사용자에게 만족을 주고 깊은 인상을 심어주려면 애플리케이션이 단지 여러 화면을 <em>지원</em>하는 데 그치지 않고 화면 구성별로 사용자 환경을 <em>최적화</em>해야 합니다.</p> + +<p>이번 강의에서는 여러 화면 구성에 최적화된 사용자 인터페이스를 구현하는 방법을 설명합니다.</p> + +<p>각 강의에서 사용되는 코드는 여러 화면에 대한 최적화의 모범 사례를 보여주는 샘플 애플리케이션에서 가져온 것입니다. 샘플(오른쪽)을 다운로드하여 본인의 애플리케이션에 코드로 재사용할 수 있습니다. </p> + +<p class="note"><strong>참고:</strong> 이 강의 및 강의와 관련된 샘플은 <a +href="{@docRoot}tools/extras/support-library.html">호환성 라이브러리</a>를 사용하며 이는 Android 3.0 이하 버전에서 <PH>{@link android.app.Fragment}</PH> API를 사용하기 위해서입니다. 이 강의에서 API를 모두 사용하려면 라이브러리를 다운로드하여 애플리케이션에 추가해야 합니다.</p> + + +<h2>강의</h2> + +<dl> + <dt><b><a href="screensizes.html">다양한 화면 크기 지원</a></b></dt> + <dd>이 강의에서는 여러 다양한 화면 크기에 조정되는 레이아웃을 디자인하는 방법(유연한 보기 크기, <PH>{@link android.widget.RelativeLayout}</PH>, 화면 크기 및 방향 한정자, 별칭 필터 및 나인-패치 비트맵 사용하기)을 안내합니다.</dd> + + <dt><b><a href="screendensities.html">다양한 화면 밀도 지원</a></b></dt> + <dd>이 강의에서는 다양한 픽셀 밀도를 가진 화면을 지원하는 방법(밀도 독립형 픽셀(density-independent pixel) 사용하기 및 밀도별로 적합한 비트맵 제공하기)을 설명합니다.</dd> + + <dt><b><a href="adaptui.html">조정형 UI 플로우 구현</a></b></dt> + <dd>이 강의에서는 여러 화면 크기/밀도 조합에 조정되도록 UI 플로우를 구현하는 방법(활성 레이아웃의 런타임 감지, 현재 레이아웃에 따른 대응, 화면 구성 변경 처리)을 설명합니다.</dd> +</dl> diff --git a/docs/html-intl/ko/training/multiscreen/screendensities.jd b/docs/html-intl/ko/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..5d6e2f3 --- /dev/null +++ b/docs/html-intl/ko/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=다양한 화면 밀도 지원 +parent.title=다양한 화면 지원 +parent.link=index.html + +trainingnavtop=true +previous.title=다양한 화면 크기 지원 +previous.link=screensizes.html +next.title=조정형 UI 플로우 구현 +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#TaskUseDP">DIP(Density Independent Pixel) 사용</a></li> + <li><a href="#TaskProvideAltBmp">대체 비트맵 제공</a></li> +</ol> + +<h2>참고자료</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">여러 화면 지원</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">아이콘 디자인 가이드라인</a></li> +</ul> + +<h2>다운로드 </h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">샘플 앱 다운로드</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>이 강의에서는 다양한 리소스를 제공하고 해상도 독립형(resolution-independent) 측정 단위를 사용함으로써 다양한 화면 밀도를 지원하는 방법을 설명합니다.</p> + +<h2 id="TaskUseDP">DIP(Density Independent Pixel) 사용</h2> + +<p>레이아웃을 디자인할 때 범하기 쉬운 실수 중 하나는 절대 픽셀(absolute pixel)을 사용하여 거리나 크기를 정의하는 것입니다. 각 화면은 픽셀 밀도가 서로 다른데 레이아웃 크기를 픽셀로 정의하면 동일한 픽셀 수치가 다른 기기에서 다른 물리적 크기와 대응할 수 있어 문제가 됩니다. 따라서 크기를 지정할 때에는 항상 <code>dp</code> 또는 <code>sp</code> 단위를 사용하시기 바랍니다. <code>dp</code>는 160dpi에서 픽셀의 물리적 크기에 대응하는 밀도 독립형 픽셀(Density Independent Pixel)입니다. <code>sp</code>는 동일한 기본 단위이지만 사용자의 기본 텍스트 크기에 따라 확대/축소될 수 있으므로(배율 독립형 픽셀(Scale Independent Pixel)임) 텍스트 크기를 정의할 때 이 측정 단위를 사용해야 합니다(레이아웃 크기에 사용해서는 안됨).</p> + +<p>예를 들어 두 개의 보기 사이에 여백을 지정할 때 <code>px</code>가 아닌 <code>dp</code>를 사용합니다.</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>텍스트 크기를 지정할 때에는 항상 <code>sp</code>를 사용합니다.</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">대체 비트맵 제공</h2> + +<p>Android는 화면 밀도가 다양한 기기에서 실행되므로 각각의 일반화된 밀도 종류(저, 중, 고 및 초고 밀도)에 맞춤화된 비트맵 리소스를 제공해야 합니다. 이렇게 하면 모든 화면 밀도에서 좋은 그래픽 품질 및 성능을 얻는데 도움이 됩니다.</p> + +<p>이러한 이미지를 생성하려면 벡터 형식의 원본 리소스부터 시작해야 하며 다음 크기 배율을 사용하여 각 밀도에 사용할 이미지를 생성해야 합니다.</p> + +<p><ul> + <li><code>xhdpi</code>: 2.0 + <li><code>hdpi</code>: 1.5 + <li><code>mdpi</code>: 1.0 (기선) + <li><code>ldpi</code>: 0.75 +</ul></p> + +<p>즉 <code>xhdpi</code> 기기에 대해 200x200 이미지를 생성하는 경우 <code>hdpi</code> 기기에 대해 동일한 리소스를 150x150으로 생성해야 하며 <code>mdpi</code> 기기에 대해서는 100x100, <code>ldpi</code> 기기에 대해서는 75x75으로 동일한 리소스를 생성해야 합니다.</p> + +<p>그런 다음 생성된 이미지 파일을 <code>res/</code> 아래의 적절한 하위 디렉토리에 배치하면 시스템에서 애플리케이션이 실행되는 기기의 화면 밀도에 따라 정확한 이미지 파일을 자동으로 선택합니다.</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>그런 다음 언제든지 <code>@drawable/awesomeimage</code>를 참조하면 시스템이 화면의 dpi에 따라 적합한 비트맵을 선택합니다.</p> + +<p>애플리케이션에 사용할 아이콘 저작물 제작에 대한 자세한 도움말 및 가이드라인은 <a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">아이콘 디자인 가이드라인</a>을 참조하세요.</p> + diff --git a/docs/html-intl/ko/training/multiscreen/screensizes.jd b/docs/html-intl/ko/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..f2e77a6 --- /dev/null +++ b/docs/html-intl/ko/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=다양한 화면 크기 지원 +parent.title=다양한 화면 지원 +parent.link=index.html + +trainingnavtop=true +next.title=다양한 화면 밀도 지원 +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>강의 목표</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">'wrap_content' 및 'match_parent' 사용</a></li> + <li><a href="#TaskUseRelativeLayout">RelativeLayout 사용</a></li> + <li><a href="#TaskUseSizeQuali">크기 한정자 사용</a></li> + <li><a href="#TaskUseSWQuali">최소 너비 한정자 사용</a></li> + <li><a href="#TaskUseAliasFilters">레이아웃 별칭 사용</a></li> + <li><a href="#TaskUseOriQuali">방향 한정자 사용</a></li> + <li><a href="#TaskUse9Patch">나인-패치 비트맵 사용</a></li> +</ol> + +<h2>참고자료</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">다양한 화면 지원</a></li> +</ul> + +<h2>다운로드 </h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">샘플 앱 다운로드</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>이 강의에서는 다양한 화면 크기를 지원하는 방법을 설명합니다.</p> +<ul> + <li>화면에 맞게 레이아웃 크기 조정</li> + <li>화면 구성에 따라 적합한 UI 레이아웃 제공</li> + <li>올바른 화면에 올바른 레이아웃 적용</li> + <li>정확하게 확대되는 비트맵 제공</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">'wrap_content' 및 'match_parent' 사용</h2> + +<p>레이아웃이 다양한 화면 크기에 따라 유연하게 조정되도록 하려면 일부 뷰 구성요소의 너비와 높이에 <code>"wrap_content"</code> 및 <code>"match_parent"</code>를 사용해야 합니다. <code>"wrap_content"</code>를 사용하면 뷰의 너비와 높이가 해당 뷰 내에 콘텐츠가 들어가는데 필요한 최소 크기로 설정되는 반면, <code>"match_parent"</code>(API 수준 8 이전에는 <code>"fill_parent"</code>라고도 함)를 사용하면 구성요소가 확장되어 부모뷰의 크기와 일치하게 됩니다.</p> + +<p>하드코딩된 크기 대신 <code>"wrap_content"</code> 크기 값을 사용하면 뷰가 해당 뷰에 필요한 여백만을 사용하며 <code>"match_parent"</code> 크기 값을 사용하면 뷰가 확대되어 사용 가능한 여백을 채웁니다. 예를 들면 다음과 같습니다.</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>샘플에서 구성요소 크기에 특정 크기가 아닌 <code>"wrap_content"</code> 및 <code>"match_parent"</code>가 사용된 것을 눈여겨 보시기 바랍니다. 이렇게 하면 레이아웃이 다양한 화면 크기 및 방향에 맞게 조정됩니다.</p> + +<p>예를 들어 세로 및 가로 모드에서 레이아웃은 다음과 같이 표시됩니다. 구성요소의 크기가 너비와 높이에 맞게 자동으로 조정됩니다.</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>그림 1.</strong> 세로 모드(왼쪽) 및 가로 모드(오른쪽)에서의 뉴스 리더 샘플 앱</p> + + +<h2 id="TaskUseRelativeLayout">RelativeLayout 사용</h2> + +<p>비교적 복잡한 레이아웃을 만들려면 <PH>{@link android.widget.LinearLayout}의 중첩 인스턴스와</PH> <code>"wrap_content"</code> 및 <code>"match_parent"</code> 크기의 조합을 사용합니다. 하지만 <PH>{@link android.widget.LinearLayout}</PH> 을 사용하면 자식뷰의 여백 관계를 정확하게 제어할 수 없으며 <PH>{@link android.widget.LinearLayout}</PH> 단순히 나란하게 표시됩니다. 자식뷰를 일직선이 아닌 다양한 방향으로 표시해야 하는 경우 구성요소 사이의 여백 관계를 중심으로 레이아웃을 지정할 수 있는 <PH>{@link android.widget.RelativeLayout}</PH>을 사용하는 것이 더 좋은 방법일 수 있습니다. 예를 들어 화면 왼쪽에 하나의 자식뷰를, 오른쪽에 다른 자식뷰를 정렬할 수 있습니다.</p> + +<p>예를 들면 다음과 같습니다.</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>그림 2는 이 레이아웃이 QVGA 화면에 어떻게 표시되는지 보여줍니다.</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>그림 2.</strong> QVGA 화면(작은 화면)의 스크린샷</p> + +<p>그림 3은 이 레이아웃이 큰 화면에서 어떻게 표시되는지 보여줍니다.</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>그림 3.</strong> WSVGA 화면(큰 화면)의 스크린샷</p> + +<p>구성요소의 크기가 변하더라도 여백 관계가 <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH>.</p> + + +<h2 id="TaskUseSizeQuali">크기 한정자 사용</h2> + +<p>이전 섹션에서 다룬 유연한 레이아웃이나 상대적 레이아웃으로는 한계가 있습니다. 이러한 레이아웃이 구성요소 내부 및 주위의 여백을 확장하여 다양한 화면에 맞게 조정되긴 하지만 화면 크기별로 최적의 사용자 환경을 제공하지는 못할 수 있습니다. 따라서 애플리케이션은 유연한 레이아웃을 구현할 뿐 아니라 다양한 화면 구성을 타겟팅할 수 있도록 다양한 대체 레이아웃을 제공해야 합니다. 그 방법은 런타임이 현재 기기의 구성에 따라 적합한 리소스(예: 화면 크기별로 다른 레이아웃 디자인)를 자동으로 선택하도록 해 주는 <a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">구성 한정자</a>를 사용하는 것입니다.</p> + +<p>예를 들어 많은 애플리케이션이 큰 화면에 '이중 창(two pane)' 패턴을 구현합니다(한 쪽 창에는 아이템의 목록을 표시하고 다른 창에는 콘텐츠를 표시). 태블릿 및 TV는 두 개의 창 모두가 화면에 동시에 들어갈 정도로 크지만 휴대전화 화면은 두 창을 따로 표시해야 합니다. 따라서 이러한 레이아웃을 구현하려면 다음 파일이 있어야 합니다.</p> + +<ul> + <li><code>res/layout/main.xml</code>, 단일 창(기본값) 레이아웃: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>, 이중 창 레이아웃: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>두 번째 레이아웃의 디렉토리 이름에서 <code>large</code> 한정자를 눈여겨 보시기 바랍니다. 이 레이아웃은 대형(예: 7인치 태블릿 이상)으로 분류된 화면을 가진 기기에서 선택됩니다. 한정자가 없는 다른 레이아웃은 소형 기기에서 선택됩니다.</p> + + +<h2 id="TaskUseSWQuali">최소 너비 한정자 사용</h2> + +<p>Android 3.2 이전 기기에서 개발자가 어려움을 느꼈던 문제 중의 하나는 Dell Streak, 최초의 Galaxy 탭 및 7인치 태블릿에 두루 사용되는 '큰' 화면 크기 빈이었습니다. 하지만 많은 애플리케이션은 화면이 '큰' 기기라 하더라도 이 카테고리(예: 5인치 및 7인치 기기)에 속하는 다양한 기기에 다양한 레이아웃을 표시하고 싶어 합니다. 이것이 Android에서 Android 3.2에 '최소 너비' 한정자를 도입한 이유입니다.</p> + +<p>최소 너비 한정자를 사용하면 dp 단위의 특정 최소 너비를 가진 화면을 타겟팅할 수 있습니다. 예를 들어 일반적인 7인치 태블릿에는 600dp라는 최소 너비가 있으므로 이러한 화면에서 두 개의 창에 UI를 사용(작은 화면에서는 단일 목록 사용) 하고 싶은 경우 단일 및 이중 창 레이아웃에 이전 섹션과 동일한 레이아웃을 사용하면 되지만, 이중 창 레이아웃은 최소 너비가 600dp인 화면에 사용한다는 것을 나타내기 위해서 <code>large</code> 크기 한정자 대신 <code>sw600dp</code>를 사용해야 합니다.</p> + +<ul> + <li><code>res/layout/main.xml</code>, 단일 창(기본값) 레이아웃: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>, 이중 창 레이아웃: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>이는 최소 너비가 600dp 이상인 기기는 <code>layout-sw600dp/main.xml</code>(이중 창) 레이아웃을 선택하는 반면 소형 화면은 <code>layout/main.xml</code> (단일 창) 레이아웃을 선택한다는 것을 의미합니다.</p> + +<p>하지만 Android 3.2 이전 기기는 <code>sw600dp</code>를 크기 한정자로 인식하지 않기 때문에 최소 너비 한정자가 제대로 작동하지 않으며 따라서 <code>large</code> 한정자도 계속 사용해야 합니다. 따라서 <code>res/layout-large/main.xml</code>라는 이름의 파일이 있어야 하며 이 파일은 <code>res/layout-sw600dp/main.xml</code>과 동일한 파일입니다. 다음 섹션에서는 이런 식으로 레이아웃 파일이 중복되지 않게 하는 기술을 살펴보겠습니다.</p> + + +<h2 id="TaskUseAliasFilters">레이아웃 별칭 사용</h2> + +<p>최소 너비 한정자는 Android 3.2 이상 버전에서만 사용할 수 있습니다. 따라서 이전 버전과 호환되도록 하려면 추상화 크기 빈(소형, 보통, 대형 및 초대형)을 계속 사용해야 합니다. 예를 들어 휴대전화에서는 단일 창 UI가 표시되고 7인치 태블릿, TV 및 기타 대형 기기에서는 다중 창 UI가 표시되도록 UI를 디자인하려면 다음 파일을 제공해야 합니다.</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> 단일 창 레이아웃</li> +<li><code>res/layout-large:</code> 다중 창 레이아웃</li> +<li><code>res/layout-sw600dp:</code> 다중 창 레이아웃</li> +</ul></p> + +<p>마지막 두 개의 파일은 하나는 Android 3.2 기기와 일치하고 다른 하나는 이전 버전의 Android가 탑재된 태블릿 및 TV를 위한 것으로 서로 동일한 파일입니다.</p> + +<p>이 경우 별칭 파일을 사용하면 태블릿 및 TV용으로 동일한 파일이 중복되지 않도록 하고 이를 관리해야 하는 번거로움을 없앨 수 있습니다. 예를 들어 다음 레이아웃을 지정할 수 있습니다.</p> + +<ul> +<li><code>res/layout/main.xml</code>, 단일 창 레이아웃</li> +<li><code>res/layout/main_twopanes.xml</code>, 이중 창 레이아웃</li> +</ul> + +<p>또한 다음 두 개의 파일을 추가합니다.</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>뒤에 있는 두 개의 파일은 콘텐츠는 동일하지만 실제로 레이아웃을 지정하지는 않으며 단지 <PH>{@code main}</PH> 이 <PH>{@code main_twopanes}에 대한 별칭이 되도록 설정합니다.</PH> 이 파일에는 <code>large</code> 및 <code>sw600dp</code> 선택기가 있으므로 Android 버전에 관계없이 태블릿 및 TV에 적용됩니다(3.2 버전 이전의 태블릿 및 TV는 +<PH>{@code large}</PH>,3.2 이후 버전은 <code>sw600dp</code>와 일치).</p> + + +<h2 id="TaskUseOriQuali">방향 한정자 사용</h2> + +<p>일부 레이아웃은 가로 및 세로 방향 모두에서 잘 작동하지만 대부분의 레이아웃은 조정을 통해 많은 이점을 누릴 수 있습니다. 다음은 뉴스 리더 샘플 앱에서 화면 크기와 방향별로 레이아웃이 어떻게 작동하는지 보여줍니다.</p> + +<p><ul> +<li><b>소형 화면, 세로:</b> 단일 창, 로고 표시</li> +<li><b>소형 화면, 가로:</b> 단일 창, 로고 표시</li> +<li><b>7인치 태블릿, 세로:</b> 단일 창, 작업 표시줄 표시</li> +<li><b>7인치 태블릿, 가로:</b> 이중 창, 와이드, 작업 표시줄 표시</li> +<li><b>10인치 태블릿, 세로:</b> 이중 창, 내로우, 작업 표시줄 표시</li> +<li><b>10인치 태블릿, 가로:</b> 이중 창, 와이드, 작업 표시줄 표시</li> +<li><b>TV, 가로:</b> 이중 창, 와이드, 작업 표시줄 표시</li> +</ul></p> + +<p>따라서 이러한 각 레이아웃은 <code>res/layout/</code> 디렉토리의 XML 파일에서 지정됩니다. 그러면 앱은 각 레이아웃을 다양한 화면 구성에 지정하기 위해 레이아웃 별칭을 사용해 레이아웃을 각 구성과 일치시킵니다.</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>가능한 레이아웃을 모두 지정했으므로 구성 한정자를 사용하여 올바른 레이아웃을 각 구성에 매핑하기만 하면 되며 이는 레이아웃 별칭 기술을 사용하면 됩니다.</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">나인-패치 비트맵 사용</h2> + +<p>일반적으로 다양한 화면 크기를 지원하려면 이미지 리소스도 다양한 크기에 맞게 조정될 수 있어야 합니다. 예를 들어 버튼 배경은 버튼 배경이 적용되는 모든 버튼 모양과 맞아야 합니다.</p> + +<p>구성요소에 크기가 바뀔 수 있는 단순한 이미지를 사용하는 경우 런타임이 이미지를 균등하게 확대하거나 축소하기 때문에 기대에 미치지 못하는 결과가 나옵니다. 이에 대한 해결 방법은 확대될 수 있는 영역과 확대될 수 없는 영역을 나타내는 특별한 형식의 PNG 파일인 나인-패치 비트맵을 사용하는 것입니다.</p> + +<p>따라서 다양한 크기를 가진 구성요소에 사용할 비트맵을 디자인할 때에는 항상 나인-패치를 사용하시기 바랍니다. 비트맵을 나인-패치로 변환하려면 일반적인 이미지부터 시작합니다(그림 4, 명확하게 보이도록 4배 줌으로 표시).</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>그림 4.</strong> <code>button.png</code></p> + +<p>그 다음 이 이미지에 <ode +href="{@docRoot}tools/help/draw9patch.html">SDK의 <code>draw9patch</code></a> 유틸리티(<code>tools/</code> 디렉토리에 있음)를 실행합니다. 이 때 왼쪽 및 상단 테두리를 따라 픽셀을 그려 확대되어야 할 영역을 표시할 수 있습니다. 또한 오른쪽 및 하단 테두리를 따라 픽셀을 그려 콘텐츠가 들어가야 할 영역을 표시할 수 있으며 그 결과는 그림 5와 같습니다.</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>그림 5.</strong> <code>button.9.png</code></p> + +<p>테두리를 따라 있는 검은색 픽셀을 눈여겨 보시기 바랍니다. 상단 및 왼쪽 테두리의 픽셀은 이미지가 확대될 수 있는 영역을 나타내며 오른쪽 및 하단 테두리는 콘텐츠가 위치해야 하는 영역을 나타냅니다.</p> + +<p>또한 <code>.9.png</code> 확장자를 확인하시기 바랍니다. 프레임워크는 이 확장자를 통해 이미지가 일반적인 PNG 이미지가 아닌 나인-패치 이미지임을 감지할 수 있으므로 이 확장자를 사용해야 합니다.</p> + +<p><code>android:background="@drawable/button"</code>을 설정하여 이 배경을 구성요소에 적용하면 그림 6의 다양한 크기로 표시된 것처럼 프레임워크가 버튼의 크기를 수용할 수 있도록 이미지를 올바르게 확대합니다.</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>그림 6.</strong> 다양한 크기에 <code>button.9.png</code> 나인-패치를 사용하는 버튼</p> + diff --git a/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..26daf04 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=Monitoring the Battery Level and Charging State +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true +next.title=Determining and Monitoring the Docking State and Type +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#DetermineChargeState">Определение текущего состояния зарядки</a></li> + <li><a href="#MonitorChargeState">Отслеживание изменений состояния зарядки</a></li> + <li><a href="#CurrentLevel">Определение текущего уровня заряда батареи</a></li> + <li><a href="#MonitorLevel">Отслеживание существенных изменений уровня заряда батареи</a></li> +</ol> + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Если вы хотите изменить частоту фоновых обновлений, чтобы продлить время работы устройства от батареи, сначала рекомендуется проверить текущий уровень заряда и состояние зарядки.</p> + +<p>Именно от этих двух факторов зависит, как обновления повлияют на время работы устройства от батареи. Когда устройство подключено к сети переменного тока, приложение можно обновлять максимально часто, поскольку процесс обновления не будет сказываться на уровне заряда батареи. Если устройство не подключено к сети, следует воздержаться от обновлений, чтобы продлить время его работы от батареи.</p> + +<p>Если заряд батареи практически исчерпан, можно снизить частоту обновлений (вплоть до их полного прекращения).</p> + + +<h2 id="DetermineChargeState">Определение текущего состояния зарядки</h2> + +<p>Начните с определения текущего состояния зарядки. {@link android.os.BatteryManager} передает все сведения о батарее и зарядке в закрепленном намерении {@link android.content.Intent}, которое содержит также информацию о состоянии зарядки.</p> + +<p>Поскольку это намерение является закрепленным, регистрировать {@link android.content.BroadcastReceiver} не нужно. Чтобы получить текущее состояние батареи в виде намерения, нужно вызвать {@code registerReceiver}, передав {@code null} в качестве приемника, как показано в коде ниже. Можно также передать фактический объект {@link android.content.BroadcastReceiver}, но это необязательно, поскольку обработка обновлений будет выполняться позднее.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Можно извлечь данные как о текущем состоянии, так и об источнике зарядки (USB или сеть переменного тока), если устройство заряжается:<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>Как правило, если устройство подключено к сети переменного тока, фоновые обновления можно выполнять с максимальной частотой. Если устройство заряжается через USB, частоту можно несколько сократить, а если устройство не подключено к сети – сократить еще больше.</p> + + +<h2 id="MonitorChargeState">Отслеживание изменений состояния зарядки</h2> + +<p>Состояние зарядки изменяется всякий раз, когда пользователь подключает устройство к источнику питания. Поскольку это случается довольно часто, важно отслеживать изменения этого состояния и соответствующим образом корректировать частоту обновления приложения.</p> + +<p>{@link android.os.BatteryManager} передает действие каждый раз, когда устройство подключается к источнику питания или отключается от него. Важно получать эти события, даже если приложение не работает. Они помогут, в частности, определить, как часто будет запускаться приложение для выполнения фоновых обновлений. Чтобы отслеживать их, зарегистрируйте {@link android.content.BroadcastReceiver} в манифесте, задав {@link android.content.Intent#ACTION_POWER_CONNECTED} и {@link android.content.Intent#ACTION_POWER_DISCONNECTED} в фильтре намерений.</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>Соответствующая реализация {@link android.content.BroadcastReceiver} позволяет извлечь данные о текущем состоянии и способе зарядки, как описано в предыдущем шаге.</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">Определение текущего уровня заряда батареи</h2> + +<p>В некоторых случаях целесообразно определять текущий уровень заряда батареи. Если он ниже определенного значения, частоту фоновых обновлений следует уменьшить.</p> + +<p>Узнать, каков в настоящий момент заряд батареи, можно путем извлечения данных о текущем и максимальном уровне заряда из намерения состояния батареи, как показано в этом коде:</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">Отслеживание существенных изменений уровня заряда батареи</h2> + +<p>Отслеживать состояние батареи непрерывно не следует,</p> + +<p>поскольку при этом нагрузка на батарею будет значительно выше, чем при обычной работе приложения. Рекомендуется отслеживать только существенные изменения уровня заряда, в частности, переход устройства в состояние низкого заряда и обратно.</p> + +<p>Фрагмент манифеста, приведенный ниже, относится к фильтру намерений в приемнике широковещательных намерений. Приемник срабатывает, когда батарея устройства переходит в состояние низкого заряда или выходит из него. Для этого прослушиваются события {@link android.content.Intent#ACTION_BATTERY_LOW} и {@link android.content.Intent#ACTION_BATTERY_OKAY}.</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>Общепринятой практикой является отключение всех фоновых обновлений, когда заряд батареи достигает критически низкого уровня. Будет уже неважно, насколько актуальны данные в вашем приложении, если телефон самопроизвольно выключится, прежде чем пользователь успеет их просмотреть.</p> + +<p>Во многих случаях начало зарядки устройства совпадает с моментом его установки в док-станцию. В следующем уроке описаны способы определения текущего состояния подключения устройства к док-станции и отслеживания изменений этого состояния.</p> + diff --git a/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..ca1a942 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=Determining and Monitoring the Connectivity Status +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true + +previous.title=Determining and Monitoring the Docking State and Type +previous.link=docking-monitoring.html +next.title=Manipulating Broadcast Receivers On Demand +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#DetermineConnection">Определение наличия подключения к Интернету</a></li> + <li><a href="#DetermineType">Определение типа подключения к Интернету</a></li> + <li><a href="#MonitorChanges">Отслеживание изменения возможностей подключения</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Чаще всего повторяющиеся оповещения и фоновые службы используются для планового обновления приложения из Интернета, кэширования или загрузки больших объемов данных. Однако если подключение к Интернету не установлено или скорость соединения слишком низкая, выполнять загрузку не имеет смысла.</p> + +<p>Проверить наличие подключения к Интернету и его тип можно с помощью {@link android.net.ConnectivityManager}.</p> + + +<h2 id="DetermineConnection">Определение наличия подключения к Интернету</h2> + +<p>Если подключение отсутствует, нет смысла планировать обновление из Интернета. В приведенном ниже коде показано, как использовать {@link android.net.ConnectivityManager} для отправки запросов об активной сети и определять возможности подключения.</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">Определение типа подключения к Интернету</h2> + +<p>Также можно определить тип доступного в настоящий момент подключения к Интернету.</p> + +<p>Устройство может подключаться по сети мобильной связи, WiMAX, Wi-Fi и Ethernet. Получив ответ на запрос о типе активной сети, как показано ниже, можно изменить частоту обновлений на основе ее пропускной способности.</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>Стоимость передачи данных по мобильной сети, как правило, значительно выше, чем по сети Wi-Fi, поэтому частота обновлений в первом случае должна быть ниже. То же касается загрузки большого количества данных: ее следует отложить, пока не будет установлено подключение к сети Wi-Fi.</p> + +<p>Когда обновления отключены, необходимо отслеживать изменения доступных соединений, чтобы возобновить их сразу после подключения устройства к Интернету.</p> + + +<h2 id="MonitorChanges">Отслеживание изменения возможностей подключения</h2> + +<p>{@link android.net.ConnectivityManager} передает действие {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code "android.net.conn.CONNECTIVITY_CHANGE"}) при каждом изменении сведений о подключении. Зарегистрируйте в манифесте приемник широковещательных намерений, чтобы отслеживать эти изменения и запускать (или приостанавливать) фоновые обновления соответствующим образом.</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>Доступные соединения могут меняться очень часто – эта передача инициируется при каждом переключении между сетью мобильной связи и Wi-Fi. Ее рекомендуется отслеживать, только когда необходимо запускать ранее приостановленные обновления или загрузки. Как правило, достаточно проверить наличие подключения к Интернету перед запуском обновления и, если оно отсутствует, приостановить дальнейшие обновления до восстановления соединения.</p> + +<p>Для использования этого метода необходимо включать и отключать приемники широковещательных намерений, объявленные в манифесте. В следующем уроке описано, как это делать.</p> diff --git a/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..d94f357 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=Determining and Monitoring the Docking State and Type +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true +previous.title= Monitoring the Battery Level and Charging State +previous.link=battery-monitoring.html +next.title= Determining and Monitoring the Connectivity Status +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#CurrentDockState">Запрос аудиофокуса</a></li> + <li><a href="#DockType">Определение типа док-станции</a></li> + <li><a href="#MonitorDockState">Отслеживание изменений состояния подключения к док-станции и ее типа</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Устройства под управлением ОС Android можно подключать к нескольким типам док-станций: настольным, которые делятся на цифровые и аналоговые, и автомобильным. В большинстве случаев устройства заряжаются при подключении к док-станции, поэтому состояние подключения к док-станции часто связано с состоянием зарядки.</p> + +<p>Насколько состояние подключения к док-станции влияет на частоту обновления, зависит от конкретного приложения. Например, можно увеличить частоту обновлений приложения, показывающего спортивные новости, когда устройство подключено к настольной док-станции, и полностью отключить обновления при подключении к автомобильной. И наоборот, если используется приложение, которое в фоновом режиме загружает данные о дорожной обстановке, то при подключении устройства к автомобильной док-станции следует выполнять обновления максимально часто.</p> + +<p>Состояние подключения к док-станции также передается в виде закрепленного намерения {@link android.content.Intent}, что позволяет запрашивать сведения о наличии подключения к док-станции и ее типе.</p> + + +<h2 id="CurrentDockState">Определение текущего состояния подключения к док-станции</h2> + +<p>Сведения о состоянии подключения к док-станции передаются в качестве дополнительных данных в закрепленном оповещении действия {@link android.content.Intent#ACTION_DOCK_EVENT}. Поскольку это закрепленное намерение, регистрировать {@link android.content.BroadcastReceiver} не требуется. Достаточно вызвать {@link android.content.Context#registerReceiver registerReceiver()}, передав {@code null} в качестве приемника широковещательных намерений, как показано в коде ниже.</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>Сведения о текущем состоянии подключения к док-станции можно извлечь из дополнительных данных {@code EXTRA_DOCK_STATE}:<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">Определение типа док-станции</h2> + +<p>Док-станция, к которой подключено устройство, может быть одного из четырех типов: +<ul><li>автомобильная;</li> +<li>настольная;</li> +<li>настольная с минимальным набором функций (аналоговая);</li> +<li>настольная с широким набором функций (цифровая).</li></ul></p> + +<p>Обратите внимание, что последние два типа поддерживаются только на уровне API 11, поэтому, даже если вас не интересует, является ли док-станция цифровой или аналоговой, а интересует только ее тип, рекомендуется выполнять проверку по всем трем типам:</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">Отслеживание изменений состояния подключения к док-станции и ее типа</h2> + +<p>При каждом подключении устройства к док-станции или отключении от нее передается действие {@link android.content.Intent#ACTION_DOCK_EVENT}. Чтобы отслеживать состояние подключения к док-станции, достаточно зарегистрировать в манифесте приложения приемник широковещательных намерений, как показано ниже.</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>Данные о типе док-станции и о состоянии подключения к ней можно извлечь внутри реализации приемника с помощью методов, описанных в предыдущем шаге.</p> diff --git a/docs/html-intl/ru/training/monitoring-device-state/index.jd b/docs/html-intl/ru/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..c87d9af --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=Optimizing Battery Life + +trainingnavtop=true +startpage=true +next.title=Monitoring the Battery Level and Charging State +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Требования</h2> +<ul> + <li>Android 2.0 (API уровня 5) или более поздней версии</li> + <li>Опыт работы с <a href="{@docRoot}guide/components/intents-filters.html">намерениями и фильтрами намерений</a></li> +</ul> + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">Службы</a> +</ul> + +</div> +</div> + +<p>Качественное приложение должно оказывать минимальное влияние на время работы устройства от батареи. В этом уроке вы научитесь создавать приложения, способные изменять функционал и режим работы в зависимости от состояния устройства.</p> + +<p>Отключение обновления данных фоновых служб при потере подключения и снижение частоты обновления при низком заряде батареи позволяет снизить расход энергии и продлить работу устройства без подзарядки.</p> + +<h2>Уроки</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">Отслеживание уровня заряда батареи и состояния зарядки</a></b></dt> + <dd>Вы узнаете, как изменять частоту обновления приложения, определяя и отслеживая текущий уровень заряда батареи и изменение состояния зарядки.</dd> + + <dt><b><a href="docking-monitoring.html">Отслеживание состояния подключения к док-станции и определение ее типа</a></b></dt> + <dd>Оптимальная частота обновления зависит от способа использования устройства. Вы узнаете, как определять и отслеживать состояние подключения к док-станции и ее тип, чтобы соответствующим образом корректировать работу приложения.</dd> + + <dt><b><a href="connectivity-monitoring.html">Определение и отслеживание состояния подключения</a></b></dt> + <dd>Приложение невозможно обновить через Интернет, если отсутствует подключение. Вы узнаете, как проверить состояние подключения, чтобы при необходимости изменить частоту фоновых обновлений. Также вы научитесь проверять наличие мобильного подключения или подключения по сети Wi-Fi перед началом операций, требующих передачи больших объемов данных.</dd> + + <dt><b><a href="manifest-receivers.html">Операции с приемниками широковещательных намерений по запросу</a></b></dt> + <dd>Приемники широковещательных намерений, объявленные в манифесте, можно включать и отключать во время работы приложения. Это позволяет отключать ненужные приемники в зависимости от состояния устройства. Вы узнаете, как повысить эффективность путем включения, отключения или каскадирования приемников изменения состояния и как отложить действие до момента перехода устройства в заданное состояние.</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..724ee93 --- /dev/null +++ b/docs/html-intl/ru/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=Manipulating Broadcast Receivers On Demand +parent.title=Optimizing Battery Life +parent.link=index.html + +trainingnavtop=true + +previous.title=Determining and Monitoring the Connectivity Status +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#ToggleReceivers">Включение, отключение и каскадирование приемников изменения состояния для повышения эффективности</a></li> +</ol> + + +<h2>Дополнительные материалы</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">Намерения и фильтры намерений</a> +</ul> + +</div> +</div> + +<p>Самый простой способ отслеживать изменения состояния устройства – создать приемники {@link android.content.BroadcastReceiver} для каждого отслеживаемого состояния и зарегистрировать их в манифесте приложения. Затем в каждом из этих приемников можно переопределять график повторяющихся оповещений в зависимости от текущего состояния устройства.</p> + +<p>Этот способ имеет недостатки: приложение активирует устройство при каждом запуске любого из этих приемников, что далеко не всегда оправданно.</p> + +<p>Оптимальный вариант – включать и выключать приемники широковещательных намерений во время работы приложения. Это позволяет использовать приемники, объявленные в манифесте, как пассивные оповещения, которые инициируются системными событиями только в случае необходимости.</p> + + +<h2 id="ToggleReceivers">Включение, отключение и каскадирование приемников изменения состояния для повышения эффективности </h2> + +<p>{@link android.content.pm.PackageManager} позволяет включать и выключать любые компоненты, определенные в манифесте, в том числе все приемники широковещательных намерений:</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>При разрыве соединения этот метод позволяет выключить все приемники, кроме приемника изменения состояния подключения. И наоборот, когда подключение уже установлено, отслеживать изменения его состояния не требуется. Достаточно проверить наличие подключения к Интернету непосредственно перед обновлением или изменением графика оповещений о регулярном обновлении.</p> + +<p>Точно так же можно отложить загрузку, для выполнения которой требуется более высокая пропускная способность. Просто включите приемник широковещательных намерений, который будет отслеживать изменения возможности подключения и инициировать загрузку только после подключения к сети Wi-Fi.</p> diff --git a/docs/html-intl/ru/training/multiscreen/adaptui.jd b/docs/html-intl/ru/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..490a64a --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=Implementing Adaptative UI Flows +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Densities +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">Определение текущего макета</a></li> + <li><a href="#TaskReactToLayout">Дальнейшие действия в зависимости от текущего макета</a></li> + <li><a href="#TaskReuseFrag">Повторное использование фрагментов в других активностях</a></li> + <li><a href="#TaskHandleConfigChanges">Обработка изменений конфигурации экрана</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Поддержка планшетных ПК и мобильных телефонов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>Алгоритм пользовательского интерфейса зависит от макета, который в данный момент отображается. Например, если приложение работает в двухпанельном режиме, то при нажатии на элемент в левой панели содержание отобразится в правой. В однопанельном режиме содержание откроется отдельно (в другой активности).</p> + + +<h2 id="TaskDetermineCurLayout">Определение текущего макета</h2> + +<p>Так как в реализации макетов существуют отличия, первое, что необходимо сделать, – определить, какой макет отображается в данный момент. Например, работает ли приложение в однопанельном или двухпанельном режиме. Для этого создадим запрос о том, существует ли данное представление и отображается ли оно в настоящий момент:</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>Обратите внимание: представленный выше код содержит запрос о том, доступна ли панель article, поскольку это удобнее, чем писать отдельные запросы для каждого макета.</p> + +<p>Кроме того, для работы с учетом существующих компонентов можно также проверять их доступность, прежде чем выполнять с ними какие-либо операции. Например, в учебном приложении News Reader есть кнопка, которая служит для доступа в меню, однако она отображается только в операционных системах Android версии ниже, чем 3.0, потому что в последующих версиях ее функцию выполняет элемент <PH>{@link android.app.ActionBar}</PH> на уровне API 11 и выше. Чтобы проверить наличие этой кнопки, добавим прослушиватель событий с помощью следующего кода:</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">Дальнейшие действия в зависимости от текущего макета</h2> + +<p>Результаты некоторых операций зависят от текущего макета. Например, если в приложении News Reader в двухпанельном режиме нажать на заголовок в списке, то статья откроется в правой панели. Если же интерфейс работает в однопанельном режиме, будет запущена отдельная активность:</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>Аналогично, в двухпанельном режиме должна отображаться панель действий с навигационными вкладками, а в однопанельном навигация должна быть реализована с помощью раскрывающегося списка. Приложение должно проверять, какой из этих вариантов следует использовать:</p> + +<pre> +final String CATEGORIES[] = { "Лучшие статьи", "Политика", "Экономика", "Новости технологий" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">Повторное использование фрагментов в других активностях</h2> + +<p>Одним из примеров повторяющегося фрагмента является реализация части интерфейса как панели в одних конфигурациях и как отдельной активности в других. Например, если приложение News Reader работает на достаточно большом экране, текст новостной статьи отображается в правой панели, а если на маленьком, то он открывается в отдельной активности.</p> + +<p>В таких случаях следует повторно использовать подкласс <PH>{@link android.app.Fragment}</PH> в нескольких активностях. Например, в двухпанельном макете используется подкласс <code>ArticleFragment</code>:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>Он же (без макета) используется при работе на маленьком экране (активность <code>ArticleActivity</code>):</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>Результат будет таким же, как если бы мы объявили фрагмент в макете XML, однако в этом случае макет XML не требуется, так как фрагмент article является единственным компонентом этой активности.</p> + +<p>При создании фрагментов важно не привязывать их строго к конкретной активности. Для этого можно определить интерфейс с абстрактным описанием всех необходимых способов взаимодействия фрагмента с активностью, в которой он содержится. Затем этот интерфейс нужно реализовать в самой активности.</p> + +<p>Например, именно так работает фрагмент <code>HeadlinesFragment</code> в приложении News Reader:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>Затем, когда пользователь выбирает заголовок, фрагмент оповещает об этом не указанную в коде активность, а заданный ею прослушиватель:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p>Этот метод рассматривается подробнее в разделе <a +href="{@docRoot}guide/practices/tablets-and-handsets.html">Поддержка планшетных ПК и мобильных телефонов</a>.</p> + + +<h2 id="TaskHandleConfigChanges">Обработка изменений конфигурации экрана</h2> + +<p>При реализации отдельных частей интерфейса с помощью разных активностей нужно учитывать, что интерфейс должен уметь реагировать на определенные изменения конфигурации, такие как поворот экрана.</p> + +<p>Например, на типичном планшетном ПК с размером экрана 7 дюймов под управлением ОС Android 3.0 или более поздней версии при вертикальной ориентации статья в приложении News Reader открывается с помощью отдельной активности, а при горизонтальной используется двухпанельный макет.</p> + +<p>Это означает, что если пользователь держит планшетный ПК вертикально и на экране запущена активность для просмотра статьи, приложение должно уметь определить, что ориентация была изменена на горизонтальную. Затем оно должно соответствующим образом отреагировать на изменение, то есть завершить эту активность и вернуться к основной активности, чтобы содержание отобразилось в двухпанельном макете:</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/ru/training/multiscreen/index.jd b/docs/html-intl/ru/training/multiscreen/index.jd new file mode 100644 index 0000000..023eaec --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/index.jd @@ -0,0 +1,64 @@ +page.title=Designing for Multiple Screens + +trainingnavtop=true +startpage=true +next.title=Supporting Different Screen Sizes +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Требования</h2> + +<ul> + <li>Android 1.6 или более поздней версии (для запуска учебного приложения требуется версия 2.1 или более поздняя)</li> + <li>Начальные знания о компонентах <a +href="http://developer.android.com/guide/components/activities.html">Activity</a> (активность) и <a href="http://developer.android.com/guide/components/fragments.html">Fragment</a> (фрагмент)</li> + <li>Опыт создания <a +href="http://developer.android.com/guide/topics/ui/index.html">пользовательских интерфейсов</a> для Android</li> + <li>Некоторые функции требуют использования <a +href="{@docRoot}tools/extras/support-library.html">вспомогательной библиотеки</a></li> +</ul> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>На платформе Android работают устройства с самыми разными размерами экрана: от телефонов до телевизоров. Чтобы с вашим приложением могли работать как можно больше пользователей, оно должно корректно отображаться на всех этих устройствах.</p> + +<p>Однако совместимость с разными типами устройств – это еще не все. От размера экрана зависит, какие возможности будет иметь пользователь при работе с приложением. Чтобы пользователи действительно остались довольны вашим приложением, оно должно не просто <em>поддерживать</em> разные экраны, но и быть <em>оптимизировано</em> для каждого из них.</p> + +<p>Этот модуль посвящен реализации пользовательского интерфейса, оптимизированного для разных конфигураций экрана.</p> + +<p>Код, приведенный в каждом уроке, взят из учебного приложения, в котором демонстрируются способы оптимизации для разных экранов. Вы можете загрузить его (в правой части экрана) и использовать части кода в собственном приложении.</p> + +<p class="note"><strong>Примечание</strong>. В этом модуле и в учебном приложении используется <a +href="{@docRoot}tools/extras/support-library.html">вспомогательная библиотека</a>, позволяющая работать с API <PH>{@link android.app.Fragment}</PH> в версиях до Android 3.0. Чтобы иметь возможность использовать все необходимые API, загрузите библиотеку и добавьте ее в свое приложение.</p> + + +<h2>Уроки</h2> + +<dl> + <dt><b><a href="screensizes.html">Поддержка разных размеров экрана</a></b></dt> + <dd>В этом уроке рассказывается, как создать макет, который адаптируется к разным размерам экрана, используя масштабируемые представления, объекты <PH>{@link android.widget.RelativeLayout}</PH>, квалификаторы размера и ориентации, фильтры псевдонимов и растровые изображений формата nine-patch.</dd> + + <dt><b><a href="screendensities.html">Поддержка разных разрешений экрана</a></b></dt> + <dd>В этом уроке рассказывается, как работать с экранами разного разрешения с помощью не зависящих от разрешения пикселей и как подготовить растровые изображения для каждого из них.</dd> + + <dt><b><a href="adaptui.html">Реализация адаптируемых алгоритмов работы пользовательского интерфейса</a></b></dt> + <dd>В этом уроке рассказывается, как реализовать алгоритм работы интерфейса, адаптирующийся к размеру и разрешению экрана, то есть способный определять активный макет во время выполнения приложения, выбирать дальнейшие действия на основе текущего макета и обрабатывать изменения конфигурации экрана.</dd> +</dl> diff --git a/docs/html-intl/ru/training/multiscreen/screendensities.jd b/docs/html-intl/ru/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..cfd4724 --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=Supporting Different Densities +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Sizes +previous.link=screensizes.html +next.title=Implementing Adaptative UI Flows +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#TaskUseDP">Использование пикселей, не зависящих от разрешения</a></li> + <li><a href="#TaskProvideAltBmp">Предоставление альтернативных растровых изображений</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Рекомендации по созданию значков</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>В этом уроке рассказывается, как создать интерфейс, поддерживающий разные разрешения экрана, за счет использования разных ресурсов и не зависящих от разрешения единиц измерения.</p> + +<h2 id="TaskUseDP">Использование пикселей, не зависящих от разрешения</h2> + +<p>Разработчики часто допускают одну и ту же ошибку при создании макетов – указывают размеры и расстояния с помощью абсолютных значений в пикселях. Задавать размеры в пикселях не рекомендуется, поскольку из-за различной плотности пикселей на экранах разных устройств фактический размер макета будет неодинаков. Всегда задавайте размеры в единицах <code>dp</code> или <code>sp</code>. <code>dp</code> – это не зависящий от разрешения пиксель, равный физическому пикселю на экране с плотностью 160 точек/дюйм. <code>sp</code> является аналогичной единицей измерения, но масштабируется на основе выбранного пользователем размера текста, поэтому ее следует применять для указания величины шрифта, но не размера макета.</p> + +<p>Например, если вы задаете расстояние между двумя представлениями, рекомендуется использовать <code>dp</code>, а не <code>px</code>:</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>Для определения размера шрифта всегда используйте <code>sp</code>:</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">Предоставление альтернативных растровых изображений</h2> + +<p>Так как платформа Android предназначена для устройств с разными разрешениями экрана, необходимо позаботиться о наличии растровых изображений для каждого из четырех обобщенных типов разрешения: низкого, среднего, высокого и очень высокого. Это обеспечит оптимальное сочетание качества графики и производительности на всех устройствах.</p> + +<p>На основе исходного векторного рисунка создайте растровые изображения для каждого из указанных разрешений согласно следующей шкале размеров:</p> + +<p><ul> + <li><code>xhdpi</code>: 2,0 + <li><code>hdpi</code>: 1,5 + <li><code>mdpi</code>: 1,0 (стандартный размер) + <li><code>ldpi</code>: 0,75 +</ul></p> + +<p>Это означает, что изображение, которое на устройствах с разрешением экрана <code>xhdpi</code> имеет размер 200 x 200, на устройствах <code>hdpi</code> должно иметь размер 150 x 150, на устройствах <code>mdpi</code> – 100 x 100, а на устройствах <code>ldpi</code> – 75 x 75.</p> + +<p>Поместите файлы изображений в соответствующие подкаталоги в папке <code>res/</code>, и система автоматически выберет подходящий в зависимости от разрешения экрана устройства, на котором выполняется приложение:</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>При каждом обращении к файлу <code>@drawable/awesomeimage</code> система будет выбирать изображение, отвечающее разрешению экрана.</p> + +<p>Дополнительную информацию и советы можно найти в разделе <a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Рекомендации по созданию значков</a>.</p> + diff --git a/docs/html-intl/ru/training/multiscreen/screensizes.jd b/docs/html-intl/ru/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..9684d77 --- /dev/null +++ b/docs/html-intl/ru/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=Supporting Different Screen Sizes +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +next.title=Supporting Different Screen Densities +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Содержание урока</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">Использование параметров wrap_content и match_parent</a></li> + <li><a href="#TaskUseRelativeLayout">Использование объекта RelativeLayout</a></li> + <li><a href="#TaskUseSizeQuali">Использование квалификаторов размера</a></li> + <li><a href="#TaskUseSWQuali">Использование квалификатора Smallest-width</a></li> + <li><a href="#TaskUseAliasFilters">Использование псевдонимов макетов</a></li> + <li><a href="#TaskUseOriQuali">Использование квалификаторов ориентации</a></li> + <li><a href="#TaskUse9Patch">Использование растровых изображений nine-patch</a></li> +</ol> + +<h2>Дополнительные материалы</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">Поддержка нескольких экранов</a></li> +</ul> + +<h2>Упражнение</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Загрузить учебное приложение</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>В этом уроке описаны следующие аспекты обеспечения совместимости интерфейса с разными экранами:</p> +<ul> + <li>обеспечение способности макета адаптироваться к размеру экрана;</li> + <li>выбор макета интерфейса, отвечающего конфигурации экрана;</li> + <li>контроль правильности применяемого макета;</li> + <li>использование масштабируемых растровых изображений.</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">Использование параметров wrap_content и match_parent</h2> + +<p>Чтобы создать масштабируемый макет, способный адаптироваться к разным экранам, используйте в качестве значений ширины и высоты отдельных компонентов представления параметры <code>"wrap_content"</code> и <code>"match_parent"</code>. Если используется <code>"wrap_content"</code>, для ширины или высоты представления устанавливается минимальное значение, позволяющее уместить содержание на экран, а параметр <code>"match_parent"</code> (известный как <code>"fill_parent"</code> в API до 8 уровня) служит для растягивания компонента по размеру родительского представления.</p> + +<p>Если указать параметры <code>"wrap_content"</code> и <code>"match_parent"</code> вместо строго заданных размеров, в представлениях будет использоваться минимально необходимое место или они будут растягиваться на всю доступную длину и ширину соответственно. Например:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>Обратите внимание на то, что в коде учебного приложения размеры компонентов заданы с помощью параметров <code>"wrap_content"</code> и <code>"match_parent"</code>. В результате макет правильно отображается на экранах разных размеров при разных ориентациях.</p> + +<p>Например, вот так он выглядит в вертикальной и горизонтальной ориентациях. Обратите внимание на то, как размеры компонентов автоматически адаптируются к длине и ширине:</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>Рисунок 1</strong>. Приложение News Reader при вертикальной (слева) и горизонтальной (справа) ориентации.</p> + + +<h2 id="TaskUseRelativeLayout">Использование объекта RelativeLayout</h2> + +<p>С помощью вложенных экземпляров объекта <PH>{@link android.widget.LinearLayout}</PH> и параметров <code>"wrap_content"</code> и <code>"match_parent"</code> можно создавать достаточно сложные макеты. Однако <PH>{@link android.widget.LinearLayout}</PH> не дает возможности точно управлять взаимным расположением дочерних представлений: в <PH>{@link android.widget.LinearLayout}</PH> они просто помещаются в ряд друг за другом. Если необходимо расположить дочерние представления иным образом, используйте объект <PH>{@link android.widget.RelativeLayout}</PH>, позволяющий задать относительные позиции компонентов. Например, одно дочернее представление можно выровнять по левому краю экрана, а другое – по правому.</p> + +<p>Например:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>На рис. 2 показано, как этот макет выглядит на экране QVGA.</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>Рисунок 2</strong>. Скриншот экрана QVGA (маленького размера).</p> + +<p>На рис. 3 показано, как он выглядит на экране с большей диагональю.</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>Рисунок 3</strong>. Скриншот экрана WSVGA (большего размера).</p> + +<p>Обратите внимание: несмотря на изменение размера компонентов их взаимное расположение остается прежним, так как оно задано объектом <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH>.</p> + + +<h2 id="TaskUseSizeQuali">Использование квалификаторов размера</h2> + +<p>Масштабируемые или относительные макеты, один из которых продемонстрирован выше, имеют свои ограничения. Хотя они позволяют создать интерфейс, способный адаптироваться к разным экранам за счет растягивания пространства внутри и вокруг компонентов, пользователю может оказаться не слишком удобно работать с таким интерфейсом. Поэтому в приложении должен использоваться не один масштабируемый макет, а несколько альтернативных вариантов для разных конфигураций экрана. Их можно создать с помощью <a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">квалификаторов конфигураций</a>, которые позволяют оперативно выбирать ресурсы, отвечающие текущим параметрам экрана (например, разные варианты макетов для экранов разных размеров).</p> + +<p>Многие приложения отображаются на больших экранах в двухпанельном режиме, при котором список элементов расположен в одной панели, а их содержание открывается в другой. Такой режим просмотра удобен на достаточно больших экранах планшетных ПК и телевизоров, однако на экране телефона эти панели следует отображать по отдельности. Для каждого режима просмотра нужно создать отдельный файл.</p> + +<ul> + <li><code>res/layout/main.xml</code>, однопанельный макет (по умолчанию): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>, двухпанельный макет: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Обратите внимание, что во втором случае в названии каталога использован квалификатор <code>large</code>. Этот макет будет выбран на устройствах, экраны которых считаются большими (например, 7 дюймов и более). Первый макет (без квалификаторов) будет выбран для устройств с маленьким экраном.</p> + + +<h2 id="TaskUseSWQuali">Использование квалификатора Smallest-width</h2> + +<p>Одной из проблем, с которой сталкивались разработчики приложений для устройств Android версий до 3.2, было слишком общее определение "большого" экрана. Это касалось устройств Dell Streak, первой модели Galaxy Tab и планшетных ПК с экраном размером 7 дюймов. Многие приложения требовалось по-разному отображать на разных устройствах (например, с 5- и 7-дюймовыми экранами), хотя они и относились к одной категории "больших" экранов. В Android версии 3.2 и более поздних доступен квалификатор Smallest-width.</p> + +<p>Он позволяет определять экраны с заданной минимальной шириной в dp. Например, типичный планшетный ПК с экраном 7 дюймов имеет минимальную ширину 600 dp, и если вы хотите, чтобы приложение работало на нем в двухпанельном режиме (а на меньших экранах в однопанельном), используйте два макета из предыдущего раздела, но вместо квалификатора размера <code>large</code> укажите <code>sw600dp</code>. В таком случае на экранах, минимальная ширина которых составляет 600 dp, будет использоваться двухпанельный макет.</p> + +<ul> + <li><code>res/layout/main.xml</code>, однопанельный макет (по умолчанию): + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>, двухпанельный макет: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>Это означает, что на устройствах, минимальная ширина экрана которых не меньше 600 dp, будет выбран <code>layout-sw600dp/main.xml</code> (двухпанельный макет), а на экранах меньшего размера – <code>layout/main.xml</code> (однопанельный макет).</p> + +<p>Следует учесть, что на Android-устройствах до версии 3.2 квалификатор <code>sw600dp</code> не будет работать, поэтому для них по-прежнему нужно использовать <code>large</code>. Таким образом, вам потребуется еще один файл с названием <code>res/layout-large/main.xml</code>, идентичный файлу <code>res/layout-sw600dp/main.xml</code>. В следующем разделе вы познакомитесь с методом, который позволяет избежать дублирования таких файлов макета.</p> + + +<h2 id="TaskUseAliasFilters">Использование псевдонимов макетов</h2> + +<p>Квалификатор Smallest-width работает только на устройствах Android 3.2 или более поздних версий. Для совместимости с более ранними устройствами по-прежнему следует использовать абстрактные размеры (small, normal, large и xlarge). Например, чтобы интерфейс открывался в однопанельном режиме на телефонах и в многопанельном на планшетных ПК с 7-дюймовым экраном, телевизорах и других крупных устройствах, подготовьте следующие файлы:</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> однопанельный макет;</li> +<li><code>res/layout-large:</code> многопанельный макет;</li> +<li><code>res/layout-sw600dp:</code> многопанельный макет.</li> +</ul></p> + +<p>Последние два файла идентичны: один из них предназначен для устройств Android 3.2 и новее, а второй для более старых планшетных ПК и телевизоров на платформе Android.</p> + +<p>Чтобы не создавать дубликаты файлов и упростить процесс поддержки приложения, используйте псевдонимы. Например, можно определить следующие макеты:</p> + +<ul> +<li><code>res/layout/main.xml</code> (однопанельный макет);</li> +<li><code>res/layout/main_twopanes.xml</code> (двухпанельный макет).</li> +</ul> + +<p>Затем добавьте следующие два файла:</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>Содержание последних двух файлов одинаково, но сами по себе они не определяют макет. Они служат для того, чтобы назначить файл <PH>{@code main}</PH> в качестве псевдонима <PH>{@code main_twopanes}</PH>. Так как в них используются селекторы <code>large</code> и <code>sw600dp</code>, они применяются к планшетным ПК и телевизорам на платформе Android независимо от версии (для версий до 3.2 используется +<PH>{@code large}</PH>, а для более новых – <code>sw600dp</code>).</p> + + +<h2 id="TaskUseOriQuali">Использование квалификаторов ориентации</h2> + +<p>Хотя некоторые макеты одинаково хорошо смотрятся в вертикальной и горизонтальной ориентациях, в большинстве случаев интерфейс все же приходится адаптировать. Ниже показано, как изменяется макет в приложении News Reader в зависимости от размера и ориентации экрана.</p> + +<p><ul> +<li><b>Маленький экран, вертикальная ориентация</b>: однопанельный вид с логотипом.</li> +<li><b>Маленький экран, горизонтальная ориентация</b>: однопанельный вид с логотипом.</li> +<li><b>Планшетный ПК с 7-дюймовым экраном, вертикальная ориентация</b>: однопанельный вид с панелью действий.</li> +<li><b>Планшетный ПК с 7-дюймовым экраном, горизонтальная ориентация</b>: двухпанельный вид с панелью действий.</li> +<li><b>Планшетный ПК с 10-дюймовым экраном, вертикальная ориентация</b>: двухпанельный вид (узкий вариант) с панелью действий.</li> +<li><b>Планшетный ПК с 10-дюймовым экраном, горизонтальная ориентация</b>: двухпанельный вид (широкий вариант) с панелью действий.</li> +<li><b>Телевизор, горизонтальная ориентация</b>: двухпанельный вид с панелью действий.</li> +</ul></p> + +<p>Каждый из этих макетов определен в XML-файле в каталоге <code>res/layout/</code>. Чтобы сопоставить их с определенными конфигурациями экрана, в приложении используются псевдонимы:</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>После того как все возможные макеты определены, остается сопоставить каждый из них с подходящей конфигурацией, используя квалификаторы конфигураций. Воспользуемся псевдонимами макетов:</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">Использование растровых изображений nine-patch</h2> + +<p>Чтобы интерфейс был совместим с экранами разных размеров, используемые в нем графические элементы также должны быть адаптированы соответствующим образом. Например, фон кнопки должен одинаково хорошо выглядеть независимо от ее формы.</p> + +<p>Если использовать для компонентов, размеры которых меняются, обычные изображения, то они будут равномерно сжиматься и растягиваться, и результат будет далек от идеального. Решением являются растровые изображения формата nine-patch – специальные PNG-файлы, содержащие информацию о том, какие области можно растягивать, а какие нет.</p> + +<p>Создавая растровые изображения для масштабируемых компонентов, обязательно используйте формат nine-patch. На рис. 4 показано обычное растровое изображение (увеличенное в 4 раза для наглядности), которое мы переведем в формат nine-patch.</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>Рисунок 4</strong>. <code>button.png</code></p> + +<p>Откройте его с помощью утилиты <ode +href="{@docRoot}tools/help/draw9patch.html"><code>draw9patch</code></a>, входящей в комплект разработчика (в каталоге <code>tools/</code>). Установите метки на левом и верхнем краях, чтобы ограничить области, которые можно растягивать. Можно также провести линию вдоль правого и нижнего краев, как показано на рис. 5, чтобы отметить области, в которых содержание должно быть зафиксировано.</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>Рисунок 5</strong>. <code>button.9.png</code></p> + +<p>Обратите внимание на черные пиксели по краям. Метки у верхней и левой границ обозначают те области, которые можно растягивать, а метки у правой и нижней границ – те, куда должно быть помещено содержание.</p> + +<p>Также обратите внимание на расширение <code>.9.png</code>. Оно должно быть задано именно в таком виде, чтобы система могла определить, что это формат nine-patch, а не обычный PNG-файл.</p> + +<p>При применении этого фона к компоненту (с помощью <code>android:background="@drawable/button"</code>) изображение будет растянуто по размеру кнопки, как показано на рис. 6.</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>Рисунок 6</strong>. Кнопки разных размеров с файлом фона <code>button.9.png</code> в формате nine-patch.</p> + diff --git a/docs/html-intl/zh-cn/training/monitoring-device-state/battery-monitoring.jd b/docs/html-intl/zh-cn/training/monitoring-device-state/battery-monitoring.jd new file mode 100644 index 0000000..0e1ccb7 --- /dev/null +++ b/docs/html-intl/zh-cn/training/monitoring-device-state/battery-monitoring.jd @@ -0,0 +1,120 @@ +page.title=监控电池电量和充电状态 +parent.title=优化电池使用时间 +parent.link=index.html + +trainingnavtop=true +next.title=确定和监控基座对接状态和类型 +next.link=docking-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#DetermineChargeState">确定当前的充电状态</a></li> + <li><a href="#MonitorChargeState">监控充电状态的变化</a></li> + <li><a href="#CurrentLevel">确定当前的电池电量</a></li> + <li><a href="#MonitorLevel">监控电池电量的显著变化</a></li> +</ol> + +<h2>您还应参阅</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">intent 和 intent 过滤器</a> +</ul> + +</div> +</div> + +<p>如果您要更改后台更新频率,从而减少更新对电池使用时间的影响,最好先查看当前的电池电量和充电状态。</p> + +<p>对应用进行更新会影响电池使用时间,具体取决于设备的电池电量和充电状态。如果用户正在通过交流电源为设备充电,更新应用的影响就可以忽略不计。因此,在大多数情况下,只要设备连接了充电器,您就可以最大程度地提高刷新频率。相反,如果设备在消耗电池电量,那么降低更新频率就可以延长电池使用时间。</p> + +<p>同样,您也可以查看电池电量,如果电量即将耗尽,您就可以降低更新频率,甚至停止更新。</p> + + +<h2 id="DetermineChargeState">确定当前的充电状态</h2> + +<p>请先确定当前的充电状态。{@link android.os.BatteryManager} 会通过一个包含充电状态的持续 {@link android.content.Intent} 广播所有的电池详情和充电详情。</p> + +<p>由于这是个持续 intent,因此您无需通过将传入 {@code null} 的 {@code registerReceiver} 作为接收器直接调用(如下一代码段所示)来注册 {@link android.content.BroadcastReceiver},系统会返回当前电池状态 intent。您可以在此处传入实际的 {@link android.content.BroadcastReceiver} 对象,不过我们会在下文中介绍如何处理更新,因此您不一定要执行此操作。</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); +Intent batteryStatus = context.registerReceiver(null, ifilter);</pre> + +<p>如果设备正在充电,则您可以提取当前的充电状态和充电方式(无论是通过 USB 还是交流充电器),如下所示:<p> + +<pre>// Are we charging / charged? +int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); +boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + +// How are we charging? +int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); +boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; +boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre> + +<p>通常,如果设备连接了交流充电器,您就应最大程度地提高后台更新频率;如果设备通过 USB 充电,请降低更新频率;如果电池在耗电,请进一步降低更新频率。</p> + + +<h2 id="MonitorChargeState">监控充电状态的变化</h2> + +<p>充电状态的改变就像设备连接电源那样容易,因此监控充电状态的变化并相应地调整刷新频率就很重要了。</p> + +<p>只要设备连接或断开电源,{@link android.os.BatteryManager} 就会广播相应的操作。即使您的应用没有运行,也请务必接收这些事件,尤其是当这些事件会影响您启动应用以执行后台更新的频率时。因此,您应该通过在 intent 过滤器中定义 {@link android.content.Intent#ACTION_POWER_CONNECTED} 和 {@link android.content.Intent#ACTION_POWER_DISCONNECTED},在清单中注册 {@link android.content.BroadcastReceiver} 来侦听这两个事件。</p> + +<pre><receiver android:name=".PowerConnectionReceiver"> + <intent-filter> + <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> + </intent-filter> +</receiver></pre> + +<p>在实施相关的 {@link android.content.BroadcastReceiver} 时,您可以按上一步骤所述提取当前的充电状态和充电方式。</p> + +<pre>public class PowerConnectionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB; + boolean acCharge = chargePlug == BATTERY_PLUGGED_AC; + } +}</pre> + + +<h2 id="CurrentLevel">确定当前的电池电量</h2> + +<p>在某些情况下,确定当前的电池电量会对您有所帮助。如果电池电量低于一定水平,您可以降低后台更新频率。</p> + +<p>您可以从电池状态 intent 中提取要了解的当前电池电量以及电池容量,具体如下所示:</p> + +<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); +int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + +float batteryPct = level / (float)scale;</pre> + + +<h2 id="MonitorLevel">监控电池电量的显著变化</h2> + +<p>您无法轻松地对电池状态进行持续监控,不过也无需这么做。</p> + +<p>一般来说,与应用的正常行为相比,持续监控电池电量会消耗更多电量。因此,比较合适的做法是只监控电池电量的显著变化(尤其是在设备进入或结束低电量状态的情况下)。</p> + +<p>以下清单代码段提取自广播接收器中的 intent 过滤器元素。通过侦听 {@link android.content.Intent#ACTION_BATTERY_LOW} 和 {@link android.content.Intent#ACTION_BATTERY_OKAY},只要设备的电池进入或结束低电量状态,系统就会触发接收器。</p> + +<pre><receiver android:name=".BatteryLevelReceiver"> +<intent-filter> + <action android:name="android.intent.action.ACTION_BATTERY_LOW"/> + <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/> + </intent-filter> +</receiver></pre> + +<p>如果电池电量极低,通常比较合适的做法是停用所有后台更新。如果您还没用上更新的数据,手机就自动关机了,那这些数据再新也没有意义。</p> + +<p>在很多情况下,将设备插入基座就可以为其充电。下一教程将向您介绍如何确定当前基座状态及如何监控设备对接的变化。</p> + diff --git a/docs/html-intl/zh-cn/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html-intl/zh-cn/training/monitoring-device-state/connectivity-monitoring.jd new file mode 100644 index 0000000..8313e08 --- /dev/null +++ b/docs/html-intl/zh-cn/training/monitoring-device-state/connectivity-monitoring.jd @@ -0,0 +1,70 @@ +page.title=确定和监控网络连接状态 +parent.title=优化电池使用时间 +parent.link=index.html + +trainingnavtop=true + +previous.title=确定和监控基座对接状态和类型 +previous.link=docking-monitoring.html +next.title=根据需要操作广播接收器 +next.link=manifest-receivers.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#DetermineConnection">确定是否已连接互联网</a></li> + <li><a href="#DetermineType">确定互联网连接的类型</a></li> + <li><a href="#MonitorChanges">监控连接情况的变化</a></li> +</ol> + + +<h2>您还应参阅</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">intent 和 intent 过滤器</a> +</ul> + +</div> +</div> + +<p>重复提醒和后台服务最常见的用途之一,就是为来自互联网资源的应用数据、缓存数据安排定期更新或执行长时间运行的下载任务。但是,如果您没有连接互联网,或因连接过慢而无法完成下载,那就根本没必要唤醒设备并安排更新了。</p> + +<p>您可以使用 {@link android.net.ConnectivityManager} 查看是否确实已连接互联网,如果已连接,您还可以了解当前的连接类型。</p> + + +<h2 id="DetermineConnection">确定是否已连接互联网</h2> + +<p>如果设备未连接互联网,就没有必要根据互联网资源安排更新了。以下代码段说明如何使用 {@link android.net.ConnectivityManager} 查询有效网络并确定该网络是否已连接互联网。</p> + +<pre>ConnectivityManager cm = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + +NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre> + + +<h2 id="DetermineType">确定互联网连接的类型</h2> + +<p>您也可以确定当前可用的互联网连接的类型。</p> + +<p>通过移动数据、WiMAX、Wi-Fi 和以太网连接可提供设备连接。您可以查询有效网络的类型(具体如下所示),以便根据可用带宽调整刷新频率。</p> + +<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre> + +<p>移动数据的费用往往比 Wi-Fi 高很多,因此在大多数情况下,如果您使用的是移动连接,就应降低应用更新频率。同样,在没有 Wi-Fi 连接的情况下,您就应暂停较大的下载任务。</p> + +<p>停用更新后,请务必侦听连接情况的变化,以便在建立互联网连接后恢复更新。</p> + + +<h2 id="MonitorChanges">监控连接情况的变化</h2> + +<p>只要连接的具体情况发生变化,{@link android.net.ConnectivityManager} 就会广播 {@link android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code "android.net.conn.CONNECTIVITY_CHANGE"}) 操作。您可以在清单中注册广播接收器,以便侦听这些变化并相应地恢复(或暂停)后台更新。</p> + +<pre><action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre> + +<p>设备连接情况的变化可能会非常频繁,只要您在移动数据和 Wi-Fi 之间相互切换,系统就会触发此广播。因此比较合适的做法是,仅当之前暂停了更新或下载时才监控此广播,以便恢复更新或下载。通常,您只需在开始更新前检查互联网连接情况即可,如果未连接互联网,请暂停后续更新,直到连接恢复。</p> + +<p>此技巧需要切换您在清单中声明的广播接收器,具体说明请见下一教程。</p> diff --git a/docs/html-intl/zh-cn/training/monitoring-device-state/docking-monitoring.jd b/docs/html-intl/zh-cn/training/monitoring-device-state/docking-monitoring.jd new file mode 100644 index 0000000..53b951d --- /dev/null +++ b/docs/html-intl/zh-cn/training/monitoring-device-state/docking-monitoring.jd @@ -0,0 +1,74 @@ +page.title=确定和监控基座对接状态和类型 +parent.title=优化电池使用时间 +parent.link=index.html + +trainingnavtop=true +previous.title= 监控电池电量和充电状态 +previous.link=battery-monitoring.html +next.title= 确定和监控网络连接状态 +next.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#CurrentDockState">确定当前的基座状态</a></li> + <li><a href="#DockType">确定当前的基座类型</a></li> + <li><a href="#MonitorDockState">监控基座状态或类型的变化</a></li> +</ol> + + +<h2>您还应参阅</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">intent 和 intent 过滤器</a> +</ul> + +</div> +</div> + +<p>Android 设备支持几种不同类型的基座。这些类型包括车载或家用基座以及数字和模拟基座。许多基座可用于为插入的设备充电,因此基座状态通常与充电状态紧密相关。</p> + +<p>您可以根据手机的基座状态调整更新频率,具体取决于相关应用。如果设备插入的是桌面基座,您就可以提高体育中心类应用的更新频率;如果设备插入的是车载基座,您就可以完全停用此类更新。相反,如果设备插入的是车载基座且后台服务正在更新路况,您就可以最大程度地提高更新频率。</p> + +<p>系统是以持续 {@link android.content.Intent} 的形式广播基座状态的,这样您就可以查询设备是否插入了基座,如果已插入,您还可以查询基座类型。</p> + + +<h2 id="CurrentDockState">确定当前的基座状态</h2> + +<p>基座状态详情是以附加信息的形式包含在 {@link android.content.Intent#ACTION_DOCK_EVENT} 操作的持续广播中的。由于这属于持续广播,因此您无需注册 {@link android.content.BroadcastReceiver}。您可以将传入 {@code null} 的 {@link android.content.Context#registerReceiver registerReceiver()} 作为广播接收器直接调用,具体如下一代码段所示。</p> + +<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT); +Intent dockStatus = context.registerReceiver(null, ifilter);</pre> + +<p>您可以从 {@code EXTRA_DOCK_STATE} 附加信息中提取当前的基座对接状态:<p> + +<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1); +boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre> + + +<h2 id="DockType">确定当前的基座类型</h2> + +<p>用户可以将设备插入以下四种类型的基座: +<ul><li>车载基座</li> +<li>桌面基座</li> +<li>低端(模拟)桌面基座</li> +<li>高端(数字)桌面基座</li></ul></p> + +<p>请注意,后两种类型仅适用于 API 级别为 11 及以上的 Android,因此如果您只关注基座类型,而不在意基座究竟是数字的还是模拟的,那么比较合适的做法就是查看全部三种类型:</p> + +<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;</pre> + + +<h2 id="MonitorDockState">监控基座状态或类型的变化</h2> + +<p>无论设备是否插入了基座,系统都会广播 {@link android.content.Intent#ACTION_DOCK_EVENT} 操作。要监控设备基座状态的变化,您只需在应用清单中注册广播接收器即可,具体如以下代码段所示:</p> + +<pre><action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre> + +<p>您可以使用上一步骤中所述的技术在接收器实施过程中提取基座的类型和状态。</p> diff --git a/docs/html-intl/zh-cn/training/monitoring-device-state/index.jd b/docs/html-intl/zh-cn/training/monitoring-device-state/index.jd new file mode 100644 index 0000000..aa10753 --- /dev/null +++ b/docs/html-intl/zh-cn/training/monitoring-device-state/index.jd @@ -0,0 +1,49 @@ +page.title=优化电池使用时间 + +trainingnavtop=true +startpage=true +next.title=监控电池电量和充电状态 +next.link=battery-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>依存关系和前提条件</h2> +<ul> + <li>Android 2.0(API 级别 5)或更高版本</li> + <li><a href="{@docRoot}guide/components/intents-filters.html">intent 和 intent 过滤器</a>的使用经验</li> +</ul> + +<h2>您还应参阅</h2> +<ul> + <li><a href="{@docRoot}guide/components/services.html">服务</a> +</ul> + +</div> +</div> + +<p>为了打造一个优秀的应用,您应设法降低应用对电池使用时间的影响。阅读完本教程后,您就可以让自己构建的应用根据其所在设备的状态来监控和调整自身的功能和行为。</p> + +<p>要确保在不影响用户体验的情况下最大程度地降低应用对电池使用时间的影响,您可以采取一些措施,例如在网络连接断开时停用后台服务更新,或在电池电量较低时降低此类更新的频率。</p> + +<h2>教程</h2> + +<!-- Create a list of the lessons in this class along with a short description of each lesson. +These should be short and to the point. It should be clear from reading the summary whether someone +will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="battery-monitoring.html">监控电池电量和充电状态</a></b></dt> + <dd>了解如何通过确定和监控当前的电池电量和充电状态的变化来相应地调整应用的更新频率。</dd> + + <dt><b><a href="docking-monitoring.html">确定和监控基座对接状态和类型</a></b></dt> + <dd>最佳刷新频率可能各有不同,具体取决于安装了相关应用的设备的使用方式。了解如何确定和监控所用基座的对接状态和类型,以便相应地调整应用的行为。</dd> + + <dt><b><a href="connectivity-monitoring.html">确定和监控网络连接状态</a></b></dt> + <dd>如果没有互联网连接,您就无法通过在线来源更新应用。了解如何查看连接状态,以便相应地调整后台更新频率。您还可以了解如何在执行高带宽操作前查看 Wi-Fi 或移动连接的状态。</dd> + + <dt><b><a href="manifest-receivers.html">根据需要操作广播接收器</a></b></dt> + <dd>您可以在运行时切换自己在清单中声明的广播接收器,以便根据当前设备状态停用不需要的接收器。了解如何在设备未处于特定状态的情况下切换和层叠状态变化接收器和延迟操作,以便提高效率。</dd> +</dl>
\ No newline at end of file diff --git a/docs/html-intl/zh-cn/training/monitoring-device-state/manifest-receivers.jd b/docs/html-intl/zh-cn/training/monitoring-device-state/manifest-receivers.jd new file mode 100644 index 0000000..07c014f --- /dev/null +++ b/docs/html-intl/zh-cn/training/monitoring-device-state/manifest-receivers.jd @@ -0,0 +1,50 @@ +page.title=根据需要操作广播接收器 +parent.title=优化电池使用时间 +parent.link=index.html + +trainingnavtop=true + +previous.title=确定和监控网络连接状态 +previous.link=connectivity-monitoring.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#ToggleReceivers">切换和层叠状态变化接收器以提高效率</a></li> +</ol> + + +<h2>您还应参阅</h2> +<ul> + <li><a href="{@docRoot}guide/components/intents-filters.html">intent 和 intent 过滤器</a> +</ul> + +</div> +</div> + +<p>监控设备状态变化的最简单方法就是,为您监控的每种状态创建 {@link android.content.BroadcastReceiver} 并在应用清单中逐一进行注册。然后,您只需根据当前设备状态在每个接收器中重新安排重复提醒即可。</p> + +<p>此方法的负面影响在于,只要系统触发了这些接收器中的任何一个,相关应用就会唤醒设备,其频率可能会远远超过所需的水平。</p> + +<p>更好的方法是在运行时停用或启用广播接收器。这样的话,您就可以将自己在清单中声明的接收器用作被动提醒,只有在需要时才会由系统事件触发。</p> + + +<h2 id="ToggleReceivers">切换和层叠状态变化接收器以提高效率 </h2> + +<p>您可以使用 {@link android.content.pm.PackageManager} 切换清单中定义的任意组件的启用状态(包括您要启用或停用的任意广播接收器),具体如以下片段所示:</p> + +<pre>ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)</pre> + +<p>在使用此技巧时,如果您确定连接已断开,就可以停用除连接变化接收器外的所有接收器。相反,成功连接后,您就可以停止侦听连接变化,同时只需在执行更新和重新安排重复更新提醒前查看是否在线即可。</p> + +<p>您可以使用同样的方法来延迟需要较高带宽的下载任务。只有在连接 Wi-Fi 后,您才能直接启用用于侦听连接变化和启动下载任务的广播接收器。</p> diff --git a/docs/html-intl/zh-cn/training/multiscreen/adaptui.jd b/docs/html-intl/zh-cn/training/multiscreen/adaptui.jd new file mode 100644 index 0000000..89908fe --- /dev/null +++ b/docs/html-intl/zh-cn/training/multiscreen/adaptui.jd @@ -0,0 +1,212 @@ +page.title=实施自适应用户界面流程 +parent.title=针对多种屏幕进行设计 +parent.link=index.html + +trainingnavtop=true +previous.title=支持各种屏幕密度 +previous.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> + +<ol> + <li><a href="#TaskDetermineCurLayout">确定当前布局</a></li> + <li><a href="#TaskReactToLayout">根据当前布局做出响应</a></li> + <li><a href="#TaskReuseFrag">重复使用其他活动中的片段</a></li> + <li><a href="#TaskHandleConfigChanges">处理屏幕配置变化</a></li> +</ol> + +<h2>您还应参阅</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">支持平板电脑和手持设备</a></li> +</ul> + +<h2>试试看</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">下载示例应用</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>根据您的应用当前显示的布局,用户界面流程可能会有所不同。例如,如果您的应用处于双面板模式下,点击左侧面板上的项即可直接在右侧面板上显示相关内容;如果该应用处于单面板模式下,相关内容就应以其他活动的形式在同一面板上显示。</p> + + +<h2 id="TaskDetermineCurLayout">确定当前布局</h2> + +<p>由于每种布局的实施都会稍有不同,因此您可能需要先确定当前向用户显示的布局。例如,您可以了解用户所处的是“单面板”模式还是“双面板”模式。要做到这一点,您可以查询指定视图是否存在以及是否已显示出来。</p> + +<pre class="prettyprint"> +public class NewsReaderActivity extends FragmentActivity { + boolean mIsDualPane; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); + + View articleView = findViewById(R.id.article); + mIsDualPane = articleView != null && + articleView.getVisibility() == View.VISIBLE; + } +} +</pre> + +<p>请注意,这段代码用于查询“报道”面板是否可用,与针对具体布局的硬编码查询相比,这段代码的灵活性要大得多。</p> + +<p>再举一个适应各种组件的存在情况的方法示例:在对这些组件执行操作前先查看它们是否可用。例如,新闻阅读器示例应用中有一个用于打开菜单的按钮,但只有在版本低于 3.0 的 Android 上运行该应用时,这个按钮才会存在,因为 API 级别 11 或更高级别中的 <PH>{@link android.app.ActionBar}</PH> 已取代了该按钮的功能。因此,您可以使用以下代码为此按钮添加事件侦听器:</p> + +<pre class="prettyprint"> +Button catButton = (Button) findViewById(R.id.categorybutton); +OnClickListener listener = /* create your listener here */; +if (catButton != null) { + catButton.setOnClickListener(listener); +} +</pre> + + +<h2 id="TaskReactToLayout">根据当前布局做出响应</h2> + +<p>有些操作可能会因当前的具体布局而产生不同的结果。例如,在新闻阅读器示例中,如果用户界面处于双面板模式下,那么点击标题列表中的标题就会在右侧面板中打开相应报道;但如果用户界面处于单面板模式下,那么上述操作就会启动一个独立活动:</p> + +<pre> +@Override +public void onHeadlineSelected(int index) { + mArtIndex = index; + if (mIsDualPane) { + /* display article on the right pane */ + mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); + } else { + /* start a separate activity */ + Intent intent = new Intent(this, ArticleActivity.class); + intent.putExtra("catIndex", mCatIndex); + intent.putExtra("artIndex", index); + startActivity(intent); + } +} +</pre> + +<p>同样,如果该应用处于双面板模式下,就应设置带导航标签的操作栏;但如果该应用处于单面板模式下,就应使用旋转窗口小部件设置导航栏。因此您的代码还应确定哪种情况比较合适:</p> + +<pre> +final String CATEGORIES[] = { "热门报道", "政治", "经济", "Technology" }; + +public void onCreate(Bundle savedInstanceState) { + .... + if (mIsDualPane) { + /* use tabs for navigation */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); + int i; + for (i = 0; i < CATEGORIES.length; i++) { + actionBar.addTab(actionBar.newTab().setText( + CATEGORIES[i]).setTabListener(handler)); + } + actionBar.setSelectedNavigationItem(selTab); + } + else { + /* use list navigation (spinner) */ + actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); + SpinnerAdapter adap = new ArrayAdapter<String>(this, + R.layout.headline_item, CATEGORIES); + actionBar.setListNavigationCallbacks(adap, handler); + } +} +</pre> + + +<h2 id="TaskReuseFrag">重复使用其他活动中的片段</h2> + +<p>多屏幕设计中的重复模式是指,对于某些屏幕配置,已实施界面的一部分会用作面板;但对于其他配置,这部分就会以独立活动的形式存在。例如,在新闻阅读器示例中,对于较大的屏幕,新闻报道文本会显示在右侧面板中;但对于较小的屏幕,这些文本就会以独立活动的形式存在。</p> + +<p>在类似情况下,您通常可以在多个活动中重复使用相同的 <PH>{@link android.app.Fragment}</PH> 子类以避免代码重复。例如,您在双面板布局中使用了 <code>ArticleFragment</code>:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p>然后又在小屏幕的活动布局中重复使用(无布局)了它 (<code>ArticleActivity</code>):</p> + +<pre> +ArticleFragment frag = new ArticleFragment(); +getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit(); +</pre> + +<p>当然,这与在 XML 布局中声明片段的效果是一样的,但在这种情况下却没必要使用 XML 布局,因为报道片段是此活动中的唯一组件。</p> + +<p>请务必在设计片段时注意,不要针对具体活动创建强耦合。要做到这一点,您通常可以定义一个界面,该界面概括了相关片段与其主活动交互所需的全部方式,然后让主活动实施该界面:</p> + +<p>例如,新闻阅读器应用的 <code>HeadlinesFragment</code> 会精确执行以下代码:</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + OnHeadlineSelectedListener mHeadlineSelectedListener = null; + + /* Must be implemented by host activity */ + public interface OnHeadlineSelectedListener { + public void onHeadlineSelected(int index); + } + ... + + public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) { + mHeadlineSelectedListener = listener; + } +} +</pre> + +<p>然后,如果用户选择某个标题,相关片段就会通知由主活动指定的侦听器(而不是通知某个硬编码的具体活动):</p> + +<pre> +public class HeadlinesFragment extends ListFragment { + ... + @Override + public void onItemClick(AdapterView<?> parent, + View view, int position, long id) { + if (null != mHeadlineSelectedListener) { + mHeadlineSelectedListener.onHeadlineSelected(position); + } + } + ... +} +</pre> + +<p><a +href="{@docRoot}guide/practices/tablets-and-handsets.html">支持平板电脑和手持设备</a>的指南中进一步介绍了此技术。</p> + + +<h2 id="TaskHandleConfigChanges">处理屏幕配置变化</h2> + +<p>如果您使用独立活动实施界面的独立部分,那么请注意,您可能需要对特定配置变化(例如屏幕方向的变化)做出响应,以便保持界面的一致性。</p> + +<p>例如,在运行 Android 3.0 或更高版本的标准 7 英寸平板电脑上,如果新闻阅读器示例应用运行在纵向模式下,就会在使用独立活动显示新闻报道;但如果该应用运行在横向模式下,就会使用双面板布局。</p> + +<p>也就是说,如果用户处于纵向模式下且屏幕上显示的是用于阅读报道的活动,那么您就需要在检测到屏幕方向变化(变成横向模式)后执行相应操作,即停止上述活动并返回主活动,以便在双面板布局中显示相关内容:</p> + +<pre> +public class ArticleActivity extends FragmentActivity { + int mCatIndex, mArtIndex; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mCatIndex = getIntent().getExtras().getInt("catIndex", 0); + mArtIndex = getIntent().getExtras().getInt("artIndex", 0); + + // If should be in two-pane mode, finish to return to main activity + if (getResources().getBoolean(R.bool.has_two_panes)) { + finish(); + return; + } + ... +} +</pre> + + diff --git a/docs/html-intl/zh-cn/training/multiscreen/index.jd b/docs/html-intl/zh-cn/training/multiscreen/index.jd new file mode 100644 index 0000000..35c48e0 --- /dev/null +++ b/docs/html-intl/zh-cn/training/multiscreen/index.jd @@ -0,0 +1,64 @@ +page.title=针对多种屏幕进行设计 + +trainingnavtop=true +startpage=true +next.title=支持各种屏幕尺寸 +next.link=screensizes.html + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>依存关系和前提条件</h2> + +<ul> + <li>Android 1.6 或更高版本(示例应用则需要 2.1 或更高版本)</li> + <li><a +href="http://developer.android.com/guide/components/activities.html">活动</a>和<a href="http://developer.android.com/guide/components/fragments.html">片段</a>的基本知识</li> + <li>构建 Android <a +href="http://developer.android.com/guide/topics/ui/index.html">用户界面</a>的经验</li> + <li>多个功能需要用到<a +href="{@docRoot}tools/extras/support-library.html">支持库</a></li> +</ul> + +<h2>您还应参阅</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">支持多种屏幕</a></li> +</ul> + +<h2>试试看</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">下载示例应用</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>Android 支持数百种屏幕尺寸不同的设备,包括小型手机和大型电视机。因此,请务必将您的应用设计为与所有的屏幕尺寸兼容,以便让尽可能多的用户使用该应用。</p> + +<p>不过,与各种类型的设备兼容还远远不够。由于各种屏幕尺寸对用户互动产生的利弊有所不同,因此要真正满足用户需求并广获好评,您的应用不仅需要支持多种屏幕,还应针对各类屏幕配置的用户体验进行优化。<em></em><em></em></p> + +<p>本教程将向您介绍如何针对多种屏幕配置优化和实施相应的用户界面。</p> + +<p>各教程中都提及了一种来自一个示例应用的代码,该应用展示了关于针对多种分辨率进行优化的最佳实践。您可以在右侧下载该示例,并在自己的应用内重复使用其中的代码。</p> + +<p class="note"><strong>请注意</strong>:本教程和相关的示例使用了<a +href="{@docRoot}tools/extras/support-library.html">支持库</a>,以便在 3.0 版以下的 Android 上使用 <PH>{@link android.app.Fragment}</PH> API。因此,您需要下载该库并将其添加到您的应用,才能使用本教程中涉及的所有 API。</p> + + +<h2>教程</h2> + +<dl> + <dt><b><a href="screensizes.html">支持各种屏幕尺寸</a></b></dt> + <dd>本教程将向您介绍如何设计可适应多种屏幕尺寸的布局(使用灵活的视图尺寸、 <PH>{@link android.widget.RelativeLayout}</PH>、屏幕尺寸和屏幕方向限定符、别名过滤器以及自动拉伸位图)。</dd> + + <dt><b><a href="screendensities.html">支持各种屏幕密度</a></b></dt> + <dd>本教程将向您介绍如何支持具有不同像素密度的屏幕(使用非密度制约像素并提供各种密度的相应位图)。</dd> + + <dt><b><a href="adaptui.html">实施自适应用户界面流程</a></b></dt> + <dd>本教程将向您介绍如何以可适应多种屏幕尺寸/屏幕密度组合的方式实施用户界面流程(运行时对当前布局的检测,根据当前布局做出响应,处理屏幕配置变化)。</dd> +</dl> diff --git a/docs/html-intl/zh-cn/training/multiscreen/screendensities.jd b/docs/html-intl/zh-cn/training/multiscreen/screendensities.jd new file mode 100644 index 0000000..cdb9b7f --- /dev/null +++ b/docs/html-intl/zh-cn/training/multiscreen/screendensities.jd @@ -0,0 +1,100 @@ +page.title=支持各种屏幕密度 +parent.title=针对多种屏幕进行设计 +parent.link=index.html + +trainingnavtop=true +previous.title=支持各种屏幕尺寸 +previous.link=screensizes.html +next.title=实施自适应用户界面流程 +next.link=adaptui.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#TaskUseDP">使用非密度制约像素</a></li> + <li><a href="#TaskProvideAltBmp">提供备用位图</a></li> +</ol> + +<h2>您还应参阅</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">支持多种屏幕</a></li> + <li><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">图标设计指南</a></li> +</ul> + +<h2>试试看</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">下载示例应用</a> +<p class="filename">NewsReader.zip</p> +</div> + + +</div> +</div> + +<p>本教程将向您介绍如何通过提供不同资源和使用独立于分辨率的测量单位来支持不同屏幕密度。</p> + +<h2 id="TaskUseDP">使用非密度制约像素</h2> + +<p>在设计布局时,大家经常会误使用绝对像素来定义距离或尺寸,您一定要避免犯这种错误。由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也有所差异,这样使用像素定义布局尺寸就会产生问题。因此,请务必使用 <code>dp</code> 或 <code>sp</code> 单位指定尺寸。<code>dp</code> 是一种非密度制约像素,其尺寸与 160 dpi 像素的实际尺寸相同。<code>sp</code> 也是一种基本单位,但它可根据用户的偏好文字大小进行调整(即尺度独立性像素),因此您应将该测量单位用于定义文字大小(请勿用其定义布局尺寸)。</p> + +<p>例如,请使用 <code>dp</code>(而非 <code>px</code>)指定两个视图间的间距:</p> + +<pre> +<Button android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/clickme" + android:layout_marginTop="20dp" /> +</pre> + +<p>请务必使用 <code>sp</code> 指定文字大小:</p> + +<pre> +<TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20sp" /> +</pre> + + +<h2 id="TaskProvideAltBmp">提供备用位图</h2> + +<p>由于 Android 可在具有各种屏幕密度的设备上运行,因此您提供的位图资源应始终可以满足各类普遍密度范围的要求:低密度、中等密度、高密度以及超高密度。这将有助于您的图形在所有屏幕密度上都能得到出色的质量和效果。</p> + +<p>要生成这些图片,您应先提取矢量格式的原始资源,然后根据以下尺寸范围针对各密度生成相应的图片。</p> + +<p><ul> + <li><code>xhdpi</code>:2.0 + <li><code>hdpi</code>:1.5 + <li><code>mdpi</code>:1.0(最低要求) + <li><code>ldpi</code>:0.75 +</ul></p> + +<p>也就是说,如果您为 <code>xhdpi</code> 设备生成了 200x200 尺寸的图片,就应该使用同一资源为 <code>hdpi</code>、<code>mdpi</code> 和 <code>ldpi</code> 设备分别生成 150x150、100x100 和 75x75 尺寸的图片。</p> + +<p>然后,将生成的图片文件放在 <code>res/</code> 下的相应子目录中(如下所示),系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片:</p> + +<pre class="classic no-pretty-print"> +MyProject/ + res/ + drawable-xhdpi/ + awesomeimage.png + drawable-hdpi/ + awesomeimage.png + drawable-mdpi/ + awesomeimage.png + drawable-ldpi/ + awesomeimage.png +</pre> + +<p>这样一来,无论您何时引用 <code>@drawable/awesomeimage</code>,系统都能根据相应屏幕的 dpi 选取合适的位图。</p> + +<p>有关为您的应用创建图标资产的更多提示和指南,请参阅<a +href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">图标设计指南</a>。</p> + diff --git a/docs/html-intl/zh-cn/training/multiscreen/screensizes.jd b/docs/html-intl/zh-cn/training/multiscreen/screensizes.jd new file mode 100644 index 0000000..904d097 --- /dev/null +++ b/docs/html-intl/zh-cn/training/multiscreen/screensizes.jd @@ -0,0 +1,279 @@ +page.title=支持各种屏幕尺寸 +parent.title=针对多种屏幕进行设计 +parent.link=index.html + +trainingnavtop=true +next.title=支持各种屏幕密度 +next.link=screendensities.html + +@jd:body + + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>本教程将指导您</h2> +<ol> + <li><a href="#TaskUseWrapMatchPar">使用“wrap_content”和“match_parent”</a></li> + <li><a href="#TaskUseRelativeLayout">使用相对布局</a></li> + <li><a href="#TaskUseSizeQuali">使用尺寸限定符</a></li> + <li><a href="#TaskUseSWQuali">使用最小宽度限定符</a></li> + <li><a href="#TaskUseAliasFilters">使用布局别名</a></li> + <li><a href="#TaskUseOriQuali">使用屏幕方向限定符</a></li> + <li><a href="#TaskUse9Patch">使用自动拉伸位图</a></li> +</ol> + +<h2>您还应参阅</h2> + +<ul> + <li><a href="{@docRoot}guide/practices/screens_support.html">支持多种屏幕</a></li> +</ul> + +<h2>试试看</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">下载示例应用</a> +<p class="filename">NewsReader.zip</p> +</div> + +</div> +</div> + +<p>此教程将向您介绍如何通过以下方法支持各种尺寸的屏幕:</p> +<ul> + <li>确保系统可以适当地调整您布局的尺寸以便适应屏幕</li> + <li>根据屏幕配置提供合适的用户界面布局</li> + <li>确保正确的布局应用到了正确的屏幕上</li> + <li>提供可正确缩放的位图</li> +</ul> + + +<h2 id="TaskUseWrapMatchPar">使用“wrap_content”和“match_parent”</h2> + +<p>要确保布局的灵活性并适应各种尺寸的屏幕,您应使用 <code>"wrap_content"</code> 和 <code>"match_parent"</code> 控制某些视图组件的宽度和高度。如果您使用 <code>"wrap_content"</code>,系统就会将视图的宽度或高度设置成所需的最小尺寸以适应视图中的内容,而 <code>"match_parent"</code>(在低于 API 级别 8 的级别中称为 <code>"fill_parent"</code>)则会展开组件以匹配其父视图的尺寸。</p> + +<p>如果使用 <code>"wrap_content"</code> 和 <code>"match_parent"</code> 尺寸值而不是硬编码的尺寸,您的视图就会相应地仅使用自身所需的空间或展开以填满可用空间。例如:</p> + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p>请注意示例中使用 <code>"wrap_content"</code> 和 <code>"match_parent"</code> 控制组件尺寸的方法,而不是关注具体的尺寸。此方法可让布局正确适应各种屏幕尺寸和屏幕方向。</p> + +<p>此视图在纵向模式和横向模式下的显示效果如下所示。请注意,组件的尺寸会自动适应屏幕的高度和宽度:</p> + +<img src="{@docRoot}images/training/layout-hvga.png" /> +<p class="img-caption"><strong>图 1</strong>。纵向模式(左)和横向模式(右)下的新闻阅读器示例应用。</p> + + +<h2 id="TaskUseRelativeLayout">使用相对布局</h2> + +<p>您可以使用 <PH>{@link android.widget.LinearLayout}</PH> 的嵌套实例并结合 <code>"wrap_content"</code> 和 <code>"match_parent"</code> 尺寸,以便构建相当复杂的布局。不过,您无法通过 <PH>{@link android.widget.LinearLayout}</PH> 精确控制子视图的特殊关系;系统会将 <PH>{@link android.widget.LinearLayout}</PH> 中的视图直接并排列出。如果您需要将子视图排列出各种效果而不是一条直线,通常更合适的解决方法是使用 <PH>{@link android.widget.RelativeLayout}</PH>,这样您就可以根据各组件之间的特殊关系指定布局了。例如,您可以将某个子视图对齐到屏幕左侧,同时将另一个视图对齐到屏幕右侧。</p> + +<p>例如:</p> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Type here:"/> + <EditText + android:id="@+id/entry" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/label"/> + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/entry" + android:layout_alignParentRight="true" + android:layout_marginLeft="10dp" + android:text="OK" /> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@id/ok" + android:layout_alignTop="@id/ok" + android:text="Cancel" /> +</RelativeLayout> +</pre> + +<p>图 2 展示的是此布局在 QVGA 屏幕上的显示效果。</p> + +<img src="{@docRoot}images/training/relativelayout1.png" /> +<p class="img-caption"><strong>图 2</strong>。QVGA 屏幕(小屏幕)上的截图。</p> + +<p>图 3 展示的是此布局在较大屏幕上的显示效果。</p> + +<img src="{@docRoot}images/training/relativelayout2.png" /> +<p class="img-caption"><strong>图 3</strong>。WSVGA 屏幕(大屏幕)上的截图。</p> + +<p>请注意,虽然组件的尺寸有所变化,但它们的空间关系仍会保留,具体由 <PH>{@link android.widget.RelativeLayout.LayoutParams}</PH> 指定。</p> + + +<h2 id="TaskUseSizeQuali">使用尺寸限定符</h2> + +<p>上文所述的灵活布局或相对布局可以为您带来的优势就只有这么多了。虽然这些布局可以拉伸组件内外的空间以适应各种屏幕,但它们不一定能为每种屏幕都提供最佳的用户体验。因此,您的应用不仅应实施灵活布局,还应针对各种屏幕配置提供一些备用布局。要做到这一点,您可以使用<a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">配置限定符</a>,这样就可以在运行时根据当前的设备配置自动选择合适的资源了(例如根据各种屏幕尺寸选择不同的布局)。</p> + +<p>例如,很多应用会在较大的屏幕上实施“双面板”模式(相关应用可能会在一个面板上显示项目列表,并在另一面板上显示对应内容)。平板电脑和电视的屏幕已经大到可以同时容纳这两个面板了,但手机屏幕就需要分别显示。因此,您可以使用以下文件以便实施这些布局:</p> + +<ul> + <li><code>res/layout/main.xml</code>,单面板(默认)布局: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-large/main.xml</code>,双面板布局: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>请注意第二种布局名称目录中的 <code>large</code> 限定符。系统会在属于较大屏幕(例如 7 英寸或更大的平板电脑)的设备上选择此布局。系统会在较小的屏幕上选择其他布局(无限定符)。</p> + + +<h2 id="TaskUseSWQuali">使用最小宽度限定符</h2> + +<p>在版本低于 3.2 的 Android 设备上,开发人员遇到的问题之一是“较大”屏幕的尺寸范围,该问题会影响戴尔 Streak、早期的 Galaxy Tab 以及大部分 7 英寸平板电脑。即使这些设备的屏幕属于“较大”的尺寸,但很多应用可能会针对此类别中的各种设备(例如 5 英寸和 7 英寸的设备)显示不同的布局。这就是 Android 3.2 版在引入其他限定符的同时引入“最小宽度”限定符的原因。</p> + +<p>最小宽度限定符可让您通过指定某个最小宽度(以 dp 为单位)来定位屏幕。例如,标准 7 英寸平板电脑的最小宽度为 600 dp,因此如果您要在此类屏幕上的用户界面中使用双面板(但在较小的屏幕上只显示列表),您可以使用上文中所述的单面板和双面板这两种布局,但您应使用 <code>sw600dp</code> 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 <code>large</code> 尺寸限定符:</p> + +<ul> + <li><code>res/layout/main.xml</code>,单面板(默认)布局: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} +</li> + <li><code>res/layout-sw600dp/main.xml</code>,双面板布局: + +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} +</li> +</ul> + +<p>也就是说,对于最小宽度大于等于 600 dp 的设备,系统会选择 <code>layout-sw600dp/main.xml</code>(双面板)布局,否则系统就会选择 <code>layout/main.xml</code>(单面板)布局。</p> + +<p>但 Android 版本低于 3.2 的设备不支持此技术,原因是这些设备无法将 <code>sw600dp</code> 识别为尺寸限定符,因此您仍需使用 <code>large</code> 限定符。这样一来,就会有一个名称为 <code>res/layout-large/main.xml</code> 的文件(与 <code>res/layout-sw600dp/main.xml</code> 一样)。您将在下一教程中了解到避免此类布局文件出现重复的技术。</p> + + +<h2 id="TaskUseAliasFilters">使用布局别名</h2> + +<p>最小宽度限定符仅适用于 Android 3.2 及更高版本。因此,您仍需使用与较低版本兼容的概括尺寸范围(小、正常、大和特大)。例如,如果您要将用户界面设计成在手机上显示单面板,但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板,请提供以下文件:</p> + +<p><ul> +<li><code>res/layout/main.xml:</code> 单面板布局</li> +<li><code>res/layout-large:</code> 多面板布局</li> +<li><code>res/layout-sw600dp:</code> 多面板布局</li> +</ul></p> + +<p>后两个文件是相同的,因为其中一个用于和 Android 3.2 设备匹配,而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。</p> + +<p>要避免平板电脑和电视的文件出现重复(以及由此带来的维护问题),您可以使用别名文件。例如,您可以定义以下布局:</p> + +<ul> +<li><code>res/layout/main.xml</code>,单面板布局</li> +<li><code>res/layout/main_twopanes.xml</code>,双面板布局</li> +</ul> + +<p>然后添加这两个文件:</p> + +<p><ul> +<li><code>res/values-large/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> +</li> + +<li><code>res/values-sw600dp/layout.xml</code>: +<pre> +<resources> + <item name="main" type="layout">@layout/main_twopanes</item> +</resources> +</pre> + +</li> +</ul></p> + +<p>后两个文件的内容相同,但它们并未实际定义布局。它们只是将 <PH>{@code main}</PH> 设置成了 <PH>{@code main_twopanes}</PH> 的别名。由于这些文件包含 <code>large</code> 和 <code>sw600dp</code> 选择器,因此无论 Android 版本如何,系统都会将这些文件应用到平板电脑和电视上(版本低于 3.2 的平板电脑和电视会匹配 +<PH>{@code large}</PH>,版本低于 3.2 的平板电脑和电视则会匹配 <code>sw600dp</code>)。</p> + + +<h2 id="TaskUseOriQuali">使用屏幕方向限定符</h2> + +<p>某些布局会同时支持横向模式和纵向模式,但您可以通过调整优化其中大部分布局的效果。在新闻阅读器示例应用中,每种屏幕尺寸和屏幕方向下的布局行为方式如下所示:</p> + +<p><ul> +<li><b>小屏幕,纵向</b>:单面板,带徽标</li> +<li><b>小屏幕,横向</b>:单面板,带徽标</li> +<li><b>7 英寸平板电脑,纵向</b>:单面板,带操作栏</li> +<li><b>7 英寸平板电脑,横向</b>:双面板,宽,带操作栏</li> +<li><b>10 英寸平板电脑,纵向</b>:双面板,窄,带操作栏</li> +<li><b>10 英寸平板电脑,横向</b>:双面板,宽,带操作栏</li> +<li><b>电视,横向</b>:双面板,宽,带操作栏</li> +</ul></p> + +<p>因此,这些布局中的每一种都定义在了 <code>res/layout/</code> 目录下的某个 XML 文件中。为了继续将每个布局分配给各种屏幕配置,该应用会使用布局别名将两者相匹配:</p> + +<p><code>res/layout/onepane.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +<p><code>res/layout/onepane_with_bar.xml:</code></p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +<p><code>res/layout/twopanes.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +<p><code>res/layout/twopanes_narrow.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +<p>既然您已定义了所有可能的布局,那就只需使用配置限定符将正确的布局映射到各种配置即可。您现在只需使用布局别名技术即可做到这一点:</p> + +<p><code>res/values/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +<p><code>res/values-sw600dp-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +<p><code>res/values-sw600dp-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +<p><code>res/values-large-land/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all} + +<p><code>res/values-large-port/layouts.xml</code>:</p> +{@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all} + + + +<h2 id="TaskUse9Patch">使用自动拉伸位图</h2> + +<p>支持各种屏幕尺寸通常意味着您的图片资源还必须能适应各种尺寸。例如,无论要应用到什么形状的按钮上,按钮背景都必须能适应。</p> + +<p>如果在可以更改尺寸的组件上使用了简单的图片,您很快就会发现显示效果多少有些不太理想,因为系统会在运行时平均地拉伸或收缩您的图片。解决方法为使用自动拉伸位图,这是一种格式特殊的 PNG 文件,其中会指明可以拉伸以及不可以拉伸的区域。</p> + +<p>因此,如果设计的是用于尺寸可变的组件上的位图,请务必使用自动拉伸技术。要将某个位图转换成自动拉伸位图,您可以先准备好普通图片(图 4,放大了 4 倍以便清楚显示)。</p> + +<img src="{@docRoot}images/training/button.png" /> +<p class="img-caption"><strong>图 4</strong>。<code>button.png</code></p> + +<p>然后通过 SDK 的 <ode +href="{@docRoot}tools/help/draw9patch.html"><code>draw9patch</code></a> 实用工具(位于 <code>tools/</code> 目录中)运行该图片,您可以在该工具中绘制像素以标出要拉伸的区域以及左侧和顶部的边界。您还可以沿右侧和底部边界绘制像素以标出用于放置内容的区域,具体如图 5 所示。</p> + +<img src="{@docRoot}images/training/button_with_marks.png" /> +<p class="img-caption"><strong>图 5</strong>。<code>button.9.png</code></p> + +<p>请注意沿边界显示的黑色像素。顶部和左侧边界上的像素用于指定可以拉伸的图片区域,右侧和底部边界上的像素则用于指定放置内容的区域。</p> + +<p>另请注意 <code>.9.png</code> 的扩展名。您必须使用此扩展名,因为系统框架需要通过此扩展名确定相关图片是自动拉伸位图,而不是普通 PNG 图片。</p> + +<p>如果您将此背景应用到某个组件(通过设置 <code>android:background="@drawable/button"</code>),系统框架就会正确拉伸图片以适应按钮的尺寸,具体如图 6 中的各种尺寸所示。</p> + +<img src="{@docRoot}images/training/buttons_stretched.png" /> +<p class="img-caption"><strong>图 6</strong>。在各种尺寸下使用 <code>button.9.png</code> 自动拉伸位图的按钮。</p> + |