Android 6.0 Marshmallow
-Prepárese para la próxima versión de -Android. Pruebe sus aplicaciones en Nexus 5, 6, 9 y Player.
- - +Android N Developer Preview
++ Get ready for the next version of Android! + Test your apps on Nexus and other devices. Support new system + behaviors to save power and memory. + Extend your apps with multi-window UI, + direct reply notifications and more. +
+ - ¡Empiece hoy mismo!- + Learn more + + +
-
+
- + + + Get the SDK + + +
- + + + Browse sample code + + +
- + + + Watch stories + + +
Build Beautiful Apps
Contenido del documento - - mostrar más - mostrar menos
- --
-
- Vinculación de la aplicación -
- Copia de seguridad automática para aplicaciones -
- Autenticación - - -
- Compartir de forma directa -
- Interacciones de voz -
- Asistencia de API -
- Notificaciones -
- Soporte del lápiz Bluetooth -
- Exploración mejorada de Bluetooth de bajo consumo -
- Soporte de Hotspot 2.0 versión 1 -
- Modo de pantalla 4K -
- ColorStateLists para poder aplicar temas -
- Características de audio -
- Características de video -
- Características de la cámara - - -
- Características de Android for Work -
Diferencias de las API
- - -M Developer Preview le brinda una perspectiva avanzada de la próxima versión de la plataforma Android, que ofrece nuevas características para usuarios y desarrolladores de aplicaciones. - - En este documento, se brinda una introducción sobre las API más distinguidas.
- -M Developer Preview está destinado a usuarios desarrolladores principiantes y evaluadores. - Si le interesa influenciar la dirección del marco de trabajo de Android, -pruebe M Developer Preview y envíenos sus comentarios. - -
- -Advertencia: No publique las aplicaciones que utilizan M Developer Preview en la tienda de Google Play. -
- -Nota: Este documento, a menudo, hace referencia a clases y métodos que aún no cuentan con materiales de referencia disponibles en developer.android.com. - Estos elementos de API tienen el formato {@code code style} en este documento (sin hipervínculos). - Para obtener la documentación preliminar de la API para estos elementos, descargue la referencia de la versión preliminar. -
- -Importantes cambios en los comportamientos
- -Si publicó anteriormente una aplicación para Android, tenga en cuenta que su aplicación podría verse afectada por los cambios en la plataforma. -
- -Consulte la sección Cambios en los comportamientos para obtener información detallada.
- -Vinculación de la aplicación
-Esta versión preliminar mejora el sistema de intentos de Android al proporcionar una vinculación más sólida de la aplicación. Esta característica le permite asociar una aplicación con un dominio web propio. - Según esta asociación, la plataforma puede determinar la aplicación predeterminada que se debe utilizar para controlar un vínculo web en particular y omitir el paso de pedirles a los usuarios que seleccionen una aplicación. Para aprender a implementar esta característica, consulte la sección -Vinculación de la aplicación. - - - -
Copia de seguridad automática para aplicaciones
-Ahora, el sistema realiza restauraciones y copias de seguridad de datos completas y automáticas para las aplicaciones. Este comportamiento se habilita de forma predeterminada para las aplicaciones que tienen como destino la versión preliminar de Android M; usted no necesita agregar ningún código adicional. - Si los usuarios eliminan sus cuentas de Google, también se eliminarán sus datos de copias de seguridad. - Para obtener información sobre cómo funciona esta característica y cómo configurar qué elementos incluir en la copia de seguridad del sistema de archivo, consulte la sección -Copia de seguridad automática para aplicaciones. -
- -Autenticación
-Esta versión preliminar ofrece nuevas API para permitirle autenticar usuarios al usar escaneos de huellas dactilares en los dispositivos compatibles y verificar cuán reciente es la última autenticación del usuario al utilizar un mecanismo de desbloqueo de dispositivos (como una contraseña de pantalla de bloqueo). - - Use estas API junto con el sistema Android Keystore. -
- -Autenticación por huellas dactilares
- -Para autenticar usuarios mediante el escaneo de huellas dactilares, obtenga una instancia de la nueva clase -{@code android.hardware.fingerprint.FingerprintManager} y llame al método -{@code FingerprintManager.authenticate()}. Su aplicación se debe ejecutar en un dispositivo compatible con un sensor de huellas dactilares. - Debe implementar la interfaz de usuario para el flujo de autenticación por huellas dactilares en su aplicación y debe utilizar el ícono de huella dactilar estándar de Android en la UI. El ícono de huella dactilar de Android ({@code c_fp_40px.png}) se incluye en la -aplicación de muestra. Si está desarrollando múltiples aplicaciones que utilizan la autenticación por huellas dactilares, tenga en cuenta que cada aplicación debe autenticar la huella dactilar del usuario de manera independiente. - - - -
- -Para utilizar esta característica en su aplicación, primero agregue el permiso {@code USE_FINGERPRINT} en su manifiesto. -
- --<uses-permission - android:name="android.permission.USE_FINGERPRINT" /> -- - - -
Para ver cómo una aplicación implementa la autenticación por huellas dactilares, consulte la sección - -Ejemplo de diálogo de huella dactilar.
- -Si está evaluando esta característica, siga estos pasos:
--
-
- Instale la Revisión de herramientas del SDK de Android versión 24.3, si todavía no la instaló. -
- Registre una huella dactilar nueva en el emulador; para hacerlo, vaya a -Settings > Security > Fingerprint, luego siga las instrucciones de registro. -
- Use un emulador para emular eventos táctiles de huellas dactilares con el siguiente comando.
- Utilice el mismo comando para emular eventos táctiles de huellas dactilares en la pantalla de bloqueo o en su aplicación.
-
-
-adb -e emu finger touch <finger_id> -
-En Windows, posiblemente tenga que ejecutar {@code telnet 127.0.0.1
-} seguido de - {@code finger touch }. -
-
Confirmar credencial
-Su aplicación puede autenticar usuarios según el tiempo que haya pasado desde que desbloquearon su dispositivo por última vez. Esta característica evita que los usuarios tengan que recordar contraseñas adicionales específicas de la aplicación y elimina la necesidad de que usted tenga que implementar su propia interfaz de usuario de autenticación. - - Su aplicación debe utilizar esta característica junto con una implementación de clave pública o secreta para la autenticación del usuario. -
- -Para definir la duración del tiempo de espera en el que se puede volver a usar la misma clave después de que un usuario se haya autenticado correctamente, llame al nuevo método -{@code android.security.keystore.KeyGenParameterSpec.setUserAuthenticationValidityDurationSeconds()} -cuando configure {@link javax.crypto.KeyGenerator} o -{@link java.security.KeyPairGenerator}. - Esta característica actualmente funciona para operaciones criptográficas simétricas. -
- -Evite mostrar el diálogo de nueva autenticación de forma excesiva: sus aplicaciones deben intentar utilizar el objeto criptográfico primero y, si se agota el tiempo de espera, deben usar el método -{@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence) createConfirmDeviceCredentialIntent()} -para volver a autenticar el usuario dentro de su aplicación. - -
- -Para ver cómo la aplicación implementa esta característica, consulte la sección - -Ejemplo de cómo confirmar la credencial.
- -Compartir de forma directa
- - - -Esta versión preliminar le proporciona API para que la acción de compartir sea intuitiva y rápida para los usuarios. Ahora, puede definir destinos para compartir de forma directa que inician una actividad específica en su aplicación. Estos destinos para compartir de forma directa se exponen a los usuarios a través del menú Share. - - Esta característica les permite a los usuarios compartir contenido con los destinos, como contactos, dentro de otras aplicaciones. - Por ejemplo, el destino para compartir de forma directa podría iniciar una actividad en otra aplicación de red social, lo que le permite al usuario compartir contenido directamente con una comunidad o un amigo específicos de esa aplicación. - -
- -Para habilitar destinos para compartir de forma directa, debe definir una clase que extienda el
-{@code android.service.}
-Clase {@code chooser.ChooserTargetService}. Declare su
-{@code ChooserTargetService} en el manifiesto. En esa declaración, especifique el permiso
-{@code BIND_CHOOSER_TARGET_SERVICE} y un filtro de intento con la acción
-{@code SERVICE_INTERFACE}.
El ejemplo a continuación muestra de qué manera podría declarar {@code ChooserTargetService} en su manifiesto. -
--<service android:name=".ChooserTargetService" - android:label="@string/service_name" - android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"> - <intent-filter> - <action android:name="android.service.chooser.ChooserTargetService" /> - </intent-filter> -</service> -- -
Para cada actividad que desee exponer a {@code ChooserTargetService}, agregue un elemento
-{@code
-<activity android:name=".MyShareActivity” - android:label="@string/share_activity_label"> - <intent-filter> - <action android:name="android.intent.action.SEND" /> - </intent-filter> -<meta-data - android:name="android.service.chooser.chooser_target_service" - android:value=".ChooserTargetService" /> -</activity> -- -
Interacciones de voz
--Esta versión preliminar proporciona una nueva API de interacción de voz que, junto con las -acciones de voz, -le permite compilar experiencias de conversaciones de voz en sus aplicaciones. Llame al método -{@code android.app.Activity.isVoiceInteraction()} para determinar si su actividad se inició en respuesta a una acción de voz. - De ser así, su aplicación puede utilizar la clase -{@code android.app.VoiceInteractor} para solicitar una confirmación de voz por parte del usuario, realizar una selección de una lista de opciones y mucho más. - Para obtener más información sobre cómo implementar acciones de voz, consulte el -sitio para desarrolladores de acciones de voz. -
- -Asistencia de API
--Esta versión preliminar ofrece una nueva manera para que los usuarios interactúen con sus aplicaciones a través de un asistente. Si desea utilizar esta característica, el usuario debe habilitar el asistente para utilizar el contexto actual. - Una vez habilitado, para invocar al asistente dentro de cualquier aplicación, el usuario debe mantener presionado el botón Home. -
-Su aplicación puede optar por no compartir el contexto actual con el asistente al configurar la marca -{@link android.view.WindowManager.LayoutParams#FLAG_SECURE}. Además del conjunto de información estándar que la plataforma le pasa al asistente, su aplicación puede compartir información adicional usando la nueva clase {@code android.app.Activity.AssistContent}. - -
- -Para proporcionarle al asistente contexto adicional desde su aplicación, siga estos pasos:
- --
-
- Implemente la interfaz {@link android.app.Application.OnProvideAssistDataListener}. -
- Registre esta escucha usando -{@link android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener) registerOnProvideAssistDataListener()}. -
- Para proporcionar información contextual específica de la actividad, invalide la devolución de llamada -{@link android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()} -y, opcionalmente, la nueva devolución de llamada {@code Activity.onProvideAssistContent()}. -
Notificaciones
-Esta versión preliminar agrega los siguientes cambios de API para las notificaciones:
--
-
- Nuevo nivel de filtro {@code NotificationListenerService.INTERRUPTION_FILTER_ALARMS} que corresponde al nuevo modo ocupado Solo alarmas. - -
- Nuevo valor de categoría {@code Notification.CATEGORY_REMINDER} que se utiliza para distinguir recordatorios programados por el usuario de otros eventos - ({@link android.app.Notification#CATEGORY_EVENT}) y alarmas - ({@link android.app.Notification#CATEGORY_ALARM}). - -
- Nueva clase {@code android.graphics.drawable.Icon} que se puede adjuntar a sus notificaciones a través de los métodos {@code Notification.Builder.setSmallIcon(Icon)} y -{@code Notification.Builder.setLargeIcon(Icon)}. - -
- Nuevo método {@code NotificationManager.getActiveNotifications()} que permite que sus aplicaciones descubran qué notificaciones se encuentran actualmente activas. - Para ver una implementación de la aplicación que utilice esta característica, consulte la sección Ejemplo de notificaciones activas. - -
Compatibilidad del lápiz Bluetooth
-Esta versión preliminar ofrece soporte mejorado para las entradas de usuarios que utilizan un lápiz Bluetooth. Los usuarios pueden sincronizar y conectar un lápiz Bluetooth compatible con su teléfono o tablet. - Mientras está conectado, la información de posición de la pantalla táctil se fusiona con la información de los botones y la presión del lápiz para proporcionar una mayor variedad de expresiones que al utilizar la pantalla táctil solamente. - - Su aplicación puede obedecer cuando se presiona el botón del lápiz y cuando se realizan acciones secundarias al registrar las nuevas devoluciones de llamadas -{@code View.onStylusButtonPressListener} y {@code GestureDetector.OnStylusButtonPressListener} -en su actividad. -
- -Utilice las constantes y los métodos {@link android.view.MotionEvent} para detectar las interacciones del botón del lápiz: -
--
-
- Si el usuario toca un lápiz con un botón en la pantalla de su aplicación, el método -{@link android.view.MotionEvent#getToolType(int) getTooltype()} devuelve -{@link android.view.MotionEvent#TOOL_TYPE_STYLUS}. -
- Para las aplicaciones que tienen como destino la versión preliminar de Android M, el método -{@link android.view.MotionEvent#getButtonState() getButtonState()} -devuelve {@code MotionEvent.STYLUS_BUTTON_PRIMARY} cuando el usuario presiona el botón principal del lápiz. - Si el lápiz tiene un segundo botón, el mismo método devuelve -{@code MotionEvent.STYLUS_BUTTON_SECONDARY} cuando el usuario lo presiona. Si el usuario presiona ambos botones simultáneamente, el método devuelve ambos valores juntos separados por “OR” ({@code STYLUS_BUTTON_PRIMARY|STYLUS_BUTTON_SECONDARY}). - - -
- -Para las aplicaciones que tienen como destino una versión anterior de la plataforma, el método -{@link android.view.MotionEvent#getButtonState() getButtonState()} devuelve -{@link android.view.MotionEvent#BUTTON_SECONDARY} (cuando se presiona el botón principal), -{@link android.view.MotionEvent#BUTTON_TERTIARY} (cuando se presiona el botón secundario) o ambos. - -
Exploración mejorada de Bluetooth de bajo consumo
--Si su aplicación realiza exploraciones de Bluetooth de bajo consumo, puede utilizar el nuevo método -{@code android.bluetooth.le.ScanSettings.Builder.setCallbackType()} para especificar que usted desea que las devoluciones de llamadas se notifiquen solo cuando se encuentre por primera vez un paquete de anuncio que coincida con el conjunto -{@link android.bluetooth.le.ScanFilter} y cuando no se vea durante un período determinado. - - Este enfoque de exploración es más eficaz en cuanto al consumo de energía que la que se proporciona en la versión anterior de la plataforma. - -
- -Soporte de Hotspot 2.0 versión 1
--Esta versión preliminar agrega soporte para la especificación de Hotspot 2.0 versión 1 en los dispositivos Nexus 6 y Nexus 9. Para proveer credenciales de Hotspot 2.0 en su aplicación, use los métodos nuevos de la clase -{@link android.net.wifi.WifiEnterpriseConfig}, como {@code setPlmn()} y -{@code setRealm()}. - En el objeto {@link android.net.wifi.WifiConfiguration}, puede configurar los campos -{@link android.net.wifi.WifiConfiguration#FQDN} y {@code providerFriendlyName}. La nueva propiedad {@code ScanResult.PasspointNetwork} indica si una red detectada representa un punto de acceso de Hotspot 2.0. - - -
- -Modo de pantalla 4K
-Ahora, la plataforma permite que las aplicaciones soliciten que la resolución de pantalla se actualice a una representación 4K en el hardware compatible. - Para consultar la resolución física actual, use las nuevas API -{@code android.view.Display.Mode}. Si la UI se establece en una resolución lógica más baja y se aumenta a una resolución física más alta, tenga en cuenta que la resolución física que devuelve el método -{@code Display.Mode.getPhysicalWidth()} puede ser diferente de la resolución lógica informada por {@link android.view.Display#getSize(android.graphics.Point) getSize()}. - -
- -Puede pedirle al sistema que cambie la resolución física en su aplicación mientras se ejecuta y, para ello, debe configurar la propiedad {@code WindowManager.LayoutParams.preferredDisplayModeId} de la ventana de su aplicación. - Esta característica resulta útil si desea cambiar a la resolución de pantalla 4K. - Mientras se encuentra en el modo de pantalla 4K, la UI se continúa representando en la resolución original (como 1080p) y se aumenta a 4K, pero los objetos -{@link android.view.SurfaceView} pueden mostrar contenido en la resolución nativa. -
- -ColorStateLists para poder aplicar temas
-Ahora, los atributos de tema se admiten en -{@link android.content.res.ColorStateList} para los dispositivos que ejecutan la versión preliminar de Android M. Los métodos -{@link android.content.res.Resources#getColorStateList(int) getColorStateList()} y -{@link android.content.res.Resources#getColor(int) getColor()} se dejaron de usar. Si desea llamar a estas API, en su lugar, llame a los métodos nuevos {@code Context.getColorStateList()} o -{@code Context.getColor()}. - Estos métodos también se encuentran disponibles en la biblioteca AppCompat v4 vía {@link android.support.v4.content.ContextCompat}. -
- -Características de audio
- -Esta versión preliminar agrega mejoras al procesamiento de audio en Android, lo que incluye lo siguiente:
--
-
- Soporte para el protocolo MIDI -, con las nuevas API {@code android.media.midi}. Utilice estas API para enviar y recibir eventos MIDI. - -
- Clases nuevas {@code android.media.AudioRecord.Builder} y {@code android.media.AudioTrack.Builder} - para crear capturas de audio digital y objetos de reproducción respectivamente, y configurar propiedades de receptores y fuentes de audio para invalidar los valores predeterminados del sistema. - -
- Enlaces de API para asociar dispositivos de entrada y de audio. Esto resulta particularmente útil si su aplicación les permite a los usuarios iniciar una búsqueda por voz desde un controlador para juegos o un control remoto conectados a un TV con Android. El sistema invoca la nueva devolución de llamada {@code android.app.Activity.onSearchRequested()} cuando el usuario inicia una búsqueda. - - - Para determinar si el dispositivo de entrada del usuario tiene un micrófono incorporado, recupere el objeto {@link android.view.InputDevice} de esa devolución de llamada y luego llame al nuevo método -{@code InputDevice.hasMic()}. - -
- Nueva clase {@code android.media.AudioDevicesManager}, que le permite recuperar una lista de todos los dispositivos de audio receptores y fuente adjuntos. - También puede especificar un objeto -{@code android.media.OnAudioDeviceConnectionListener} si desea que su aplicación reciba una notificación cuando se conecta o desconecta un dispositivo de audio. - -
Características de video
-Esta versión preliminar agrega nuevas capacidades a las API de procesamiento de video, entre ellas, las siguientes:
--
-
- Nueva clase {@code android.media.MediaSync} que ayuda a las aplicaciones a representar de forma sincrónica transmisiones de audio y video. - Los búferes de audio se envían de manera que no generan bloqueo y regresan mediante una devolución de llamada. - Además, admite una velocidad de reproducción dinámica. - -
- Nuevo evento {@code MediaDrm.EVENT_SESSION_RECLAIMED}, que indica cuando una sesión abierta por la aplicación es reclamada por el administrador de recursos. - Si su aplicación utiliza sesiones DRM, debe controlar este evento y asegurarse de no utilizar una sesión reclamada. - - -
- Nuevo código de error {@code MediaCodec.CodecException.ERROR_RECLAIMED}, que indica que el administrador de recursos reclamó el recurso multimedia utilizado por el códec. - Con esta excepción, se debe liberar el códec, ya que pasó al estado terminal. - - -
- Nueva interfaz {@code MediaCodecInfo.CodecCapabilities.getMaxSupportedInstances()} para obtener una indicación de la cantidad máxima de instancias concurrentes de códec admitidas. - - -
- Nuevo método {@code MediaPlayer.setPlaybackParams()} para configurar la velocidad de reproducción multimedia para reproducciones rápidas o lentas. - Además, alarga o acelera la reproducción de audio de forma automática junto con el video. - -
Características de la cámara
-Esta versión preliminar incluye las siguientes API nuevas para acceder a la luz de flash de la cámara y para el reprocesamiento de imágenes de la cámara: -
- -API para luz de flash
-Si un dispositivo de cámara cuenta con una unidad de flash, puede llamar al método {@code CameraManager.setTorchMode()} -para activar o desactivar el modo linterna de una unidad de flash sin abrir el dispositivo de cámara. La aplicación no tiene propiedad exclusiva de la unidad de flash ni del dispositivo de cámara. - El modo linterna se desactiva y deja de estar disponible cuando la cámara no se encuentra disponible o cuando otros recursos de la cámara que mantienen la linterna encendida dejan de estar disponibles. - - Otras aplicaciones también pueden llamar a {@code setTorchMode()} -para desactivar el modo linterna. Cuando se cierra la última aplicación que activó el modo linterna, este modo se desactiva. -
- -Si desea registrar una devolución de llamada para recibir una notificación sobre el estado del modo linterna, llame al método -{@code CameraManager.registerTorchCallback()}. La primera vez que se registra la devolución de llamada, se llama inmediatamente con el estado del modo linterna de todos los dispositivos de cámara que se conocen actualmente y que tengan una unidad de flash. - - Si el modo linterna se activa o desactiva correctamente, se invoca al método -{@code CameraManager.TorchCallback.onTorchModeChanged()}.
- -API de reprocesamiento
-La API {@link android.hardware.camera2 Camera2} se extiende para admitir el reprocesamiento de imágenes privadas de formato opaco y YUV. - Su aplicación determina si las capacidades de reprocesamiento se encuentran disponibles vía {@code CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES}. - Si un dispositivo admite el reprocesamiento, usted puede crear una sesión de captura de cámara reprocesable llamando a -{@code CameraDevice.createReprocessableCaptureSession()} y puede crear solicitudes para el reprocesamiento de búferes de entrada. - -
- -Utilice la clase {@code ImageWriter} para conectar el flujo del búfer de entrada a la entrada de reprocesamiento de la cámara. - Para obtener un búfer vacío, siga el modelo de programación que se indica a continuación:
- --
-
- Llame al método {@code ImageWriter.dequeueInputImage()}. -
- Complete los datos en el búfer de entrada. -
- Envíe el búfer a la cámara llamando al método {@code ImageWriter.queueInputImage()}. -
Si está utilizando un objeto {@code ImageWriter} junto con una imagen -{@code android.graphics.ImageFormat.PRIVATE}, su aplicación no puede acceder a los datos de la imagen de forma directa. - En cambio, pase la imagen {@code ImageFormat.PRIVATE} directamente a -{@code ImageWriter} llamando al método {@code ImageWriter.queueInputImage()} sin ninguna copia del búfer. -
- -La clase {@code ImageReader} ahora admite secuencias de imagen de formato {@code android.graphics.ImageFormat.PRIVATE}. - Este soporte le permite que su aplicación mantenga una cola de imagen circular de imágenes de salida -{@code ImageReader}, seleccione una o más imágenes y las envíe a -{@code ImageWriter} para el reprocesamiento de la cámara.
- -Características de Android for Work
-Esta versión preliminar incluye las siguientes API nuevas para Android for Work:
--
-
- Controles mejorados para dispositivos corporativos de uso único: El propietario de dispositivo ahora puede controlar las configuraciones que se describen a continuación para mejorar la administración de los dispositivos corporativos de uso único (Corporate-Owned, Single-Use, COSU).
-
-
-
-
-
- Deshabilitar o volver a habilitar la protección de seguridad con el método -{@code DevicePolicyManager.setKeyguardEnabledState()}. -
- Deshabilitar o volver a habilitar la barra de estado (lo que incluye configuraciones rápidas, notificaciones y el gesto de navegación al deslizar el dedo hacia arriba para iniciar Google Now) con el método -{@code DevicePolicyManager.setStatusBarEnabledState()}. - -
- Deshabilitar o volver a habilitar el inicio seguro con la constante {@link android.os.UserManager} -{@code DISALLOW_SAFE_BOOT}. -
- Evitar que se apague la pantalla mientras el dispositivo se encuentra conectado con la constante - {@link android.provider.Settings.Global} {@code STAY_ON_WHILE_PLUGGED_IN}. -
- - Instalación y desinstalación automáticas de aplicaciones por parte del propietario de dispositivo: Un propietario de dispositivo ahora puede instalar y desinstalar aplicaciones de manera automática con las API {@link android.content.pm.PackageInstaller} -, independiente de Google Play for Work. - Ahora, puede aprovisionar los dispositivos a través de un propietario de dispositivo que obtiene e instala aplicaciones sin interacción del usuario. - Esta característica es útil para habilitar el aprovisionamiento con un toque de quioscos u otros dispositivos similares sin activar una cuenta de Google. - -
- Acceso automático al certificado de empresa: Ahora cuando una aplicación llama a -{@link android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity,android.security.KeyChainAliasCallback,java.lang.String[],java.security.Principal[],java.lang.String,int,java.lang.String) choosePrivateKeyAlias()}, antes de que se indique al usuario que seleccione un certificado, el propietario de dispositivo o perfil puede llamar al método {@code DeviceAdminReceiver.onChoosePrivateKeyAlias()} para proporcionar el alias de forma automática a la aplicación que realiza la solicitud. - - - Esta característica le permite conceder a las aplicaciones gestionadas acceso a certificados sin interacción del usuario. - -
- Aceptación automática de actualizaciones del sistema: Al configurar una directiva de actualización del sistema con -{@code DevicePolicyManager.setSystemUpdatePolicy()}, el propietario de dispositivo ahora puede aceptar automáticamente una actualización del sistema, por ejemplo, en el caso de un dispositivo de quiosco, o posponer la actualización y evitar que el usuario la ejecute durante un plazo de hasta 30 días. - - Además, un administrador puede configurar un período de tiempo diario en el que se debe ejecutar una actualización, por ejemplo, durante las horas en que no se usa el dispositivo de quiosco. - Cuando hay una actualización del sistema disponible, el sistema verifica si la aplicación Work Policy Controller definió una directiva de actualización del sistema y se comporta según corresponda. - - - -
-
-Instalación delegada de certificados: Ahora, un propietario de dispositivo o perfil puede concederle a una aplicación de terceros la capacidad de llamar a estas API de administración de certificados {@link android.app.admin.DevicePolicyManager}:
-
-
-
-
-
- {@link android.app.admin.DevicePolicyManager#getInstalledCaCerts(android.content.ComponentName) -getInstalledCaCerts()} -
- {@link android.app.admin.DevicePolicyManager#hasCaCertInstalled(android.content.ComponentName,byte[]) -hasCaCertInstalled()} -
- {@link android.app.admin.DevicePolicyManager#installCaCert(android.content.ComponentName,byte[]) -installCaCert()} -
- {@link android.app.admin.DevicePolicyManager#uninstallCaCert(android.content.ComponentName,byte[]) -uninstallCaCert()} -
- {@link android.app.admin.DevicePolicyManager#uninstallAllUserCaCerts(android.content.ComponentName) -uninstallAllUserCaCerts()} -
- {@link android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName,java.security.PrivateKey,java.security.cert.Certificate,java.lang.String) -installKeyPair()} -
- - Protección de restablecimiento de la configuración predeterminada de fábrica: Al aprovisionar a un propietario de dispositivo, ahora podrá configurar parámetros para desbloquear la protección de restablecimiento de la configuración predeterminada de fábrica (Factory Reset Protection, FRP) configurando el paquete
-{@code DeviceManagerPolicy.EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS}.
- Una aplicación de Programador NFC puede proporcionar estos parámetros después del restablecimiento de un dispositivo para desbloquear la FRP y aprovisionar al dispositivo sin requerir la cuenta de Google configurada previamente.
-
- Si no modifica estos parámetros, la FRP se conserva y evita que el dispositivo se active sin las credenciales de Google activadas previamente.
-
-
-
Además, al configurar las restricciones de la aplicación en los servicios de Google Play, los propietarios de dispositivos pueden especificar cuentas de Google alternativas para desbloquear la FRP y reemplazar las que se encuentran activadas en el dispositivo. -
-
-
- - Seguimiento del uso de datos: Ahora, un propietario de dispositivo o perfil puede consultar las estadísticas de uso de datos que se pueden ver en Settings > Data utilizando los nuevos métodos -{@code android.app.usage.NetworkStatsManager}. - A los propietarios de perfiles se les concede automáticamente permiso para consultar los datos del perfil que administran, mientras que los propietarios de dispositivo obtienen acceso a los datos de uso del usuario principal administrado. - - -
- Administración de permisos de tiempo de ejecución:
-
Un propietario de dispositivo o perfil puede configurar una directiva de permisos para todas las solicitudes de tiempo de ejecución de todas las aplicaciones que utilizan -{@code DevicePolicyManager.setPermissionPolicy()}, a fin de pedirle confirmación al usuario para conceder el permiso de manera normal, o bien, para conceder o negar el permiso automáticamente sin notificarlo. - - Si se configura la última directiva, el usuario no puede modificar la selección realizada por el propietario de dispositivo o perfil dentro de la pantalla de permisos de la aplicación en Settings. - -
- - VPN en Settings: Las aplicaciones de la VPN (red privada virtual) ahora se pueden ver en -Settings > More > VPN. Además, las notificaciones que acompañan el uso de la VPN ahora son específicas para la manera en que dicha VPN está configurada. - - Para el propietario de perfil, las notificaciones son específicas dependiendo de si la VPN se configura para un perfil administrado, un perfil personal o ambos. - Para un propietario de dispositivo, las notificaciones son específicas dependiendo de si la VPN se configura para todo el dispositivo. - -
- Notificación del estado del trabajo: Ahora aparecerá un ícono de maletín en la barra de estado siempre que una aplicación del perfil administrado tenga una actividad en primer plano. - Además, si el dispositivo se desbloquea directamente para la actividad de una aplicación del perfil administrado, se mostrará una notificación del sistema para informarle al usuario que se encuentra dentro del perfil de trabajo. - - - -
- Para obtener una vista detallada de todos los cambios de la API en M Developer Preview, consulte el Informe de diferencias de las API. -
diff --git a/docs/html-intl/intl/es/preview/backup/index.jd b/docs/html-intl/intl/es/preview/backup/index.jd deleted file mode 100644 index 7e230836ad5361ae42aca29e37aeb9c9ff9b0cf7..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/es/preview/backup/index.jd +++ /dev/null @@ -1,327 +0,0 @@ -page.title=Copia de seguridad automática para aplicaciones -page.tags=copia de seguridad, recursos de la versión preliminar, androidm -page.keywords=copia de seguridad, copia de seguridad automática, versión preliminar -page.image=images/cards/card-auto-backup_2x.png -@jd:body - -Contenido del documento
- -- A menudo, los usuarios invierten tiempo y esfuerzo significativos para crear datos y configurar preferencias dentro de las aplicaciones. - Preservar los datos de los usuarios en caso de que reemplacen un dispositivo averiado o se actualicen a uno nuevo es una parte importante para garantizar una excelente experiencia del usuario. - Los dispositivos que ejecutan el sistema de la versión preliminar de Android M ayudan a garantizar una buena experiencia para los usuarios en estas circunstancias al realizar automáticamente copias de seguridad de los datos de la aplicación en Google Drive. - - Los datos de la aplicación se restauran automáticamente si un usuario cambia o actualiza un dispositivo. - -
- -- Las copias de seguridad automáticas se habilitan para todas las aplicaciones instaladas en dispositivos que ejecuten la versión preliminar de Android M. No se requiere ningún código de aplicación adicional. - El sistema les proporciona a los usuarios la capacidad de desactivar las copias de seguridad de datos automáticas. - También puede optar por limitar qué datos de su aplicación se incluyen en la copia de seguridad. -
- -- En este documento, se describe el nuevo comportamiento del sistema y el modo de especificar qué datos incluir en la copia de seguridad de la aplicación. - -
- -Información general
- -- Para preservar los datos que su aplicación crea en un dispositivo de usuario, la característica de copia de seguridad automática los carga a la cuenta de Google Drive del usuario y los cifra. - No se aplican cargos para usted ni para el usuario por el almacenamiento de datos y los datos guardados no se consideran al calcular la capacidad máxima de la cuenta personal de Google Drive del usuario. - Durante el período de la versión preliminar de Android M, los usuarios pueden almacenar hasta 25 MB por aplicación de Android. - -
- -- Las copias de seguridad automáticas se realizan cada 24 horas, cuando el dispositivo está inactivo, se está cargando y está conectado a una red Wi-Fi. - Cuando se cumplen estas condiciones, el servicio Backup Manager carga todos los datos de copia de seguridad disponibles a la nube. - Cuando el usuario pasa a un dispositivo nuevo, o desinstala y vuelve a instalar la aplicación de la copia de seguridad, una operación de restauración copia los datos incluidos en la copia de seguridad en el directorio de datos de la aplicación recientemente instalada. - - -
- -- Nota: Si su aplicación utiliza el servicio Android Backup heredado, este nuevo comportamiento no se aplica y el comportamiento de copia de seguridad existente funciona de manera habitual. - - -
- - -Archivos de datos automáticamente excluidos
- -- No todos los datos de la aplicación se deben incluir en la copia de seguridad, como los archivos temporales y los cachés, por lo que el servicio de copias de seguridad automáticas excluye ciertos archivos de datos de manera predeterminada: - -
- --
-
- Archivos de los directorios a los que hacen referencia los métodos {@link android.content.Context#getCacheDir - getCacheDir()} y {@link android.content.ContextWrapper#getCodeCacheDir getCodeCacheDir()} -. - - -
- Archivos ubicados en almacenamiento externo, salvo que residan en el directorio al que hace referencia el método - {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} -. - - -
- Archivos ubicados en el directorio a los que hace referencia el método - {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()}. - -
Configuración de la copia de seguridad de datos
- -- Las copias de seguridad se realizan para los datos creados por cualquier aplicación instalada en un dispositivo con la versión preliminar de Android M, excepto en el caso de los archivos excluidos automáticamente que se mencionaron en la sección anterior. - Usted puede limitar y configurar aún más los datos que se incluyen en la copia de seguridad de su aplicación y, para ello, debe utilizar configuraciones en el manifiesto de su aplicación. - -
- -Cómo incluir o excluir datos
- -- De acuerdo con los datos que su aplicación necesita y el modo en que usted guarda estos datos, es posible que tenga que definir reglas específicas para incluir o excluir ciertos archivos o directorios. - El servicio de copias de seguridad automáticas admite la configuración de estas reglas de copias de seguridad a través del uso de un archivo de configuración XML y el manifiesto de la aplicación. - - En el manifiesto de la aplicación, puede especificar un archivo de configuración de esquema de la copia de seguridad, como se muestra en el siguiente ejemplo: - -
- --<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="MNC"/> - <uses-sdk android:targetSdkVersion="MNC"/> - <app ... - android:fullBackupContent="@xml/mybackupscheme"> - </app> - ... -</manifest> -- -
- En este código de ejemplo, el atributo android:fullBackupContent
especifica un archivo XML, ubicado en el directorio res/xml/
del proyecto de desarrollo de su aplicación, con el nombre mybackupscheme.xml
.
-
- Este archivo de configuración incluye reglas sobre los archivos para los que se realiza una copia de seguridad.
- El siguiente código de ejemplo muestra un archivo de configuración que excluye un archivo específico de las copias de seguridad:
-
-
-<?xml version="1.0" encoding="utf-8"?> -<full-backup-content> - <exclude domain="database" path="device_info.db"/> -</full-backup-content> -- -
- Este ejemplo de configuración de copia de seguridad solo excluye un archivo específico de base de datos que no se incluirá en la copia de seguridad. - Todos los demás archivos se incluirán en la copia de seguridad. -
- -Sintaxis de la configuración de copia de seguridad
- -- La configuración del servicio de copias de seguridad le permite especificar qué archivos incluir en la copia de seguridad o excluir de ella. - La sintaxis del archivo de configuración XML de copia de seguridad de datos es la siguiente: -
- --<full-backup-content> - <include domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> - <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> -</full-backup-content> -- -
- Los siguientes elementos y atributos le permiten especificar qué archivos incluir de la copia de seguridad o excluir de ella: - -
- --
-
-
-
<include>
. Use este elemento si desea especificar un conjunto de recursos para realizar una copia de seguridad, en lugar de hacer que el sistema realice una copia de seguridad de todos los datos de su aplicación de forma predeterminada. - Cuando especifica una etiqueta<include>
, el sistema realiza una copia de seguridad solo de los recursos que se especifican - con este elemento. - -
-
- -
-
<exclude>
. Use este elemento para especificar un conjunto de recursos para excluir de la copia de seguridad. - El sistema realizará una copia de seguridad de todos los datos de su aplicación, excepto de los recursos que se especifican con este elemento. - -
-
- -
-
domain.
El tipo de recurso que desea incluir en la copia de seguridad o excluir de esta. Entre los valores válidos que usted puede especificar para este atributo se incluyen los siguientes: - -
-
- -
-
-
-
-
-
root
. Especifica que el recurso se encuentra en el directorio raíz de la aplicación. -
-
- -
-
file
. Corresponde a un recurso del directorio devuelto por el método -{@link android.content.Context#getFilesDir getFilesDir()}. -
-
- -
-
database
. Corresponde a una base de datos devuelta por el método -{@link android.content.Context#getDatabasePath getDatabasePath()} o mediante el uso de la clase -{@link android.database.sqlite.SQLiteOpenHelper}. -
-
- -
-
sharedpref
. Corresponde a un objeto {@link android.content.SharedPreferences} devuelto por el método {@link android.content.Context#getSharedPreferences getSharedPreferences()} -. - -
-
- -
-
external
. Especifica que el recurso se encuentra en almacenamiento externo y corresponde a un archivo del directorio devuelto por el método -{@link android.content.Context#getExternalFilesDir getExternalFilesDir()}. - -
-
- -
-
path
. La ruta de archivo para un recurso que desea incluir en la copia de seguridad o excluir de esta. - -
-
- -
-
Cómo prohibir las copias de seguridad de datos
- -
- Puede optar por impedir que se realicen copias de seguridad automáticas de los datos de su aplicación y, para ello, debe configurar el atributo
-android:allowBackup
en false
en el elemento de la aplicación de su manifiesto.
- Esta configuración se ilustra en el siguiente código de ejemplo:
-
-<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="MNC"/> - <uses-sdk android:targetSdkVersion="MNC"/> - <app ... - android:allowBackup="false"> - </app> - ... -</manifest> -- - -
Pruebas de la configuración de copia de seguridad
- -- Cuando haya creado una configuración de copia de seguridad, debe probarla para garantizar que su aplicación guarde los datos y se pueda restaurar correctamente. - -
- - -Cómo habilitar un registro de copias de seguridad
- -- Para ayudar a determinar la manera en que la característica de copia de seguridad está analizando su archivo XML, habilite el registro antes de realizar una copia de seguridad de prueba: - -
- --$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE -- -
Cómo probar la copia de seguridad
- -Para ejecutar manualmente una copia de seguridad, primero debe inicializar Backup Manager llamando al siguiente comando: - -
- --$ adb shell bmgr run -- -
- Luego, realice una copia de seguridad de su aplicación manualmente utilizando el comando que se indica a continuación y especificando el nombre de paquete para su aplicación como el parámetro <PACKAGE>
:
-
-
-$ adb shell bmgr fullbackup <PACKAGE>- - -
Cómo probar la restauración
- -
- Para iniciar una restauración manualmente después de realizar una copia de seguridad de los datos, llame al comando que se indica a continuación y especifique el nombre de paquete para su aplicación como el parámetro <PACKAGE>
:
-
-
-$ adb shell bmgr restore <PACKAGE> -- -
- Advertencia: Esta acción detiene la aplicación y borra sus datos antes de realizar la operación de restauración. - -
- -- Para iniciar el proceso de restauración de su aplicación, desinstale su aplicación y vuelva a instalarla. Los datos de la aplicación se restaurarán automáticamente desde la nube una vez que se complete la instalación. - -
- - -Solución de problemas de las copias de seguridad
- -- Si tiene algún problema, borre los datos de la copia de seguridad y los metadatos asociados; para hacerlo, desactive y vuelva a activar la copia de seguridad en Settings > Backup, restablezca el dispositivo a la configuración predeterminada de fábrica o llame al siguiente comando: - - -
- -$ adb shell bmgr wipe <TRANSPORT> <PACKAGE>- -
- El valor <TRANSPORT>
debe estar precedido por com.google.android.gms
.
- Para obtener una lista de transportes, llame al siguiente comando:
-
$ adb shell bmgr list transports- -
Problemas conocidos
- -Los siguientes son problemas conocidos del servicio de copias de seguridad automáticas:
- --
-
- Google Cloud Messaging: En las aplicaciones que utilizan Google Cloud Messaging para notificaciones push, existe un problema conocido en el que al realizar una copia de seguridad de la Id. de registro devuelta por el registro de Google Cloud Messaging, se pueden romper las notificaciones push de la aplicación restaurada. Es importante realizar una consulta a la API para obtener una nueva Id. de registro después de realizar la instalación en un dispositivo nuevo, lo que no sucede si se realizó una copia de seguridad de la Id. de registro anterior. - - - - - Para evitar esta situación, excluya la Id. de registro del conjunto de archivos para incluir en la copia de seguridad. - - -
Contenido del documento
- --
-
- Permisos de tiempo de ejecución -
- Optimizaciones de ahorro de energía
-
-
-
- Doze -
- App Standby -
- - Dispositivos de almacenamiento adoptables -
- Eliminación del cliente HTTP de Apache -
- Cambios en AudioManager -
- Selección de texto -
- Cambios en Android Keystore -
- Cambios en las funciones de red y Wi-Fi -
- Cambios en el servicio de cámara -
- Tiempo de ejecución de ART -
- Validación de APK -
- Cambios en Android for Work -
Diferencias de las API
- - - -Consulte también
- - -Además de nuevas características y capacidades, M Developer Preview incluye diversos cambios en el sistema y cambios en los comportamientos de la API. - En este documento, se destacan algunos de los cambios principales que debe comprender y justificar en sus aplicaciones. -
- -Si publicó anteriormente una aplicación para Android, tenga en cuenta que su aplicación podría verse afectada por estos cambios en la plataforma. -
- -Permisos de tiempo de ejecución -
Esta versión preliminar introduce un nuevo modelo de permisos en el que los usuarios ahora pueden administrar directamente los permisos de la aplicación en tiempo de ejecución. - Este modelo les proporciona a los usuarios mayor visibilidad y control sobre los permisos y, al mismo tiempo, simplifica los procesos de instalación y actualización automática para los desarrolladores de aplicaciones. Los usuarios pueden conceder o revocar permisos de forma individual para las aplicaciones instaladas. - -
- -En sus aplicaciones que tienen como destino la versión preliminar de Android M, asegúrese de comprobar y solicitar los permisos en tiempo de ejecución. - Para determinar si se concedió un permiso a su aplicación, llame al nuevo método {@code Context.checkSelfPermission()}. - Para solicitar un permiso, llame al nuevo método -{@code Activity.requestPermission()}. Incluso si su aplicación no tiene como destino la versión preliminar de Android M, debería probar su aplicación de acuerdo con el nuevo modelo de permisos. -
- -Para obtener detalles sobre la compatibilidad del nuevo modelo de permisos en su aplicación, consulte la página - -Permisos de la versión preliminar para desarrolladores. Para obtener consejos sobre cómo evaluar el impacto en su aplicación, consulte la Guía de prueba. -
- -Optimizaciones de ahorro de energía
-Esta versión preliminar introduce nuevas optimizaciones de ahorro de energía para aplicaciones y dispositivos inactivos.
- -Doze
-Si un dispositivo está desconectado y permanece quieto con la pantalla apagada durante un período determinado, pasará al modo Doze, en el que el dispositivo intenta mantener el sistema en estado de suspensión. - En este modo, los dispositivos reanudan periódicamente el funcionamiento normal durante períodos breves, de manera que la aplicación se pueda sincronizar y el sistema pueda realizar las operaciones pendientes. - -
- -Durante el modo Doze, se aplican las siguientes restricciones a sus aplicaciones:
--
-
- Se deshabilita el acceso a la red, salvo que su aplicación reciba una señal de prioridad alta de Google Cloud Messaging (envío de mensajes a través de la nube de Google). - -
- Se ignoran los Wakelocks. -
- Se deshabilitan las alarmas programadas con la clase {@link android.app.AlarmManager}, salvo las alarmas que haya configurado con el método {@link android.app.AlarmManager#setAlarmClock setAlarmClock()} -y con {@code AlarmManager.setAndAllowWhileIdle()}. - -
- No se realiza la detección de Wi-Fi. -
- No se permite la ejecución de sincronizaciones ni trabajos para sus adaptadores de sincronización y {@link android.app.job.JobScheduler}. - -
Al salir del modo Doze, el dispositivo ejecuta los trabajos y las sincronizaciones pendientes.
-Para probar esta característica, conecte un dispositivo que esté ejecutando la versión preliminar de Android M a su equipo de desarrollo y llame a los siguientes comandos: - -
--$ adb shell dumpsys battery unplug -$ adb shell dumpsys deviceidle step -$ adb shell dumpsys deviceidle -h --
Nota: La próxima versión de - -Google Cloud Messaging le permite designar mensajes de prioridad alta. - Si su aplicación recibe mensajes de GCM de prioridad alta, se le concede un breve acceso a la red, incluso cuando el dispositivo se encuentra en modo Doze. - -
- -Consulte la -Guía de prueba para obtener consejos sobre cómo probar el modo Doze en su aplicación. -
- -App Standby
-Con esta versión preliminar, el sistema puede determinar que las aplicaciones se encuentran inactivas cuando no están en uso activo. - La aplicación se considera inactiva después de un cierto período, salvo que el sistema detecte alguna de las siguientes señales: -
- --
-
- El usuario inicia explícitamente la aplicación. -
- La aplicación actualmente tiene un proceso en primer plano (ya sea como una actividad o un servicio en primer plano, o en uso por parte de otra actividad u otro servicio en primer plano). - -
- La aplicación genera una notificación que los usuarios ven en la pantalla de bloqueo o en la bandeja de notificaciones. - -
- El usuario solicita explícitamente que la aplicación esté exenta de optimizaciones mediante las Configuraciones. - -
Si el dispositivo está desconectado, las aplicaciones que se consideren inactivas tendrán deshabilitado el acceso a la red y se suspenderán sus sincronizaciones y trabajos. - Cuando el dispositivo se conecte a un sistema de alimentación, estas aplicaciones se podrán conectar a la red y podrán ejecutar los trabajos y las sincronizaciones pendientes. - Si el dispositivo queda inactivo durante períodos prolongados, las aplicaciones inactivas pueden acceder a la red aproximadamente una vez al día. -
- -Para probar esta característica, conecte un dispositivo que esté ejecutando la versión preliminar de Android M a su equipo de desarrollo y llame a los siguientes comandos: - -
--$ adb shell dumpsys battery unplug -$ adb shell am set-idle <packageName> true -$ adb shell am set-idle <packageName> false -$ adb shell am get-idle <packageName> -- -
Nota: La próxima versión de - -Google Cloud Messaging (GCM) le permite designar mensajes de prioridad alta. - Si su aplicación recibe mensajes de GCM de prioridad alta, se le concede un breve acceso a la red, incluso cuando la aplicación está inactiva. - -
- -Consulte la -Guía de prueba para obtener consejos sobre cómo probar el modo App Standby en sus aplicaciones. -
- -Dispositivos de almacenamiento adoptables
--Con esta versión preliminar, los usuarios pueden adoptar dispositivos de almacenamiento externo, como tarjetas SD. Al adoptar un dispositivo de almacenamiento externo, el dispositivo se cifra y se formatea para que actúe como un elemento de almacenamiento interno. - Esta característica les permite a los usuarios mover tanto las aplicaciones como los datos privados de esas aplicaciones entre dispositivos de almacenamiento. - Al mover aplicaciones, el sistema respeta la preferencia -{@code android:installLocation} -del manifiesto. -
- -Si su aplicación accede a las API o a los campos que se indican a continuación, tenga en cuenta que las rutas de archivo que devuelven se modificarán dinámicamente cuando la aplicación se mueva entre dispositivos de almacenamiento interno y externo. Al crear rutas de archivo, lo más recomendable es que siempre llame a estas API de forma dinámica. No use rutas de archivo codificadas de forma rígida ni continúe usando rutas de archivo completas que se hayan creado anteriormente. - - -
- --
-
- Métodos {@link android.content.Context}:
-
-
-
- {@link android.content.Context#getFilesDir() getFilesDir()} -
- {@link android.content.Context#getCacheDir() getCacheDir()} -
- {@link android.content.Context#getCodeCacheDir() getCodeCacheDir()} -
- {@link android.content.Context#getDatabasePath(java.lang.String) getDatabasePath()} -
- {@link android.content.Context#getDir(java.lang.String,int) getDir()} -
- {@link android.content.Context#getNoBackupFilesDir() getNoBackupFilesDir()} -
- {@link android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()} -
- {@link android.content.Context#getPackageCodePath() getPackageCodePath()} -
- {@link android.content.Context#getPackageResourcePath() getPackageResourcePath()} -
- - Campos {@link android.content.pm.ApplicationInfo}:
-
-
-
- {@link android.content.pm.ApplicationInfo#dataDir dataDir} -
- {@link android.content.pm.ApplicationInfo#sourceDir sourceDir} -
- {@link android.content.pm.ApplicationInfo#nativeLibraryDir nativeLibraryDir} -
- {@link android.content.pm.ApplicationInfo#publicSourceDir publicSourceDir} -
- {@link android.content.pm.ApplicationInfo#splitSourceDirs splitSourceDirs} -
- {@link android.content.pm.ApplicationInfo#splitPublicSourceDirs splitPublicSourceDirs} -
-
Para depurar esta característica en la versión preliminar para desarrolladores, puede habilitar la opción de adoptar una unidad USB que esté conectada a un dispositivo Android mediante un cable USB On-The-Go (OTG) y para habilitarla puede ejecutar el siguiente comando: -
- --$ adb shell sm set-force-adoptable true -- -
Eliminación del cliente HTTP de Apache
-Esta versión preliminar elimina el soporte del cliente HTTP de Apache. Si su aplicación utiliza este cliente y tiene como destino Android 2.3 (API de nivel 9) o una versión posterior, use, en su lugar, la clase {@link java.net.HttpURLConnection}. - - Esta API es más eficaz porque reduce el uso de la red mediante compresión y almacenamiento de respuesta en caché transparentes, y minimiza el consumo de energía. - Para continuar utilizando las API HTTP de Apache, primero debe declarar la siguiente dependencia en tiempo de compilación en su archivo {@code build.gradle}: - -
--android { - useLibrary 'org.apache.http.legacy' -} --
Android está migrando de la biblioteca OpenSSL a -BoringSSL -. Si utiliza Android NDK en su aplicación, no vincule bibliotecas criptográficas que no forman parte de la API de NDK, como {@code libcrypto.so} y {@code libssl.so}. - Estas bibliotecas no son API públicas y se pueden modificar o interrumpir sin aviso en todas las versiones y todos los dispositivos. Además, puede exponerse a vulnerabilidades de seguridad. - - En cambio, modifique su código nativo para llamar a las API de criptografía de Java a través de JNI o para vincular estáticamente una biblioteca criptográfica de su elección. - -
- -Cambios en AudioManager
-Ya no se admitirán las funciones de ajustar el volumen de forma directa o silenciar secuencias específicas por medio de la clase {@link android.media.AudioManager} -. El método {@link android.media.AudioManager#setStreamSolo(int,boolean) -setStreamSolo()} es obsoleto, por lo que debe llamar al método -{@code AudioManager.requestAudioFocus()} en su lugar. Del mismo modo, el método -{@link android.media.AudioManager#setStreamMute(int,boolean) setStreamMute()} es obsoleto; en su lugar, llame al método{@code AudioManager.adjustStreamVolume()} y pase los valores de dirección {@code ADJUST_MUTE} o {@code ADJUST_UNMUTE}. - -
- -Selección de texto
- - - -Ahora, cuando los usuarios seleccionen texto en su aplicación, usted puede mostrar acciones de selección de texto, como -cortar, copiar y pegar en una -barra de herramientas flotante. La implementación de la interacción del usuario es similar a la de la barra de acciones contextuales, como se describe en la sección - -Habilitación del modo de acción contextual para vistas individuales. -
- -Si desea implementar una barra de herramientas flotante para selección de texto, realice los siguientes cambios en sus aplicaciones existentes: -
--
-
- En su objeto {@link android.view.View} o {@link android.app.Activity}, cambie sus llamados -{@link android.view.ActionMode} de -{@code startActionMode(Callback)} a {@code startActionMode(Callback, ActionMode.TYPE_FLOATING)}. -
- Tome su implementación existente de {@code ActionMode.Callback} y, en su lugar, haga que sea extendida -{@code ActionMode.Callback2}. -
- Invalide el método {@code Callback2.onGetContentRect()} para proporcionar las coordenadas del objeto {@link android.graphics.Rect} de contenido (como un rectángulo de selección de texto) en la vista. - -
- Si el posicionamiento del rectángulo ya no es válido y este es el único elemento por invalidar, llame al método {@code ActionMode.invalidateContentRect()}. - -
Si utiliza la biblioteca -Android Support Library versión 22.2, tenga en cuenta que las barras de herramientas flotantes no son compatibles con versiones anteriores y AppCompat toma el control de los objetos {@link android.view.ActionMode} de forma predeterminada. - - Esto impide que se muestren las barras de herramientas flotantes. Para permitir la compatibilidad de -{@link android.view.ActionMode} en -{@link android.support.v7.app.AppCompatActivity}, llame a -{@code android.support.v7.app.AppCompatActivity.getDelegate()}, luego llame a -{@code android.support.v7.app.AppCompatDelegate.setHandleNativeActionModesEnabled()} en el objeto -{@link android.support.v7.app.AppCompatDelegate} devuelto y configure el parámetro de entrada como {@code false}. - Esta llamada devuelve el control de los objetos {@link android.view.ActionMode} al marco de trabajo. - En los dispositivos que ejecutan la versión preliminar de Android M, eso permite que el marco de trabajo admita los modos de barras de herramientas flotantes o -{@link android.support.v7.app.ActionBar}, mientras que en los dispositivos anteriores a la versión preliminar de Android M solo se admiten los modos {@link android.support.v7.app.ActionBar}. -
- -Cambios en Android Keystore
-Con esta versión preliminar, el -proveedor de Android Keystore ya no admite DSA. - Aún se admite ECDSA.
- -Las claves que no requieren cifrado de datos estáticos ya no se eliminarán cuando se restablezca o deshabilite la pantalla de bloqueo seguro (por ejemplo, cuando lo haga el usuario o el administrador del dispositivo). - Las claves que requieren el cifrado de datos estáticos se eliminarán durante estos eventos. -
- -Cambios en las funciones de red y Wi-Fi
- -Esta versión preliminar introduce en las API de redes y Wi-Fi los siguientes cambios en los comportamientos.
--
-
- Ahora sus aplicaciones pueden cambiar el estado de los objetos {@link android.net.wifi.WifiConfiguration} solo si usted creó estos objetos. - Usted no puede modificar ni eliminar objetos -{@link android.net.wifi.WifiConfiguration} creados por el usuario o por otras aplicaciones. - -
- -Anteriormente, si una aplicación forzaba al dispositivo a conectarse a una red Wi-Fi específica utilizando -{@link android.net.wifi.WifiManager#enableNetwork(int,boolean) enableNetwork()} con la configuración -{@code disableAllOthers=true}, el dispositivo se desconectaba de otras redes, como los datos móviles. - En esta versión preliminar, el dispositivo ya no se desconectará de otras redes como estas. Si {@code targetSdkVersion} de su aplicación es {@code “20”} o inferior, se anclará a la red Wi-Fi seleccionada. - - Si {@code targetSdkVersion} de su aplicación es {@code “21”} o posterior, use las API de redes múltiples (como -{@link android.net.Network#openConnection(java.net.URL) openConnection()}, -{@link android.net.Network#bindSocket(java.net.Socket) bindSocket()} y el nuevo método -{@code ConnectivityManager.bindProcessToNetwork()}) para garantizar que el tráfico de su red se envíe a la red seleccionada. - - -
Cambios en el servicio de cámara
-En esta versión preliminar, el modelo para acceder a los recursos compartidos en el servicio de cámara se cambió del modelo de acceso anterior “por orden de llegada” a un modelo de acceso en el que se favorecen los procesos de prioridad alta. - - Los cambios en el comportamiento del servicio incluyen los siguientes:
--
-
- El acceso a los recursos del subsistema de la cámara, lo que incluye abrir y configurar un dispositivo de cámara, se concede según la “prioridad” del proceso de la aplicación cliente. - Por lo general, los procesos de la aplicación con actividades en primer plano o visibles para el usuario, reciben una prioridad más alta, lo que hace que el uso y la adquisición de recursos de la cámara sean más dependientes. - - -
- Los clientes con cámara activa para aplicaciones de menor prioridad pueden ser “expulsados” cuando una aplicación de mayor prioridad intenta utilizar la cámara. - En la API {@link android.hardware.Camera} obsoleta, esto hace que se llame al método -{@link android.hardware.Camera.ErrorCallback#onError(int,android.hardware.Camera) onError()} para el cliente expulsado. - - En la API {@link android.hardware.camera2 Camera2}, esto hace que se llame al método -{@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected(android.hardware.camera2.CameraDevice) onDisconnected()} -para el cliente expulsado. -
- En los dispositivos con hardware de cámara correcto, distintos procesos de la aplicación pueden abrir y utilizar de forma independiente dispositivos de cámara separados al mismo tiempo. - Sin embargo, ahora el servicio de cámara detecta y no permite los casos de uso de procesos múltiples, donde el acceso simultáneo genera una degradación considerable del rendimiento o de las capacidades de cualquiera de los dispositivos de cámara abiertos. - - Este cambio puede generar “expulsiones” de clientes de menor prioridad, incluso cuando ninguna otra aplicación esté intentando acceder directamente al mismo dispositivo de cámara. - - - -
- -Cambiar el usuario actual provoca que se expulsen los clientes con cámara activa en las aplicaciones que pertenecen a la cuenta de usuario anterior. - El acceso a la cámara se limita a perfiles de usuario que pertenecen al usuario actual del dispositivo. En la práctica, esto significa que una cuenta de “invitado”, por ejemplo, no podrá abandonar los procesos en ejecución que utilicen el subsistema de la cámara cuando el usuario haya cambiado a otra cuenta. - - - -
Tiempo de ejecución de ART
-El tiempo de ejecución de ART ahora implementa correctamente reglas de acceso para el método -{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()}. Este cambio soluciona el problema que ocurría con Dalvik, que comprobaba las reglas de acceso incorrectamente en las versiones anteriores. Si su aplicación utiliza el método -{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} y usted desea invalidar comprobaciones de acceso, llame al método -{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} con el parámetro de entrada configurado en {@code true}. - - - - Si su aplicación utiliza la -biblioteca AppCompat versión 7 o la -biblioteca RecyclerView versión 7, debe actualizar su aplicación para utilizar las versiones más recientes de estas bibliotecas. - De lo contrario, asegúrese de que las clases personalizadas a las que se haga referencia desde el XML estén actualizadas, de manera que se pueda acceder a sus constructores de clases. -
- -Esta versión preliminar actualiza el comportamiento del vinculador dinámico. El vinculador dinámico ahora entiende la diferencia entre {@code soname} de una biblioteca y su ruta de acceso ( -error público 6670), y ahora se implementa la búsqueda por {@code soname}. - - - Las aplicaciones que anteriormente funcionaban y que tenían entradas {@code DT_NEEDED} incorrectas (generalmente, rutas absolutas en el sistema de archivo del equipo de compilación) pueden generar error al cargarse. -
- -Ahora se implementa correctamente la marca {@code dlopen(3) RTLD_LOCAL}. Tenga en cuenta que -{@code RTLD_LOCAL} es lo predeterminado, por lo que se verán afectadas las llamadas a {@code dlopen(3)} que no utilizaron explícitamente -{@code RTLD_LOCAL} (salvo que su aplicación haya usado {@code RTLD_GLOBAL} explícitamente). Con -{@code RTLD_LOCAL}, los símbolos no estarán disponibles para las bibliotecas cargadas por llamadas posteriores a -{@code dlopen(3)} (a diferencia de lo que sucede al hacer referencia mediante entradas {@code DT_NEEDED}).
- - -Validación de APK
-Ahora la plataforma realiza validaciones más estrictas de APK. El APK se considera dañado si un archivo está declarado en el manifiesto, pero no está presente en el APK en sí. - Si se elimina algún contenido, se debe volver a firmar el APK. -
- -Cambios en Android for Work
-Esta versión preliminar incluye los siguientes cambios en los comportamientos para Android for Work:
--
-
- Contactos de trabajo en contextos personales: Ahora, el registro de llamadas de Google Dialer muestra los contactos de trabajo cuando el usuario ve las llamadas anteriores. Si se configura {@code DevicePolicyManager.setCrossProfileCallerIdDisabled()} en {@code true}, se ocultan los contactos de perfiles de trabajo en el registro de llamadas de Google Dialer. - - - Los contactos de trabajo se pueden mostrar junto con los contactos personales en los dispositivos a través de Bluetooth solo si usted configura {@code DevicePolicyManager.setBluetoothContactSharingDisabled()} en {@code false}. - - De forma predeterminada, se configura en {@code true}. - - -
- Eliminación de configuraciones de Wi-Fi: Las configuraciones de Wi-Fi agregadas por un propietario de perfil (por ejemplo, al llamar al método -{@link android.net.wifi.WifiManager#addNetwork(android.net.wifi.WifiConfiguration) -addNetwork()}) ahora se borran si se elimina ese perfil de trabajo. - -
- Bloqueo de configuraciones de Wi-Fi: El usuario ya no puede modificar ni eliminar las configuraciones de Wi-Fi creadas por un propietario activo del dispositivo. - El usuario aún puede crear y modificar sus propias configuraciones de Wi-Fi, siempre que no se haya definido la constante {@link android.os.UserManager} -{@link android.os.UserManager#DISALLOW_CONFIG_WIFI} para ese usuario. - -
- Descarga de Work Policy Controller mediante la incorporación de una cuenta de Google: Cuando una cuenta de Google que requiere gestión a través de una aplicación de Work Policy Controller (WPC) se agrega a un dispositivo fuera de un contexto administrado, el flujo de incorporación de la cuenta ahora le pide al usuario que instale el WPC apropiado. Este comportamiento también se aplica a las cuentas agregadas mediante -Settings > Accounts en el asistente para instalación inicial del dispositivo. - - - -
- Cambios en comportamientos específicos de la API DevicePolicyManager:
-Llamar al método {@link android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName,boolean) setCameraDisabled()}
-afecta la cámara solo del usuario que lo llama; llamarlo desde el perfil administrado no afecta las aplicaciones de cámara que se ejecutan en el usuario principal.
- Asimismo, el método
-{@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,int) setKeyguardDisabledFeatures()}
-ahora se encuentra disponible para propietarios de perfiles, además de propietarios de dispositivos. Un propietario de perfil puede configurar las siguientes restricciones de protección de seguridad:
-
-
-
-
- {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} y - {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_FINGERPRINT}, que afectan las configuraciones de protección de seguridad para el usuario primario del perfil. - -
- {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, que solo afecta las notificaciones generadas por aplicaciones en el perfil administrado. - -
-
Antes de descargar e instalar los componentes del SDK de la versión preliminar de Android, debe aceptar los términos y las condiciones que se describen a continuación. -
- -Términos y condiciones
- -Contenido del documento
- - -Legacy downloads
- -- El SDK de la versión preliminar de Android M incluye herramientas de desarrollo, archivos de sistema de Android y archivos de biblioteca que lo ayudarán a probar su aplicación y las nuevas API que se incluirán en la próxima versión de la plataforma. - En este documento, se describe la manera de obtener los componentes que se pueden descargar de la versión preliminar para probar su aplicación. - -
- - -Android 6.0 SDK
- -- El SDK de la versión preliminar se encuentra disponible para descargarlo a través del Administrador de SDK de Android. Para obtener más información sobre cómo descargar y configurar el SDK de la versión preliminar, consulte la sección Configurar el SDK de la versión preliminar. - -
- - -Documentación para desarrolladores
- -- El paquete de descarga de documentación para desarrolladores brinda información detallada de referencia sobre las API y un informe de diferencias de las API para la versión preliminar. -
- -Description | -Download / Checksums | -
---|---|
Android M Preview 3 Developer Docs |
- m-preview-3-developer-docs.zip - MD5: d99b14b0c06d31c8dfecb25072654ca3 - SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1 - |
-
Imágenes del sistema de hardware
- -- Estas imágenes del sistema le permiten instalar una versión preliminar de la plataforma en un dispositivo físico para realizar pruebas. - Al configurar un dispositivo con una de estas imágenes, puede instalar y probar su aplicación para ver cómo funciona en la próxima versión de la plataforma. - El proceso de instalación de una imagen del sistema en un dispositivo elimina todos los datos del dispositivo, por lo que debe hacer una copia de seguridad de los datos antes de instalar una imagen del sistema. - - -
- -- Advertencia: Las siguientes imágenes del sistema de Android son versiones preliminares y están sujetas a cambios. El uso que haga de estas imágenes del sistema se rige por el Contrato de licencia de la versión preliminar del SDK de Android. - Las imágenes del sistema de la versión preliminar de Android no son versiones estables y pueden contener errores y defectos que pueden generar daños en sus sistemas informáticos, dispositivos y datos. - - Las imágenes del sistema de la versión preliminar de Android no se someten a las mismas pruebas que el OS de fábrica y podrían hacer que el teléfono, y las aplicaciones y los servicios instalados dejen de funcionar. - - -
- -Device | -Download / Checksums | -
---|---|
Nexus 5 (GSM/LTE) "hammerhead" |
- hammerhead-MPA44I-preview-2ebbc049.tgz - MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb - SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3 - |
-
Nexus 6 "shamu" |
- shamu-MPA44I-preview-62b9c486.tgz - MD5: ac6e58da86125073d9c395257fd42664 - SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff - |
-
Nexus 9 "volantis" |
- volantis-MPA44I-preview-5c30a6e2.tgz - MD5: 7f83768757913d3fea945a661020d185 - SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699 - |
-
Nexus Player "fugu" |
- fugu-MPA44I-preview-2860040a.tgz - MD5: 438da8d37da9e341a69cfb16a4001ac5 - SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98 - |
-
Instalar una imagen en un dispositivo
- -- Si desea utilizar una imagen del dispositivo para realizar pruebas, debe instalarla en un dispositivo compatible. Siga las instrucciones que se ofrecen a continuación para instalar una imagen del sistema: - -
- --
-
- Descargue y descomprima uno de los paquetes de imágenes del sistema que se enumeran aquí. -
- Realice una copia de seguridad de los datos del dispositivo que desee conservar. -
- Siga las instrucciones que se describen en el sitio developers.google.com/android - para actualizar la imagen en su dispositivo. - -
- Nota: Cuando haya actualizado un dispositivo de desarrollo con la imagen del sistema de la versión preliminar, se actualizará automáticamente con la próxima versión preliminar a través de actualizaciones OTA. - -
- -Restablecer las especificaciones de fábrica en un dispositivo
- -- Si desea desinstalar la versión preliminar y restablecer las especificaciones de fábrica en un dispositivo, visite el sitio developers.google.com/android y descargue la imagen con la que desea actualizar su dispositivo. - - Siga las instrucciones que se describen en esa página para actualizar la imagen en su dispositivo. - -
- -Contenido del documento
- -- El sistema Android Intent es un mecanismo flexible para permitir a las aplicaciones controlar contenido y solicitudes. - Es posible que múltiples aplicaciones declaren modelos URI coincidentes en sus filtros de intento. Cuando un usuario hace clic en un vínculo web que no tiene un controlador de inicio predeterminado, la plataforma puede mostrar un diálogo para que el usuario seleccione una opción de una lista de aplicaciones que han declarado filtros de intento coincidentes. - - -
- -- Android M Developer Preview ofrece soporte para los vínculos de la aplicación, lo que mejora los controles de vínculos existentes al permitir a los desarrolladores de la aplicación asociar una aplicación con un dominio web propio. - Cuando los desarrolladores crean esta asociación, la plataforma puede determinar automáticamente la aplicación predeterminada utilizada para controlar un vínculo web particular y omitir el paso de solicitarles esta información a los usuarios. - - -
- - -Declarar una asociación de sitio web
- -- Los propietarios de un sitio web deben declarar las asociaciones con las aplicaciones a fin de establecer el vínculo de una aplicación. El propietario del sitio declara la relación con una aplicación al alojar un archivo JSON, denominado {@code statements.json}, en la ubicación conocida del domino: - - -
- -http://<domain>:<optional port>/.well-known/statements.json- -
- Nota: - Durante el período de M Developer Preview, el archivo JSON se verifica vía el protocolo http. Para la versión oficial de la plataforma, el archivo se verifica mediante el protocolo https cifrado. - -
- -- Este archivo JSON indica la aplicación Android que se debe utilizar como el controlador predeterminado para las URL de este dominio. - Identifica la aplicación según estos campos: -
- --
-
- {@code package_name}: El nombre de paquete declarado en el manifiesto de la aplicación. - -
- {@code sha256_cert_fingerprints}: La huella dactilar SHA256 del certificado de firma de su aplicación.
- Puede usar la herramienta Keytool de Java para generar la huella dactilar mediante el siguiente comando:
-
keytool -list -v -keystore my-release-key.keystore
-
-
- El siguiente listado de archivo muestra un ejemplo de los contenidos y del formato de un archivo -{@code statements.json}: -
- --[{ - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "<package name>", - "sha256_cert_fingerprints": ["6C:EC:C5:0E:34:AE....EB:0C:9B"] - } -}] -- - -
Solicitar verificación del vínculo de la aplicación
- -- Una aplicación puede solicitar que la plataforma verifique automáticamente cualquier vínculo de aplicación definido por los nombres de host en los elementos de datos de sus filtros de intento, comparando con los archivos {@code statements.json} alojados en los respectivos dominios web. - - Para solicitar la verificación del vínculo de la aplicación, agregue un atributo {@code android:autoVerify} a cada filtro de intento deseado en el manifiesto, como se muestra en el siguiente fragmento de código de manifiesto: - - -
- --<activity ...> - <intent-filter android:autoVerify="true"> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="http" android:host="www.android.com" /> - <data android:scheme="https" android:host="www.android.com" /> - </intent-filter> -</activity> -- -
- Cuando el atributo {@code android:autoVerify} está presente en un manifiesto de aplicación, la plataforma intenta verificar los vínculos de la aplicación al instalar la aplicación. - Si la plataforma no puede verificar exitosamente los vínculos de la aplicación, la aplicación no se configura como la aplicación preferida para controlar los vínculos web. - La próxima vez que un usuario abra uno de estos vínculos, la plataforma recurrirá a mostrar al usuario un diálogo. - - -
- -- Nota: Durante la prueba, existe la posibilidad de un falso positivo si la verificación falla, pero el usuario ha habilitado explícitamente la aplicación para que abra los vínculos compatibles sin preguntar, utilizando la aplicación de Configuraciones del sistema. En este caso, no se muestra el diálogo y el vínculo se dirige directamente a su aplicación, pero solo debido a la configuración del usuario y no porque la verificación se haya realizado correctamente. - - - -
- - -Gestionar las configuraciones del vínculo de la aplicación
- -- Los usuarios pueden cambiar las configuraciones del vínculo de la aplicación de manera que las URL se controlen como ellos lo prefieran. Puede revisar y gestionar los vínculos de la aplicación en la aplicación de Configuraciones del sistema, en Settings > Apps > App Info > Open by default. - - -
diff --git a/docs/html-intl/intl/es/preview/features/runtime-permissions.jd b/docs/html-intl/intl/es/preview/features/runtime-permissions.jd deleted file mode 100644 index ce94f5bbe3b59e9476f9bd114ef82542a8133d31..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/es/preview/features/runtime-permissions.jd +++ /dev/null @@ -1,794 +0,0 @@ -page.title=Permisos -page.tags=previewresources, androidm -page.keywords=permissions, runtime, preview -page.image={@docRoot}preview/features/images/permissions_check.png -@jd:body - - -Quickview
--
-
- Si su aplicación tiene como destino el SDK de la versión preliminar de Android M, se solicitará a los usuarios que concedan permisos durante el tiempo de ejecución, en lugar de durante la instalación. - -
- Los usuarios pueden cancelar los permisos en cualquier momento desde la pantalla Settings de la aplicación. - -
- La aplicación necesita controlar los permisos cada vez que se ejecuta. - -
Contenido del documento
- - - - - -- M Developer Preview introduce un nuevo modelo de permisos de la aplicación que facilita a los usuarios el proceso de instalación y actualización de aplicaciones. - Si una aplicación que se ejecuta en la versión preliminar de Android M es compatible con el nuevo modelo de permisos, el usuario no tiene que conceder ningún permiso al instalar o actualizar la aplicación. En su lugar, la aplicación solicitará los permisos a medida que los vaya necesitado y el sistema mostrará al usuario un diálogo en el que le solicitará los permisos necesarios. - - - - -
- -- Si la aplicación es compatible con el nuevo modelo de permisos, podrá instalarse y ejecutarse en los dispositivos con versiones anteriores de Android, utilizando el modelo de permisos anterior en esos dispositivos. - - -
- -- Información general -
- -- En M Developer Preview, la plataforma introduce un nuevo modelo -de permisos de la aplicación. A continuación, se presenta un resumen de los componentes principales de este nuevo modelo: -
- --
-
- - Declaración de los permisos: Al igual que en las plataformas anteriores de Android, la aplicación declara todos los permisos que necesita en el manifiesto. - - - -
-
- Grupos de permisos: Según su función, los permisos se dividen en
-grupos de permisos. Por ejemplo, el grupo de permisos
-
CONTACTS
contiene permisos para leer y escribir los contactos y la información de perfil del usuario. - -
-
- -
-
Permisos limitados concedidos durante la instalación: Cuando el usuario instala o actualiza la aplicación, el sistema le concede a la aplicación todos los permisos que la aplicación solicita que corresponden a {@link - android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL}. - - - Por ejemplo, los permisos para la alarma y los permisos de intento corresponden a {@link - android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL}, por lo que se conceden automáticamente durante la instalación. - -
- -El sistema puede concederle a la aplicación permisos de firma y de sistema, como se especifica en la sección Permisos de firma y de sistema de la aplicación. - - Al usuario no se le solicitará conceder ningún permiso durante la instalación. -
-
-
- - - Solicitud de permisos al usuario durante el tiempo de ejecución: Cuando la aplicación solicita un permiso, el sistema le muestra al usuario un diálogo y luego llama a la función de devolución de llamada de la aplicación para notificarle si el permiso se otorgó. - - Si el usuario concede un permiso, la aplicación recibe todos los permisos del área funcional de dicho permiso, los cuales fueron declarados en el manifiesto de la aplicación. - - - - -
- Este modelo de permisos cambia la forma en la que la aplicación se comporta para características que requieren permisos. - A continuación, se presenta un resumen de las prácticas de desarrollo que debe seguir para ajustarse a este modelo: - -
- --
-
-
- - Siempre compruebe los permisos: Siempre que una aplicación necesite realizar una acción que requiere algún permiso, primero debe comprobar si ya tiene otorgado ese permiso. - - En caso de no tenerlo, solicitará que se le otorgue ese permiso. - - - -
- - Administre la falta de permisos correctamente: Si la aplicación no recibe un permiso adecuado, deberá administrar la falla sin errores. - - Por ejemplo, si se necesita el permiso solo para una característica añadida, la aplicación puede desactivar esa característica. - Si el permiso es fundamental para que la aplicación funcione, la aplicación podrá desactivar toda su funcionalidad e informar al usuario que se deben conceder dichos permisos. - - - - -
- - Los permisos son revocables: Los usuarios pueden revocar los permisos en cualquier momento. - Si un usuario desactiva los permisos de una aplicación, la aplicación no recibe ningún aviso. - Nuevamente, la aplicación deberá verificar que cuenta con los permisos necesarios antes de realizar cualquier acción restringida. - - -
- Nota: Si una aplicación tiene como destino M Developer Preview, debe utilizar el nuevo modelo de permisos. - -
- -- A partir del lanzamiento de M Developer Preview, no todas las aplicaciones de Google implementarán por completo el nuevo modelo de permisos. - Google actualiza estas aplicaciones durante el transcurso de M Developer Preview para respetar adecuadamente las configuraciones de alternancia de los permisos. - - -
- -- Nota: Si la aplicación cuenta con su propia superficie de API, no transmita permisos sin antes asegurarse de que el iniciador de la llamada cuente con los permisos requeridos para acceder a esa información. - - -
- -- Permisos de las aplicaciones de firma y de sistema -
- -- Generalmente, cuando el usuario instala una aplicación, el sistema solo otorga a la aplicación -{@link android.content.pm.PermissionInfo#PROTECTION_NORMAL - PROTECTION_NORMAL}. Sin embargo, en ciertas circunstancias, el sistema le concede a la aplicación más permisos: - -
- --
-
- Si una aplicación es parte de la imagen del sistema, la aplicación recibe automáticamente todos los permisos enumerados en el manifiesto. - - - -
- Si la aplicación solicita permisos en el manifiesto que corresponden a {@link - android.content.pm.PermissionInfo#PROTECTION_SIGNATURE PROTECTION_SIGNATURE} y la aplicación está firmada con el mismo certificado que el de la aplicación que declaró dichos permisos, el sistema le concede a la aplicación que los solicita esos permisos durante la instalación. - - - - -
- En ambos casos, el usuario aún puede revocar los permisos en cualquier momento si accede a la pantalla Settings del sistema y selecciona Apps > - - app_name > Permissions. La aplicación debe seguir controlando los permisos al momento de la ejecución y solicitarlos si fuese necesario. - - -
- -- Compatibilidad con modelos anteriores y posteriores -
- -- Si una aplicación no tiene como destino M Developer Preview, la aplicación continúa utilizando el modelo de permisos anterior, incluso en dispositivos con la versión preliminar de Android M. - Cuando el usuario instala la aplicación, el sistema le solicita al usuario que otorgue todos los permisos enumerados en el manifiesto de la aplicación. - - -
- -- Nota: En dispositivos que ejecutan M Developer Preview, el usuario puede desactivar los permisos para cualquier aplicación (incluso para aplicaciones heredadas) desde la pantalla Settings de la aplicación. - - Si un usuario desactiva permisos para una aplicación heredada, el sistema desactiva las funciones correspondientes de forma automática. - Cuando la aplicación intenta realizar una operación que requiere ese permiso, la operación no generará necesariamente una excepción. - - En su lugar, devolverá un conjunto de datos vacíos, indicará un error o, de lo contrario, mostrará un comportamiento inesperado. - Por ejemplo, si realiza una consulta sobre el calendario sin permisos, el método devuelve un conjunto de datos vacíos. - -
- -- Si instala una aplicación que utiliza el nuevo modelo de permisos en un dispositivo que no ejecuta la versión preliminar de Android M, el sistema la trata como cualquier otra aplicación: el sistema le pide al usuario, durante la instalación, que conceda los permisos declarados. - - - -
- -- Nota: Para el lanzamiento de la versión preliminar, debe configurar la versión mínima del SDK en M Preview SDK para compilar con la versión del SDK preliminar. - Esto significa que no podrá probar dichas aplicaciones en plataformas anteriores durante la versión preliminar para desarrolladores. - - -
- -Permisos frente a intentos
- -- En muchas situaciones, puede elegir entre dos formas para que sus aplicaciones realicen una tarea. - Puede hacer que su aplicación solicite permiso para realizar la operación por sí misma. - De lo contrario, puede hacer que la aplicación utilice un intento para que otra aplicación realice la tarea. - -
- -
- Por ejemplo, supongamos que su aplicación necesita poder tomar fotografías con la cámara del dispositivo.
- Su aplicación puede solicitar el permiso
-android.permission.CAMERA
, lo que le permite a su aplicación acceder a la cámara directamente.
- Entonces, su aplicación utilizará las API de la cámara para controlar la cámara y tomar una fotografía.
- Este enfoque le otorga a su aplicación total control del proceso de fotografía y le permite incorporar la UI de la cámara en su aplicación.
-
-
-
- Sin embargo, si no necesita dicho control, puede utilizar {@link - android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} para solicitar una imagen. - Cuando ejecute el intento, se le solicita al usuario que elija una aplicación de cámara (en caso de que no haya una aplicación de cámara predeterminada) y esa aplicación tomará la fotografía. - - La aplicación de cámara devuelve la fotografía al método {@link - android.app.Activity#onActivityResult onActivityResult()} de su aplicación. -
- -- De manera similar, si necesita realizar una llamada telefónica, acceder a los contactos del usuario, etc., lo puede hacer creando intentos apropiados o puede solicitar los permisos e ingresar directamente a los objetos apropiados. - - Cada enfoque tiene ventajas y desventajas. - -
- -- Si utiliza los permisos: -
- --
-
- La aplicación posee total control sobre la experiencia del usuario cuando usted realiza la operación. - Sin embargo, un control tan amplio complica su tarea, ya que usted deberá diseñar una UI apropiada. - - - -
- Se le solicita al usuario otorgar el permiso una vez, la primera vez que usted realiza la operación. - Luego, su aplicación puede realizar la operación sin requerir interacción adicional por parte del usuario. - Sin embargo, si el usuario no concede el permiso (o lo revoca luego), su aplicación queda inhabilitada para realizar la operación. - - - -
- Si utiliza un intento: -
- --
-
- No debe diseñar la UI para la operación. La aplicación que controla el intento provee la UI. Sin embargo, esto significa que usted no tiene control sobre la experiencia del usuario. - - El usuario podrá interactuar con una aplicación que usted no conoce. - - - -
- Si el usuario no tiene una aplicación predeterminada para la operación, el sistema le solicita al usuario que elija una aplicación. Si el usuario no designa un controlador predeterminado, es probable que surja un diálogo adicional cada vez que realice la operación. - - - - -
Codificación para permisos de tiempo de ejecución
- -- Si su aplicación tiene como destino el nuevo M Developer Preview, deberá usar el nuevo modelo de permisos. - Esto significa que, además de declarar los permisos necesarios en el manifiesto, también debe comprobar si tiene los permisos de tiempo de ejecución y solicitarlos en caso de no tenerlos. - - - -
- -- Habilitar el nuevo modelo de permisos -
- -
- Para habilitar el nuevo modelo de permisos de M Developer Preview, configure el atributo
-targetSdkVersion
de la aplicación en "MNC"
y
-compileSdkVersion
en "android-MNC"
. Al hacerlo, se habilitan todas las características de los nuevos permisos.
-
-
- Para el lanzamiento de la versión preliminar, debe establecer minSdkVersion
en
-"MNC"
para compilar con el SDK preliminar.
-
- Establecer un permiso solo para la versión preliminar de Android M -
- -
- Puede utilizar el nuevo elemento <uses-permission-sdk-m>
en el manifiesto de la aplicación para indicar que se necesita un permiso solo para M Developer Preview.
- Si declara un permiso de esta manera, cuando la aplicación se instale en un dispositivo anterior, el sistema no le solicitará al usuario el permiso ni se lo otorgará a la aplicación. Al usar el elemento <uses-permission-sdk-m>
, puede añadir nuevos permisos a las versiones actualizadas de su aplicación sin forzar a los usuarios a otorgar permisos cuando instalen la actualización.
-
-
-
-
-
-
-
- Si la aplicación se ejecuta en un dispositivo con M Developer Preview,
-<uses-permission-sdk-m>
se comporta al igual que
-<uses-permission>
.
- El sistema no le solicita al usuario que otorgue ningún permiso al instalar la aplicación y la aplicación solicita los permisos a medida que se necesiten.
-
-
- Solicitar permisos -
- -- Si su aplicación utiliza el nuevo modelo de permisos de M Developer Preview, no se le pedirá al usuario que otorgue todos los permisos cuando la aplicación se ejecute por primera vez en un dispositivo con la versión preliminar de Android M. - - En su lugar, su aplicación solicita los permisos a medida que los necesita. - Cuando su aplicación solicita un permiso, el sistema le muestra un diálogo al usuario. - -
- -
- Si su aplicación se ejecuta en un dispositivo con SDK 22 o anterior, la aplicación utiliza el modelo de permisos anterior.
- Cuando el usuario instala la aplicación, se le solicita que otorgue todos los permisos que la aplicación requiere en su manifiesto, excepto aquellos permisos marcados con <uses-permission-sdk-m>
.
-
-
-
Controlar en qué plataforma se ejecuta la aplicación
- -
- Este modelo de permisos es compatible solamente con dispositivos que ejecutan M Developer Preview.
- Antes de llamar a cualquiera de estos métodos, la aplicación debe verificar en qué plataforma se está ejecutando y, para hacerlo, se controla el valor de {@link android.os.Build.VERSION#CODENAME
- Build.VERSION.CODENAME}.
-
- Si el dispositivo ejecuta M Developer Preview,
-{@link android.os.Build.VERSION#CODENAME CODENAME} es "MNC"
.
-
Controlar si la aplicación cuenta con los permisos necesarios
- -Cuando el usuario intenta realizar algo que requiere un permiso, la aplicación controla si ya tiene el permiso para realizar esa operación.
- Para hacerlo, la aplicación llama a Context.checkSelfPermission(
-
-permission_name)
. La aplicación debe realizar este control incluso si sabe que el usuario ya ha concedido ese permiso, ya que el usuario puede revocar los permisos de una aplicación en cualquier momento.
-
-
- Por ejemplo, si un usuario quiere usar una aplicación para tomar una fotografía, la aplicación llama a Context.checkSelfPermission(Manifest.permission.CAMERA)
.
-
-
Grupo de permisos | -Permisos | -
---|---|
android.permission-group.CALENDAR |
-
-
|
-
android.permission-group.CAMERA |
-
-
|
-
android.permission-group.CONTACTS |
-
-
|
-
android.permission-group.LOCATION |
-
-
|
-
android.permission-group.MICROPHONE |
-
-
|
-
android.permission-group.PHONE |
-
-
|
-
android.permission-group.SENSORS |
-
-
|
-
android.permission-group.SMS |
-
-
|
-
Solicitar permisos si se necesitan
- -Si la aplicación no posee los permisos que necesita, llama al método
-Activity.requestPermissions(String[], int)
para solicitar el permiso o los permisos apropiados.
- La aplicación pasa el permiso o los permisos que necesita y un “código de solicitud” entero.
-
- Este método funciona de manera asincrónica: realiza la devolución inmediatamente y cuando el usuario responde a la ventana de diálogo, el sistema llama al método de devolución de llamada de la aplicación con los resultados, y pasa el mismo “código de solicitud” que pasó la aplicación a
-requestPermissions()
.
-
-
El siguiente código verifica si la aplicación tiene permisos para leer los contactos del usuario y solicita los permisos de ser necesario: -
- --if (checkSelfPermission(Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, - MY_PERMISSIONS_REQUEST_READ_CONTACTS); - - // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an - // app-defined int constant - - return; -} -- -
Administrar la respuesta a la solicitud de permisos
- -
- Cuando una aplicación solicita permisos, el sistema le muestra al usuario una ventana de diálogo.
- Cuando el usuario responde, el sistema invoca
-Activity.onRequestPermissionsResult(int, String[], int[])
- de su aplicación y le transfiere la respuesta del usuario. Su aplicación necesita invalidar ese método. La devolución de llamada pasa el mismo código de solicitud que usted pasó a requestPermissions()
.
-
- Por ejemplo, si una aplicación solicita acceso READ_CONTACTS
, es posible que tenga el siguiente método de devolución de llamada:
-
-
-
-@Override -public void onRequestPermissionsResult(int requestCode, - String permissions[], int[] grantResults) { - switch (requestCode) { - case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - - // permission was granted, yay! do the - // calendar task you need to do. - - } else { - - // permission denied, boo! Disable the - // functionality that depends on this permission. - } - return; - } - - // other 'switch' lines to check for other - // permissions this app might request - } -} -- -
Si el usuario concede un permiso, el sistema le otorga a la aplicación todos los permisos enumerados en el manifiesto para esa área funcional. - Se deben tomar acciones apropiadas si el usuario rechaza la solicitud. - Por ejemplo, usted podría desactivar cualquier acción del menú que dependa de este permiso. - - -
- -
- Cuando el sistema le solicita al usuario que otorgue un permiso, el usuario tiene la opción de indicarle al sistema que no solicite ese permiso de nuevo.
- En ese caso, cuando la aplicación utiliza requestPermissions()
para solicitar ese permiso, el sistema rechaza la solicitud inmediatamente.
-
- En este caso, el sistema llama a su onRequestPermissionsResult()
de la misma manera en que lo haría si el usuario hubiese rechazado explícitamente su solicitud nuevamente.
-
- Por esta razón, su aplicación no puede asumir que se ha llevado a cabo algún tipo de interacción con el usuario.
-
-
Prueba de permisos de tiempo de ejecución
- - -- Si su aplicación tiene como destino M Developer Preview, debe probar que administre los permisos correctamente. - No debe asumir que su aplicación tiene algún permiso en particular cuando se ejecuta. - Cuando la aplicación se ejecuta por primera vez, es muy probable que no tenga permisos y el usuario puede revocar o reestablecer los permisos en cualquier momento. - - -
- -- Debe probar su aplicación para asegurarse de que funciona correctamente en todas las situaciones de permisos. - Con el SDK de la versión preliminar de Android M, hemos brindado nuevos comandos Android Debug Bridge (adb) que le permitirán probar su aplicación con cualquier configuración de permisos que necesite probar. - - - -
- -- Nuevas opciones y comandos adb -
- -- Las herramientas de plataforma del SDK de la versión preliminar de Android M contienen varios comandos nuevos que le permiten probar la manera en que su aplicación administra los permisos. - -
- -- Instalar con permisos -
- -
- Puede utilizar la nueva opción -g
del comando adb
- install
, que instala la aplicación y concede todos los permisos enumerados en el manifiesto de la aplicación:
-
-
-$ adb install -g <path_to_apk> -- -
- Conceder y revocar permisos -
- -- Puede utilizar los comandos ADB nuevos package manager (pm) para conceder y revocar permisos a una aplicación instalada. Esta funcionalidad puede resultar útil para pruebas automáticas. - - -
- -
- Para conceder un permiso, utilice el comando grant
de package manager:
-
-$ adb pm grant <package_name> <permission_name> -- -
- Por ejemplo, para conceder el paquete de permisos com.example.myapp para grabar audio utilice este comando: - -
- --$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO -- -
- Para revocar un permiso, utilice el comando revoke
de package manager:
-
-$ adb pm revoke <package_name> <permission_name> -- -
Mejores prácticas
- -- El nuevo modelo de permisos brinda a los usuarios una experiencia más fluida y les facilita la instalación de aplicaciones, además de hacerlos sentir cómodos con las actividades de sus aplicaciones. - - Sugerimos las siguientes mejores prácticas para obtener el mayor beneficio del nuevo modelo. - -
- - -Solicite solo los permisos que necesite
- -- Cada vez que solicite un permiso, usted obliga al usuario a tomar una decisión. - La funcionalidad de su aplicación se verá reducida si el usuario rechaza la solicitud. - Debe minimizar la cantidad de veces que realiza estas solicitudes. -
- -- Por ejemplo, a menudo, su aplicación puede obtener la funcionalidad necesaria a través de un intento en lugar de una solicitud de permiso. - - Si su aplicación necesita tomar fotografías con la cámara del teléfono, la aplicación puede utilizar un intento {@link - android.provider.MediaStore#ACTION_IMAGE_CAPTURE - MediaStore.ACTION_IMAGE_CAPTURE}. - Cuando su aplicación ejecuta el intento, el sistema le solicita al usuario que elija una aplicación para la cámara que ya está instalada a fin de tomar la fotografía. - - -
- -- No abrume al usuario -
- -- Si expone al usuario a muchas solicitudes de permisos al mismo tiempo, lo abrumará y hará que deje de usar su aplicación. Por el contrario, debe pedir permisos en la medida que los necesite. - - -
- -- A veces, uno o más permisos pueden ser absolutamente necesarios para la aplicación. En ese caso, es recomendable pedir todos los permisos no bien se inicie la aplicación. - - Por ejemplo, si crea una aplicación de fotografía, la aplicación necesitará acceso a la cámara del dispositivo. - Cuando el usuario inicie la aplicación por primera vez, no se sorprenderá si la aplicación le solicita permiso para usar la cámara. - - Sin embargo, si la misma aplicación además tuviese una característica para compartir fotografías con los contactos del usuario, no solicite ese permiso la primera vez que se ejecute. - - En su lugar, espere hasta que el usuario utilice la característica “compartir” para solicitar el permiso en ese momento. - -
- -- Si su aplicación proporciona un tutorial, se recomienda que se pidan los permisos esenciales de la aplicación al final del tutorial. - -
- -- Explique por qué se necesitan los permisos -
- -
- El diálogo de permisos que muestra el sistema cuando llama a
- requestPermissions()
informa qué permisos necesita su aplicación pero no establece el motivo.
- A veces, el usuario puede confundirse.
- Es una buena idea explicarle al usuario los motivos por los que la aplicación necesita esos permisos antes de llamar a requestPermissions()
.
-
-
- Por ejemplo, una aplicación de fotografía puede solicitar servicios de ubicación para añadir una etiqueta geográfica a las fotografías.
- Es posible que un usuario típico no sepa que una fotografía puede contener información sobre la ubicación y se confundiría si una aplicación de fotografía solicita la ubicación.
-
- En este caso, es recomendable que la aplicación le informe al usuario acerca de esta característica antes de llamar a
-requestPermissions()
.
-
-
- Una forma de hacerlo es incorporar estas solicitudes en el tutorial de la aplicación. El tutorial puede mostrar todas las características de la aplicación, una por vez, y mientras lo hace explicar los permisos que son necesarios.
-
- Por ejemplo, el tutorial de la aplicación de fotografía puede mostrar la característica “compartir fotografías con contactos” y luego explicarle al usuario que debe otorgar permisos para que la aplicación vea los contactos del usuario.
-
-
- La aplicación puede entonces llamar a requestPermissions()
para solicitarle al usuario ese acceso.
- Por supuesto, no todos los usuarios siguen el tutorial, por lo que aun así debe controlar y solicitar los permisos durante el funcionamiento normal de la aplicación.
-
-
-
Android M Developer Preview
-- Prepárese para la próxima versión de Android. Pruebe sus aplicaciones en Nexus 5, 6, 9 y Player. - Explore las novedades en los— permisos de ejecución, las características de ahorro de energía Doze y App Standby, la nueva tecnología de asistencia y mucho más. - - -
- - - - ¡Empiece hoy mismo! -- - - - Developer Preview 3 (final SDK) - -
Recursos
--
-
- - - - Informe los problemas - - -
- - - Únase a la comunidad en G+ - - -
-Para comenzar con la versión preliminar del SDK de Android, debe aceptar los términos y las condiciones que se describen a continuación. -Como se describe a continuación, tenga en cuenta que esta es una versión preliminar del SDK de Android, que está sujeta a cambios y que usted utiliza bajo su cuenta y riesgo. La versión preliminar del SDK de Android no es una versión estable y puede contener errores y defectos que pueden provocar daños graves a sus sistemas informáticos, dispositivos y datos. -
- --Este es el Contrato de licencia de la versión preliminar del SDK de Android (el “Contrato de licencia”). -
-- Developer Preview 2 is now available -
- --
-
- - - - Read the Notes - - -
- - - - Get the Update - - -
- - - - Report Issues - -
- Bienvenido a Android M Developer Preview, el programa que le brinda todo lo que necesita para probar y optimizar sus aplicaciones para la próxima versión de Android. - - Es gratis y puede comenzar a utilizarlo ahora mismo. Solo tiene que descargar las herramientas de M Developer Preview. - -
- -- Imágenes del sistema emulador y de hardware -
- -- Ejecute y pruebe sus aplicaciones en Nexus 5, 6, 9 y Player (para TV), además del emulador. - -
-- Último código de la plataforma -
- -- Durante la versión preliminar, ofreceremos múltiples actualizaciones, por lo que usted realizará la prueba comparando los últimos cambios de la plataforma. - -
-- Actualizaciones vía OTA -
- -- Luego de actualizar su dispositivo a la versión preliminar inicial, usted podrá obtener actualizaciones por red inalámbrica (over-the-air, OTA). - -
-- Nuevos comportamientos y capacidades -
- -- Inicie el funcionamiento con anticipación para admitir los comportamientos de la nueva plataforma como el nuevo modelo de permisos de tiempos de ejecución y las opciones de ahorro de energía. - -
-- Ventana de prioridad para los problemas informados por los desarrolladores -
- -- Durante las primeras semanas, daremos prioridad a los problemas informados por los desarrolladores; por lo tanto, realice las pruebas y envíe sus comentarios lo antes posible. - -
-- Comentarios y soporte -
- -- Infórmenos los problemas y envíenos comentarios a través de nuestro seguimiento de problemas. - Póngase en contacto con otros desarrolladores de la comunidad M Developer Community. - -
-- Escala de tiempo y actualizaciones -
- -- M Developer Preview estará disponible a partir del 28 de mayo hasta la versión final del SDK de Android M, que lanzaremos al poco tiempo del lanzamiento público durante el tercer trimestre de 2015. - - -
- -- En momentos clave del desarrollo, lanzaremos actualizaciones para sus dispositivos de prueba. - Los momentos clave tentativos son los siguientes: -
- --
-
- - Preview 1 (lanzamiento inicial de la versión preliminar, fines de mayo) - - -
- - Preview 2 (fines de junio, comienzos de julio) - - -
- - Preview 3 (casi la versión final, a fines de julio) - -
- Estas actualizaciones terminan con el SDK final (más adelante durante el tercer trimestre), lo que proporcionará tanto las API oficiales para la nueva versión de Android como los comportamientos y las características finales del sistema. - - -
- -- A medida que usted prueba y desarrolla en Android M, le recomendamos que mantenga su entorno de desarrollo actualizado a medida que se lanzan las actualizaciones de la versión preliminar. - - Para que el proceso sea más fácil, lanzaremos actualizaciones OTA para los dispositivos que ya hayan sido actualizados a una compilación de la versión preliminar y brindaremos imágenes del sistema que puede descargar y actualizar manualmente. - - -
-- Nota: El SDK final y las imágenes del sistema no se pueden proporcionar vía OTA y deberán actualizarse manualmente en sus dispositivos de prueba. - - -
- -- Le informaremos cuando las actualizaciones de la versión preliminar se encuentren disponibles a través del blog de Android para desarrolladores (Android Developers Blog), de este sitio y de la comunidad de desarrolladores Android M Developer Community. - - -
- -- ¿Qué ofrece la versión preliminar? -
- -- M Developer Preview incluye todo lo que necesita para probar sus aplicaciones actuales en una variedad de tamaños de pantalla, de tecnologías de redes, de conjuntos de chip CPU/GPU y de arquitecturas de hardware. - - -
- -- Herramientas del SDK -
- -- Estos componentes se pueden descargar mediante SDK Manager en Android Studio: -
- --
-
- Herramientas del SDK de M Developer Preview - - -
- Imagen del sistema emulador (32-bit y 64-bit) de M Developer Preview - - - -
- Imagen del sistema emulador para Android TV (32-bit) de M Developer Preview - - -
- Imágenes del sistema de hardware -
- -- Puede descargar estas imágenes del sistema de hardware para dispositivos Nexus desde la página de Descargas: - -
- --
-
- - Nexus 5 (GSM/LTE) imagen del sistema del dispositivo “hammerhead” - - -
- - Nexus 6 imagen del sistema del dispositivo “shamu” - - -
- - Nexus 9 (Wi-Fi) imagen del sistema del dispositivo “volantis” - - -
- - Nexus Player (Android TV) imagen del sistema del dispositivo “fugu” - -
- Documentación y código de muestra -
- -- Estos recursos de documentación lo ayudan a obtener información sobre la versión preliminar: -
- --
-
- - Configurar el SDK: contiene instrucciones paso a paso para comenzar. - - - -
- - Guía de prueba y Cambios en los comportamientos: le indican las áreas más importantes que debe probar. - - -
- Documentación sobre las nuevas API, lo que incluye Información general de la API, Referencia de la API que se puede descargar y guías detalladas para desarrolladores sobre características clave como permisos, copias de seguridad de la aplicación, entre otras. - - - - - - -
- - Código de ejemplo: indica cómo admitir permisos y otras características nuevas. - - - -
- - Notas de la versión para la versión actual de M Developer Preview, lo que incluye notas sobre los cambios e informes de diferencias. - - -
- Recursos de soporte -
- -- Utilice los siguientes recursos de soporte durante el proceso de prueba y desarrollo en M Developer Preview: - -
- --
-
- El seguimiento de problemas de M Developer Preview es su canal principal de comentarios. - - A través de este seguimiento de problemas, usted puede informarnos errores o problemas de rendimiento, y enviarnos comentarios generales. - También puede buscar problemas recurrentes y encontrar soluciones alternativas detalladas. - - - -
- Android M Developer Community es una comunidad en Google+ donde usted puede contactarse con otros desarrolladores que estén trabajando con Android M. Puede compartir comentarios o ideas, o encontrar respuestas a sus dudas sobre Android M. - - - - -
- Selección del destino, API preliminares y publicación -
- -
- Android M Developer Preview es una versión solo para desarrollo y no tiene un nivel de API estándar.
- Si quiere darse de baja de los comportamientos de compatibilidad para probar su aplicación (lo que es muy recomendado), puede elegir como destino M Developer Preview estableciendo targetSdkVersion
de su aplicación como “MNC”
.
-
-
-
-
- Android M Developer Preview ofrece API preliminares - — las API no serán oficiales hasta que se lance el SDK final, lo que actualmente está planeado para el tercer trimestre de 2015. - Esto quiere decir que surgirán cambios menores en la API con el tiempo, particularmente durante las primeras semanas del programa. - - Con cada actualización de Android M Developer Preview, proporcionaremos un resumen con los cambios realizados. - -
- -- Tenga en cuenta que aunque las API preliminares pueden modificarse, los comportamientos del sistema subyacente, como los permisos de tiempo de ejecución y las opciones de ahorro de energía, se mantienen estables y disponibles para cualquier prueba inmediata. - - -
- -- En cuanto a la publicación, Google Play no permite que se publiquen aplicaciones que tienen como destino M Developer Preview. - Una vez que el SDK final de Android M esté disponible, podrá seleccionar como destino el nivel de API oficial de Android M y publicar su aplicación en Google Play. - - Mientras tanto, si desea distribuir una aplicación con Android M como destino a otros evaluadores, lo puede hacer por correo electrónico o mediante descarga directa desde su sitio. - - -
- -- ¿Cómo comenzar? -
- -- Para comenzar a probar su aplicación: -
- --
-
- Revise el artículo Información general de la API y Cambios en los comportamientos para obtener una idea sobre las novedades y cómo estas pueden afectar sus aplicaciones. - - En especial, infórmese sobre el nuevo modelo de permisos de tiempo de ejecución, las opciones de ahorro de energía y las copias de seguridad automáticas. - - - - -
- Configure su entorno siguiendo las instrucciones para Configurar el SDK de la versión preliminar y configurar los dispositivos de prueba. - - - - -
- Siga las instrucciones de actualización para actualizar la última imagen del sistema del desarrollador de Android M para Nexus 5, 6, 9 y Player. - - Cuando haya actualizado su dispositivo de desarrollo, recibirá las actualizaciones de la versión preliminar mediante actualizaciones OTA. - - - -
- Descargue la Referencia de la API de M Preview y los Ejemplos de M Preview para obtener más información sobre las nuevas características de la API y sobre cómo utilizarlas en su aplicación. - - - - - -
- Únase a la comunidad Android M Developer Community para recibir las últimas noticias y para contactarse con otros desarrolladores que estén trabajando con la nueva plataforma. - - - -
- ¡Agradecemos su participación en el programa Android M Developer Preview! -
diff --git a/docs/html-intl/intl/es/preview/samples.jd b/docs/html-intl/intl/es/preview/samples.jd deleted file mode 100644 index 03f41e478dcc8b4e4711c2e426497ad242542e32..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/es/preview/samples.jd +++ /dev/null @@ -1,70 +0,0 @@ -page.title=Ejemplos -page.image=images/cards/samples-new_2x.png -@jd:body - -- Los siguientes códigos de ejemplo se proporcionan para M Developer Preview. Para descargar los ejemplos en Android Studio, seleccione la opción del menú File > Import Samples. - -
- -- Nota: Estos proyectos que se pueden descargar están diseñados para usarlos con Gradle y Android Studio. - -
- - -Permisos de tiempo de ejecución
- -- Android M modifica la manera en que funcionan los permisos del sistema. Los usuarios deben aprobar solicitudes de permiso durante la ejecución, en lugar de durante la instalación. - Este ejemplo muestra cómo solicitar estos permisos. - -
- - - -Confirmar credencial
- -- Este ejemplo muestra cómo usar las credenciales del dispositivo como método de autenticación en su aplicación. -
- - - -Diálogo de huellas dactilares
- -- Este ejemplo muestra cómo reconocer huellas dactilares registradas para autenticar al usuario en su aplicación. - -
- - - -Copia de seguridad automática para aplicaciones
- -- Android M incorpora la copia de seguridad automática para las configuraciones de la aplicación. Este ejemplo muestra cómo agregar reglas de filtrado en una aplicación para administrar la copia de seguridad de las configuraciones. - -
- - - -Camera 2 Raw
- -
- Muestra cómo usar la API Camera2
para capturar imágenes fotográficas RAW y guardarlas como archivos DNG
.
-
-
Notificación activa
- -
- Este ejemplo muestra cómo NotificationManager
puede indicarle cuántas notificaciones está mostrando actualmente su aplicación.
-
-
-
Contenido del documento
- -M Developer Preview SDK se encuentra disponible desde Android SDK Manager. En este documento, se asume que usted está familiarizado con el desarrollo de aplicaciones de Android, como el uso de Android SDK Manager y la creación de proyectos. - - Si no está familiarizado con Android, consulte primero la sección de capacitación Desarrollo de su primera aplicación. - -
- -Obtener Android Studio 1.3
- -La versión preliminar para desarrolladores funciona mejor con Android Studio 1.3, que es una versión preliminar. - Se recomienda que instale la versión preliminar de Android Studio 1.3 para trabajar con el SDK de la versión preliminar. -
- -Advertencia: La versión preliminar Canary de Android Studio 1.3 aún se encuentra en desarrollo activo. - Si utiliza su equipo de desarrollo principal para probar la versión preliminar para desarrolladores, puede instalar una segunda instancia de Android para realizar las pruebas. - -
- -Para instalar la versión preliminar de Android Studio 1.3:
- --
-
- Descargue y ejecute Android Studio - - - -
- Abra la ventana Settings (en Windows, puede hacerlo desde File > Settings).
- Seleccione el panel Appearance & Behavior > System Settings > Updates.
-
-
-
-
En OSX, puede encontrar el panel Appearance & Behavior en la ventana Preferences de Android Studio. - -
-
-
- - En el panel Updates, elija la opción Automatically check updates for: - Canary Channel. - - -
- En el panel Updates, elija Check Now para verificar la última compilación de Canary. - Descargue e instale la compilación cuando se lo pida. - - -
Obtener el SDK de la versión preliminar
- -Para añadir los componentes del SDK de la versión preliminar a su entorno de desarrollo:
- --
-
- Ejecute la versión preliminar de Android Studio 1.3. - - -
- Abra la ventana Settings (en Windows, puede hacerlo desde File > Settings).
- Seleccione el panel Appearance & Behavior > System Settings > Updates.
-
-
-
-
En OSX, puede encontrar el panel Appearance & Behavior en la ventana Preferences de Android Studio. - -
-
-
- - En el panel Updates, elija las opciones Automatically check updates for: - Canary Channel y Automatically check updates for Android SDK: - Preview Channel. - - -
- Ejecute Android SDK Manager. (En Android Studio 1.3, SDK Manager está integrado a Android Studio, en lugar de ser una aplicación independiente). - - - - -
- En la sección Platforms, elija Android MNC Preview. - - - -
- En la sección Tools, elija las últimas SDK Tools, Platform-tools y Build-tools de Android. - - - - -
- Seleccione Install packages y acepte el contrato de licencia para todos los paquetes. - - - -
- Verifique que M Developer Preview esté instalado; para hacerlo, abra la ventana Settings y elija el panel Appearance & Behavior > System Settings > Android SDK. - - - -
- En el panel Android SDK, elija la pestaña SDK Platforms. - Android MNC Preview deberá figurar como Installed. - Luego, abra la pestaña SDK Tools para verificar que estén instaladas las últimas herramientas. - - - -
Después de completar estos pasos, los componentes de la versión preliminar ya estarán disponibles en su entorno de desarrollo. -
- - -Crear o actualizar un proyecto
- -- Si desea utilizar las API de la versión preliminar, debe crear o actualizar un proyecto de desarrollo para utilizar los componentes de la versión preliminar. - -
- - -Crear un proyecto nuevo
- -- Recomendamos que utilice Android Studio para crear un proyecto con la versión preliminar. Siga los pasos que se describen en Crear un proyecto hasta que llegue a la pantalla Form Factors en el asistente. - - Luego, realice los siguientes pasos para crear un proyecto configurado para la versión preliminar. - -
- --
-
- Seleccione Phone and Tablet. -
- Seleccione MNC: Android M (Preview) en Minimum SDK. - -
Actualizar un proyecto existente
- -
- Para proyectos existentes, debe modificar la configuración del proyecto para habilitar las API de la versión preliminar. En su entorno de desarrollo, abra el archivo
-build.gradle
para su módulo y configure estos valores de la siguiente manera:
-
-
-
-
compileSdkVersion
se configura en'android-MNC'
- minSdkVersion
se configura en'MNC'
- targetSdkVersion
se configura en'MNC'
-
Configurar para realizar pruebas
- -- Probar una aplicación con la versión preliminar requiere un dispositivo o un dispositivo virtual configurado con la versión preliminar de la plataforma. - Si tiene un dispositivo compatible, puede instalar la plataforma de la versión preliminar para realizar la prueba. - De lo contrario, puede configurar un dispositivo virtual para realizar la prueba. -
- -Configurar un dispositivo físico
- -- Si tiene un Nexus 5, Nexus 6, Nexus 9 o Android TV, puede instalar una imagen de sistema de la versión preliminar en estos dispositivos para probar su aplicación. Con la herramienta Android Virtual Device Manager, puede configurar un dispositivo virtual con la versión preliminar de la plataforma desde Android Studio - - - -
- -- Importante: El proceso de instalación de una imagen preliminar en un dispositivo elimina todos los datos del dispositivo, por lo que debe hacer una copia de seguridad de los datos antes de instalar una imagen preliminar. - -
- -Configurar un dispositivo virtual
- -- Con la herramienta Android Virtual Device, puede configurar un dispositivo virtual para la versión preliminar de la plataforma desde Android Studio. - -
- -Crear un AVD (dispositivo virtual de Android) con AVD Manager:
- --
-
- Instale el SDK de la versión preliminar en su entorno de desarrollo, como se detalla en Configurar el SDK de la versión preliminar. - - -
- Siga los pasos en Administración de los ADV con ADV Manager.
-
- Utilice las siguientes configuraciones:
-
-
-
- Dispositivo: Nexus 5, Nexus 6, Nexus 9 o Android TV -
- Destino: - Android M (versión preliminar) - Nivel de API M -
- ABI: x86 -
-
- Para obtener más información sobre cómo crear dispositivos virtuales para realizar pruebas, consulte Administración de dispositivos virtuales. -
diff --git a/docs/html-intl/intl/es/preview/testing/guide.jd b/docs/html-intl/intl/es/preview/testing/guide.jd deleted file mode 100644 index 138d6ca96c9a454fa11a654ac4d0c8245dfe30f1..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/es/preview/testing/guide.jd +++ /dev/null @@ -1,187 +0,0 @@ -page.title=Guía de prueba -page.image=images/cards/card-build_16x9_2x.png -page.keywords=recursos de la versión preliminar,androidm,pruebas,permisos - -@jd:body - -Contenido del documento
- -- Android M Developer Preview le brinda la oportunidad de garantizar que sus aplicaciones funcionen con la próxima versión de la plataforma. - Esta versión preliminar incluye diversas API y cambios en los comportamientos que pueden tener impactos en su aplicación, como se describe en las secciones Información general de la API y Cambios en los comportamientos. - - Al probar su aplicación con la versión preliminar, se debe centrar en algunos cambios específicos del sistema para garantizar que los usuarios disfruten de una buena experiencia. - - -
- -- En esta guía, se describen qué y cómo probar las características preliminares con su aplicación. Debe priorizar la prueba de estas características específicas preliminares, puesto que podrían tener un alto impacto en el comportamiento de su aplicación: - - -
- --
-
- Permisos - -
- Modos Doze y App Standby - -
- Copia de seguridad automática e identificadores de dispositivos -
- Para obtener más información sobre cómo configurar dispositivos o dispositivos virtuales con una imagen del sistema de la versión preliminar para realizar pruebas, consulte la sección Configurar el SDK de la versión preliminar. - -
- - -Prueba de los permisos
- -- El nuevo modelo de permisos cambia el modo en que el usuario asigna permisos a su aplicación. - En lugar de conceder todos los permisos durante el procedimiento de instalación, su aplicación debe solicitar al usuario los permisos individuales en el tiempo de ejecución. - - Para los usuarios, este comportamiento ofrece más control granular sobre las actividades de cada aplicación, así como un mejor contexto para comprender por qué la aplicación está solicitando un permiso específico. - Los usuarios pueden conceder o revocar los permisos concedidos a una aplicación de forma individual en cualquier momento. - Es muy probable que esta característica de la versión preliminar tenga un impacto en el comportamiento de su aplicación y puede hacer que algunas características de su aplicación no funcionen o funcionen en un estado degradado. - - -
- -- Este cambio afecta a todas las aplicaciones que se ejecutan en la nueva plataforma, incluso a aquellas que no tienen como destino la nueva versión de la plataforma. - La plataforma ofrece un comportamiento de compatibilidad limitada para las aplicaciones heredadas, pero usted debe comenzar a planificar ahora la migración de su aplicación al nuevo modelo de permisos, con el objetivo de publicar una versión actualizada de su aplicación cuando se lance la plataforma oficial. - - -
- - -Consejos para pruebas
- -- Use los siguientes consejos para pruebas como ayuda para planificar y ejecutar las pruebas de su aplicación con el nuevo comportamiento de permisos. - -
- --
-
- Identifique los permisos actuales de su aplicación y las rutas de códigos relacionadas. -
- Pruebe los flujos del usuario en los datos y servicios protegidos por permisos. -
- Realice pruebas con varias combinaciones de permisos concedidos/revocados. -
- Use la herramienta {@code adb} para administrar permisos desde la línea de comando:
-
-
-
- Enumere los permisos y estados por grupo:
-
adb shell pm list permissions -d -g
-
- - Conceda o revoque un permiso o más permisos utilizando la siguiente sintaxis:
-adb shell pm [grant|revoke] <permission.name> ...
-
-
- - Enumere los permisos y estados por grupo:
-
- Analice su aplicación para detectar servicios que utilizan permisos. -
Estrategia de prueba
- -- El cambio en los permisos afecta la estructura y el diseño de su aplicación, además de la experiencia del usuario y los flujos que usted proporciona a los usuarios. - Debe evaluar el uso de los permisos actuales de su aplicación y comenzar a planificar los nuevos flujos que desea ofrecer. - La versión oficial de la plataforma proporciona un comportamiento de compatibilidad, pero debe prever la actualización de su aplicación y no depender de estos comportamientos. - - -
- -- Identifique los permisos que su aplicación verdaderamente necesita y utiliza, y luego busque las diversas rutas de códigos que utilizan los servicios protegidos por permisos. - Puede realizar esto mediante una combinación de pruebas en la plataforma nueva y análisis de códigos. - Al realizar las pruebas, debe centrarse en incluir permisos de tiempo de ejecución cambiando {@code targetSdkVersion} de la aplicación a la versión preliminar. - Para obtener más información, consulte la sección Configurar el SDK de la versión preliminar. - -
- -- Realice pruebas con diversas combinaciones de permisos revocados y agregados, a fin de destacar los flujos del usuario que dependen de permisos. - Cuando una dependencia no sea obvia ni lógica, debe considerar la opción de refactorizar o compartimentar ese flujo para eliminar la dependencia o aclarar por qué se necesita el permiso. - - -
- -- Para obtener más información sobre el comportamiento de los permisos de tiempo de ejecución, las pruebas y las mejores prácticas, consulte la página Permisos de la versión preliminar para desarrolladores. - - -
- - -Prueba de los modos Doze y App Standby
- -- Las características de ahorro de energía de los modos Doze y App Standby limitan la cantidad de procesamiento en segundo plano que puede realizar su aplicación cuando un dispositivo se encuentra en estado inactivo o mientras su aplicación no está en foco. - Entre las restricciones que el sistema puede imponer en las aplicaciones se incluyen el acceso limitado a la red o denegación de acceso, suspensión de las tareas en segundo plano, suspensión de notificaciones, y alarmas y solicitudes de reactivación ignoradas. - - Para garantizar que su aplicación tenga un comportamiento correcto con estas optimizaciones de ahorro de energía, debe probar su aplicación simulando estos estados de bajo consumo. - - -
- -Cómo probar la aplicación en modo Doze
- -Para probar el modo Doze con su aplicación, realice lo siguiente:
- --
-
- Configure un dispositivo de hardware o un dispositivo virtual con una imagen del sistema de la versión preliminar de Android M. -
- Conecte el dispositivo a su equipo de desarrollo e instale la aplicación. -
- Ejecute su aplicación y déjela activa. -
- Simule la activación del modo Doze en el dispositivo ejecutando los siguientes comandos:
-
-
-$ adb shell dumpsys battery unplug -$ adb shell dumpsys deviceidle step -$ adb shell dumpsys deviceidle -h -
- -
- - Observe el comportamiento de su aplicación cuando se reactive el dispositivo. Asegúrese de que se recupere correctamente cuando el dispositivo salga del modo Doze. - -
Cómo probar aplicaciones en modo App Standby
- -Para probar el modo App Standby con su aplicación, realice lo siguiente:
- --
-
- Configure un dispositivo de hardware o un dispositivo virtual con una imagen del sistema de la versión preliminar de Android M. -
- Conecte el dispositivo a su equipo de desarrollo e instale su aplicación. -
- Ejecute su aplicación y déjela activa. -
- Simule la activación del modo App Standby en la aplicación ejecutando los siguientes comandos:
-
-
-$ adb shell am broadcast -a android.os.action.DISCHARGING -$ adb shell am set-idle <packageName> true -
- -
- - Simule la activación de su aplicación con el siguiente comando:
-
$ adb shell am set-idle <packageName> false
-
- - Observe el comportamiento de su aplicación al reactivarse. Asegúrese de que se recupere correctamente del modo App Standby. - En particular, debe comprobar si los trabajos en segundo plano y las notificaciones de su aplicación continúan funcionando de la manera esperada. - -
Copia de seguridad automática para aplicaciones e identificadores específicos del dispositivo
- -Si su aplicación continúa teniendo algún identificador específico del dispositivo, como la Id. de registro de Google Cloud Messaging, en el almacenamiento interno, asegúrese de seguir las mejores prácticas para excluir la ubicación de almacenamiento de la copia de seguridad automática, como se describe en la sección Copia de seguridad automática para aplicaciones. - - - -
diff --git a/docs/html-intl/intl/es/preview/testing/performance.jd b/docs/html-intl/intl/es/preview/testing/performance.jd deleted file mode 100644 index 734697676b9731fa6c2c5959596bb03fa36aaff1..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/es/preview/testing/performance.jd +++ /dev/null @@ -1,656 +0,0 @@ -page.title=Prueba de rendimiento de video -page.image=images/cards/card-test-performance_2x.png -page.keywords=rendimiento, fotogramas por segundo, herramientas - -@jd:body - - -Contenido del documento
- -- La prueba de rendimiento de la UI le garantiza que su aplicación no solo cumpla con los requisitos funcionales sino que la interacción del usuario con su aplicación sea fluida y funcione constantemente a 60 fotogramas por segundo (Why 60fps?) sin disminuir o retrasar fotogramas (lo que llamamos “jank”). - - - Este documento explica las herramientas disponibles para medir el rendimiento de la UI y establece un enfoque para integrar las medidas de rendimiento de la UI en sus prácticas de prueba. - - -
- - -Medición del rendimiento de la UI
- -- Para mejorar el rendimiento, primero necesita poder medir el rendimiento de su sistema y, luego, diagnosticar e identificar los problemas que puedan surgir debido a las varias secciones de su canalización. - - -
- -- dumpsys es una herramienta de Android que se ejecuta en el dispositivo y vuelca información útil sobre el estado de los servicios del sistema. - - Al pasar el comando gxinfo a dumsys, se obtiene una salida de logcat con información de rendimiento en relación con los fotogramas de animación que ocurren durante la fase de grabado. - - -
- --> adb shell dumpsys gfxinfo <PACKAGE_NAME> -- -
- Este comando puede crear múltiples variantes diferentes de datos del intervalo del fotograma. -
- -Incorporación de Frame Stats
- -- En la versión preliminar de Android M, el comando emite un análisis adicional a logcat sobre los datos del fotograma. Estos datos se recopilan en toda la duración del proceso. - Por ejemplo: -
- --Stats since: 752958278148ns -Total frames rendered: 82189 -Janky frames: 35335 (42.99%) -90th percentile: 34ms -95th percentile: 42ms -99th percentile: 69ms -Number Missed Vsync: 4706 -Number High input latency: 142 -Number Slow UI thread: 17270 -Number Slow bitmap uploads: 1542 -Number Slow draw: 23342 -- -
- Estas estadísticas de alto nivel representan, en un nivel avanzado, el rendimiento de representación de la aplicación y su estabilidad en muchos fotogramas. - -
- - -Información precisa del intervalo del fotograma
- -- La versión preliminar de Android M ofrece un nuevo comando para gfxinfo, es framestats que brinda información extremadamente detallada sobre el intervalo del fotograma reciente, de manera que usted puede localizar y depurar errores de manera más precisa. - - -
- -->adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats -- -
- Este comando emite información sobre el intervalo del fotograma, medida en nanosegundos, de los últimos 120 fotogramas que produjo la aplicación. A continuación, se muestra un ejemplo sin formato de adb dumpsys gxinfo <PACKAGE_NAME> framestats: - - -
- --0,49762224585003,49762241251670,9223372036854775807,0,49762257627204,49762257646058,49762257969704,49762258002100,49762265541631,49762273951162,49762300914808,49762303675954, -0,49762445152142,49762445152142,9223372036854775807,0,49762446678818,49762446705589,49762447268818,49762447388037,49762453551527,49762457134131,49762474889027,49762476150120, -0,49762462118845,49762462118845,9223372036854775807,0,49762462595381,49762462619287,49762462919964,49762462968454,49762476194547,49762476483454,49762480214964,49762480911527, -0,49762479085548,49762479085548,9223372036854775807,0,49762480066370,49762480099339,49762481013089,49762481085850,49762482232152,49762482478350,49762485657620,49762486116683, -- -
- Cada línea de esta salida representa un fotograma producido por la aplicación. Cada línea tiene un número fijo de columnas que describen el tiempo transcurrido en cada etapa de la canalización de producción de fotogramas. - En la siguiente sección, se describe este formato en detalle y se explica qué representa cada columna. - -
- - -Formato de datos de framestats
- -- Debido a que el bloque de datos se emite en formato CSV, es muy sencillo pegarlo en su herramienta de hoja de cálculo preferida, o recopilar y redistribuir con un script. - La siguiente tabla explica el formato de las columnas de los datos de salida. - Las marcas de tiempo están en nanosegundos. -
- --
-
- FLAGS
-
-
-
- El tiempo total del fotograma de las filas con “0” en la columna FLAGS se puede calcular restando la columna INTENDED_VSYNC a la columna FRAME_COMPLETED. - - - -
- Si el resultado no es cero, la fila se debe ignorar, ya que se ha determinado que el fotograma contiene un valor atípico de rendimiento, donde se espera que el diseño y la imagen tomen más de 16 ms.
-
- Razones por las que esto puede suceder:
-
-
-
- Se cambió el diseño de la ventana (ya sea el primer fotograma de la aplicación o luego de una rotación) - - - -
- También es posible que se haya omitido el fotograma. En ese caso, alguno de los valores tendrán marcas de tiempo no utilizables. - Se puede omitir un fotograma si, por ejemplo, supera los 60 fotogramas por segundo o si no había nada desfasado en pantalla. Esto no necesariamente indica que la aplicación tenga algún problema. - - - -
-
-
- - INTENDED_VSYNC
-
-
-
- El punto de partida previsto del fotograma. Si este valor es diferente de VSYNC, el subproceso de la interfaz de usuario se encontraba ocupado, lo que evitó la respuesta a la señal vsync de manera oportuna. - - - -
-
- - VSYNC
-
-
-
- El valor de tiempo que se utilizó en todas las escuchas vsync y las imágenes para el fotograma (devolución de llamada del fotograma Choreographer, animaciones, View.getDrawingTime(), etc.). - - - -
- Para obtener más información sobre VSYNC y cómo influye en su aplicación, consulte el video -Understanding VSYNC. - - -
-
- - OLDEST_INPUT_EVENT
-
-
-
- La marca de tiempo del evento de entrada más antiguo de la cola de entrada, o Long.MAX_VALUE en caso de que el fotograma no tengan ninguna entrada. - - - -
- Este valor está diseñado principalmente para trabajar en la plataforma y tiene utilidad limitada para los desarrolladores de aplicaciones. - - -
-
- - NEWEST_INPUT_EVENT
-
-
-
- La marca de tiempo del evento de entrada más reciente de la cola de entrada, o 0 en caso de que el fotograma no contenga ninguna entrada. - - - -
- Este valor está diseñado principalmente para trabajar en la plataforma y tiene utilidad limitada para los desarrolladores de aplicaciones. - - - -
- Sin embargo, puede obtener una idea general sobre la cantidad de latencia que la aplicación está añadiendo consultando (FRAME_COMPLETED - NEWEST_INPUT_EVENT). - - -
-
- - HANDLE_INPUT_START
-
-
-
- La marca de tiempo en que el evento de entrada se distribuye a la aplicación. - - -
- Al observar el tiempo entre esto y ANIMATION_START, se puede medir cuánto tiempo dedicó la aplicación a la administración de eventos de entrada. - - - -
- Si este valor es alto (mayor a 2 ms), esto significa que la aplicación dedica tiempo poco común al proceso de los eventos de entrada, como View.onTouchEvent(), lo que indica que este proceso se debe optimizar o descargar a otro subproceso. - - Tenga en cuenta que, en algunas ocasiones, como cuando al hacer clic en un evento que lanza nuevas actividades o algo parecido, se espera y es aceptable que este valor sea alto. - - - -
-
- - ANIMATION_START
-
-
-
- La marca de tiempo en la que se ejecutaron las animaciones registradas con Choreographer. - - -
- Al observar el tiempo entre esto y PERFORM_TRANVERSALS_START, se puede determinar cuánto tiempo llevó evaluar todos los mecanismos de animación (los más comunes son ObjectAnimator, ViewPropertyAnimator y Transitions) que se estén ejecutando. - - - - -
- Si este valor es alto (mayor a 2 ms), controle si su aplicación escribió alguna animación personalizada o qué campos está animando ObjectAnimators y asegúrese de que su animación sea adecuada. - - - - -
- Para obtener más información sobre Choreographer, consulte el video For Butter or Worse. - - -
-
- - PERFORM_TRAVERSALS_START
-
-
-
- Si a este valor le resta DRAW_START, puede saber cuánto tardaron en completarse las fases de medición y diseño. (Durante el desplazamiento o la animación, este número deberá ser cercano a cero). - - - - -
- Para obtener más información sobre las fases de medición y diseño de la canalización de representación, consulte el video -Invalidations, Layouts and Performance. - - -
-
- - DRAW_START
-
-
-
- El momento en que comenzó la fase de dibujo de performTraversals. Este es el punto inicial de grabación de la listas de visualización de cualquier vista invalidada. - - - -
- El tiempo entre esto y SYNC_START muestra cuánto se tardó en llamar a View.draw() en todas las vistas invalidadas en el árbol. - - - -
- Para obtener más información sobre el modelo de dibujo, consulte los videos Hardware Acceleration - o -Invalidations, Layouts and Performance. - -
-
- - SYNC_START
-
-
-
- El momento en que comenzó la fase de sincronización del dibujo. - - -
- Si el tiempo entre esto e ISSUE_DRAW_COMMANDS_START es muy alto (mayor a 0,4 ms o similar), generalmente esto significa que se dibujaron muchos mapas de bits que se deben subir a GPU. - - - - -
- Para obtener más información sobre la fase de sincronización, consulte el video -Profile GPU Rendering. - -
-
- - ISSUE_DRAW_COMMANDS_START
-
-
-
- El momento en que el representador de hardware comenzó a enviar comandos de dibujo a GPU. - - -
- El tiempo entre esto y FRAME_COMPLETED permite obtener una idea general sobre cuánto trabajo le genera la aplicación a GPU. - Aquí aparecen los problemas como el exceso de dibujos o efectos de representación ineficientes. - - -
-
- - SWAP_BUFFERS
-
-
-
- El momento en que se llamó a eglSwapBuffers, generalmente de poca importancia fuera del trabajo en plataforma. - - -
-
- - FRAME_COMPLETED
-
-
-
- ¡Todo listo! El tiempo total dedicado al trabajo en este fotograma se puede calcular al hacer FRAME_COMPLETED - INTENDED_VSYNC. - - -
-
-
- Puede utilizar esta información de distintas maneras. Un método de visualización simple pero eficaz es el histograma que muestra la distribución de los tiempos del fotograma (FRAME_COMPLETED - INTENDED_VSYNC) en distintos bloques de latencia; vea la siguiente figura. - - Este gráfico indica brevemente que la mayoría de los fotogramas estuvieron muy bien, es decir, por debajo del límite de 16 ms (marcado en rojo). Sin embargo, algunos fotogramas estuvieron muy por arriba del límite. - - En el histograma, podemos observar los cambios con el correr del tiempo para ver la creación de los cambios totales o los nuevos valores atípicos. - También puede graficar la latencia de entrada, el tiempo dedicado al diseño o cualquier otra medición interesante similar sobre las marcas de tiempo en los datos. - - -
- - - - -Volcado simple del intervalo del fotograma
- -
- Si, en las Opciones de Desarrollador, Profile GPU rendering se configura en In adb shell dumpsys gfinfo, el comando adb shell dumpsys gfxinfo
emite sobre el tiempo de los 120 fotogramas más recientes y los agrupa en algunas categorías diferentes con valores separados por tabulación.
-
-
- Esta información puede resultar útil para indicar qué partes de la canalización del dibujo podrían funcionar lento en un nivel alto.
-
-
- Al igual que framestats, es muy sencillo pegar esta información en su herramienta de hoja de cálculo preferida, o recolectar y redistribuir con un script. - - El siguiente gráfico detalla dónde pasaron tiempo muchos de los fotogramas generados por la aplicación. - -
- - - -- El resultado de ejecutar gfxinfo, copiar la salida, pegar en una aplicación de hoja de cálculo y graficar la información en forma de barras apiladas. - -
- -- Cada barra vertical representa un fotograma de animación, su altura representa la cantidad de milisegundos que le llevó calcular ese fotograma de animación. - Cada segmento de color de la barra representa una etapa diferente de la canalización de representación, de manera que usted pueda observar qué partes de su aplicación pueden estar creando un cuello de botella. - - Para obtener más información sobre la canalización de representación y cómo optimizarla, consulte el video -Invalidations Layouts and Performance. - -
- - -Control del período de recopilación de datos
- -- Los intervalos de framestats y del fotograma simple recopilan datos durante un período muy breve: aproximadamente dos segundos que valen la pena representar. - Para poder controlar este período con precisión, por ejemplo para limitar los datos a una animación en particular, puede restablecer todos los contadores y agregar los datos recopilados. - - -
- -->adb shell dumpsys gfxinfo <PACKAGE_NAME> reset -- -
- Esto se puede usar junto con los comandos de volcado para recopilar y restablecer a una cadencia normal a fin de capturar continuamente períodos de fotogramas de menos de dos segundos. - - -
- - -Diagnóstico de regresiones de rendimiento
- -- La identificación de regresiones es un buen primer paso para localizar los problemas y mantener la aplicación funcionando correctamente. - Sin embargo, dumpsys solo identifica la existencia y la gravedad relativa de los problemas. - Usted todavía debe diagnosticar la causa particular de los problemas de rendimiento y encontrar las soluciones adecuadas. - Para esto, es sumamente recomendable que utilice la herramienta systrace. - -
- - -Recursos adicionales
- -- Para obtener más información sobre el funcionamiento de la canalización de representación de Android, los problemas comunes que puede encontrar y cómo solucionarlos, es posible que algunos de los siguientes recursos le resulten útiles: - - -
- --
-
- Rendering Performance 101 - -
- Why 60fps? - -
- Android UI and the GPU - -
- Invalidations Layouts and performance - -
- Analyzing UI Performance with Systrace - -
Pruebas automatizadas de rendimiento de la UI
- -- Un enfoque para realizar la prueba de rendimiento de la UI es solicitar a un evaluador que realice una serie de operaciones de usuario en la aplicación objetivo para identificar visualmente jank, o bien, pasar mucho tiempo utilizando un enfoque basado en alguna herramienta para encontrar jank. - - Sin embargo, este enfoque manual tiene sus riesgos, la habilidad humana para percibir cambios en los índices de los fotogramas varía de manera alarmante. Además, este proceso lleva mucho tiempo, es tedioso y propenso a errores. - - -
- -- Un método más eficiente es registrarse y analizar las mediciones de rendimiento clave a partir de pruebas automatizadas de UI. - Android M Developer Preview incluye nuevas capacidades de registro que facilitan la determinación de la cantidad y gravedad de jank en las animaciones de su aplicación y pueden utilizarse para crear un proceso estricto a fin de determinar su rendimiento actual y realizar un seguimiento de futuros objetivos de rendimiento. - - - -
- -- Este artículo lo guía a través de un enfoque recomendado para utilizar esa información a fin de automatizar su prueba de rendimiento. - -
- -- Esto se divide básicamente en dos acciones clave. Primero, identificar qué está probando y cómo lo prueba. Segundo, configurar y mantener un entorno de prueba automatizado. - - -
- - -Configuración de pruebas de UI
- -- Antes de comenzar con las pruebas automatizadas, es importante establecer algunas decisiones de alto nivel para entender correctamente el espacio de prueba y las necesidades que puede tener. - -
- -- Identifique flujos/animaciones clave que desea probar -
- -- Recuerde que el usuario visualiza el rendimiento negativo cuando una animación fluida se interrumpe. - Por lo tanto, al identificar qué tipo de acciones de UI desea probar, se recomienda centrarse en aquellas animaciones clave que el usuario ve más o que son más importantes para su experiencia. - - Por ejemplo, a continuación, se mencionan situaciones comunes que es útil identificar: -
- --
-
- Desplazamiento por ListView o RecyclerView principales - - -
- Animaciones durante ciclos de espera no sincronizados - - -
- Animaciones que puedan contener manipulación o carga de mapa de bits - - -
- Animaciones que incluyan combinación alfa - - -
- Dibujos personalizados con Canvas - -
- Trabaje con los ingenieros, diseñadores y gerentes de productos de su equipo a fin de priorizar estas animaciones clave para la cobertura de la prueba. - -
- -- Establezca sus objetivos futuros y realice un seguimiento en virtud de ellos -
- -- Desde un nivel alto, puede ser crítico identificar sus metas de rendimiento específicas y concentrarse en escribir pruebas y recopilar datos sobre ellas. - Por ejemplo: -
- --
-
- ¿Simplemente desea comenzar a realizar un seguimiento del rendimiento de la UI por primera vez para obtener más información? - - -
- ¿Desea evitar regresiones que podrían aparecer en el futuro? - - -
- ¿Se encuentra hoy en un 90 % de fluidez de fotogramas y quiere alcanzar un 98 % en este trimestre? - - -
- ¿Se encuentra en un 98 % de fluidez de fotogramas y no quiere retroceder? - - -
- ¿Tiene como objetivo mejorar el rendimiento en dispositivos de gama baja? - -
- Para todas estas situaciones, es recomendable realizar un seguimiento que muestre el rendimiento en múltiples versiones de su aplicación. - -
- -- Identifique los dispositivos en los que desea realizar la prueba -
- -- El rendimiento de la aplicación varía según el dispositivo en el que se ejecuta. Algunos dispositivos pueden tener menos memoria, GPU menos potentes o CPU más lentos. - Esto significa que las animaciones que funcionan bien en un conjunto de hardware pueden no hacerlo en otros, o peor, pueden provocar un cuello de botella en diferentes secciones de la canalización. - - Por lo tanto, para justificar esta variación en lo que un usuario puede ver, seleccione una serie de dispositivos, tanto de alta gama como de baja, tablets, etc., en los que ejecutará las pruebas. - - Busque variedad en rendimiento de CPU, memoria RAM, resolución de pantalla, tamaño, etc. - Las pruebas exitosas en un dispositivo de alta gama pueden fallar en uno de baja gama. - -
- -- Marcos básicos para pruebas de UI -
- -- Algunos conjuntos de herramientas, como UI Automator y Espresso, están diseñados para ayudar a automatizar el desplazamiento de un usuario por su aplicación. - - Estos son marcos simples que imitan la interacción del usuario con el dispositivo. - Para utilizar estos marcos, debe crear con éxito scripts únicos que se ejecuten en un conjunto de acciones de usuarios y reproducirlos en el dispositivo en sí. - - -
- -
- Al combinar estas pruebas automatizadas junto con dumpsys gfxinfo
, puede crear rápidamente un sistema reproducible que le permite ejecutar una prueba y medir la información de rendimiento de esa condición particular.
-
-
-
Configurar pruebas automatizadas de UI
- -- Una vez que pueda ejecutar una prueba de UI y una canalización para recopilar datos de una sola prueba, el próximo paso importante es elegir un marco que pueda ejecutar esa prueba muchas veces en múltiples dispositivos y agregar los datos de rendimiento resultantes para que su equipo de desarrollo los analice mejor. - - - -
- -- Un marco para la automatización de pruebas -
- -- Vale la pena mencionar que los marcos para pruebas de UI (como UI Automator) se ejecutan directamente en el emulador/dispositivo objetivo. - A la recopilación de información de rendimiento realizada por -dumpsys gfxinfo la impulsa un equipo de host que envía comandos por ADB. Para ayudar a unir la automatización de estas entidades separadas, se diseñó el marco MonkeyRunner. Un sistema de scripts que se ejecuta en su equipo de host y que puede emitir comandos a un conjunto de dispositivos conectados y recibir datos de ellos. - - - -
- -- Al crear un conjunto de scripts para la automatización adecuada de las pruebas de rendimiento de UI, usted podrá, como mínimo, utilizar MonkeyRunner para realizar con éxito las siguientes tareas: - -
- --
-
- Cargar e iniciar un APK deseado en un dispositivo objetivo, en múltiples dispositivos o en un emulador. - - -
- Iniciar una prueba de UI automatizada y permitir que se ejecute. - - -
- Recopilar información de rendimiento mediante dumpsys gfxinfo. - - -
- Añadir información y presentársela de manera útil al desarrollador. - -
Clasificar y solucionar problemas detectados
- -- Una vez que se identifican los patrones de problemas o las regresiones, el paso siguiente es identificar y aplicar la solución. - Si su marco de pruebas automatizadas preserva detalles precisos del intervalo para los fotogramas, puede ayudarlo a investigar cambios sospechosos de código o diseño (en el caso de una regresión), o delimitar la parte del sistema que está analizando al cambiar a una investigación manual. - - - Para realizar una investigación manual, systrace es un buen lugar para comenzar, ya que muestra información precisa sobre cada etapa de la canalización de representación, cada subproceso y núcleo del sistema, además de cualquier marca de evento personalizada que usted defina. - - -
- -- Descripción adecuada de intervalos temporales -
- -- Es importante mencionar las dificultades para obtener y medir los intervalos que son producto del rendimiento de la representación. - Estos números son, por naturaleza, no deterministas y, a menudo, fluctúan según el estado del sistema, la cantidad de memoria disponible, el límite térmico y la última vez que un rayo solar tocó el área de la tierra donde se encuentra. - - El punto es que puede ejecutar la misma prueba dos veces y obtener números apenas diferentes que pueden estar cerca pero no ser iguales. - - -
- -- Para recopilar y definir datos correctamente de esta manera, deberá ejecutar la misma prueba muchas veces y acumular los resultados como un promedio o un valor promedio (para que resulte más fácil, lo llamaremos un “lote”). Esto le ofrece una aproximación estimada del rendimiento de la prueba, sin requerir intervalos exactos. - - - -
- -- Los lotes se pueden usar entre cambios de código para verificar el impacto relativo que esos cambios tienen en el rendimiento. - Si el índice de fotograma promedio para el lote previo al cambio es que el lote después del cambio, entonces, generalmente está en presencia de un incremento general en relación con el rendimiento para ese cambio particular. - - -
- -- Esto significa que cualquier prueba automatizada de UI que lleve a cabo debería tener en cuenta este concepto, además de justificar cualquier anomalía que pudiera surgir durante una prueba. - Por ejemplo, si el rendimiento de su aplicación disminuye repentinamente debido a algún problema con el dispositivo (que no sea provocado por la aplicación), deberá volver a ejecutar el lote para obtener intervalos menos caóticos. - - - -
- -- Entonces, ¿cuántas veces debe ejecutar una prueba para que los resultados sean significativos? El mínimo debe ser 10 veces y con números más altos, como 50 o 100, para obtener resultados más precisos (por supuesto, ahora cambia el tiempo por la precisión). - - -
diff --git a/docs/html-intl/intl/es/training/material/animations.jd b/docs/html-intl/intl/es/training/material/animations.jd new file mode 100644 index 0000000000000000000000000000000000000000..5bd289eb99de87dfcfc38ce5f030d75f11b2e205 --- /dev/null +++ b/docs/html-intl/intl/es/training/material/animations.jd @@ -0,0 +1,550 @@ +page.title=Definir animaciones personalizadas + +@jd:body + +Esta lección te enseña a realizar lo siguiente:
+-
+
- Personalizar la respuesta táctil +
- Usar el efecto Revelar +
- Personalizar transiciones de actividades +
- Animar cambios de estados de las vistas +
- Animar interfaces dibujables en vector +
También deberías leer
+ +Las animaciones en Material Design proporcionan a los usuarios comentarios sobre sus acciones y continuidad visual +a medida que los usuarios interactúan con su aplicación. El tema material proporciona algunas animaciones predeterminadas +para botones y transiciones de actividades; Android 5.0 (API nivel 21) y superior te permite personalizar estas +animaciones y crear unas nuevas:
+ +-
+
- Respuesta táctil +
- Efecto revelar circular +
- Transiciones de actividades +
- Movimiento curvo +
- Ver cambios de estados +
Personalizar la respuesta táctil
+ +La respuesta táctil en Material Design proporciona una confirmación visual instantánea en el punto +de contacto cuando los usuarios interactúan con los elementos de la IU. Las animaciones predeterminadas de la respuesta táctil para +botones usan la nueva clase {@link android.graphics.drawable.RippleDrawable}, que realiza una transición +entre diferentes estados con un efecto de ondas.
+ +En la mayoría de los casos, debes aplicar esta funcionalidad en la vista XML especificando el fondo +de la vista como:
+ +-
+
?android:attr/selectableItemBackground
para un efecto de ondas con límites.
+?android:attr/selectableItemBackgroundBorderless
para un efecto de ondas que se extiende más allá de +la vista. Se lo dibujará en la vista primaria más cercana de la vista (que lo limitará) con un fondo de valor no +nulo.
+
Nota: selectableItemBackgroundBorderless
es un nuevo
+atributo introducido en la API de nivel 21.
Alternativamente, puedes definir un {@link android.graphics.drawable.RippleDrawable}
+como un recurso XML que usa el elemento ripple
.
Puedes asignar un color a los objetos {@link android.graphics.drawable.RippleDrawable}. Para cambiar
+el color predeterminado de la respuesta táctil, usa el atributo android:colorControlHighlight
+del tema.
Para más información, consulta la referencia de la API para la clase {@link +android.graphics.drawable.RippleDrawable}.
+ + +Usar el efecto revelar
+ +Las animaciones del efecto revelar proporcionan a los usuarios una continuidad visual cuando muestras u ocultas un grupo de elementos +de la IU. El método {@link android.view.ViewAnimationUtils#createCircularReveal +ViewAnimationUtils.createCircularReveal()} te permite animar un círculo de recorte para +revelar u ocultar una vista.
+ +Para revelar una vista previamente invisible usando este efecto:
+ ++// previously invisible view +View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the final radius for the clipping circle +int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); + +// create the animator for this view (the start radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); + +// make the view visible and start the animation +myView.setVisibility(View.VISIBLE); +anim.start(); ++ +
Para ocultar una vista previamente invisible usando este efecto:
+ ++// previously visible view +final View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the initial radius for the clipping circle +int initialRadius = myView.getWidth(); + +// create the animation (the final radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); + +// make the view invisible when the animation is done +anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + myView.setVisibility(View.INVISIBLE); + } +}); + +// start the animation +anim.start(); ++ + +
Personalizar transiciones de actividades
+ + +Las transiciones de actividades en las aplicaciones de Material Design proporcionan conexiones visuales entre diferentes estados +mediante el movimiento y las transformaciones entre elementos comunes. Puedes especificar las animaciones personalizadas para +entrar y salir de las transiciones y para las transiciones de elementos compartidos entre actividades.
+ +-
+
- Una transición de entrada determina cómo entran en escena las vistas en una actividad. +Por ejemplo, en la transición de entrada expandir, las vistas entran en escena desde el exterior +y vuelan hacia el centro de la pantalla. + +
- Una transición de salida determina cómo salen de escena las vistas en una actividad. Por +ejemplo, en la transición de salida expandir, las vistas salen de escena lejos del +centro. + +
- Una transición de elementos compartidos determina cómo las vistas que están compartidas entre +dos actividades realizan la transición entre estas. Por ejemplo, si dos actividades tienen la misma +imagen en diferentes posiciones y tamaños, la transición de elementos compartidos changeImageTransform +traduce y escala la imagen suavemente entre estas actividades. +
Android 5.0 (API nivel 21) admite estas transiciones de entrada y salida:
+ +-
+
- expandir: desplaza vistas hacia adentro o hacia afuera del centro de la escena. +
- deslizar: desplaza vistas hacia adentro o hacia afuera de uno de los bordes de la escena. +
- difuminar: agrega o quita una vista de la escena al cambiar su opacidad. +
Toda transición que extiende la clase {@link android.transition.Visibility} se admite +como una transición de entrada o salida. Para más información, consulta la referencia de la API para la clase +{@link android.transition.Transition}.
+ +Android 5.0 (API nivel 21) también admite estas transiciones de elementos compartidos:
+ +-
+
- changeBounds: anima los cambios en los límites de las vistas de destino. +
- changeClipBounds: anima los cambios en los límites de recorte de las vistas de destino. +
- changeTransform: anima los cambios en escala y rotación de las vistas de destino. +
- changeImageTransform: anima los cambios de tamaño y escala de imágenes de destino. +
Cuando habilitas las transiciones de actividades en tu aplicación, la transición entre difuminados predeterminada se +activa entre las actividades que ingresan y salen.
+ + + + +Especificar transiciones personalizadas
+ +Primero, habilita las transiciones de contenido de la ventana con el atributo android:windowContentTransitions
+cuando definas un estilo que herede del tema material. También puedes especificar
+transiciones de entrada, salida y elementos compartidos en tu definición de estilo:
+<style name="BaseAppTheme" parent="android:Theme.Material"> + <!-- enable window content transitions --> + <item name="android:windowContentTransitions">true</item> + + <!-- specify enter and exit transitions --> + <item name="android:windowEnterTransition">@transition/explode</item> + <item name="android:windowExitTransition">@transition/explode</item> + + <!-- specify shared element transitions --> + <item name="android:windowSharedElementEnterTransition"> + @transition/change_image_transform</item> + <item name="android:windowSharedElementExitTransition"> + @transition/change_image_transform</item> +</style> ++ +
La transición change_image_transform
en este ejemplo se define en la siguiente forma:
+<!-- res/transition/change_image_transform.xml --> +<!-- (see also Shared Transitions below) --> +<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> + <changeImageTransform/> +</transitionSet> ++ +
El elemento changeImageTransform
corresponde a la clase
+{@link android.transition.ChangeImageTransform}. Para más información, consulta la referencia de la
+API para {@link android.transition.Transition}.
Para habilitar las transiciones del contenido de las ventanas en tu código, llama al método +{@link android.view.Window#requestFeature Window.requestFeature()}:
+ ++// inside your activity (if you did not enable transitions in your theme) +getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + +// set an exit transition +getWindow().setExitTransition(new Explode()); ++ +
Para especificar transiciones en tu código, llama a estos métodos con un objeto {@link +android.transition.Transition}:
+ +-
+
- {@link android.view.Window#setEnterTransition Window.setEnterTransition()} +
- {@link android.view.Window#setExitTransition Window.setExitTransition()} +
- {@link android.view.Window#setSharedElementEnterTransition + Window.setSharedElementEnterTransition()} +
- {@link android.view.Window#setSharedElementExitTransition + Window.setSharedElementExitTransition()} +
Los métodos {@link android.view.Window#setExitTransition setExitTransition()} y {@link +android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} definen +la transición de salida para la actividad que realiza la llamada. Los métodos {@link android.view.Window#setEnterTransition +setEnterTransition()} y {@link android.view.Window#setSharedElementEnterTransition +setSharedElementEnterTransition()} definen la transición de entrada para la actividad invocada.
+ +Para obtener el efecto completo de una transición, debes habilitar las transiciones de contenido de las ventanas tanto para las +actividades que realizan la llamada como para aquellas que son invocadas. De lo contrario, la actividad que realiza la llamada comenzará la transición de salida, +pero luego observarás una ventana de transición (como escalar o difuminar).
+ +Para comenzar una transición de entrada lo antes posible, usa el método +{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} +en la actividad invocada. Esto te permite tener transiciones de entrada más intensas.
+ +Iniciar una actividad mediante el uso de transiciones
+ +Si permites transiciones y estableces una transición de salida para una actividad, la transición se activa +cuando inicias otra actividad, como alguna de las siguientes:
+ ++startActivity(intent, + ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); ++ +
Si estableciste una transición de entrada para la segunda actividad, la transición también se activa
+cuando se inicia la actividad. Para deshabilitar las transiciones cuando inicias otra actividad, proporciona
+una agrupación de opciones null
.
Iniciar una actividad con un elemento compartido
+ +Para realizar una animación de transiciones de pantallas entre dos actividades que tienen un elemento compartido:
+ +-
+
- Habilita las transiciones de contenido de ventanas en tu tema. +
- Especifica una transición de elementos compartidos en tu estilo. +
- Define tu transición como un recurso XML. +
- Asigna un nombre en común para los elementos compartidos en ambos diseños con el atributo
+
android:transitionName
.
+ - Usa el método {@link android.app.ActivityOptions#makeSceneTransitionAnimation +ActivityOptions.makeSceneTransitionAnimation()}. +
+// get the element that receives the click event +final View imgContainerView = findViewById(R.id.img_container); + +// get the common element for the transition in this activity +final View androidRobotView = findViewById(R.id.image_small); + +// define a click listener +imgContainerView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(this, Activity2.class); + // create the transition animation - the images in the layouts + // of both activities are defined with android:transitionName="robot" + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(this, androidRobotView, "robot"); + // start the new activity + startActivity(intent, options.toBundle()); + } +}); ++ +
Para las vistas dinámicas compartidas que generas en tu código, usa el método +{@link android.view.View#setTransitionName View.setTransitionName()} para especificar un nombre de +elemento en común en ambas actividades.
+ +Para invertir la animación de transición de escenas cuando terminas la segunda actividad, llama al método +{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} +en lugar del {@link android.app.Activity#finish Activity.finish()}.
+ +Iniciar una actividad con múltiples elementos compartidos
+ +Para realizar una animación de transición de escenas entre dos actividades que tienen más de un elemento
+compartido, define los elementos compartidos en ambos diseños con el atributo android:transitionName
+(o usa el método {@link android.view.View#setTransitionName View.setTransitionName()}
+en ambas actividades) y crea un objeto {@link android.app.ActivityOptions} como se indica a continuación:
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, + Pair.create(view1, "agreedName1"), + Pair.create(view2, "agreedName2")); ++ + +
Usar movimiento curvo
+ +Las animaciones en Material Design se basan en curvas para la interpolación de tiempo y los modelos de movimiento +espacial. Con Android 5.0 (API nivel 21) y superior, puedes definir las curvas de sincronización personalizadas y +los modelos de movimientos curvos para las animaciones.
+ +La clase {@link android.view.animation.PathInterpolator} es un nuevo interpolador que se basa en una curva +Bézier o un objeto {@link android.graphics.Path}. Este interpolador especifica una curva de movimiento +en un cuadrado de 1x1, con puntos de anclaje a (0,0) y (1,1), y puntos de control según lo especificado en los argumentos del +constructor. También puedes definir un interpolador para la ruta de acceso como un recurso XML:
+ ++<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.4" + android:controlY1="0" + android:controlX2="1" + android:controlY2="1"/> ++ +
El sistema proporciona recursos XML para las tres curvas básicas en la especificación +de Material Design:
+ +-
+
@interpolator/fast_out_linear_in.xml
+ @interpolator/fast_out_slow_in.xml
+ @interpolator/linear_out_slow_in.xml
+
Puedes pasar un objeto {@link android.view.animation.PathInterpolator} al método {@link +android.animation.Animator#setInterpolator Animator.setInterpolator()}.
+ +La clase {@link android.animation.ObjectAnimator} tiene nuevos constructores que te permiten animar +coordenadas junto a una ruta de acceso, usando dos o más propiedades a la vez. Por ejemplo, el siguiente animador +usa un objeto{@link android.graphics.Path} para animar las propiedades X e Y de una vista:
+ ++ObjectAnimator mAnimator; +mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); +... +mAnimator.start(); ++ + +
Animar cambios de estados de las vistas
+ +La clase {@link android.animation.StateListAnimator} te permite definir los animadores que se ejecutan cuando +cambia el estado de una vista. En el siguiente ejemplo, se muestra cómo definir un {@link +android.animation.StateListAnimator} como un recurso XML:
+ ++<!-- animate the translationZ property of a view when pressed --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="@android:integer/config_shortAnimTime" + android:valueTo="2dp" + android:valueType="floatType"/> + <!-- you could have other objectAnimator elements + here for "x" and "y", or other properties --> + </set> + </item> + <item android:state_enabled="true" + android:state_pressed="false" + android:state_focused="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="100" + android:valueTo="0" + android:valueType="floatType"/> + </set> + </item> +</selector> ++ +
Para adjuntar animaciones personalizadas de los estados de visualizaciones, define un animador usando el elemento
+selector
en un archivo de recurso XML como en este ejemplo y asígnalo a tu
+vista con el atributo android:stateListAnimator
. Para asignar un animador de lista de estados
+a una vista en tu código, usa el método {@link android.animation.AnimatorInflater#loadStateListAnimator
+AnimationInflater.loadStateListAnimator()} y asigna el animador a tu vista con el método
+{@link android.view.View#setStateListAnimator View.setStateListAnimator()}.
Cuando tu tema extiende al tema material, los botones tendrán una animación Z de manera predeterminada. Para evitar este
+comportamiento en los botones, establece el atributo android:stateListAnimator
en
+@null
.
La clase {@link android.graphics.drawable.AnimatedStateListDrawable} te permite crear elementos de diseño +que muestren animaciones entre los cambios de estados de la vista asociada. Algunos de los widgets del sistema en +Android 5.0 usan estas animaciones de manera predeterminada. En el siguiente ejemplo, se muestra cómo +definir un {@link android.graphics.drawable.AnimatedStateListDrawable} como un recurso XML:
+ ++<!-- res/drawable/myanimstatedrawable.xml --> +<animated-selector + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- provide a different drawable for each state--> + <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" + android:state_pressed="true"/> + <item android:id="@+id/focused" android:drawable="@drawable/drawableF" + android:state_focused="true"/> + <item android:id="@id/default" + android:drawable="@drawable/drawableD"/> + + <!-- specify a transition --> + <transition android:fromId="@+id/default" android:toId="@+id/pressed"> + <animation-list> + <item android:duration="15" android:drawable="@drawable/dt1"/> + <item android:duration="15" android:drawable="@drawable/dt2"/> + ... + </animation-list> + </transition> + ... +</animated-selector> ++ + +
Animar interfaces dibujables en vector
+ +Las interfaces dibujables en vector son +escalables sin perder definición. La clase {@link android.graphics.drawable.AnimatedVectorDrawable} +te permite animar las propiedades de un elemento de diseño en vector.
+ +Generalmente, las interfaces animadas dibujables en vector se definen en tres archivos XML:
+ +-
+
- Una interfaz dibujable en vector con el elemento
<vector>
en +res/drawable/
+ - Una interfaz dibujable animada en vector con el elemento
<animated-vector>
en +res/drawable/
+ - Uno o más animadores de objeto con el elemento
<objectAnimator>
en +res/anim/
+
Las interfaces animadas dibujables en vector pueden animar los atributos de los elementos <group>
y
+<path>
. Los elementos <group>
definen un conjunto de
+rutas de acceso o subgrupos y el elemento <path>
define rutas de acceso para dibujar.
Cuando definas una interfaz dibujable en vector que desees animar, usa el atributo android:name
+para asignar un nombre único a grupos o rutas de acceso, de manera que puedas hacer referencia a ellos desde tus definiciones del
+animador. Por ejemplo:
+<!-- res/drawable/vectordrawable.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600"> + <group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:name="v" + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + </group> +</vector> ++ +
La definición de la interfaz animada dibujable en vector hace referencia a grupos y rutas de acceso en el elemento de diseño en vector +por sus nombres:
+ ++<!-- res/drawable/animvectordrawable.xml --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vectordrawable" > + <target + android:name="rotationGroup" + android:animation="@anim/rotation" /> + <target + android:name="v" + android:animation="@anim/path_morph" /> +</animated-vector> ++ +
Las definiciones de animación representan objetos {@link android.animation.ObjectAnimator} o {@link +android.animation.AnimatorSet}. El primer animador en este ejemplo rota el grupo +objetivo unos 360 grados:
+ ++<!-- res/anim/rotation.xml --> +<objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360" /> ++ +
El segundo animador en este ejemplo transforma la ruta de acceso de la interfaz dibujable en vector de una forma a +otra. Ambas rutas de acceso deben ser compatibles para transformarse: deben tener el mismo número de comandos +y el mismo número de parámetros para cada comando.
+ ++<!-- res/anim/path_morph.xml --> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="3000" + android:propertyName="pathData" + android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" + android:valueType="pathType" /> +</set> ++ +
Para más información, consulta la referencia de la API para {@link +android.graphics.drawable.AnimatedVectorDrawable}.
diff --git a/docs/html-intl/intl/es/training/material/compatibility.jd b/docs/html-intl/intl/es/training/material/compatibility.jd new file mode 100644 index 0000000000000000000000000000000000000000..ad2e953fed4f53819e2647878a8429e5b95cf4c7 --- /dev/null +++ b/docs/html-intl/intl/es/training/material/compatibility.jd @@ -0,0 +1,168 @@ +page.title=Mantener la compatibilidad + +@jd:body + +Esta lección te enseña a realizar lo siguiente:
+-
+
- Definir estilos alternativos +
- Proporcionar diseños alternativos +
- Usar la Biblioteca de soporte +
- Comprobar la versión del sistema +
También deberías leer
+ +Algunas características de Material Design, como el tema material y las transiciones de actividades personalizadas, solo +están disponibles en Android 5.0 (API nivel 21) y superior. Sin embargo, puedes diseñar tus aplicaciones para +usar estas características cuando se ejecutan en dispositivos que admiten Material Design y aún son compatibles +con dispositivos que ejecutan versiones anteriores de Android.
+ + +Definir estilos alternativos
+ +Puedes configurar tu aplicación para usar el tema material en los dispositivos que los admiten y revertir +a un tema anterior en los dispositivos que ejecutan versiones anteriores de Android:
+ +-
+
- Define un tema que herede de un tema anterior (como Holo) en
+
res/values/styles.xml
.
+ - Define un tema con el mismo nombre que hereda del tema material en
+
res/values-v21/styles.xml
.
+ - Establece este tema como el tema de tu aplicación en el archivo de manifiesto. +
Nota: +Si tu aplicación usa el tema material pero no proporciona un tema alternativo, +tu aplicación no se ejecutará en versiones de Android anteriores a la versión 5.0. +
+ + +Proporcionar diseños alternativos
+ +Si los diseños que realizas de acuerdo con las pautas de Material Design no usan ninguno de +los nuevos atributos XML introducidos en Android 5.0 (API nivel 21), estos trabajarán en +versiones anteriores de Android. De lo contrario, puedes proporcionar diseños alternativos. También puedes proporcionar diseños +alternativos para personalizar la apariencia de tu aplicación en versiones anteriores de Android.
+ +Crea tus archivos de diseño para Android 5.0 (API nivel 21) dentro de res/layout-v21/
y
+tus archivos de diseño alternativo para versiones anteriores de Android dentro de res/layout/
.
+Por ejemplo, res/layout/my_activity.xml
es un diseño alternativo para
+res/layout-v21/my_activity.xml
.
Para evitar duplicación de código, define tus estilos en res/values/
, modifica
+estilos en res/values-v21/
para las nuevas API y usa transmisión por herencia de estilos, definiendo estilos
+base en res/values/
y heredando de los que están en res/values-v21/
.
Usar la Biblioteca de soporte
+ +Las Bibliotecas de soporte v7 +r21 y superiores incluyen las siguientes características de Material Design:
+ +-
+
- Estilos de Material Design para algunos widgets
+del sistema cuando aplicas uno de los temas
Theme.AppCompat
.
+ - Atributos del tema de la paleta de colores
+en los temas
Theme.AppCompat
.
+ - El widget {@link android.support.v7.widget.RecyclerView} para mostrar conjuntos +de datos. +
- El widget {@link android.support.v7.widget.CardView} para crear tarjetas. +
- La clase {@link android.support.v7.graphics.Palette} para extraer colores prominentes de +imágenes. +
Widgets del sistema
+ +Los temas Theme.AppCompat
proporcionan estilos de Material Design para estos widgets:
-
+
- {@link android.widget.EditText} +
- {@link android.widget.Spinner} +
- {@link android.widget.CheckBox} +
- {@link android.widget.RadioButton} +
- {@link android.support.v7.widget.SwitchCompat} +
- {@link android.widget.CheckedTextView} +
Paleta de colores
+ +Para obtener estilos de Material Design y personalizar la paleta de colores con la Biblioteca de soporte
+v7 de Android, aplica uno de los temas Theme.AppCompat
:
+<!-- extend one of the Theme.AppCompat themes --> +<style name="Theme.MyTheme" parent="Theme.AppCompat.Light"> + <!-- customize the color palette --> + <item name="colorPrimary">@color/material_blue_500</item> + <item name="colorPrimaryDark">@color/material_blue_700</item> + <item name="colorAccent">@color/material_green_A200</item> +</style> ++ +
Listas y tarjetas
+ +Los widgets {@link android.support.v7.widget.RecyclerView} y {@link +android.support.v7.widget.CardView} están disponible en versiones anteriores de Android mediante +la Biblioteca de soporte v7 con estas limitaciones:
+-
+
- {@link android.support.v7.widget.CardView} regresa a una implementación de sombras programáticas +mediante el uso de espaciado adicional. +
- {@link android.support.v7.widget.CardView} no recorta las vistas de sus hijos que forman intersecciones +con esquinas redondeadas. +
Dependencias
+ +Para usar estas características en versiones de Android anteriores a la 5.0 (API nivel 21), incluye +en tu proyecto la Biblioteca de soporte v7 de Android como una dependencia de Gradle:
+ ++dependencies { + compile 'com.android.support:appcompat-v7:21.0.+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} ++ + +
Comprobar la versión del sistema
+ +Las siguientes características están disponibles solo en Android 5.0 (nivel de API 21) y superior:
+ +-
+
- Transiciones de actividades +
- Respuesta táctil +
- Animaciones con el efecto revelar +
- Animaciones basadas en rutas +
- Interfaces dibujables en vector +
- Matiz de la interfaz dibujable +
Para conservar la compatibilidad con versiones anteriores de Android, comprueba la {@link +android.os.Build.VERSION#SDK_INT version} del sistema en tiempo de ejecución antes de invocar las API para cualquiera de estas +características:
+ ++// Check if we're running on Android 5.0 or higher +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // Call some material design APIs here +} else { + // Implement this feature without material design +} ++ +
Nota: Para especificar qué versiones de Android admite tu aplicación,
+usa los atributos android:minSdkVersion
y android:targetSdkVersion
+en tu archivo de manifiesto. Para usar las características de Material Design en Android 5.0, establece el
+atributo android:targetSdkVersion
en 21
. Para más información, consulta
+la guía de <uses-sdk> de la
+API.
Esta lección te enseña a realizar lo siguiente:
+-
+
- Cambiar el matiz de los recursos dibujables +
- Extraer colores prominentes de una imagen +
- Crear interfaces dibujables en vector +
También deberías leer
+ +Las siguientes capacidades para las interfaces dibujables te ayudan a implementar Material Design en tus aplicaciones:
+ +-
+
- Matiz de la interfaz dibujable +
- Extracción de color prominente +
- Interfaces dibujables en vector +
Esta lección te muestra cómo usar estas características en tu aplicación.
+ + +Cambiar el matiz de los recursos dibujables
+ +Con Android 5.0 (API nivel 21) y superior, puedes cambiar el matiz de los mapas de bits y nueve parches definidos como
+máscaras alfa. Puedes cambiar el matiz con recursos de colores o atributos de temas que se resuelven a
+recursos de colores (por ejemplo, ?android:attr/colorPrimary
). Generalmente, puedes crear estos recursos
+solo una vez y agregarles color automáticamente para que coincidan con tu tema.
Puedes aplicar un matiz a los objetos {@link android.graphics.drawable.BitmapDrawable} o {@link
+android.graphics.drawable.NinePatchDrawable} con el método {@code setTint()}. También puedes
+establecer el color de matiz y el modo en tus diseños con los atributos android:tint
y
+android:tintMode
.
Extraer colores prominentes de una imagen
+ +La Biblioteca de soporte de Android r21 y superiores incluye la clase {@link +android.support.v7.graphics.Palette}, que te permite extraer colores prominentes de una imagen. +Esta clase extrae los siguientes colores prominentes:
+ +-
+
- Brillante +
- Oscuro brillante +
- Claro brillante +
- Apagado +
- Oscuro apagado +
- Claro apagado +
Para extraer estos colores, pasa un objeto {@link android.graphics.Bitmap} al método estático +{@link android.support.v7.graphics.Palette#generate Palette.generate()} en el subproceso en +segundo plano en donde cargas tus imágenes. Si no puedes usar dicho subproceso, llama al método +{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} y proporciona +un gestor de eventos en su lugar.
+ +Puedes recuperar los colores prominentes de la imagen mediante los métodos de obtención en la clase
+Palette
, como Palette.getVibrantColor
.
Para usar la clase {@link android.support.v7.graphics.Palette} en tu proyecto, agrega la siguiente +Dependencia Gradle al módulo de +tu aplicación:
+ ++dependencies { + ... + compile 'com.android.support:palette-v7:21.0.0' +} ++ +
Para más información, consulta la referencia de la API para la clase {@link android.support.v7.graphics.Palette}. +
+ + +Crear interfaces dibujables en vector
+ + + +Video
+Gráficos en vector de Android
+En Android 5.0 (API nivel 21) y superiores, puedes definir las interfaces dibujables en vector, que escalan sin
+perder definición. Solo necesitas un archivo de recurso para una imagen en vector, en oposición a un archivo de recurso para
+la densidad de cada pantalla en el caso de imágenes de mapa de bits. Para crear una imagen en vector, defines los detalles
+de la forma dentro de un elemento XML <vector>
.
El siguiente ejemplo define una imagen en vector con la forma de un corazón:
+ ++<!-- res/drawable/heart.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + <!-- intrinsic size of the drawable --> + android:height="256dp" + android:width="256dp" + <!-- size of the virtual canvas --> + android:viewportWidth="32" + android:viewportHeight="32"> + + <!-- draw a path --> + <path android:fillColor="#8fff" + android:pathData="M20.5,9.5 + c-1.955,0,-3.83,1.268,-4.5,3 + c-0.67,-1.732,-2.547,-3,-4.5,-3 + C8.957,9.5,7,11.432,7,14 + c0,3.53,3.793,6.257,9,11.5 + c5.207,-5.242,9,-7.97,9,-11.5 + C25,11.432,23.043,9.5,20.5,9.5z" /> +</vector> ++ +
Las imágenes en vector están representadas en Android como objetos {@link android.graphics.drawable.VectorDrawable}.
+ Para más información sobre la sintaxis pathData
, consulta la referencia de ruta de acceso SVG. Para más información
+sobre la animación de las propiedades de las interfaces dibujables en vector, consulta
+Animación de interfaces dibujables en vector.
Esta lección te enseña a realizar lo siguiente:
+-
+
- Aplicar el tema Material +
- Realizar tus diseños +
- Especificar la elevación en tus vistas +
- Crear listas y tarjetas +
- Personalizar tus animaciones +
También deberías leer
+ +Para crear aplicaciones con Material Design:
+ +-
+
- + Revisar la especificación de Material Design. +
- + Aplicar el tema material a tu aplicación. +
- + Crear tus diseños siguiendo las pautas de Material Design. +
- + Especificar la elevación de tus vistas para convertir sombras. +
- + Usar widgets del sistema para listas y tarjetas. +
- + Personalizar las animaciones en tu aplicación. +
Mantener la compatibilidad con versiones anteriores
+ +Puedes agregar muchas características de Material Design a tu aplicación mientras mantienes la compatibilidad con las +versiones anteriores a Android 5.0. Para más información, consulta +Mantener la compatibilidad.
+ +Actualización de tu aplicación con Material Design
+ +Para actualizar una aplicación existente para incorporar Material Design, actualiza tus diseños siguiendo +las pautas de Material Design. Además, asegúrate de incorporar profundidad, respuesta táctil y +animaciones.
+ +Crear nuevas aplicaciones con Material Design
+ +Si creas una nueva aplicación con las características de Material Design, las pautas de Material Design te proporcionan un framework +de diseño cohesivo. Sigue estas pautas y usa la nueva funcionalidad del framework de +Android para diseñar y desarrollar tu aplicación.
+ + +Aplicar el tema Material
+ +Para aplicar el tema material en tu aplicación, especifica el estilo que hereda de
+android:Theme.Material
:
+<!-- res/values/styles.xml --> +<resources> + <!-- your theme inherits from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- theme customizations --> + </style> +</resources> ++ +
El tema material proporciona widgets de sistema actualizados y te permite establecer la paleta de colores y las animaciones +predeterminadas para la respuesta táctil y las transiciones de actividades. Para obtener más detalles, consulta +Usar el tema Material.
+ + +Realizar tus diseños
+ +Además de aplicar y personalizar el tema material, tus diseños deben cumplir con +las pautas de Material Design. Cuando realices +tus diseños, presta especial atención a lo siguiente:
+ +-
+
- Cuadrículas de referencia +
- Líneas clave +
- Espaciado +
- Tamaño del objetivo táctil +
- Estructura del diseño +
Especificar la elevación en tus vistas
+ +Las vistas pueden proyectar sombras y el valor de elevación de una vista
+determina el tamaño de su sombra y el orden en que será dibujada. Para establecer la elevación de una vista, usa el atributo
+android:elevation
en tus diseños:
+<TextView + android:id="@+id/my_textview" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/next" + android:background="@color/white" + android:elevation="5dp" /> ++ +
La nueva propiedad translationZ
te permite crear animaciones que reflejen cambios
+temporales en la elevación de una vista. Los cambios de elevación pueden ser útiles cuando
+responden a gestos
+táctiles.
Para obtener más detalles, consulta Definir +vistas de recorte y sombras.
+ + +Crear listas y tarjetas
+ +{@link android.support.v7.widget.RecyclerView} es una versión más acoplable de {@link +android.widget.ListView} que admite diferentes tipos de diseños y proporciona mejoras en el rendimiento. +{@link android.support.v7.widget.CardView} te permite mostrar partes de información dentro de las tarjetas con +una apariencia uniforme entre distintas aplicaciones. El siguiente ejemplo de códigos muestra cómo incluir un +{@link android.support.v7.widget.CardView} en tu diseño:
+ ++<android.support.v7.widget.CardView + android:id="@+id/card_view" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="3dp"> + ... +</android.support.v7.widget.CardView> ++ +
Para obtener más información, consulta Crear listas +y tarjetas.
+ + +Personalizar tus animaciones
+ +Android 5.0 (API nivel 21) incluye nuevas API para crear animaciones personalizadas en tu aplicación. +Por ejemplo, puedes habilitar las transiciones de actividades y definir una transición de salida dentro de una +actividad:
+ ++public class MyActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // enable transitions + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + setContentView(R.layout.activity_my); + } + + public void onSomeButtonClicked(View view) { + getWindow().setExitTransition(new Explode()); + Intent intent = new Intent(this, MyOtherActivity.class); + startActivity(intent, + ActivityOptions + .makeSceneTransitionAnimation(this).toBundle()); + } +} ++ +
Cuando comienzas otra actividad desde esta actividad, se activa la transición de salida.
+ +Para más información sobre las nuevas API de animación, consulta Definir animaciones personalizadas.
diff --git a/docs/html-intl/intl/es/training/material/index.jd b/docs/html-intl/intl/es/training/material/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..1af0ead3db937a84c63c0d9fc7a3eb0bcc63095b --- /dev/null +++ b/docs/html-intl/intl/es/training/material/index.jd @@ -0,0 +1,60 @@ +page.title=Material Design para desarrolladores +page.image=images/cards/material_2x.png +page.metaDescription=Aprende a aplicar Material Design a tus aplicaciones. + + +@jd:body + +Dependencias y requisitos previos
+-
+
- Android 5.0 (API nivel 21) +
Material Design es una guía integral para el diseño visual, de movimientos y de interacción en distintas +plataformas y dispositivos. Para usar Material Design en tus aplicaciones de Android, sigue las pautas +descritas en la +especificación de Material +Design y usa los nuevos componentes y funcionalidades disponibles en Android 5.0 +(API nivel 21).
+ +Esta clase muestra cómo crear aplicaciones de Material Design con los siguientes elementos:
+ +-
+
- Tema Material +
- Widget para tarjetas y listas +
- Personalizar sombras y ver recortes +
- Interfaces dibujables en vector +
- Animaciones personalizadas +
Esta clase también te enseña cómo mantener la compatibilidad con versiones anteriores de Android +5.0 (API nivel 21) cuando usas las características de Material Design en tu aplicación.
+ +Lecciones
+ +-
+
- Comencemos +
- Aprende a actualizar tu aplicación con las características de Material Design. + +
- Usar el tema Material +
- Aprende a aplicar los estilos de Material Design a tu aplicación. + +
- Crear listas y tarjetas +
- Aprende a crear listas y tarjetas con un aspecto consistente mediante el uso de widgets del sistema. + +
- Definir vistas de recorte y sombras +
- Aprende a establecer la elevación para tus vistas para crear sombras personalizadas y cómo recortar vistas. + +
- Trabajar con interfaces dibujables +
- Aprende cómo crear interfaces dibujables en vector y cómo agregar un matiz a los recursos dibujables. + +
- Definir animaciones personalizadas +
- Aprende a crear animaciones personalizadas para vistas y transiciones de actividades con elementos compartidos. + +
- Mantener la compatibilidad +
- Aprende a mantener la compatibilidad con versiones de plataforma anteriores a Android 5.0. +
Esta lección te enseña a realizar lo siguiente:
+ +También deberías leer
+ +Para crear listas completas y tarjetas con estilos de Material Design en tus aplicaciones, puedes usar los widgets +{@link android.support.v7.widget.RecyclerView} y {@link android.support.v7.widget.CardView}. +
+ + +Crear listas
+ +El widget {@link android.support.v7.widget.RecyclerView} es una versión más +flexible y avanzada de {@link android.widget.ListView}. Este widget es un contenedor para mostrar grandes conjuntos de +datos que se pueden desplazar de manera muy eficiente al mantener una cantidad limitada de vistas. Usa el widget +{@link android.support.v7.widget.RecyclerView} cuando tengas conjuntos de datos cuyos elementos +cambien en tiempo de ejecución sobre la base de la acción del usuario o los eventos de la red.
+ +La clase {@link android.support.v7.widget.RecyclerView} simplifica la pantalla y la manipulación de grandes conjuntos de +datos al proporcionar lo siguiente:
+ +-
+
- Administradores de diseño para el posicionamiento de elementos +
- Animaciones predeterminadas para las operaciones comunes con elementos, como quitar o agregar elementos +
También tienes la flexibilidad para definir administradores de diseño personalizados y animaciones para los widgets {@link +android.support.v7.widget.RecyclerView}.
+ + + + +Para usar el widget {@link android.support.v7.widget.RecyclerView}, tienes que especificar un +adaptador y un administrador de diseño. Para crear un adaptador, extiende la clase {@link +android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}. Los detalles +de la implementación dependen de las especificaciones de tu conjunto de datos y los tipos de vistas. Para más +información, consulta los ejemplos que figuran a continuación.
+ +Un administrador de diseño posiciona las vistas de artículos dentro de un {@link +android.support.v7.widget.RecyclerView} y determina cuándo volver a usar las vistas de elementos que ya +no están visibles para el usuario. Para reutilizar (o reciclar) una vista, un administrador de diseño puede solicitarle al +adaptador que reemplace el contenido de la vista con un elemento diferente del conjunto de datos. De esta manera, +cuando se reciclan las vistas se mejora el rendimiento al evitar la creación de vistas innecesarias o +realizar búsquedas costosas de {@link android.app.Activity#findViewById findViewById()}.
+ +{@link android.support.v7.widget.RecyclerView} te proporciona estos administradores de diseño incorporados:
+ +-
+
- {@link android.support.v7.widget.LinearLayoutManager} muestra elementos en una lista de desplazamiento horizontal o +vertical. +
- {@link android.support.v7.widget.GridLayoutManager} muestra elementos en una cuadrícula. +
- {@link android.support.v7.widget.StaggeredGridLayoutManager} muestra elementos en una cuadrícula escalonada. +
Para crear un administrador de diseño personalizado, extiende la clase {@link +android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager}.
+ +Animaciones
+ +Las animaciones para agregar o eliminar elementos están permitidas en forma predeterminada en {@link +android.support.v7.widget.RecyclerView}. Para personalizar estas animaciones, extiende la clase +{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator} y usa +el método {@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()}. +
+ +Ejemplos
+ +El siguiente ejemplo de códigos demuestra cómo agregar el widget +{@link android.support.v7.widget.RecyclerView} a un diseño:
+ ++<!-- A RecyclerView with some commonly used attributes --> +<android.support.v7.widget.RecyclerView + android:id="@+id/my_recycler_view" + android:scrollbars="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"/> ++ +
Una vez que hayas agregado un widget {@link android.support.v7.widget.RecyclerView} a tu diseño, +obtén un identificador para el objeto, conéctalo a un administrador de diseño y adjunta un adaptador para los datos +que se van a mostrar:
+ ++public class MyActivity extends Activity { + private RecyclerView mRecyclerView; + private RecyclerView.Adapter mAdapter; + private RecyclerView.LayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.my_activity); + mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); + + // use this setting to improve performance if you know that changes + // in content do not change the layout size of the RecyclerView + mRecyclerView.setHasFixedSize(true); + + // use a linear layout manager + mLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setLayoutManager(mLayoutManager); + + // specify an adapter (see also next example) + mAdapter = new MyAdapter(myDataset); + mRecyclerView.setAdapter(mAdapter); + } + ... +} ++ +
El adaptador proporciona acceso a los elementos en tu conjunto de datos, crea vistas para los elementos y +reemplaza el contenido de algunas de las vistas con estos elementos de datos nuevos cuando el elemento original ya no está +visible. El siguiente ejemplo de código muestra una implementación simple para un conjunto de datos que consta +de una matriz de cadenas mostradas mediante el uso de widgets {@link android.widget.TextView}:
+ ++public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { + private String[] mDataset; + + // Provide a reference to the views for each data item + // Complex data items may need more than one view per item, and + // you provide access to all the views for a data item in a view holder + public static class ViewHolder extends RecyclerView.ViewHolder { + // each data item is just a string in this case + public TextView mTextView; + public ViewHolder(TextView v) { + super(v); + mTextView = v; + } + } + + // Provide a suitable constructor (depends on the kind of dataset) + public MyAdapter(String[] myDataset) { + mDataset = myDataset; + } + + // Create new views (invoked by the layout manager) + @Override + public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + // create a new view + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.my_text_view, parent, false); + // set the view's size, margins, paddings and layout parameters + ... + ViewHolder vh = new ViewHolder(v); + return vh; + } + + // Replace the contents of a view (invoked by the layout manager) + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + // - get element from your dataset at this position + // - replace the contents of the view with that element + holder.mTextView.setText(mDataset[position]); + + } + + // Return the size of your dataset (invoked by the layout manager) + @Override + public int getItemCount() { + return mDataset.length; + } +} ++ + +
Crear tarjetas
+ +{@link android.support.v7.widget.CardView} extiende la clase {@link android.widget.FrameLayout} +y te permite mostrar información dentro de tarjetas que tienen una apariencia uniforme en la plataforma. Los widgets {@link +android.support.v7.widget.CardView} pueden tener sombras y esquinas redondeadas.
+ +Para crear una tarjeta con una sombra, usa el atributo card_view:cardElevation
.
+{@link android.support.v7.widget.CardView} usa elevación real y sombras dinámicas en Android 5.0
+(API nivel 21) y superior, y regresa a una implementación de sombras programáticas en versiones anteriores.
+Para más información, consulta Mantener
+la compatibilidad.
Usa estas propiedades para personalizar la apariencia del widget +{@link android.support.v7.widget.CardView}:
+ +-
+
- Para establecer el radio de la esquina en tus diseños, usa el atributo
card_view:cardCornerRadius
. +
+ - Para establecer el radio en tu código, usa el método
CardView.setRadius
.
+ - Para establecer el color de fondo de una tarjeta, usa el atributo
card_view:cardBackgroundColor
. +
+
El siguiente ejemplo de código muestra cómo incluir un widget {@link android.support.v7.widget.CardView} +en tu diseño:
+ ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:card_view="http://schemas.android.com/apk/res-auto" + ... > + <!-- A CardView that contains a TextView --> + <android.support.v7.widget.CardView + xmlns:card_view="http://schemas.android.com/apk/res-auto" + android:id="@+id/card_view" + android:layout_gravity="center" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="4dp"> + + <TextView + android:id="@+id/info_text" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </android.support.v7.widget.CardView> +</LinearLayout> ++ +
Para más información, consulta la referencia de la API para {@link android.support.v7.widget.CardView}.
+ + +Agregar dependencias
+ +Los widgets {@link android.support.v7.widget.RecyclerView} y {@link android.support.v7.widget.CardView} +son parte de las Bibliotecas de +soporte v7. Para usar estos widgets en tu proyecto, agrega estas +Dependencias de Gradle al módulo +de tu aplicación:
+ ++dependencies { + ... + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} +diff --git a/docs/html-intl/intl/es/training/material/shadows-clipping.jd b/docs/html-intl/intl/es/training/material/shadows-clipping.jd new file mode 100644 index 0000000000000000000000000000000000000000..5509fc8bbd44a49a6623c6103aeddae30a22f0da --- /dev/null +++ b/docs/html-intl/intl/es/training/material/shadows-clipping.jd @@ -0,0 +1,133 @@ +page.title=Definir vistas de recorte y sombras + +@jd:body + +
Esta lección te enseña a realizar lo siguiente:
+ +También deberías leer
+ +Material Design introduce una elevación para los elementos de la IU. La elevación ayuda a los usuarios a comprender la +importancia relativa de cada elemento y a centrar su atención en la tarea para realizar.
+ +La elevación de una vista, representada por la propiedad Z, determina la apariencia visual de su +sombra: las vistas con valores Z superiores, proyectan sombras más grandes y suaves. Las vistas con valores Z superiores ocluyen +las vistas con valores Z inferiores. Sin embargo, el valor Z de una vista no afecta el tamaño de la vista.
+ +El padre de la vista elevada se encarga de dibujar las sombras y así, sujetas al recorte de vista estándar, son +recortadas por el padre de manera predeterminada.
+ +La elevación también es útil para crear animaciones donde los widgets suben temporalmente sobre el +plano visual cuando realizan alguna acción.
+ +Para más información sobre la elevación en Material Design, consulta +Objetos +en el espacio 3D.
+ + +Asignar elevación a tus vistas
+ +El valor Z de una vista cualquiera tiene dos componentes: + +
-
+
- Elevación: El componente estático. +
- Traducción: El componente dinámico usado para las animaciones. +
Z = elevation + translationZ
Para establecer la elevación de una vista al definir un diseño, usa el atributo android:elevation
.
+ Para establecer la elevación de una vista en el código de una actividad, usa el método
+{@link android.view.View#setElevation View.setElevation()}.
Para establecer la traducción de una vista, usa el método {@link android.view.View#setTranslationZ +View.setTranslationZ()}.
+ +Los nuevos métodos {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} y {@link +android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} te permiten +animar fácilmente la elevación de las vistas. Para más información, consulta la referencia de la API para +{@link android.view.ViewPropertyAnimator} y la guía del desarrollador Animación de propiedades. +
+ +También puedes usar un {@link android.animation.StateListAnimator} para +especificar estas animaciones de manera declarativa. Esto es especialmente útil para casos en donde los cambios de +estados desencadenan animaciones, como cuando un usuario pulsa un botón. Para más información, consulta +Animar cambios de estados de las vistas.
+ +Los valores Z se miden en dp (píxeles independientes de la densidad).
+ + +Personalizar visualización de sombras y contornos
+ +Los límites de la interfaz dibujable en segundo plano de una vista determinan la forma predeterminada de su sombra. +Los contornos representan la forma externa de un objeto gráfico y definen el área del efecto de ondas +para la respuesta táctil.
+ +Examina esta vista, definida con una interfaz dibujable en segundo plano:
+ ++<TextView + android:id="@+id/myview" + ... + android:elevation="2dp" + android:background="@drawable/myrect" /> ++ +
La interfaz dibujable en segundo plano está definida como un rectángulo con esquinas redondeadas:
+ ++<!-- res/drawable/myrect.xml --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#42000000" /> + <corners android:radius="5dp" /> +</shape> ++ +
La vista proyecta una sombra con esquinas redondeadas, ya que la interfaz dibujable en segundo plano +define el contorno de la vista. Un contorno personalizado reemplazaría la forma predeterminada de la sombra de una vista.
+ +Para definir un contorno personalizado para una vista en tu código:
+ +
-
+
- Extiende la clase {@link android.view.ViewOutlineProvider}. +
- Reemplaza el método {@link android.view.ViewOutlineProvider#getOutline getOutline()}. +
- Asigna el nuevo proveedor de contornos a tu vista con el método {@link +android.view.View#setOutlineProvider View.setOutlineProvider()}. +
Puedes crear contornos rectangulares y ovalados con esquinas redondeadas mediante el uso de métodos en la clase
+{@link android.graphics.Outline}. El proveedor de contornos predeterminado para las
+vistas obtiene el contorno a partir del plano de fondo de la vista. Para evitar que una vista proyecte una sombra, establece su proveedor de contornos
+en null
.
Recortar vistas
+ +Recortar vistas te permite cambiar fácilmente la forma de una vista. Puedes recortar vistas para
+mantener la uniformidad con otros elementos del diseño o para cambiar la forma de una vista en respuesta a una señal de entrada del usuario.
+Puedes recortar una vista a partir de su área de contorno mediante el método {@link android.view.View#setClipToOutline
+View.setClipToOutline()} o el atributo android:clipToOutline
. Solo
+los contornos rectangulares, circulares y redondeados admiten el recorte, según lo determinado por el método
+{@link android.graphics.Outline#canClip Outline.canClip()}.
Para recortar una vista a partir de una interfaz dibujable, establece la interfaz dibujable como el plano de fondo de la vista +(como se muestra más arriba) y llama al método {@link android.view.View#setClipToOutline View.setClipToOutline()}. +
+ +Recortar vistas es una operación costosa, así que no animes la forma que usas para +recortar una vista. Para lograr este efecto, usa la animación Efecto revelar.
diff --git a/docs/html-intl/intl/es/training/material/theme.jd b/docs/html-intl/intl/es/training/material/theme.jd new file mode 100644 index 0000000000000000000000000000000000000000..d748c43dd1c1329df58185208fed1a6b92883c62 --- /dev/null +++ b/docs/html-intl/intl/es/training/material/theme.jd @@ -0,0 +1,131 @@ +page.title=Usar el tema Material + +@jd:body + +Esta lección te enseña a realizar lo siguiente:
+-
+
- Personalizar la paleta de colores +
- Personalizar la barra de estado +
- Cambiar el tema de vistas individuales +
También deberías leer
+ +El nuevo tema material proporciona:
+ +-
+
- Widgets del sistema que te permiten establecer la paleta de colores. +
- Animaciones para la respuesta táctil de los widgets del sistema. +
- Animaciones para transiciones de actividades +
Puedes personalizar la apariencia del tema material +según la identidad de tu marca, con una paleta de colores que esté bajo tu control. Puedes cambiar el matiz de la barra de acción y +la barra de estado mediante atributos de temas, como se muestra en la figura 3.
+ +Los widgets del sistema tienen un nuevo diseño y animaciones para respuesta táctil. Puedes personalizar tu aplicación cambiando su +paleta de colores, las animaciones de la respuesta táctil y sus transiciones de actividades.
+ +El tema material se define como:
+ +-
+
@android:style/Theme.Material
(versión oscura)
+ @android:style/Theme.Material.Light
(versión clara)
+ @android:style/Theme.Material.Light.DarkActionBar
+
Para obtener una lista de estilos de Material, consulta la referencia de la API para +{@link android.R.style R.style}.
+ + +Figura 1. Tema Material oscuro
+Figura 2. Tema Material claro
++
+Nota: El tema material solo está disponible en Android 5.0 (API nivel 21) y +superior. Las Bibliotecas de soporte v7 +proporcionan temas con estilos de Material Design para algunos widgets y admiten la personalización de la paleta de +colores. Para más información, consulta +Mantener la compatibilidad. +
+ + +Personalizar la paleta de colores
+ +Si deseas personalizar los colores base del tema para que se adapten a tu marca, define +tus colores personalizados mediante los atributos de temas cuando heredes del tema material:
+ ++<resources> + <!-- inherit from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- Main theme colors --> + <!-- your app branding color for the app bar --> + <item name="android:colorPrimary">@color/primary</item> + <!-- darker variant for the status bar and contextual app bars --> + <item name="android:colorPrimaryDark">@color/primary_dark</item> + <!-- theme UI controls like checkboxes and text fields --> + <item name="android:colorAccent">@color/accent</item> + </style> +</resources> ++ +
Personalizar la barra de estado
+ +El tema material te permite personalizar fácilmente la barra de estado, especifica un
+color que se adapte a tu marca y proporciona suficiente contraste para mostrar los íconos de estado en blanco. Si
+quieres establecer un color personalizado para la barra de estado, usa el atributo android:statusBarColor
+cuando extiendas el tema material. android:statusBarColor
hereda el
+valor de android:colorPrimaryDark
en forma predeterminada.
También puedes dibujar por detrás de la barra de estado. Por ejemplo, si quieres que la barra de estado se
+muestre en forma transparente sobre una foto, aplica un sutil degradado oscuro para garantizar que los íconos
+de estado blancos sigan visibles. Para hacerlo, establece el atributo android:statusBarColor
en
+@android:color/transparent
y ajusta los indicadores de la ventana según lo requerido. También puedes
+usar el método {@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} para
+las animaciones o el difuminado.
+Nota: La barra de estado casi siempre debe estar delimitada claramente de la +barra de herramientas principal, excepto para los casos en donde muestres imágenes de un extremo a otro o contenido multimedia detrás +de estas barras, y también cuando uses un degradado para garantizar que los íconos aún sean visibles. +
+ +Cuando personalizas la barra de navegación y la barra de estado, haz que ambas sean transparentes o modifica +solo la barra de estado. La barra de navegación debe permanecer de color negro en todos los otros casos.
+ + +Vistas individuales del tema + +
Los elementos en las definiciones de diseño XML pueden especificar el atributo android:theme
,
+que hace referencia al recurso del tema. Este atributo modifica el tema para el elemento y cualquier
+elemento secundario, y esto es útil para modificar las paletas de colores de los temas en una porción específica
+de una interfaz.
Prinsip desain ini dikembangkan oleh dan untuk Tim Pengalaman Pengguna + Android agar selalu mempertimbangkan kepentingan pengguna. +Untuk pengembang dan desainer Android, mereka terus +meletakkan dasar pedoman desain yang lebih detail untuk beragam tipe +perangkat.
+ ++Perhatikan prinsip-prinsip ini saat Anda menerapkan +kreativitas dan pemikiran desain sendiri. Menyimpang dengan sengaja. +
+ +Pikat Saya
+ +Senangkan saya dengan cara yang mengejutkan
+Permukaan yang cantik, animasi yang ditempatkan dengan hati-hati, atau efek suara di saat yang tepat sungguh menyenangkan untuk +dinikmati. Efek yang lembut menimbulkan perasaan serba mudah dan kesadaran bahwa kekuatan yang +bisa diandalkan ada dalam genggaman.
+ +Objek sungguhan lebih menyenangkan daripada tombol dan menu
+Biarkan orang langsung menyentuh dan memanipulasi objek dalam aplikasi Anda. Ini mengurangi upaya kognitif +yang diperlukan untuk menjalankan tugas sekaligus membuatnya lebih memuaskan secara emosional.
+ +Biarkan saya memilikinya
+Orang suka menambahkan sentuhan pribadi karena membantu mereka merasa betah dan memegang kendali. Memberikan +default yang pantas dan indah, tetapi juga mempertimbangkan penyesuaian opsional yang menyenangkan, yang tidak mengganggu +tugas utama.
+ +Kenali saya
+Pelajari preferensi orang dari waktu ke waktu. Daripada meminta mereka untuk membuat pilihan yang sama +berulang-ulang, tempatkan pilihan sebelumnya agar mudah dijangkau.
+ +Sederhanakan Hidup Saya
+ +Persingkat
+Gunakan frasa pendek dengan kata-kata sederhana. Orang cenderung melewatkan kalimat-kalimat panjang.
+ +Gambar lebih cepat dibanding kata-kata
+Pertimbangkan menggunakan gambar untuk menjelaskan gagasan. Gambar menarik perhatian orang dan bisa jauh lebih efisien +dibanding kata-kata.
+ +Putuskan untuk saya tetapi biarkan saya yang menentukan
+Gunakan tebakan terbaik Anda dan bertindaklah daripada meminta terlebih dahulu. Terlalu banyak pilihan dan keputusan membuat orang +tidak suka. Untuk berjaga-jaga jika Anda salah, izinkan 'pembatalan'.
+ +Cukup tunjukkan yang saya perlukan ketika saya memerlukannya
+Orang merasa kewalahan ketika melihat terlalu banyak hal sekaligus. Uraikan tugas dan informasi menjadi potongan-potongan +kecil yang mudah dicerna. Sembunyikan opsi yang tidak perlu pada saat ini, dan ajari orang sambil jalan.
+ +Saya harus selalu tahu di mana saya berada
+Beri orang kepercayaan diri bahwa mereka tahu di mana berada. Buat agar tempat-tempat dalam aplikasi Anda terlihat berbeda dan +gunakan transisi untuk menunjukkan hubungan antar layar. Berikan umpan balik tentang tugas yang sedang berlangsung.
+ +Jangan sekali-kali menghilangkan milik saya
+Simpan apa yang telah susah-payah dibuat orang dan biarkan mereka mengaksesnya dari mana saja. Ingat pengaturan, +sentuhan pribadi, dan kreasi lintas ponsel, tablet, dan komputer. Itu membuat pemutakhiran menjadi +hal termudah di dunia.
+ +Jika terlihat sama, seharusnya fungsinya sama
+Bantu orang merasakan perbedaan fungsional dengan membuat mereka terlihat berbeda daripada mirip. +Hindari mode, yaitu tempat yang terlihat mirip tetapi berbeda fungsinya pada input yang sama.
+ +Sela saya jika penting saja
+Layaknya asisten pribadi yang baik, lindungi orang dari detail yang tidak penting. Orang ingin tetap +fokus, dan kecuali jika memang penting dan sensitif waktu, interupsi bisa melelahkan dan menjengkelkan.
+ +Buat Saya Terpesona
+ +Beri saya trik yang efektif di mana saja
+Orang merasa senang ketika mereka memahami sendiri sesuatu. Jadikan aplikasi Anda lebih mudah dipelajari dengan +memanfaatkan pola visual dan memori otot dari aplikasi Android lainnya. Misalnya, gerakan menggeser +dapat menjadi pintasan navigasi yang bagus.
+ +Bukan salah saya
+Bersikap ramahlah dalam meminta orang untuk melakukan koreksi. Mereka ingin merasa pintar ketika menggunakan +aplikasi Anda. Jika terjadi kesalahan, berikan petunjuk perbaikan yang jelas tetapi lepaskan mereka dari detail teknis. +Jika Anda dapat memperbaikinya secara diam-diam, tentu lebih baik.
+ +Berikan dorongan
+Uraikan tugas-tugas rumit menjadi langkah-langkah kecil yang dapat dilakukan dengan mudah. Beri umpan balik tentang tindakan, +meskipun hanya sesuatu yang sederhana.
+ +Lakukan pekerjaan yang sulit untuk saya
+Buatlah pemula merasa seperti ahli dengan memungkinkan mereka untuk melakukan hal-hal yang mereka pikir tidak akan bisa. +Misalnya, pintasan yang menggabungkan beberapa efek foto dapat membuat foto amatir terlihat mengagumkan hanya +dalam beberapa langkah.
+ +Percepat hal penting
+Tidak semua tindakan itu sama. Putuskan apa yang terpenting dalam aplikasi Anda dan permudah untuk menemukannya serta +cepat untuk digunakan, seperti tombol rana pada kamera, atau tombol jeda pada pemutar musik.
+ +Dokumen Pengembang
+Membuat Aplikasi dengan Desain Bahan
+Video
+Pengantar Desain Bahan
+Video
+Kertas dan Tinta: Bahan Penting
+Video
+Desain Bahan di Aplikasi Google I/O
+Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan +interaksi lintas platform dan perangkat. Android kini menyertakan dukungan untuk +aplikasi desain bahan. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan yang didefinisikan +dalam spesifikasi desain bahan dan gunakan +komponen dan fungsionalitas baru yang tersedia di Android 5.0 (API level 21) ke atas.
+ +Android menyediakan elemen berikut untuk membangun aplikasi desain bahan:
+ +-
+
- Tema baru +
- Widget baru untuk tampilan yang kompleks +
- API baru untuk animasi dan bayangan custom +
Untuk informasi selengkapnya tentang mengimplementasikan desain bahan pada Android, lihat +Membuat Aplikasi dengan Desain Bahan.
+ + +Tema Bahan
+ +Tema bahan menyediakan gaya baru untuk aplikasi Anda, widget sistem yang memungkinkan Anda mengatur +palet warnanya, dan animasi default untuk umpan balik sentuh dan transisi aktivitas.
+ + +Tema bahan gelap
+Tema bahan terang
++
Untuk informasi selengkapnya, lihat Menggunakan Tema +Bahan.
+ + +Daftar dan Kartu
+ +Android menyediakan dua widget baru untuk menampilkan kartu dan daftar dengan gaya desain bahan +dan animasi:
+ + +Widget RecyclerView
baru adalah versi ListView
+ yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja.
Widget CardView
baru memungkinkan Anda menampilkan potongan informasi penting dalam
+ kartu yang memiliki tampilan dan cara kerja yang konsisten.
+
Untuk informasi selengkapnya, lihat Membuat Daftar +dan Kartu.
+ + +Bayangan Tampilan
+ +Selain properti X dan Y, tampilan di Android kini memiliki +properti Z. Properti baru ini mewakili ketinggian tampilan, yang menentukan:
+ +-
+
- Ukuran bayangan: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar. +
- Urutan penggambaran: tampilan dengan nilai Z lebih tinggi muncul di atas tampilan lainnya. +
Untuk informasi selengkapnya, lihat Mendefinisikan +Bayangan dan Memangkas Tampilan.
+ + +Animasi
+ +API animasi baru memungkinkan Anda membuat animasi custom untuk umpan balik sentuh dalam kontrol UI, +perubahan status tampilan, dan transisi aktivitas.
+ +API ini memungkinkan Anda:
+ +-
+
- +Merespons kejadian sentuh dalam tampilan Anda dengan animasi umpan balik sentuh. + +
- +Menyembunyikan dan memperlihatkan tampilan dengan animasi membuka melingkar. + +
- +Peralihan antar aktivitas dengan animasi transisi aktivitas custom. + +
- +Membuat animasi yang lebih alami dengan gerak melengkung. + +
- +Menganimasikan perubahan dalam satu atau beberapa properti tampilan dengan animasi perubahan status tampilan. + +
- +Menampilkan animasi di drawable daftar status di antara perubahan status tampilan. + +
Animasi umpan balik sentuh dimasukkan ke dalam beberapa tampilan standar, misalnya tombol. API baru +ini memungkinkan Anda menyesuaikan animasi ini dan menambahkannya ke tampilan custom Anda.
+ +Untuk informasi selengkapnya, lihat Mendefinisikan Animasi +Custom.
+ + +Drawable
+ +Kemampuan baru untuk drawable ini membantu Anda mengimplementasikan aplikasi desain bahan:
+ +-
+
- Drawable vektor bisa diubah skalanya tanpa kehilangan definisi dan cocok +untuk ikon satu-warna dalam-aplikasi. +
- Pewarnaan drawable memungkinkan Anda mendefinisikan bitmap sebagai alpha-mask dan mewarnainya +saat runtime. +
- Ekstraksi warna memungkinkan Anda mengekstrak warna mencolok secara otomatis dari +gambar bitmap. +
Untuk informasi selengkapnya, lihat Bekerja dengan +Drawable.
diff --git a/docs/html-intl/intl/in/design/patterns/compatibility.jd b/docs/html-intl/intl/in/design/patterns/compatibility.jd new file mode 100644 index 0000000000000000000000000000000000000000..cafaac4faca325696f18c37b5137fabc7b685cef --- /dev/null +++ b/docs/html-intl/intl/in/design/patterns/compatibility.jd @@ -0,0 +1,70 @@ +page.title=Kompatibilitas Mundur +page.tags="support" +page.metaDescription=Catatan tentang bagaimana Android 4.x menyesuaikan UI yang didesain untuk perangkat keras dan versi OS yang lebih lama. +@jd:body + + +Dokumen Pengembang
+Mendukung Perangkat Berbeda
+Perubahan signifikan dalam Android 3.0 meliputi:
+-
+
- Dihilangkannya tombol perangkat keras navigasi (Back, Menu, Search, Home) untuk membantu menangani navigasi + melalui kontrol maya (Back, Home, Recents). +
- Pola yang tangguh untuk penggunaan menu pada action-bar. +
Android 4.0 membawa perubahan ini untuk tablet dengan platform ponsel.
+ +Menyesuaikan Android 4.0 dengan Perangkat Keras dan Aplikasi yang Lebih Lama
+ +Ponsel dengan kontrol navigasi virtual
+Aplikasi Android yang ditulis untuk Android 3.0 dan yang lebih baru menampilkan tindakan dalam action-bar. Tindakan yang tidak +muat dalam action-bar atau tidak cukup penting untuk ditampilkan di tingkat atas akan muncul dalam +action-overflow.
+Pengguna mengakses action-overflow dengan menyentuhnya dalam action-bar.
+ +Ponsel dengan tombol navigasi fisik
+Ponsel Android dengan tombol perangkat keras navigasi biasa tidak menampilkan baris navigasi virtual di +bagian bawah layar. Sebagai gantinya, action-overflow tersedia dari tombol perangkat keras menu. Popup +tindakan yang dihasilkan memiliki gaya yang sama dengan contoh sebelumnya, tetapi ditampilkan di bagian bawah layar.
+ +Aplikasi lama pada ponsel dengan kontrol navigasi virtual
+Bila Anda menjalankan aplikasi yang dibuat untuk Android 2.3 atau yang lebih lama pada ponsel +dengan kontrol navigasi virtual, sebuah kontrol action-overflow akan muncul di sebelah kanan baris navigasi virtual. Anda +dapat menyentuh kontrol itu untuk menampilkan tindakan aplikasi dalam gaya menu Android biasa.
+ +Dalam beberapa situasi, bila pengguna memanggil suatu tindakan dalam aplikasi Anda, ada baiknya mengonfirmasi atau mengakui tindakan itu melalui teks.
+ +Mengonfirmasi adalah meminta pengguna untuk memverifikasi bahwa mereka benar-benar ingin melanjutkan tindakan yang baru saja mereka panggil. Dalam beberapa kasus, konfirmasi ditampilkan bersama-sama dengan peringatan atau informasi penting yang terkait dengan tindakan yang perlu mereka pertimbangkan.
+Mengakui adalah menampilkan teks untuk memberi tahu pengguna bahwa tindakan yang baru mereka panggil sudah dilakukan. Ini menghilangkan ketidakpastian tentang operasi implisit yang dilakukan sistem. Dalam beberapa kasus, pengakuan ditampilkan bersama dengan opsi untuk membatalkan tindakan.
+Berkomunikasi pada pengguna dengan cara ini bisa membantu mengurangi ketidakpastian tentang hal-hal yang sudah atau akan terjadi. Mengonfirmasi atau mengakui juga dapat mencegah pengguna melakukan kesalahan yang akan mereka sesali.
+ +Kapan Harus Mengonfirmasi atau Mengakui Tindakan Pengguna
+Tidak semua tindakan memerlukan konfirmasi atau pengakuan. Gunakan bagan alur ini untuk memandu keputusan desain Anda.
+ + +Mengonfirmasi
+Contoh: Google Play Books
+ +Dalam contoh ini, pengguna telah meminta untuk menghapus sebuah buku dari perpustakaan Google Play mereka. Sebuah peringatan muncul untuk mengonfirmasi tindakan ini karena perlu dipahami bahwa buku tersebut tidak akan tersedia lagi dari perangkat apa pun.
+Saat membuat dialog konfirmasi, buat judul bermakna dengan mencerminkan tindakan yang diminta.
+Contoh: Android Beam
+ +Konfirmasi tidak harus ditampilkan dalam peringatan dengan dua tombol. Setelah menjalankan Android Beam, pengguna diminta untuk menyentuh konten yang akan dibagikan (dalam contoh ini, sebuah foto). Jika mereka memutuskan untuk tidak melanjutkan, mereka tinggal memindahkan ponsel.
+Mengakui
+Contoh: Draf Gmail batal yang disimpan
+ +Dalam contoh ini, jika pengguna menyusuri ke belakang atau ke atas dari layar pembuatan email di Gmail, sesuatu yang tak diharapkan bisa terjadi: draf saat itu akan disimpan secara otomatis. Pengakuan dalam bentuk pemberitahuan akan lebih jelas. Ini menghilang setelah beberapa detik.
+Pembatalan tidak cocok di sini karena penyimpanan dilakukan oleh aplikasi, bukan pengguna. Cepat dan mudah untuk melanjutkan penulisan pesan dengan menyusuri daftar draf.
+ +Contoh: Percakapan Gmail dihapus
+ +Setelah pengguna menghapus percakapan dari daftar dalam Gmail, sebuah pengakuan muncul tanpa opsi pembatalan. Pengakuan tetap ada sampai pengguna melakukan tindakan yang tidak berkaitan, seperti menggulir daftar.
+Tidak ada Konfirmasi atau Pengakuan
+Contoh: memberikan +1
+ +Konfirmasi tidak diperlukan. Jika pengguna telah memberikan +1 secara tidak sengaja, tidak masalah. Mereka cukup menyentuh kembali tombol itu untuk membatalkan tindakan.
+Pengakuan tidak diperlukan. Pengguna akan melihat tombol +1 memantul dan berubah merah. Itu tanda yang sangat jelas.
+Contoh: Menghapus aplikasi dari Layar Beranda
+ +Konfirmasi tidak diperlukan. Ini adalah tindakan yang disengaja: pengguna harus menyeret dan meletakkan sebuah item di atas target yang relatif besar dan terpisah. Karena itu, kecil kemungkinan terjadi ketidaksengajaan. Tetapi jika pengguna menyesali keputusan itu, maka hanya perlu beberapa detik untuk mengembalikannya lagi.
+Pengakuan tidak diperlukan. Pengguna akan mengetahui bahwa aplikasi itu tidak ada di Layar Beranda karena mereka menghilangkannya dengan cara menyeretnya.
+ +Dokumen Pengembang
+Mengimplementasikan Navigasi yang Efektif
+Navigasi yang konsisten merupakan komponen penting dari keseluruhan pengalaman pengguna. Hampir tidak ada yang lebih membingungkan +pengguna selain navigasi dasar yang perilakunya tidak konsisten dan tidak sesuai harapan. Android 3.0 +memperkenalkan perubahan besar dalam perilaku navigasi global. Mengikuti dengan saksama +panduan untuk Back dan Up akan membuat navigasi aplikasi Anda dapat diprediksi dan dapat diandalkan pengguna.
+Android 2.3 dan versi sebelumnya mengandalkan tombol Back sistem untuk mendukung navigasi dalam +aplikasi. Dengan diperkenalkannya action-bar dalam Android 3.0, mekanisme navigasi kedua muncul: +tombol Up, yang terdiri dari ikon aplikasi dan tanda panah yang menunjuk ke kiri.
+ + + +Up vs. Back
+ +Tombol Up digunakan untuk berpindah dalam aplikasi berdasarkan hubungan hierarki +antar layar. Misalnya, jika layar A menampilkan daftar item, dan memilih sebuah item akan membuka +layar B (yang menampilkan item tersebut secara lebih detail), maka layar B akan menawarkan tombol Up untuk +kembali ke layar A.
+Jika suatu layar merupakan yang teratas dalam aplikasi (yaitu layar Home aplikasi), maka tidak perlu menampilkan tombol +Up.
+ +Tombol Back sistem digunakan untuk berpindah, dalam urutan kronologis terbalik, melalui riwayat +layar yang baru dibuka oleh pengguna. Biasanya ini berdasarkan hubungan sementara +antar layar, dan bukan hierarki aplikasi.
+ +Bila layar yang dilihat sebelumnya juga merupakan induk hierarki dari layar yang sekarang, menekan tombol +Back akan sama hasilnya dengan menekan tombol Up—ini adalah kejadian +biasa. Akan tetapi, berbeda dengan tombol Up, yang memastikan pengguna tetap berada dalam aplikasi Anda, tombol Back +dapat mengembalikan pengguna ke layar Home, atau bahkan ke aplikasi lain.
+ + + +Tombol Back juga mendukung beberapa perilaku yang tidak terkait langsung dengan navigasi antar layar: +
+-
+
- Menghilangkan jendela mengambang (dialog, popup) +
- Menghilangkan action-bar kontekstual, dan menghapus sorotan dari item yang dipilih +
- Menyembunyikan keyboard di layar (IME) +
Navigasi Dalam Aplikasi Anda
+ +Berpindah ke layar yang memiliki beberapa titik masuk
+Kadang-kadang layar tidak memiliki posisi pasti dalam hierarki aplikasi, dan bisa dimasuki +dari berbagai titik masuk—seperti layar pengaturan yang dapat dibuka dari layar lain +dalam aplikasi Anda. Dalam hal ini, tombol Up akan memilih untuk kembali ke layar pengarah, yang cara kerjanya +sama dengan tombol Back.
+Mengubah tampilan dalam layar
+Mengubah opsi tampilan untuk layar tidak mengubah perilaku Up atau Back: layar tetap +berada di tempat yang sama dalam hierarki aplikasi, dan tidak dibuat riwayat navigasi yang baru.
+Contoh perubahan tampilan tersebut adalah:
+-
+
- Mengganti tampilan menggunakan tab dan/atau geser kiri dan kanan +
- Mengubah tampilan menggunakan tarik-turun (alias tab turun) +
- Memfilter daftar +
- Menyortir daftar +
- Mengubah karakteristik tampilan (seperti zoom) +
Berpindah antar layar yang seinduk
+Bila aplikasi Anda mendukung navigasi dari daftar item ke tampilan detail salah satu item tersebut, aplikasi +juga sering diharapkan mendukung navigasi langsung dari item itu ke item sebelumnya atau +sesudahnya dalam daftar. Misalnya, dalam Gmail, begitu mudah untuk bergeser ke kiri atau kanan dari sebuah percakapan +untuk melihat percakapan yang lebih baru atau lebih lama dalam Inbox yang sama. Sama seperti saat mengubah tampilan dalam layar, navigasi +ini tidak mengubah perilaku Up atau Back.
+ + + +Akan tetapi, pengecualian khusus terhadap hal ini terjadi saat menjelajah di antara tampilan detail terkait yang tidak disatukan +oleh daftar yang merujuknya—misalnya, saat menjelajahi Play Store di antara aplikasi dari +pengembang yang sama, atau album dari artis yang sama. Dalam hal ini, mengikuti setiap tautan akan membuat +riwayat, sehingga tombol Back akan menyusuri setiap layar yang dilihat sebelumnya. Tombol Up akan terus +melewatkan semua layar terkait ini dan berpindah ke layar kontainer yang terakhir dilihat.
+ + + +Anda dapat menjadikan perilaku tombol Up lebih cerdas lagi berdasarkan pengetahuan Anda tentang tampilan +detail. Dengan memperluas contoh Play Store dari atas, bayangkan pengguna yang telah berpindah dari Buku +terakhir yang dilihat ke detail untuk adaptasi Film. Dalam hal itu, tombol Up dapat kembali ke kontainer +(Movies) yang sebelumnya belum dilalui pengguna.
+ + + +Navigasi ke Aplikasi Anda melalui Widget dan Pemberitahuan Layar Home
+ +Anda bisa menggunakan widget atau pemberitahuan layar Home untuk membantu pengguna berpindah langsung ke layar +jauh dalam hierarki aplikasi Anda. Misalnya, widget Inbox dan pemberitahuan pesan baru di Gmail dapat +melewatkan layar Inbox, dan membawa pengguna langsung ke tampilan percakapan.
+ +Untuk kedua kasus ini, tangani tombol Up sebagai berikut:
+ +-
+
- Jika layar tujuan biasanya dicapai dari satu layar tertentu dalam aplikasi +Anda, tombol Up akan mengarahkannya ke layar itu. +
- Jika tidak, tombol Up akan mengarahkan ke layar teratas ("Home") dari aplikasi Anda. +
Dalam hal tombol Back, Anda harus membuat navigasi lebih bisa diprediksi dengan menyisipkan ke dalam +back-stack tugas path navigasi naik lengkap menuju layar teratas aplikasi. Ini memungkinkan pengguna +yang lupa cara masuk ke aplikasi Anda untuk berpindah ke layar teratas aplikasi sebelum +keluar.
+ +Sebagai contoh, widget layar Home di Gmail memiliki tombol untuk menuju langsung ke layar +Compose. Tombol Up atau Back dari layar Compose akan membawa pengguna ke Inbox, dan dari sana tombol +Back berlanjut ke Home.
+ + + +Pemberitahuan tidak langsung
+ +Jika aplikasi Anda perlu menampilkan informasi tentang beberapa kejadian sekaligus, aplikasi dapat menggunakan +pemberitahuan tunggal yang mengarahkan pengguna ke layar antara. Layar ini merangkum semua +kejadian tersebut, dan menyediakan path bagi pengguna untuk menjelajah ke dalam aplikasi. Pemberitahuan dengan gaya seperti ini +disebut pemberitahuan tidak langsung.
+ +Berbeda dengan pemberitahuan standar (langsung), menekan tombol Back dari +layar antara pada pemberitahuan tidak langsung akan mengembalikan pengguna ke titik pemicu pemberitahuan tersebut—tidak ada +layar tambahan yang disisipkan ke dalam back-stack. Setelah pengguna melanjutkan ke dalam aplikasi dari +layar antara, tombol Up dan Back akan berperilaku seperti pada pemberitahuan standar, sebagaimana dijelaskan di atas: +menyusuri ke dalam aplikasi dan bukan kembali ke layar antara.
+ +Misalnya, anggaplah seorang pengguna di Gmail menerima pemberitahuan tidak langsung dari Kalender. Menyentuh +pemberitahuan ini akan membuka layar antara, yang menampilkan pengingat beberapa macam +kejadian. Menyentuh Back dari layar antara akan mengembalikan pengguna ke Gmail. Menyentuh kejadian +tertentu akan membawa pengguna dari layar antara ke aplikasi Kalender lengkap untuk menampilkan detail +kejadian. Dari detail kejadian, tombol Up dan Back akan mengarahkan ke tampilan Kalender tingkat atas.
+ + + +Pemberitahuan pop-up
+ +Pemberitahuan pop-up akan melewatkan laci pemberitahuan, bukan muncul secara langsung di +hadapan pengguna. Ini jarang digunakan, dan harus dicadangkan untuk peristiwa yang memerlukan respons tepat waktu +dan diperlukan interupsi dari konteks pengguna. Misalnya, +Talk menggunakan gaya ini untuk memberi tahu pengguna tentang ajakan dari teman untuk bergabung dalam chatting video, karena +ajakan ini akan kedaluwarsa secara otomatis setelah beberapa detik.
+ +Dalam hal perilaku navigasi, pemberitahuan pop-up sangat mirip perilaku pemberitahuan +tidak langsung pada layar antara. Tombol Back akan menghilangkan pemberitahuan pop-up. Jika pengguna berpindah +dari pop-up ke aplikasi yang memberi tahu, tombol Up dan Back akan mengikuti aturan pemberitahuan standar, +berpindah dalam aplikasi.
+ + + +Navigasi Antar Aplikasi
+ +Salah satu kekuatan dasar sistem Android adalah kemampuan aplikasi untuk saling +mengaktifkan, sehingga pengguna dapat berpindah langsung dari satu aplikasi ke aplikasi lainnya. Misalnya, sebuah +aplikasi yang perlu mengambil foto dapat mengaktifkan aplikasi Kamera, yang akan mengembalikan foto +ke aplikasi perujuk. Ini sangat menguntungkan pengembang, yang bisa dengan mudah memanfaatkan +kode dari aplikasi lain, maupun pengguna, yang menikmati pengalaman konsisten untuk tindakan yang biasa +dilakukan.
+ +Untuk memahami navigasi antar aplikasi, maka perlu memahami perilaku kerangka kerja Android +yang akan dibahas di bawah ini.
+ +Aktivitas, tugas, dan intent
+ +Dalam Android, aktivitas adalah komponen aplikasi yang mendefinisikan layar +informasi dan semua tindakan terkait yang dapat dilakukan pengguna. Aplikasi Anda adalah kumpulan +aktivitas, yang terdiri dari aktivitas yang Anda buat dan aktivitas yang Anda gunakan ulang dari aplikasi lain.
+ +Tugas adalah urutan aktivitas yang diikuti pengguna untuk mencapai tujuan. +Tugas tunggal dapat memanfaatkan aktivitas dari satu aplikasi saja, atau dapat memanfaatkan aktivitas dari sejumlah +aplikasi berbeda.
+ +Intent adalah mekanisme bagi satu aplikasi untuk memberi isyarat minta bantuan +aplikasi lain dalam menjalankan suatu tindakan. Aktivitas aplikasi dapat menunjukkan intent + apa saja yang dapat diresponsnya. Untuk intent umum seperti "Share", pengguna mungkin telah menginstal beberapa aplikasi +yang dapat memenuhi permintaan itu.
+ +Contoh: berpindah antar aplikasi untuk mendukung berbagi
+ +Untuk memahami cara kerja sama aktivitas, tugas, dan intent, perhatikan bagaimana sebuah aplikasi memungkinkan pengguna +untuk berbagi konten dengan menggunakan aplikasi lain. Misalnya, membuka aplikasi Play Store dari Home akan memulai +Task A baru (lihat gambar di bawah). Setelah menyusuri Play Store dan menyentuh buku yang dipromosikan +untuk melihat detailnya, pengguna tetap berada dalam tugas yang sama, memperluasnya dengan menambahkan aktivitas. Memicu +tindakan Share akan memberi tahu pengguna dengan dialog berisi daftar aktivitas (dari aplikasi berbeda) +yang telah terdaftar untuk menangani intent Share.
+ + + +Bila pengguna memilih untuk berbagi melalui Gmail, aktivitas penulisan di Gmail akan ditambahkan sebagai kelanjutan dari +Task A—tidak ada tugas baru yang dibuat. Jika Gmail sedang menjalankan tugasnya di latar belakang, maka +tidak akan terpengaruh.
+ +Dari aktivitas penulisan, mengirim pesan atau menyentuh tombol Back akan mengembalikan pengguna ke +aktivitas detail buku tersebut. Penyentuhan tombol Back berikutnya akan terus mengarahkan kembali melalui Play +Store, sampai akhirnya tiba di Home.
+ + + +Akan tetapi, dengan menyentuh tombol Up dari aktivitas penulisan, pengguna menunjukkan keinginan untuk tetap berada di +Gmail. Aktivitas daftar percakapan Gmail muncul, Task B yang baru akan dibuat untuk itu. Tugas baru +selalu terkait ke Home, maka menyentuh tombol Back dari daftar percakapan akan mengembalikan ke sana.
+ + + +Task A tetap berjalan di latar belakang, dan pengguna nanti dapat kembali ke sana (misalnya, melalui layar +Recents). Jika Gmail sedang menjalankan tugasnya di latar belakang, maka itu akan digantikan +dengan Task B—konteks sebelumnya akan diabaikan demi tujuan baru pengguna.
+ +Jika register aplikasi Anda menangani intent dengan aktivitas yang jauh di dalam hierarki aplikasi, +lihat Navigasi Aplikasi Anda melalui Widget Layar Home dan +Pemberitahuan untuk panduan mengenai cara menetapkan navigasi Up.
diff --git a/docs/html-intl/intl/in/guide/components/activities.jd b/docs/html-intl/intl/in/guide/components/activities.jd new file mode 100644 index 0000000000000000000000000000000000000000..6cac69638f49a6cc37da974ee4debd85ab9d26ba --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/activities.jd @@ -0,0 +1,756 @@ +page.title=Aktivitas +page.tags=aktivitas,intent +@jd:body + +Dalam dokumen ini
+-
+
- Membuat Aktivitas + + +
- Memulai Aktivitas + + +
- Mematikan Aktivitas +
- Mengelola Daur Hidup Aktivitas + + +
Kelas-kelas utama
+-
+
- {@link android.app.Activity} +
Lihat juga
+ + +{@link android.app.Activity} adalah sebuah komponen aplikasi yang menyediakan layar yang digunakan +pengguna untuk berinteraksi guna melakukan sesuatu, misalnya memilih nomor telepon, mengambil foto, mengirim email, atau +menampilkan peta. Tiap aktivitas diberi sebuah jendela untuk menggambar antarmuka penggunanya. Jendela ini +biasanya mengisi layar, namun mungkin lebih kecil daripada layar dan mengambang di atas +jendela lain.
+ +Sebuah aplikasi biasanya terdiri atas beberapa aktivitas yang terikat secara longgar +satu sama lain. Biasanya, satu aktivitas dalam aplikasi ditetapkan sebagai aktivitas "utama", yang +ditampilkan kepada pengguna saat membuka aplikasi untuk pertama kali. Tiap +aktivitas kemudian bisa memulai aktivitas lain untuk melakukan berbagai tindakan. Tiap kali +aktivitas baru dimulai, aktivitas sebelumnya akan dihentikan, namun sistem mempertahankan aktivitas +dalam sebuah tumpukan ("back-stack"). Bila sebuah aktivitas baru dimulai, aktivitas itu akan didorong ke atas back-stack dan +mengambil fokus pengguna. Back-stack mematuhi mekanisme dasar tumpukan "masuk terakhir, keluar pertama", +jadi, bila pengguna selesai dengan aktivitas saat ini dan menekan tombol Back, aktivitas +akan dikeluarkan dari tumpukan (dan dimusnahkan) dan aktivitas sebelumnya akan dilanjutkan. (Back-stack +dibahas selengkapnya dalam dokumen Tugas +dan Back-Stack.)
+ +Bila aktivitas dihentikan karena ada aktivitas baru yang dimulai, aktivitas lama akan diberi tahu tentang perubahan status ini +melalui metode callback daur hidupnya. +Ada beberapa metode callback yang mungkin diterima aktivitas, karena sebuah perubahan dalam +statusnya—apakah sistem sedang membuatnya, menghentikannya, melanjutkannya, atau menghapuskannya—dan +masing-masing callback memberi Anda kesempatan melakukan pekerjaan tertentu yang +sesuai untuk perubahan status itu. Misalnya, bila dihentikan, aktivitas Anda harus melepas +objek besar, seperti koneksi jaringan atau database. Bila aktivitas dilanjutkan, Anda bisa +memperoleh kembali sumber daya yang diperlukan dan melanjutkan tindakan yang terputus. Transisi status ini +semuanya bagian dari daur hidup aktivitas.
+ +Bagian selebihnya dari dokumen ini membahas dasar-dasar cara membuat dan menggunakan aktivitas, +yang meliputi satu pembahasan lengkap tentang cara kerja daur hidup aktivitas, sehingga Anda bisa dengan benar mengelola +transisi di antara berbagai status aktivitas.
+ + + +Membuat Aktivitas
+ +Untuk membuat sebuah aktivitas, Anda harus membuat subkelas {@link android.app.Activity} (atau +subkelasnya yang ada). Dalam subkelas itu, Anda perlu mengimplementasikan metode-metode callback yang +dipanggil sistem saat aktivitas bertransisi di antara berbagai status daur hidupnya, misalnya saat +aktivitas sedang dibuat, dihentikan, dilanjutkan, atau dimusnahkan. Dua metode callback +terpenting adalah:
+ +-
+
- {@link android.app.Activity#onCreate onCreate()} +
- Anda harus mengimplementasikan metode ini. Sistem memanggilnya saat membuat + aktivitas Anda. Dalam implementasi, Anda harus menginisialisasi komponen-komponen esensial +aktivitas. + Yang terpenting, inilah tempat Anda harus memanggil {@link android.app.Activity#setContentView + setContentView()} untuk mendefinisikan layout untuk antarmuka pengguna aktivitas. +
- {@link android.app.Activity#onPause onPause()} +
- Sistem memanggil metode ini sebagai pertanda pertama bahwa pengguna sedang meninggalkan +aktivitas Anda (walau itu tidak selalu berarti aktivitas sedang dimusnahkan). Inilah biasanya tempat Anda +harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena +pengguna mungkin tidak kembali). +
Ada beberapa metode callback daur hidup lainnya yang harus Anda gunakan untuk memberikan +pengalaman pengguna yang mengalir di antara aktivitas dan menangani interupsi tidak terduga yang menyebabkan aktivitas Anda +dihentikan dan bahkan dimusnahkan. Semua metode callback daur hidup akan dibahas nanti, di +bagian tentang Mengelola Daur Hidup Aktivitas.
+ + + +Mengimplementasikan antarmuka pengguna
+ +Antarmuka pengguna aktivitas disediakan oleh hierarki objek—tampilan yang diturunkan +dari kelas {@link android.view.View}. Tiap tampilan mengontrol sebuah ruang persegi panjang tertentu +dalam jendela aktivitas dan bisa merespons interaksi pengguna. Misalnya, sebuah tampilan mungkin berupa sebuah +tombol yang mengawali suatu tindakan bila pengguna menyentuhnya.
+ +Android menyediakan sejumlah tampilan siap-dibuat yang bisa Anda gunakan untuk mendesain dan mengatur +layout. "Widget" adalah tampilan yang menyediakan elemen-elemen visual (dan interaktif) untuk layar, +misalnya tombol, bidang teks, kotak cek, atau sekadar sebuah gambar. "Layout" adalah tampilan yang diturunkan dari {@link +android.view.ViewGroup} yang memberikan sebuah model layout unik untuk tampilan anaknya, misalnya +layout linier, layout grid, atau layout relatif. Anda juga bisa mensubkelaskan kelas-kelas {@link android.view.View} dan +{@link android.view.ViewGroup} (atau subkelas yang ada) untuk membuat widget dan +layout Anda sendiri dan menerapkannya ke layout aktivitas Anda.
+ +Cara paling umum untuk mendefinisikan layout dengan menggunakan tampilan adalah dengan file layout XML yang disimpan dalam +sumber daya aplikasi Anda. Dengan cara ini, Anda bisa memelihara desain antarmuka pengguna Anda secara terpisah dari +kode yang mendefinisikan perilaku aktivitas. Anda bisa mengatur layout sebagai UI +aktivitas Anda dengan {@link android.app.Activity#setContentView(int) setContentView()}, dengan meneruskan +ID sumber daya untuk layout itu. Akan tetapi, Anda juga bisa membuat {@link android.view.View} baru dalam +kode aktivitas dan membuat hierarki tampilan dengan menyisipkan {@link +android.view.View} baru ke dalam {@link android.view.ViewGroup}, kemudian menggunakan layout itu dengan meneruskan akar +{@link android.view.ViewGroup} ke {@link android.app.Activity#setContentView(View) +setContentView()}.
+ +Untuk informasi tentang cara membuat antarmuka pengguna, lihat dokumentasi Antarmuka Pengguna.
+ + + +Mendeklarasikan aktivitas dalam manifes
+ +Anda harus mendeklarasikan aktivitas dalam file manifes agar file itu +bisa diakses oleh sistem. Untuk mendeklarasikan aktivitas, bukalah file manifes Anda dan tambahkan sebuah elemen {@code <activity>} +sebagai anak elemen {@code <application>} +. Misalnya:
+ ++<manifest ... > + <application ... > + <activity android:name=".ExampleActivity" /> + ... + </application ... > + ... +</manifest > ++ +
Ada beberapa atribut lain yang bisa Anda sertakan dalam elemen ini, untuk mendefinisikan properti +misalnya label untuk aktivitas, ikon untuk aktivitas, atau tema untuk memberi gaya ke +UI aktivitas. Atribut {@code android:name} + adalah satu-satunya atribut yang diperlukan—atribut ini menetapkan nama kelas aktivitas. Setelah +Anda mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak +sebagian fungsionalitas, misalnya pintasan aplikasi (bacalah posting blog berjudul Things +That Cannot Change).
+ +Lihat acuan elemen {@code <activity>} +untuk informasi selengkapnya tentang cara mendeklarasikan aktivitas Anda dalam manifes.
+ + +Menggunakan filter intent
+ +Elemen {@code +<activity>} juga bisa menetapkan berbagai filter intent—dengan menggunakan elemen {@code +<intent-filter>} —untuk mendeklarasikan cara komponen aplikasi lain +mengaktifkannya.
+ +Bila Anda membuat aplikasi baru dengan Android SDK Tools, aktivitas stub +yang dibuat untuk Anda secara otomatis menyertakan filter intent yang mendeklarasikan respons +aktivitas pada tindakan "main" (utama) dan harus diletakkan dalam kategori "launcher"). Filter intent +terlihat seperti ini:
+ ++<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> ++ +
Elemen {@code +<action>} menetapkan bahwa ini adalah titik masuk "main" ke aplikasi. Elemen {@code +<category>} menetapkan bahwa aktivitas ini harus tercantum dalam launcher aplikasi +sistem (untuk memungkinkan pengguna meluncurkan aktivitas ini).
+ +Jika Anda bermaksud agar aplikasi dimuat dengan sendirinya dan tidak memperbolehkan aplikasi lain +mengaktifkan aktivitasnya, maka Anda tidak memerlukan filter intent lain. Hanya satu aktivitas yang boleh +memiliki tindakan "main" dan kategori "launcher", seperti dalam contoh sebelumnya. Aktivitas yang +tidak ingin Anda sediakan untuk aplikasi lain tidak boleh memiliki filter intent dan Anda bisa +memulai sendiri aktivitas dengan menggunakan intent secara eksplisit (seperti dibahas di bagian berikut).
+ +Akan tetapi, jika ingin aktivitas Anda merespons intent implisit yang dikirim dari +aplikasi lain (dan aplikasi Anda sendiri), maka Anda harus mendefinisikan filter intent tambahan untuk +aktivitas. Untuk masing-masing tipe intent yang ingin direspons, Anda harus menyertakan sebuah {@code +<intent-filter>} yang menyertakan elemen +{@code +<action>} dan, opsional, sebuah elemen {@code +<category>} dan/atau elemen {@code +<data>}. Elemen-elemen ini menetapkan tipe intent yang bisa +direspons oleh aktivitas Anda.
+ +Untuk informasi selengkapnya tentang cara aktivitas Anda merespons intent, lihat dokumen Intent dan Filter Intent. +
+ + + +Memulai Aktivitas
+ +Anda bisa memulai aktivitas lain dengan memanggil {@link android.app.Activity#startActivity + startActivity()}, dengan meneruskan sebuah {@link android.content.Intent} yang menjelaskan aktivitas + yang ingin Anda mulai. Intent menetapkan aktivitas persis yang ingin Anda mulai atau menjelaskan + tipe tindakan yang ingin Anda lakukan (dan sistem akan memilih aktivitas yang sesuai untuk Anda, +yang bahkan + bisa berasal dari aplikasi berbeda). Intent juga bisa membawa sejumlah kecil data untuk + digunakan oleh aktivitas yang dimulai.
+ +Saat bekerja dalam aplikasi sendiri, Anda nanti akan sering meluncurkan aktivitas yang dikenal saja. + Anda bisa melakukannya dengan membuat intent yang mendefinisikan secara eksplisit aktivitas yang ingin Anda mulai, +dengan menggunakan nama kelas. Misalnya, beginilah cara satu aktivitas memulai aktivitas lain bernama {@code +SignInActivity}:
+ ++Intent intent = new Intent(this, SignInActivity.class); +startActivity(intent); ++ +
Akan tetapi, aplikasi Anda mungkin juga perlu melakukan beberapa tindakan, misalnya mengirim email, + pesan teks, atau pembaruan status, dengan menggunakan data dari aktivitas Anda. Dalam hal ini, aplikasi Anda mungkin + tidak memiliki aktivitasnya sendiri untuk melakukan tindakan tersebut, sehingga Anda bisa memanfaatkan aktivitas + yang disediakan oleh aplikasi lain pada perangkat, yang bisa melakukan tindakan itu untuk Anda. Inilah saatnya +intent benar-benar berharga—Anda bisa membuat intent yang menjelaskan tindakan yang ingin +dilakukan dan sistem + akan meluncurkan aktivitas yang tepat dari aplikasi lain. Jika ada + beberapa aktivitas yang bisa menangani intent itu, pengguna bisa memilih aktivitas yang akan digunakan. Misalnya, + jika Anda ingin memperbolehkan pengguna mengirim pesan email, Anda bisa membuat + intent berikut:
+ ++Intent intent = new Intent(Intent.ACTION_SEND); +intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); +startActivity(intent); ++ +
Ekstra {@link android.content.Intent#EXTRA_EMAIL} yang ditambahkan ke intent adalah sebuah larik string + alamat email yang menjadi tujuan pengiriman email. Bila aplikasi email merespons intent ini, + aplikasi itu akan membaca larik string yang disediakan dalam ekstra dan meletakkannya dalam bidang "to" + pada formulir penulisan email. Dalam situasi ini, aktivitas aplikasi email dimulai dan bila + pengguna selesai, aktivitas Anda akan dilanjutkan.
+ + + + +Memulai aktivitas agar berhasil
+ +Kadang-kadang, Anda mungkin ingin menerima hasil dari aktivitas yang Anda mulai. Dalam hal itu, + mulailah aktivitas dengan memanggil {@link android.app.Activity#startActivityForResult + startActivityForResult()} (sebagai ganti {@link android.app.Activity#startActivity + startActivity()}). Untuk menerima hasil dari +aktivitas selanjutnya nanti, implementasikan metode callback {@link android.app.Activity#onActivityResult onActivityResult()} +. Bila aktivitas selanjutnya selesai, aktivitas akan mengembalikan hasil dalam {@link +android.content.Intent} kepada metode {@link android.app.Activity#onActivityResult onActivityResult()} +Anda.
+ +Misalnya, mungkin Anda ingin pengguna mengambil salah satu kontaknya, sehingga aktivitas Anda bisa +melakukan sesuatu dengan informasi dalam kontak itu. Begini caranya membuat intent tersebut dan +menangani hasilnya:
+ ++private void pickContact() { + // Create an intent to "pick" a contact, as defined by the content provider URI + Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); + startActivityForResult(intent, PICK_CONTACT_REQUEST); +} + +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // If the request went well (OK) and the request was PICK_CONTACT_REQUEST + if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { + // Perform a query to the contact's content provider for the contact's name + Cursor cursor = getContentResolver().query(data.getData(), + new String[] {Contacts.DISPLAY_NAME}, null, null, null); + if (cursor.moveToFirst()) { // True if the cursor is not empty + int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); + String name = cursor.getString(columnIndex); + // Do something with the selected contact's name... + } + } +} ++ +
Contoh ini menunjukkan logika dasar yang harus Anda gunakan dalam metode {@link +android.app.Activity#onActivityResult onActivityResult()} Anda untuk menangani +hasil aktivitas. Syarat pertama memeriksa apakah permintaan berhasil—jika ya, maka + {@code resultCode} akan berupa {@link android.app.Activity#RESULT_OK}—dan apakah permintaan +yang direspons hasil ini dikenal—dalam hal ini, {@code requestCode} cocok dengan +parameter kedua yang dikirim dengan {@link android.app.Activity#startActivityForResult +startActivityForResult()}. Dari sana, kode akan menangani hasil aktivitas dengan membuat query +data yang dihasilkan dalam{@link android.content.Intent} (parameter {@code data}).
+ +Yang terjadi adalah {@link +android.content.ContentResolver} melakukan query terhadap penyedia konten, yang menghasilkan +{@link android.database.Cursor} yang memperbolehkan data query dibaca. Untuk informasi selengkapnya, lihat dokumen +Penyedia Konten.
+ +Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen Intent dan Filter +Intent.
+ + +Mematikan Aktivitas
+ +Anda bisa mematikan aktivitas dengan memanggil metode {@link android.app.Activity#finish +finish()}-nya. Anda juga bisa mematikan aktivitas terpisah yang sebelumnya Anda mulai dengan memanggil +{@link android.app.Activity#finishActivity finishActivity()}.
+ +Catatan: Pada umumnya, Anda tidak boleh secara eksplisit mengakhiri aktivitas +dengan menggunakan metode-metode ini. Seperti yang dibahas di bagian berikut tentang daur hidup aktivitas, +sistem Android mengelola hidup aktivitas untuk Anda, sehingga Anda tidak perlu menyelesaikan sendiri +aktivitas tersebut. Memanggil metode-metode ini bisa berpengaruh negatif pada pengalaman +pengguna yang diharapkan dan hanya boleh digunakan bila Anda benar-benar tidak ingin pengguna kembali ke +instance aktivitas ini.
+ + +Mengelola Daur Hidup Aktivitas
+ +Mengelola daur hidup aktivitas dengan mengimplementasikan metode-metode callback sangat +penting untuk mengembangkan +aplikasi yang kuat dan fleksibel. Daur hidup aktivitas dipengaruhi langsung oleh kaitannya dengan +aktivitas lain, tugasnya, serta back-stack.
+ +Pada dasarnya, sebuah aktivitas bisa berada dalam tiga status:
+ +-
+
- Dilanjutkan +
- Aktivitas berada di latar depan layar dan mendapatkan fokus pengguna. (Status ini +kadang-kadang disebut juga dengan "running" (berjalan).) + +
- Dihentikan sementara +
- Aktivitas lain berada di latar depan dan mendapat fokus, namun aktivitas ini masih terlihat. Yakni, +aktivitas lain terlihat di atas aplikasi ini dan aktivitas itu setengah transparan atau tidak +menuutpi seluruh layar. Aktivitas yang dihentikan sementara adalah benar-benar hidup (objek {@link android.app.Activity} +dipertahankan dalam memori, objek itu memelihara semua informasi status dan anggota, dan tetap dikaitkan dengan +window manager), namun bisa dimatikan oleh sistem dalam situasi memori sangat rendah. + +
- Dihentikan +
- Aktivitas ditutupi sepenuhnya oleh aktivitas lain (aktivitas sekarang berada di +"latar belakang"). Aktivitas yang dihentikan juga masih hidup (objek {@link android.app.Activity} +dipertahankan dalam memori, objek itu menjaga semua informasi status dan anggota, namun tidak +dikaitkan dengan window manager). Akan tetapi, aktivitas tidak lagi terlihat bagi pengguna dan +bisa dimatikan oleh sistem bila memori diperlukan di lain. +
Jika aktivitas dihentikan sementara atau dihentikan, sistem bisa mengeluarkannya dari memori baik dengan memintanya agar +diakhiri (memanggil metode {@link android.app.Activity#finish finish()}-nya), atau sekadar mematikan +prosesnya. Bila dibuka lagi (setelah diakhiri atau dimatikan), aktivitas harus dibuat dari +awal.
+ + + +Mengimplementasikan callback daur hidup
+ +Saat bertransisi ke dalam dan ke luar berbagai status yang dijelaskan di atas, aktivitas diberi tahu +melalui berbagai metode callback. Semua metode callback adalah sangkutan yang +bisa Anda kesampingkan untuk melakukan pekerjaan yang sesuai saat status aktivitas Anda berubah. Aktivitas skeleton +berikut menyertakan setiap metode daur hidup mendasar:
+ + ++public class ExampleActivity extends Activity { + @Override + public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // The activity is being created. + } + @Override + protected void {@link android.app.Activity#onStart onStart()} { + super.onStart(); + // The activity is about to become visible. + } + @Override + protected void {@link android.app.Activity#onResume onResume()} { + super.onResume(); + // The activity has become visible (it is now "resumed"). + } + @Override + protected void {@link android.app.Activity#onPause onPause()} { + super.onPause(); + // Another activity is taking focus (this activity is about to be "paused"). + } + @Override + protected void {@link android.app.Activity#onStop onStop()} { + super.onStop(); + // The activity is no longer visible (it is now "stopped") + } + @Override + protected void {@link android.app.Activity#onDestroy onDestroy()} { + super.onDestroy(); + // The activity is about to be destroyed. + } +} ++ +
Catatan: Implementasi Anda terhadap metode-metode daur hidup ini harus +selalu memanggil implementasi superkelas sebelum melakukan pekerjaan apa pun, seperti yang ditampilkan dalam contoh-contoh di atas.
+ +Bersama-sama, semua metode ini mendefinisikan seluruh daur hidup sebuah aktivitas. Dengan mengimplementasikan +metode-metode ini, Anda bisa memantau tiga loop tersarang (nested loop) dalam daur hidup aktivitas:
+ +-
+
- Seluruh masa hidup aktivitas berlangsung antara panggilan ke {@link +android.app.Activity#onCreate onCreate()} dan panggilan ke {@link +android.app.Activity#onDestroy}. Aktivitas Anda harus melakukan penyiapan +status "global" (misalnya mendefinisikan layout) dalam {@link android.app.Activity#onCreate onCreate()}, dan +melepas semua sisa sumber daya dalam {@link android.app.Activity#onDestroy}. Misalnya, jika +aktivitas Anda memiliki sebuah thread yang berjalan di latar belakang untuk mengunduh data dari jaringan, aktivitas itu bisa membuat +thread itu dalam {@link android.app.Activity#onCreate onCreate()} kemudian menghentikan thread dalam {@link +android.app.Activity#onDestroy}. + +
Masa pakai terlihat (visible lifetime) aktivitas berlangsung antara panggilan ke {@link +android.app.Activity#onStart onStart()} dan panggilan ke {@link +android.app.Activity#onStop onStop()}. Selama ini, pengguna bisa melihat aktivitas +pada layar dan berinteraksi dengannya. Misalnya, {@link android.app.Activity#onStop onStop()} dipanggil +bila sebuah aktivitas baru dimulai dan aktivitas ini tidak lagi terlihat. Di antara dua metode ini, Anda bisa +memelihara sumber daya yang diperlukan untuk menampilkan aktivitas kepada pengguna. Misalnya, Anda bisa mendaftarkan sebuah +{@link android.content.BroadcastReceiver} dalam {@link +android.app.Activity#onStart onStart()} untuk memantau perubahan yang berdampak pada UI Anda, dan mencabut pendaftarannya +dalam {@link android.app.Activity#onStop onStop()} bila pengguna tidak bisa lagi melihat apa yang sedang Anda +tampilkan. Sistem bisa memanggil {@link android.app.Activity#onStart onStart()} dan {@link +android.app.Activity#onStop onStop()} beberapa kali selama masa pakai aktivitas, sambil +aktivitas berganti-ganti antara terlihat dan tersembunyi bagi pengguna.
+
+Masa pakai latar depan aktivitas berlangsung antara panggilan ke {@link +android.app.Activity#onResume onResume()} dan panggilan ke {@link android.app.Activity#onPause +onPause()}. Selama waktu ini, aktivitas berada di depan semua aktivitas lain pada layar dan mendapatkan +fokus input pengguna. Aktivitas bisa sering bertransisi ke dalam dan ke luar latar depan—misalnya, + {@link android.app.Activity#onPause onPause()} dipanggil bila perangkat masuk ke mode tidur atau +bila dialog muncul. Karena status ini bisa sering bertransisi, kode dalam dua metode ini harus +cukup ringan untuk menghindari transisi lamban yang membuat pengguna menunggu.
+
Gambar 1 mengilustrasikan loop dan path yang mungkin diambil sebuah aktivitas di antara status-status. +Persegi panjang mewakili metode callback yang bisa Anda implementasikan untuk melakukan operasi saat +aktivitas bertransisi di antara status.
+ + +
+ +Metode-metode callback daur hidup yang sama tercantum dalam tabel 1, yang menjelaskan setiap metode callback +secara lebih detail dan menentukan lokasinya masing-masing dalam +daur hidup aktivitas keseluruhan, termasuk apakah sistem bisa mematikan aktivitas setelah +metode callback selesai.
+ + + +Metode | Keterangan | Bisa dimatikan setelahnya? | Berikutnya | ||
---|---|---|---|---|---|
{@link android.app.Activity#onCreate onCreate()} |
+ Dipanggil saat aktivitas pertama kali dibuat.
+ Di sinilah Anda harus melakukan semua persiapan statis normal —
+ membuat tampilan, mengikat data ke daftar, dan sebagainya. Metode ini diberi
+ sebuah objek Bundle yang berisi status aktivitas sebelumnya, jika
+ status itu tertangkap (lihat Menyimpan Status Aktivitas,
+ nanti).
+ Selalu diikuti oleh {@code onStart()}. |
+ Tidak | +{@code onStart()} | +||
+ | {@link android.app.Activity#onRestart
+onRestart()} |
+ Dipanggil setelah aktivitas dihentikan, tepat sebelum
+ dimulai lagi.
+ Selalu diikuti oleh {@code onStart()} |
+ Tidak | +{@code onStart()} | +|
{@link android.app.Activity#onStart onStart()} |
+ Dipanggil tepat sebelum aktivitas menjadi terlihat bagi pengguna.
+ Diikuti oleh {@code onResume()} jika aktivitas maju + ke latar depan, atau {@code onStop()} jika menjadi tersembunyi. |
+ Tidak | +{@code onResume()} atau {@code onStop()} |
+||
+ | {@link android.app.Activity#onResume onResume()} |
+ Dipanggil tepat sebelum aktivitas mulai
+ berinteraksi dengan pengguna. Pada titik ini, aktivitas berada di
+ puncak tumpukan aktivitas, dengan input pengguna menuju kepadanya.
+ Selalu diikuti oleh {@code onPause()}. |
+ Tidak | +{@code onPause()} | +|
{@link android.app.Activity#onPause onPause()} |
+ Dipanggil bila sistem akan memulai pelanjutan
+ aktivitas lain. Metode ini biasanya digunakan untuk menerapkan (commit) perubahan yang tidak tersimpan pada
+ data persisten, menghentikan animasi dan hal-hal lain yang mungkin menghabiskan
+ CPU, dan sebagainya. Metode ini harus melakukan apa saja yang dilakukannya dengan sangat cepat, karena
+ aktivitas berikutnya tidak akan dilanjutkan hingga aktivitas ini kembali.
+ Diikuti oleh {@code onResume()} jika aktivitas + kembali ke depan, atau oleh {@code onStop()} jika menjadi + tidak terlihat bagi pengguna. |
+ Ya | +{@code onResume()} atau {@code onStop()} |
+||
{@link android.app.Activity#onStop onStop()} |
+ Dipanggil bila aktivitas tidak lagi terlihat bagi pengguna. Hal ini
+ bisa terjadi karena aktivitas sedang dimusnahkan, atau karena aktivitas lain
+ (aktivitas yang ada atau yang baru) telah dilanjutkan dan sedang menutupinya.
+ Diikuti oleh {@code onRestart()} jika + aktivitas kembali untuk berinteraksi dengan pengguna, atau oleh + {@code onDestroy()} jika aktivitas ini akan menghilang. |
+ Ya | +{@code onRestart()} atau {@code onDestroy()} |
+||
{@link android.app.Activity#onDestroy
+onDestroy()} |
+ Dipanggil sebelum aktivitas dimusnahkan. Inilah panggilan terakhir
+ yang akan diterima aktivitas. Metode ini bisa dipanggil karena
+ aktivitas selesai (seseorang memanggil {@link android.app.Activity#finish
+ finish()} padanya), atau karena sistem memusnahkan sementara
+ instance aktivitas ini untuk menghemat tempat. Anda bisa membedakan
+ kedua skenario ini dengan metode {@link
+ android.app.Activity#isFinishing isFinishing()} . |
+ Ya | +tidak ada | +
Kolom berlabel "Bisa dimatikan setelahnya?" menunjukkan apakah sistem bisa +atau tidak mematikan proses yang menjadi host aktivitas kapan saja setelah metode kembali, tanpa +menjalankan baris lain pada kode aktivitas. Tiga metode ini ditandai "ya": ({@link +android.app.Activity#onPause +onPause()}, {@link android.app.Activity#onStop onStop()}, dan {@link android.app.Activity#onDestroy +onDestroy()}). Karena {@link android.app.Activity#onPause onPause()} adalah yang pertama +dari tiga, begitu aktivitas dibuat, {@link android.app.Activity#onPause onPause()} adalah +metode terakhir yang dipastikan akan dipanggil sebelum proses bisa dimatikan—jika +sistem harus memulihkan memori dalam keadaan darurat, maka {@link +android.app.Activity#onStop onStop()} dan {@link android.app.Activity#onDestroy onDestroy()} mungkin +tidak dipanggil. Karena itu, Anda harus menggunakan {@link android.app.Activity#onPause onPause()} untuk menulis +data persisten yang penting (misalnya hasil edit pengguna) ke penyimpanan. Akan tetapi, Anda harus selektif dalam hal +informasi yang harus dipertahankan selama {@link android.app.Activity#onPause onPause()}, karena setiap +prosedur pemblokiran dalam metode ini akan memblokir transisi ke aktivitas berikutnya dan memperlambat +pengalaman pengguna.
+ +Metode-metode yang ditandai "Tidak" dalam kolom Bisa dimatikan melindungi proses yang menjadi host +aktivitas dari dimatikan sejak saat metode dipanggil. Jadi, aktivitas bisa dimatikan +sejak {@link android.app.Activity#onPause onPause()} kembali hingga waktu +{@link android.app.Activity#onResume onResume()} dipanggil. Aktivitas tidak akan lagi bisa dimatikan hingga +{@link android.app.Activity#onPause onPause()} dipanggil lagi dan kembali.
+ +Catatan: Aktivitas yang tidak "bisa dimatikan" secara teknis oleh +definisi dalam tabel 1 masih bisa dimatikan oleh sistem—namun itu hany terjadi dalam +situasi ekstrem bila tidak ada jalan lain. Kapan aktivitas bisa dimatikan +akan dibahas selengkapnya dalam dokumen Proses dan +Threading.
+ + +Menyimpan status aktivitas
+ +Pengantar untuk Mengelola Daur Hidup Aktivitas secara ringkas menyebutkan +bahwa +bila aktivitas dihentikan sementara atau dihentikan, status aktivitas akan dipertahankan. Hal itu terjadi karena +objek {@link android.app.Activity} masih ditahan dalam memori saat aktivitas dihentikan sementara atau +dihentikan—semua informasi tentang anggota dan statusnya saat ini masih hidup. Jadi, setiap perubahan +yang dibuat pengguna dalam aktivitas akan dipertahankan sehingga bila aktivitas kembali ke +latar depan (bila "dilanjutkan"), perubahan itu masih ada.
+ +Akan tetapi, bila sistem memusnahkan aktivitas untuk memulihkan memori, objek {@link +android.app.Activity} akan dimusnahkan, sehingga sistem tidak bisa sekadar melanjutkan aktivitas dengan status +tidak berubah. Sebagai gantinya, sistem harus membuat ulang objek {@link android.app.Activity} jika pengguna +menyusuri kembali ke aktivitas tersebut. Namun, pengguna tidak menyadari +bahwa sistem memusnahkan aktivitas dan membuatnya kembali dan, karena itu, mungkin +mengharapkan aktivitas untuk sama persis dengan sebelumnya. Dalam situasi ini, Anda bisa memastikan bahwa +informasi penting tentang status aktivitas tetap terjaga dengan mengimplementasikan +metode callback tambahan yang memungkinkan Anda menyimpan informasi tentang status aktivitas: {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()}.
+ +Sistem memanggil {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} +sebelum membuat aktivitas rawan terhadap pemusnahan. Sistem meneruskan ke metode ini +sebuah {@link android.os.Bundle} tempat Anda bisa menyimpan +informasi status tentang aktivitas sebagai pasangan nama-nilai, dengan menggunakan metode-metode misalnya {@link +android.os.Bundle#putString putString()} dan {@link +android.os.Bundle#putInt putInt()}. Kemudian, jika sistem mematikan proses aplikasi Anda +dan pengguna menyusuri kembali ke aktivitas tersebut, sistem akan membuat kembali aktivitas dan meneruskan +{@link android.os.Bundle} ke {@link android.app.Activity#onCreate onCreate()} maupun {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. Dengan menggunakan salah satu +metode ini, Anda bisa mengekstrak status tersimpan dari {@link android.os.Bundle} dan memulihkan +status aktivitas. Jika tidak ada informasi status untuk dipulihkan, maka {@link +android.os.Bundle} yang diteruskan kepada adalah Anda null (yang akan terjadi bila aktivitas dibuat untuk +pertama kali).
+ + + + +Catatan: Tidak ada jaminan bahwa {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} akan dipanggil sebelum +aktivitas Anda dimusnahkan, karena bisa saja terjadi aktivitas tidak perlu menyimpan status +(misalnya saat pengguna meninggalkan aktivitas Anda dengan menggunakan tombol Back, karena pengguna menutup aktivitas +secara eksplisit +). Jika sistem memanggil {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()}, ini akan dilakukan sebelum {@link +android.app.Activity#onStop onStop()} dan mungkin sebelum {@link android.app.Activity#onPause +onPause()}.
+ +Akan tetapi, sekalipun Anda tidak melakukan apa-apa dan tidak mengimplementasikan {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()}, beberapa status aktivitas +akan dipulihkan oleh implementasi default {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} dalam kelas {@link android.app.Activity}. Khususnya, +implementasi default akan memanggil metode {@link +android.view.View#onSaveInstanceState onSaveInstanceState()} yang sesuai untuk setiap {@link +android.view.View} dalam layout, yang memungkinkan setiap tampilan untuk memberi informasi tentang dirinya +yang harus disimpan. Hampir setiap widget dalam kerangka kerja Android mengimplementasikan metode ini +sebagaimana mestinya, sehingga setiap perubahan yang terlihat pada UI akan disimpan dan dipulihkan secara otomatis bila +aktivitas Anda dibuat kembali. Misalnya, widget {@link android.widget.EditText} menyimpan teks apa saja +yang dimasukkan oleh pengguna dan widget {@link android.widget.CheckBox} menyimpan baik teks itu diperiksa maupun +tidak. Satu-satunya pekerjaan yang Anda perlukan adalah memberikan ID unik (dengan atribut {@code android:id} +) untuk masing-masing widget yang ingin disimpan statusnya. Jika widget tidak memiliki ID, maka sistem +tidak bisa menyimpan statusnya.
+ +Anda juga bisa menghentikan secara eksplisit sebuah tampilan dalam layout Anda agar tidak menyimpan statusnya dengan mengatur atribut +{@link android.R.attr#saveEnabled android:saveEnabled} ke {@code "false"} atau dengan memanggil +metode {@link android.view.View#setSaveEnabled setSaveEnabled()}. Biasanya, Anda tidak boleh +menonaktifkannya, namun Anda boleh melakukannya jika ingin memulihkan status UI aktivitas secara berbeda.
+Walaupun implementasi default {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} menyimpan informasi yang berguna tentang +UI aktivitas, Anda mungkin masih perlu mengesampingkannya untuk menyimpan informasi tambahan. +Misalnya, Anda mungkin perlu menyimpan nilai-nilai anggota yang berubah selama masa pakai aktivitas (yang +mungkin berkorelasi dengan nilai-nilai yang dipulihkan dalam UI, namun anggota-anggota yang menyimpan nilai-nilai UI itu tidak +dipulihkan, secara default).
+ +Karena implementasi default {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} membantu menyimpan status UI, jika +Anda mengesampingkan metode ini untuk menyimpan informasi tambahan status, Anda harus selalu memanggil +implementasi superkelas {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} +sebelum melakukan pekerjaan apa pun. Demikian pula, Anda juga harus memanggil implementasi superkelas {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} jika Anda mengesampingkannya, sehingga +implementasi default bisa memulihkan status tampilan.
+ +Catatan: Karena {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} tidak dijamin +akan dipanggil, Anda harus menggunakannya hanya untuk mencatat status aktivitas sementara (transient) (status +UI)—Anda tidak boleh menggunakannya untuk menyimpan data persisten. Sebagai gantinya, Anda harus menggunakan {@link +android.app.Activity#onPause onPause()} untuk menyimpan data persisten (misalnya data yang harus disimpan +ke database) saat pengguna meninggalkan aktivitas.
+ +Salah satu cara yang baik untuk menguji kemampuan aplikasi dalam memulihkan statusnya adalah cukup dengan memutar +perangkat sehingga orientasi layarnya berubah. Bila orientasi layar berubah, sistem +akan memusnahkan dan membuat kembali aktivitas untuk menerapkan sumber daya alternatif yang mungkin tersedia +untuk konfigurasi layar baru. Karena alasan ini saja, sangat penting bahwa aktivitas Anda +memulihkan statusnya secara lengkap saat dibuat kembali, karena pengguna memutar layar secara rutin saat +menggunakan aplikasi.
+ + +Menangani perubahan konfigurasi
+ +Sebagian konfigurasi perangkat bisa berubah saat runtime (misalnya orientasi layar, ketersediaan keyboard +, dan bahasa). Bila terjadi perubahan demikian, Android akan membuat kembali aktivitas yang berjalan +(sistem akan memanggil {@link android.app.Activity#onDestroy}, kemudian segera memanggil {@link +android.app.Activity#onCreate onCreate()}). Perilaku ini +didesain untuk membantu aplikasi Anda menyesuaikan diri dengan konfigurasi baru dengan cara memuat ulang +aplikasi Anda secara otomatis dengan sumber daya alternatif yang telah Anda sediakan (misalnya layout yang berbeda untuk +layar orientasi dan ukuran yang berbeda).
+ +Jika Anda mendesain aktivitas dengan benar untuk menangani restart karena perubahan orientasi layar dan +memulihkan status aktivitas seperti yang dijelaskan di atas, aplikasi Anda akan lebih tahan terhadap +kejadian tidak terduga lainnya dalam daur hidup aktivitas.
+ +Cara terbaik menangani restart tersebut adalah + menyimpan dan memulihkan status aktivitas Anda dengan menggunakan {@link + android.app.Activity#onSaveInstanceState onSaveInstanceState()} dan {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (atau {@link +android.app.Activity#onCreate onCreate()}), seperti yang dibahas di bagian sebelumnya.
+ +Untuk informasi selengkapnya tentang konfigurasi perubahan yang terjadi saat program berjalan dan cara menanganinya +, bacalah panduan untuk Menangani +Perubahan Runtime.
+ + + +Mengoordinasikan aktivitas
+ +Bila suatu aktivitas memulai aktivitas lain, keduanya akan mengalami transisi daur hidup. Aktivitas pertama +akan berhenti sementara dan berhenti sama sekali (walau tidak akan berhenti jika masih terlihat di latar belakang), saat +aktivitas lain dibuat. Jika aktivitas-aktivitas ini berbagi data yang disimpan ke disk atau di tempat lain, Anda perlu +memahami bahwa aktivitas pertama tidak dihentikan sepenuhnya sebelum aktivitas kedua dibuat. +Sebagai gantinya, proses akan memulai aktivitas kedua secara tumpang tindih dengan proses penghentian +aktivitas pertama.
+ +Urutan callback daur hidup didefinisikan dengan baik, khususnya bila kedua aktivitas berada dalam +proses yang sama dan salah satunya memulai yang lain. Berikut ini adalah urutan operasi yang terjadi bila Aktivitas +A memulai Aktivitas B:
+ +-
+
- Metode {@link android.app.Activity#onPause onPause()} Aktivitas A berjalan. + +
- Metode-metode {@link android.app.Activity#onCreate onCreate()}, {@link +android.app.Activity#onStart onStart()}, dan {@link android.app.Activity#onResume onResume()} +Aktivitas B berjalan secara berurutan. (Aktivitas B sekarang mendapatkan fokus pengguna.) + +
- Kemudian, jika Aktivitas A tidak lagi terlihat di layar, metode {@link +android.app.Activity#onStop onStop()}-nya akan dijalankan. +
Urutan callback daur hidup yang bisa diramalkan ini memungkinkan Anda mengelola transisi +informasi dari satu aktivitas ke aktivitas lainnya. Misalnya, jika Anda harus menulis ke database saat +aktivitas pertama berhenti agar aktivitas berikutnya bisa membacanya, maka Anda harus menulis ke +database selama {@link android.app.Activity#onPause onPause()} sebagai ganti selama {@link +android.app.Activity#onStop onStop()}.
+ + diff --git a/docs/html-intl/intl/in/guide/components/bound-services.jd b/docs/html-intl/intl/in/guide/components/bound-services.jd new file mode 100644 index 0000000000000000000000000000000000000000..5d1f65ed7c8edfe0e61bf16a9a804672319add74 --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/bound-services.jd @@ -0,0 +1,658 @@ +page.title=Layanan Terikat +parent.title=Layanan +parent.link=services.html +@jd:body + + +-
+
- Dasar-Dasar +
- Membuat Layanan Terikat + + +
- Mengikat ke Layanan +
- Mengelola Daur Hidup Layanan Terikat +
- {@link android.app.Service} +
- {@link android.content.ServiceConnection} +
- {@link android.os.IBinder} +
- Layanan +
Dalam dokumen ini
+-
+
Kelas-kelas utama
+-
+
Contoh
+ + +Lihat juga
+-
+
Layanan terikat adalah server di antarmuka klien-server. Layanan terikat memungkinkan komponen-komponen +(seperti aktivitas) untuk diikat ke layanan, mengirim permintaan, menerima respons, dan bahkan melakukan +komunikasi antarproses (IPC). Layanan terikat biasanya hidup hanya saat melayani +komponen aplikasi lain dan tidak berjalan di latar belakang terus-menerus.
+ +Dokumen ini menampilkan cara membuat layanan terikat, termasuk cara mengikat +ke layanan dari komponen aplikasi lain. Akan tetapi, Anda juga harus mengacu dokumen Layanan untuk +informasi tambahan tentang layanan secara umum, seperti cara menyampaikan pemberitahuan dari layanan, mengatur +layanan agar berjalan di latar depan, dan lain-lain.
+ + +Dasar-Dasar
+ +Layanan terikat adalah implementasi kelas {@link android.app.Service} yang memungkinkan +aplikasi lain diikat padanya dan berinteraksi dengannya. Untuk menyediakan pengikatan bagi sebuah +layanan, Anda harus mengimplementasikan metode callback {@link android.app.Service#onBind onBind()}. Metode ini +menghasilkan objek {@link android.os.IBinder} yang mendefinisikan antarmuka pemprograman yang +bisa digunakan klien untuk berinteraksi dengan layanan.
+ +Mengikat ke Layanan yang Sudah Dimulai
+ +Seperti dibahas dalam dokumen Layanan +, Anda bisa membuat layanan yang dimulai sekaligus diikat. Yakni, layanan bisa +dimulai dengan memanggil {@link android.content.Context#startService startService()}, yang memungkinkan +layanan berjalan terus-menerus, dan juga membolehkan klien untuk mengikat ke layanan dengan memanggil {@link +android.content.Context#bindService bindService()}. +
Jika Anda mengizinkan layanan dimulai dan diikat, lalu ketika layanan telah +dimulai, sistem tidak menghapus layanan ketika semua klien melepas ikatan. Sebagai gantinya, Anda harus +menghentikan layanan secara eksplisit, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link +android.content.Context#stopService stopService()}.
+ +Walaupun Anda biasanya harus mengimplementasikan {@link android.app.Service#onBind onBind()} +atau {@link android.app.Service#onStartCommand onStartCommand()}, kadang-kadang perlu +mengimplementasikan keduanya. Misalnya, sebuah pemutar musik bisa merasakan manfaatnya karena layanannya boleh berjalan +terus-menerus dan juga menyediakan pengikatan. Dengan cara ini, sebuah aktivitas bisa memulai layanan untuk memutar beberapa +lagu dan musik terus dimainkan sekalipun pengguna meninggalkan aplikasi. Lalu, bila pengguna +kembali ke aplikasi, aktivitas bisa mengikat ke layanan untuk mendapatkan kembali kontrol atas pemutaran.
+ +Pastikan membaca bagian tentang Mengelola Daur Hidup Layanan +Terikat, untuk informasi selengkapnya tentang daur hidup layanan saat menambahkan pengikatan ke +layanan yang sudah dimulai.
+Klien bisa mengikat ke layanan dengan memanggil {@link android.content.Context#bindService +bindService()}. Bila itu dilakukan, klien harus menyediakan implementasi {@link +android.content.ServiceConnection}, yang memantau koneksi dengan layanan. Metode {@link +android.content.Context#bindService bindService()} kembali dengan serta-merta tanpa sebuah nilai, namun +bila sistem Android membuat koneksi antara klien +dan layanan, sistem akan memanggil {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} pada {@link +android.content.ServiceConnection} untuk mengirim {@link android.os.IBinder} yang +bisa digunakan klien untuk berkomunikasi dengan layanan.
+ +Beberapa klien bisa terhubung ke layanan dengan serentak. Akan tetapi, sistem akan memanggil metode +{@link android.app.Service#onBind onBind()} layanan Anda untuk mengambil {@link android.os.IBinder} hanya +bila klien pertama mengikat. Sistem lalu memberikan {@link android.os.IBinder} yang sama ke setiap +klien tambahan yang mengikat, tanpa memanggil {@link android.app.Service#onBind onBind()} lagi.
+ +Bila klien terakhir melepas ikatan dari layanan, sistem akan menghapus layanan (kecuali jika +layanan juga dimulai oleh {@link android.content.Context#startService startService()}).
+ +Bila Anda mengimplementasikan layanan terikat, yang terpenting adalah mendefinisikan antarmuka +yang dihasilkan metode callback {@link android.app.Service#onBind onBind()} Anda. Ada sedikit +cara mendefinisikan antarmuka {@link android.os.IBinder} layanan Anda dan bagian berikut +akan membahas masing-masing teknik.
+ + + +Membuat Layanan Terikat
+ +Saat membuat layanan yang menyediakan pengikatan, Anda harus menyediakan {@link android.os.IBinder} +yang menyediakan antarmuka pemrograman yang bisa digunakan klien untuk berinteraksi dengan layanan. Ada +tiga cara untuk mendefinisikan antarmuka:
+ +-
+
- Memperluas kelas Binder +
- Jika layanan Anda bersifat privat untuk aplikasi Anda sendiri dan berjalan dalam proses yang sama dengan klien
+(biasanya), Anda harus membuat antarmuka dengan memperluas kelas {@link android.os.Binder}
+dan menghasilkan instance dari
+{@link android.app.Service#onBind onBind()}. Klien akan menerima {@link android.os.Binder} dan
+bisa menggunakannya untuk mengakses langsung metode publik yang tersedia dalam implementasi {@link android.os.Binder}
+atau bahkan {@link android.app.Service}.
+
Inilah teknik yang lebih disukai bila layanan Anda sekadar pekerja latar belakang untuk aplikasi Anda +sendiri. Satu-satunya alasan tidak membuat antarmuka dengan cara ini adalah karena +layanan Anda akan digunakan oleh aplikasi lain atau pada proses-proses terpisah.
+
+ - Menggunakan Messenger +
- Jika antarmuka Anda perlu bekerja lintas proses, Anda bisa membuat
+antarmuka untuk layanan dengan {@link android.os.Messenger}. Dengan cara ini, layanan
+mendefinisikan {@link android.os.Handler} yang akan merespons aneka tipe objek {@link
+android.os.Message}. {@link android.os.Handler}
+ini adalah dasar bagi {@link android.os.Messenger} yang nanti bisa berbagi {@link android.os.IBinder}
+dengan klien, sehingga memungkinkan klien mengirim perintah ke layanan dengan menggunakan objek {@link
+android.os.Message}. Selain itu, klien bisa mendefinisikan sendiri {@link android.os.Messenger}
+sehingga layanan bisa mengirim balik pesan.
+
Inilah cara termudah melakukan komunikasi antarproses (IPC), karena {@link +android.os.Messenger} akan mengantre semua permintaan ke dalam satu thread sehingga Anda tidak perlu mendesain +layanan agar thread-safe.
+
+
+ - Menggunakan AIDL +
- AIDL (Android Interface Definition Language) melakukan semua pekerjaan untuk mengurai objek menjadi
+primitif yang bisa dipahami dan diarahkan oleh sistem operasi ke berbagai proses untuk melakukan
+IPC. Teknik sebelumnya, dengan menggunakan {@link android.os.Messenger}, sebenarnya berdasarkan AIDL sebagai
+struktur yang mendasarinya. Seperti disebutkan di atas, {@link android.os.Messenger} membuat antrean
+semua permintaan klien dalam satu thread, sehingga layanan akan menerima permintaan satu per satu. Akan tetapi,
+jika ingin layanan Anda menangani beberapa permintaan sekaligus, Anda bisa menggunakan AIDL
+secara langsung. Dalam hal ini, layanan Anda harus mampu multi-thread dan dibuat thread-safe.
+
Untuk menggunakan AIDL secara langsung, Anda harus +membuat file {@code .aidl} yang mendefinisikan antarmuka pemrograman. Alat Android SDK menggunakan +file ini untuk menghasilkan kelas abstrak yang mengimplementasikan antarmuka dan menangani IPC, yang nanti +bisa Anda perluas dalam layanan.
+
+
Catatan: Umumnya aplikasi tidak boleh menggunakan AIDL untuk +membuat layanan terikat, karena hal itu mungkin memerlukan kemampuan multi-thread dan +bisa mengakibatkan implementasi yang lebih rumit. Dengan demikian, AIDL tidak cocok untuk sebagian besar aplikasi +dan dokumen ini tidak membahas cara menggunakannya untuk layanan Anda. Jika Anda yakin perlu +menggunakan AIDL secara langsung, lihat dokumen AIDL +.
+ + + + +Memperluas kelas Binder
+ +Jika layanan Anda hanya digunakan oleh aplikasi lokal dan tidak perlu bekerja lintas proses, +maka Anda bisa mengimplementasikan kelas {@link android.os.Binder} Anda sendiri yang memberi klien Anda +akses langsung ke metode publik dalam layanan.
+ +Catatan: Hal ini hanya berhasil jika klien dan layanan berada dalam +aplikasi dan proses yang sama, suatu kondisi yang paling umum. Misalnya, cara ini sangat cocok untuk sebuah aplikasi musik +yang perlu mengikat aktivitas ke layanannya sendiri, yakni memutar musik di +latar belakang.
+ +Berikut cara menyiapkannya:
+-
+
- Dalam layanan Anda, buat sebuah instance {@link android.os.Binder} yang:
+
-
+
- berisi metode publik yang bisa dipanggil klien +
- menghasilkan instance {@link android.app.Service} saat ini, yang memiliki metode publik yang +bisa dipanggil klien +
- atau, menghasilkan instance kelas lain yang host-nya di layanan dengan metode publik yang +bisa dipanggil klien +
- Hasilkan instance {@link android.os.Binder} ini dari metode callback {@link +android.app.Service#onBind onBind()}. +
- Di klien, terima {@link android.os.Binder} dari metode callback {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} dan +buat panggilan ke layanan terikat dengan menggunakan metode yang disediakan. +
Catatan: Alasan layanan dan klien harus berada dalam aplikasi yang sama +adalah agar klien bisa mengkonversi objek yang dihasilkan dan memanggil API-nya dengan benar. Layanan +dan klien juga harus berada dalam proses yang sama, karena teknik ini tidak melakukan +pengarahan (marshalling) apa pun untuk lintas proses.
+ +Misalnya, berikut ini adalah layanan yang memberi klien akses ke metode-metode dalam layanan melalui +implementasi {@link android.os.Binder}:
+ ++public class LocalService extends Service { + // Binder given to clients + private final IBinder mBinder = new LocalBinder(); + // Random number generator + private final Random mGenerator = new Random(); + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + LocalService getService() { + // Return this instance of LocalService so clients can call public methods + return LocalService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** method for clients */ + public int getRandomNumber() { + return mGenerator.nextInt(100); + } +} ++ +
{@code LocalBinder} menyediakan {@code getService()} metode bagi klien untuk mengambil +instance {@code LocalService} saat ini. Cara ini memungkinkan klien memanggil metode publik dalam +layanan. Misalnya, klien bisa memanggil {@code getRandomNumber()} dari layanan.
+ +Berikut ini adalah aktivitas yang mengikat ke {@code LocalService} dan memanggil {@code getRandomNumber()} +bila tombol diklik:
+ ++public class BindingActivity extends Activity { + LocalService mService; + boolean mBound = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to LocalService + Intent intent = new Intent(this, LocalService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } + + /** Called when a button is clicked (the button in the layout file attaches to + * this method with the android:onClick attribute) */ + public void onButtonClick(View v) { + if (mBound) { + // Call a method from the LocalService. + // However, if this call were something that might hang, then this request should + // occur in a separate thread to avoid slowing down the activity performance. + int num = mService.getRandomNumber(); + Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); + } + } + + /** Defines callbacks for service binding, passed to bindService() */ + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mBound = false; + } + }; +} ++ +
Contoh di atas menampilkan cara klien mengikat ke layanan dengan menggunakan implementasi +{@link android.content.ServiceConnection} dan callback {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()}. Bagian +berikut menyediakan informasi selengkapnya tentang proses pengikatan ke layanan.
+ +Catatan: Contoh di atas tidak secara eksplisit melepas ikatan dari layanan, +namun semua klien harus melepas ikatan pada waktu yang tepat (seperti saat aktivitas sedang jeda).
+ +Untuk contoh kode selengkapnya, lihat kelas {@code +LocalService.java} dan kelas {@code +LocalServiceActivities.java} dalam ApiDemos.
+ + + + + +Menggunakan Messenger
+ +Dibandingkan dengan AIDL
+Bila Anda perlu melakukan IPC, menggunakan {@link android.os.Messenger} untuk antarmuka +lebih sederhana daripada mengimplementasikannya dengan AIDL, karena {@link android.os.Messenger} mengantre +semua panggilan ke layanan, sementara antarmuka AIDL murni mengirim permintaan serentak ke +layanan, yang nanti harus menangani multi-threading.
+Untuk sebagian besar aplikasi, layanan tidak perlu melakukan multi-threading, jadi dengan menggunakan {@link +android.os.Messenger} memungkinkan layanan menangani panggilan satu per satu. Jika +layanan harus multi-thread, Anda harus menggunakan AIDL untuk mendefinisikan antarmuka.
+Jika layanan perlu berkomunikasi dengan proses jauh, Anda bisa menggunakan +{@link android.os.Messenger} untuk menyediakan antarmuka bagi layanan Anda. Teknik ini memungkinkan +Anda melakukan komunikasi antarproses (IPC) tanpa harus menggunakan AIDL.
+ +Berikut ini rangkuman cara menggunakan {@link android.os.Messenger}:
+ +-
+
- Layanan mengimplementasikan {@link android.os.Handler} yang menerima callback untuk tiap +panggilan dari klien. +
- {@link android.os.Handler} digunakan untuk membuat objek {@link android.os.Messenger} +(yang merupakan acuan ke {@link android.os.Handler}). +
- {@link android.os.Messenger} membuat {@link android.os.IBinder} yang +dikembalikan layanan ke klien dari {@link android.app.Service#onBind onBind()}. +
- Klien menggunakan {@link android.os.IBinder} untuk membuat instance {@link android.os.Messenger} +(yang mengacu {@link android.os.Handler} layanan), yang digunakan klien untuk mengirim +objek {@link android.os.Message} ke layanan. +
- Layanan menerima setiap {@link android.os.Message} dalam {@link +android.os.Handler}—secara spesifik, dalam metode {@link android.os.Handler#handleMessage +handleMessage()}. +
Dengan cara ini, tidak ada "metode" untuk dipanggil klien pada layanan. Sebagai gantinya, +klien mengirim "pesan" (objek-objek {@link android.os.Message}) yang diterima layanan dalam +{@link android.os.Handler}-nya.
+ +Berikut ini contoh layanan sederhana yang menggunakan antarmuka {@link android.os.Messenger}:
+ ++public class MessengerService extends Service { + /** Command to the service to display a message */ + static final int MSG_SAY_HELLO = 1; + + /** + * Handler of incoming messages from clients. + */ + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SAY_HELLO: + Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Target we publish for clients to send messages to IncomingHandler. + */ + final Messenger mMessenger = new Messenger(new IncomingHandler()); + + /** + * When binding to the service, we return an interface to our messenger + * for sending messages to the service. + */ + @Override + public IBinder onBind(Intent intent) { + Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); + return mMessenger.getBinder(); + } +} ++ +
Perhatikan bahwa metode {@link android.os.Handler#handleMessage handleMessage()} dalam +{@link android.os.Handler} adalah tempat layanan menerima {@link android.os.Message} +yang masuk dan memutuskan aksi yang harus dilakukan, berdasarkan anggota {@link android.os.Message#what}.
+ +Klien tinggal membuat {@link android.os.Messenger} berdasarkan {@link +android.os.IBinder} yang dihasilkan layanan dan mengirim pesan menggunakan {@link +android.os.Messenger#send send()}. Misalnya, berikut ini adalah aktivitas sederhana yang mengikat ke +layanan dan mengirim pesan {@code MSG_SAY_HELLO} ke layanan:
+ ++public class ActivityMessenger extends Activity { + /** Messenger for communicating with the service. */ + Messenger mService = null; + + /** Flag indicating whether we have called bind on the service. */ + boolean mBound; + + /** + * Class for interacting with the main interface of the service. + */ + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the object we can use to + // interact with the service. We are communicating with the + // service using a Messenger, so here we get a client-side + // representation of that from the raw IBinder object. + mService = new Messenger(service); + mBound = true; + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + mService = null; + mBound = false; + } + }; + + public void sayHello(View v) { + if (!mBound) return; + // Create and send a message to the service, using a supported 'what' value + Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); + try { + mService.send(msg); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to the service + bindService(new Intent(this, MessengerService.class), mConnection, + Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } +} ++ +
Perhatikan bahwa contoh ini tidak menampilkan cara layanan merespons klien. Jika ingin +layanan merespons, Anda juga perlu membuat {@link android.os.Messenger} di klien. Lalu +saat menerima callback {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()}, klien akan mengirim {@link android.os.Message} ke layanan yang berisi +{@link android.os.Messenger} klien dalam parameter {@link android.os.Message#replyTo} +metode {@link android.os.Messenger#send send()}.
+ +Anda bisa melihat contoh cara menyediakan pertukaran pesan dua arah dalam contoh {@code +MessengerService.java} (layanan) dan {@code +MessengerServiceActivities.java} (klien).
+ + + + + +Mengikat ke Layanan
+ +Komponen-komponen aplikasi (klien) bisa mengikat ke layanan dengan memanggil +{@link android.content.Context#bindService bindService()}. Sistem Android +lalu memanggil metode {@link android.app.Service#onBind +onBind()} layanan, yang menghasilkan {@link android.os.IBinder} untuk berinteraksi dengan layanan.
+ +Pengikatan ini bersifat asinkron. {@link android.content.Context#bindService +bindService()} segera kembali dan tidak mengembalikan {@link android.os.IBinder} ke +klien. Untuk menerima {@link android.os.IBinder}, klien harus membuat instance {@link +android.content.ServiceConnection} dan meneruskannya ke {@link android.content.Context#bindService +bindService()}. {@link android.content.ServiceConnection} berisi metode callback yang +dipanggil sistem untuk mengirim {@link android.os.IBinder}.
+ +Catatan: Hanya aktivitas, layanan, dan penyedia konten yang bisa mengikat +ke layanan yang—Anda tidak bisa ikat ke layanan dari penerima siaran.
+ +Jadi, untuk mengikat ke layanan dari klien, Anda harus:
+-
+
- Mengimplementasikan {@link android.content.ServiceConnection}.
+
Implementasi Anda harus mengesampingkan dua metode callback:
+-
+
- {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} +
- Sistem memanggil ini untuk mengirim {@link android.os.IBinder} yang dihasilkan oleh +metode {@link android.app.Service#onBind onBind()} layanan. +
- {@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()} +
- Sistem Android memanggil ini bila koneksi ke layanan putus +tanpa terduga, seperti ketika layanan mengalami crash atau dimatikan. Ini tidak dipanggil ketika +klien melepas ikatan. +
+ - Panggil {@link +android.content.Context#bindService bindService()}, dengan meneruskan implementasi {@link +android.content.ServiceConnection}. +
- Bila sistem memanggil metode callback {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()}, Anda bisa mulai membuat panggilan ke layanan, dengan menggunakan +metode yang didefinisikan oleh antarmuka. +
- Untuk memutus koneksi dari layanan, panggil {@link
+android.content.Context#unbindService unbindService()}.
+
Bila telah dimusnahkan (destroyed), klien Anda akan melepas ikatan dari layanan, namun Anda harus selalu melepas ikatan +bila sudah selesai berinteraksi dengan layanan atau bila aktivitas Anda sedang jeda sehingga layanan bisa +dimatikan saat tidak sedang digunakan. (Waktu yang tepat untuk mengikat dan melepas ikatan dibahas +selengkapnya di bawah ini.)
+
+
Misalnya, cuplikan berikut menghubungkan klien ke layanan yang dibuat di atas dengan +memperluas kelas Binder, sehingga tinggal mengkonversi +{@link android.os.IBinder} yang dihasilkan ke kelas {@code LocalService} dan meminta instance {@code +LocalService}:
+ ++LocalService mService; +private ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + // Because we have bound to an explicit + // service that is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + // Called when the connection with the service disconnects unexpectedly + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "onServiceDisconnected"); + mBound = false; + } +}; ++ +
Dengan {@link android.content.ServiceConnection} ini, klien bisa mengikat ke layanan dengan meneruskannya +ke {@link android.content.Context#bindService bindService()}. Misalnya:
+ ++Intent intent = new Intent(this, LocalService.class); +bindService(intent, mConnection, Context.BIND_AUTO_CREATE); ++ +
-
+
- Parameter pertama {@link android.content.Context#bindService bindService()} adalah sebuah +{@link android.content.Intent} yang secara eksplisit menyebutkan layanan yang akan diikat (walaupun intent +boleh implisit). +
- Parameter kedua adalah objek {@link android.content.ServiceConnection}. +
- Parameter ketiga adalah tanda (flag) yang menunjukkan opsi pengikatan. Tanda ini biasanya harus {@link +android.content.Context#BIND_AUTO_CREATE} agar dapat membuat layanan jika belum hidup. +Nilai-nilai lain yang memungkinkan adalah {@link android.content.Context#BIND_DEBUG_UNBIND} +dan {@link android.content.Context#BIND_NOT_FOREGROUND}, atau {@code 0} untuk tidak satu pun. +
Catatan tambahan
+ +Berikut ini beberapa catatan penting tentang mengikat ke layanan:
+-
+
- Anda harus selalu menjebak eksepsi {@link android.os.DeadObjectException}, yang dilontarkan +bila koneksi terputus. Inilah satu-satunya eksepsi yang dilontarkan oleh metode jauh. +
- Objek adalah acuan yang dihitung lintas proses. +
- Anda biasanya harus memasangkan pengikatan dan pelepasan ikatan selama
+memasangkan momen membuat dan menghapus daur hidup klien. Misalnya:
+
-
+
- Jika Anda hanya perlu berinteraksi dengan layanan saat aktivitas terlihat, Anda +harus mengikat selama {@link android.app.Activity#onStart onStart()} dan melepas ikatan selama {@link +android.app.Activity#onStop onStop()}. +
- Jika Anda ingin aktivitas menerima tanggapan bahkan saat dihentikan di +latar belakang, Anda bisa mengikat selama {@link android.app.Activity#onCreate onCreate()} dan melepas ikatan +selama {@link android.app.Activity#onDestroy onDestroy()}. Berhati-hatilah karena hal ini menyiratkan aktivitas +Anda perlu menggunakan layanan selama dijalankan (sekalipun di latar belakang), jadi jika +layanan berada dalam proses lain, Anda meningkatkan bobot proses dan semakin besar +kemungkinan sistem akan mematikannya. +
Catatan: Anda biasanya tidak boleh mengikat dan melepas ikatan +selama {@link android.app.Activity#onResume onResume()} aktivitas Anda dan {@link +android.app.Activity#onPause onPause()}, karena callback ini terjadi pada setiap transisi daur hidup +dan Anda harus menjaga pemrosesan yang terjadi pada transisi ini tetap minim. Juga, jika +banyak aktivitas dalam aplikasi Anda mengikat ke layanan yang sama dan ada transisi antara +dua aktivitas, layanan bisa dimusnahkan dan dibuat lagi sambil aktivitas saat ini melepas ikatan +(selama jeda) sebelum aktivitas berikutnya mengikat (selama lanjutkan). (Transisi aktivitas ini untuk cara +aktivitas mengoordinasikan daur hidupnya dijelaskan dalam dokumen Aktivitas +.)
+
Untuk contoh kode selengkapnya, yang menampilkan cara mengikat ke layanan, lihat kelas {@code +RemoteService.java} dalam ApiDemos.
+ + + + + +Mengelola Daur Hidup Layanan Terikat
+ +Bila layanan dilepas ikatannya dari semua klien, sistem Android akan menghapusnya (kecuali jika layanan juga +dimulai dengan {@link android.app.Service#onStartCommand onStartCommand()}). Dengan demikian, Anda tidak harus +mengelola daur hidup layanan jika layanan itu murni sebuah layanan +terikat—yang dikelola sistem Android untuk Anda berdasarkan apakah layanan terikat ke klien atau tidak.
+ +Akan tetapi, Jika Anda memilih untuk mengimplementasikan metode callback {@link android.app.Service#onStartCommand +onStartCommand()}, maka Anda harus menghentikan layanan secara eksplisit, karena layanan +sekarang dianggap telah dimulai. Dalam hal ini, layanan akan berjalan hingga layanan +menghentikan dirinya sendiri dengan {@link android.app.Service#stopSelf()} atau panggilan komponen lain {@link +android.content.Context#stopService stopService()}, terlepas dari apakah layanan terikat ke +klien atau tidak.
+ +Selain itu, jika layanan Anda telah dimulai dan menerima pengikatan, maka saat sistem memanggil +metode {@link android.app.Service#onUnbind onUnbind()}, Anda bisa memilih untuk mengembalikan +{@code true} jika ingin menerima panggilan ke {@link android.app.Service#onRebind +onRebind()} bila nanti klien mengikat ke layanan (sebagai ganti menerima panggilan ke {@link +android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind +onRebind()} akan menghasilkan void, namun klien tetap menerima {@link android.os.IBinder} dalam callback +{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}. +Di bawah ini adalah gambar 1 yang mengilustrasikan logika untuk jenis daur hidup ini.
+ + + + + + +Untuk informasi selengkapnya tentang daur hidup layanan yang telah dimulai, lihat dokumen Layanan.
+ + + + diff --git a/docs/html-intl/intl/in/guide/components/fragments.jd b/docs/html-intl/intl/in/guide/components/fragments.jd new file mode 100644 index 0000000000000000000000000000000000000000..14d4ef3eccbfc404c7ecf4b1ca153f5b589a2a3a --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/fragments.jd @@ -0,0 +1,812 @@ +page.title=Fragmen +parent.title=Aktivitas +parent.link=activities.html +@jd:body + +Dalam dokumen ini
+-
+
- Filosofi Desain +
- Membuat Fragmen + + +
- Mengelola Fragmen +
- Melakukan Transaksi Fragmen +
- Berkomunikasi dengan Aktivitas + + +
- Menangani Daur Hidup Fragmen + + +
- Contoh +
Kelas-kelas utama
+-
+
- {@link android.app.Fragment} +
- {@link android.app.FragmentManager} +
- {@link android.app.FragmentTransaction} +
Lihat juga
+ +{@link android.app.Fragment} mewakili perilaku atau bagian dari antarmuka pengguna dalam +{@link android.app.Activity}. Anda bisa mengombinasikan beberapa fragmen dalam satu aktivitas untuk membangun UI +multipanel dan menggunakan kembali sebuah fragmen dalam beberapa aktivitas. Anda bisa menganggap fragmen sebagai bagian +modular dari aktivitas, yang memiliki daur hidup sendiri, menerima kejadian input sendiri, dan +yang bisa Anda tambahkan atau hapus saat aktivitas berjalan (semacam "sub aktivitas" yang +bisa digunakan kembali dalam aktivitas berbeda).
+ +Fragmen harus selalu tertanam dalam aktivitas dan daur hidup fragmen secara langsung +dipengaruhi oleh daur hidup aktivitas host-nya. Misalnya, saat aktivitas dihentikan sementara, +semua fragmen di dalamnya juga dihentikan sementara, dan bila aktivitas dimusnahkan, semua fragmen juga demikian. Akan tetapi, saat +aktivitas berjalan (dalam status daur hidup dilanjutkan, Anda bisa +memanipulasi setiap fragmen secara terpisah, seperti menambah atau menghapusnya. Saat melakukan transaksi +fragmen, Anda juga bisa menambahkannya ke back-stack yang dikelola oleh aktivitas +—setiap entri back-stack merupakan record transaksi fragmen yang +terjadi. Dengan back-stack pengguna dapat membalikkan transaksi fragmen (mengarah mundur), +dengan menekan tombol Back.
+ +Bila Anda menambahkan fragmen sebagai bagian dari layout aktivitas, fragmen itu berada dalam {@link +android.view.ViewGroup} di hierarki tampilan aktivitas tersebut dan fragmen mendefinisikan +layout +tampilannya sendiri. Anda bisa menyisipkan fragmen ke dalam layout aktivitas dengan mendeklarasikan fragmen dalam file layout aktivitas +, sebagai elemen {@code <fragment>}, atau dari kode aplikasi dengan menambahkannya ke + {@link android.view.ViewGroup} yang ada. Akan tetapi, fragmen tidak harus menjadi bagian dari +layout aktivitas; Anda juga bisa menggunakan fragmen tanpa UI-nya sendiri sebagai pekerja tak terlihat untuk +aktivitas tersebut.
+ +Dokumen ini menjelaskan cara membangun aplikasi menggunakan fragmen, termasuk +cara fragmen mempertahankan statusnya bila ditambahkan ke back-stack aktivitas, berbagi +kejadian dengan aktivitas, dan fragmen lain dalam aktivitas, berkontribusi pada action-bar +aktivitas, dan lainnya.
+ + +Filosofi Desain
+ +Android memperkenalkan fragmen di Android 3.0 (API level 11), terutama untuk mendukung desain UI yang lebih +dinamis dan fleksibel pada layar besar, seperti tablet. Karena +layar tablet jauh lebih besar daripada layar handset, maka lebih banyak ruang untuk mengombinasikan dan +bertukar komponen UI. Fragmen memungkinkan desain seperti itu tanpa perlu mengelola perubahan +kompleks pada hierarki tampilan. Dengan membagi layout aktivitas menjadi beberapa fragmen, Anda bisa +mengubah penampilan aktivitas saat runtime dan mempertahankan perubahan itu di back-stack +yang dikelola oleh aktivitas.
+ +Misalnya, aplikasi berita bisa menggunakan satu fragmen untuk menampilkan daftar artikel di +sebelah kiri dan fragmen lainnya untuk menampilkan artikel di sebelah kanan—kedua fragmen ini muncul di satu +aktivitas, berdampingan, dan masing-masing fragmen memiliki serangkaian metode callback daur hidup dan menangani kejadian input +penggunanya sendiri. Sehingga, sebagai ganti menggunakan satu aktivitas untuk memilih +artikel dan aktivitas lainnya untuk membaca artikel, pengguna bisa memilih artikel dan membaca semuanya dalam +aktivitas yang sama, sebagaimana diilustrasikan dalam layout tablet pada gambar 1.
+ +Anda harus mendesain masing-masing fragmen sebagai komponen aktivitas modular dan bisa digunakan kembali. Yakni, karena +setiap fragmen mendefinisikan layoutnya dan perilakunya dengan callback daur hidupnya sendiri, Anda bisa memasukkan +satu fragmen dalam banyak aktivitas, sehingga Anda harus mendesainnya untuk digunakan kembali dan mencegah +memanipulasi satu fragmen dari fragmen lain secara langsung. Ini terutama penting karena dengan +fragmen modular Anda bisa mengubah kombinasi fragmen untuk ukuran layar berbeda. Saat mendesain aplikasi +untuk mendukung tablet maupun handset, Anda bisa menggunakan kembali fragmen dalam +konfigurasi layout berbeda untuk mengoptimalkan pengalaman pengguna berdasarkan ruang layar yang tersedia. Misalnya +, pada handset, fragmen mungkin perlu dipisahkan untuk menyediakan UI panel tunggal +bila lebih dari satu yang tidak cocok dalam aktivitas yang sama.
+ + + + +Misalnya—untuk melanjutkan contoh aplikasi berita— aplikasi bisa menanamkan +dua fragmen dalam Aktivitas A, saat berjalan pada perangkat berukuran tablet. Akan tetapi, pada +layar berukuran handset, ruang untuk kedua fragmen tidak cukup, sehingga Aktivitas A hanya +menyertakan fragmen untuk daftar artikel, dan saat pengguna memilih artikel, +Aktivitas B akan dimulai, termasuk fragmen kedua untuk membaca artikel. Sehingga, aplikasi mendukung +tablet dan handset dengan menggunakan kembali fragmen dalam kombinasi berbeda, seperti diilustrasikan dalam +gambar 1.
+ +Untuk informasi selengkapnya tentang mendesain aplikasi menggunakan kombinasi fragmen berbeda +untuk konfigurasi layar berbeda, lihat panduan untuk Mendukung Tablet dan Handset.
+ + + +Membuat Fragmen
+ +Untuk membuat fragmen, Anda harus membuat subkelas {@link android.app.Fragment} (atau +subkelasnya yang ada). Kelas {@link android.app.Fragment} memiliki kode yang mirip seperti +{@link android.app.Activity}. Kelas ini memiliki metode callback yang serupa dengan aktivitas, seperti + {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()}, +{@link android.app.Fragment#onPause onPause()}, dan {@link android.app.Fragment#onStop onStop()}. Sebenarnya +, jika Anda mengkonversi aplikasi Android saat ini untuk menggunakan fragmen, Anda mungkin cukup memindahkan +kode dari metode callback aktivitas ke masing-masing metode callback +fragmen.
+ +Biasanya, Anda harus mengimplementasikan setidaknya metode daur hidup berikut ini:
+ +-
+
- {@link android.app.Fragment#onCreate onCreate()} +
- Sistem akan memanggilnya saat membuat fragmen. Dalam implementasi, Anda harus +menginisialisasi komponen penting dari fragmen yang ingin dipertahankan saat fragmen +dihentikan sementara atau dihentikan, kemudian dilanjutkan. +
- {@link android.app.Fragment#onCreateView onCreateView()} +
- Sistem akan memanggilnya saat fragmen menggambar antarmuka penggunanya +untuk yang pertama kali. Untuk menggambar UI fragmen, Anda harus mengembalikan {@link android.view.View} dari metode +ini yang menjadi akar layout fragmen. Hasil yang dikembalikan bisa berupa null jika +fragmen tidak menyediakan UI. +
- {@link android.app.Activity#onPause onPause()} +
- Sistem akan memanggil metode ini sebagai indikasi pertama bahwa pengguna sedang meninggalkan +fragmen Anda (walau itu tidak selalu berarti fragmen sedang dimusnahkan). Inilah biasanya tempat Anda +harus mengikat setiap perubahan yang harus dipertahankan selepas sesi pengguna saat ini (karena +pengguna mungkin tidak kembali). +
Kebanyakan aplikasi harus mengimplementasikan setidaknya tiga metode ini untuk setiap fragmen, namun ada +beberapa metode callback lain yang juga harus Anda gunakan untuk menangani berbagai tahap +daur hidup fragmen. Semua metode callback daur hidup akan dibahas secara lebih detail, di bagian +tentang Menangani Daur Hidup Fragmen.
+ + +Ada juga beberapa subkelas yang mungkin ingin diperpanjang, sebagai ganti kelas basis {@link +android.app.Fragment}:
+ +-
+
- {@link android.app.DialogFragment} +
- Menampilkan dialog mengambang. Penggunaan kelas ini untuk membuat dialog merupakan alternatif yang baik dari +penggunaan metode helper dialog di kelas {@link android.app.Activity}, karena Anda bisa +menyatukan dialog fragmen ke dalam back-stack fragmen yang dikelola oleh aktivitas, +sehingga pengguna bisa kembali ke fragmen yang ditinggalkan. + +
- {@link android.app.ListFragment} +
- Menampilkan daftar item yang dikelola oleh adaptor (seperti {@link +android.widget.SimpleCursorAdapter}), serupa dengan {@link android.app.ListActivity}. Menampilkan +beberapa metode pengelolaan daftar tampilan seperti callback {@link +android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} untuk +menangani kejadian klik. + +
- {@link android.preference.PreferenceFragment} +
- Menampilkan hierarki objek {@link android.preference.Preference} sebagai daftar, serupa dengan +{@link android.preference.PreferenceActivity}. Hal ini berguna saat membuat aktivitas +"pengaturan" untuk aplikasi Anda. +
Menambahkan antarmuka pengguna
+ +Fragmen biasanya digunakan sebagai bagian dari antarmuka pengguna aktivitas dan menyumbangkan +layoutnya sendiri ke aktivitas.
+ +Untuk menyediakan layout fragmen, Anda harus mengimplementasikan metode callback {@link +android.app.Fragment#onCreateView onCreateView()}, yang dipanggil sistem Android +bila tiba saatnya fragmen menggambar layoutnya. Implementasi Anda atas metode ini harus mengembalikan +{@link android.view.View} yang menjadi akar layout fragmen.
+ +Catatan: Jika fragmen adalah subkelas {@link +android.app.ListFragment}, implementasi default akan mengembalikan {@link android.widget.ListView} dari +{@link android.app.Fragment#onCreateView onCreateView()}, sehingga Anda tidak perlu mengimplementasikannya.
+ +Untuk mengembalikan layout dari {@link +android.app.Fragment#onCreateView onCreateView()}, Anda bisa memekarkannya dari sumber daya layout yang didefinisikan di XML. Untuk +membantu melakukannya, {@link android.app.Fragment#onCreateView onCreateView()} menyediakan objek +{@link android.view.LayoutInflater}.
+ +Misalnya, ini adalah subkelas {@link android.app.Fragment} yang memuat layout dari file +{@code example_fragment.xml}:
+ ++public static class ExampleFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.example_fragment, container, false); + } +} ++ +
Membuat layout
+Dalam contoh di atas, {@code R.layout.example_fragment} merupakan acuan ke sumber daya layout +bernama {@code example_fragment.xml} yang tersimpan dalam sumber daya aplikasi. Untuk informasi tentang cara +membuat layout di XML, lihat dokumentasi +Antarmuka Pengguna.
+Parameter {@code container} yang diteruskan ke {@link android.app.Fragment#onCreateView +onCreateView()} adalah induk {@link android.view.ViewGroup} (dari layout aktivitas) tempat +layout fragmen +akan disisipkan. Parameter {@code savedInstanceState} adalah {@link android.os.Bundle} yang +menyediakan data tentang instance fragmen sebelumnya, jika fragmen dilanjutkan +(status pemulihan dibahas selengkapnya di bagian tentang Menangani +Daur Hidup Fragmen).
+ +Metode {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} membutuhkan +tiga argumen:
+-
+
- ID sumber daya layout yang ingin dimekarkan. +
- {@link android.view.ViewGroup} akan menjadi induk dari layout yang dimekarkan. {@code +container} perlu diteruskan agar sistem menerapkan parameter layout ke tampilan akar layout +yang dimekarkan, yang ditetapkan dalam tampilan induk yang akan dituju. +
- Boolean yang menunjukkan apakah layout akan dimekarkan harus ditempelkan pada {@link +android.view.ViewGroup} (parameter kedua) selama pemekaran. (Dalam hal ini, ini +salah karena sistem sudah memasukkan layout yang dimekarkan ke dalam {@code +container}—meneruskan benar akan membuat tampilan grup yang berlebihan dalam layout akhir.) +
Anda kini telah melihat cara membuat fragmen yang menyediakan layout. Berikutnya, Anda perlu menambahkan +fragmen ke aktivitas.
+ + + +Menambahkan fragmen ke aktivitas
+ +Biasanya, fragmen berkontribusi pada sebagian UI ke aktivitas host, yang ditanamkan sebagai +bagian dari hierarki tampilan keseluruhan aktivitas. Ada dua cara untuk menambahkan fragmen ke layout +aktivitas:
+ +-
+
- Deklarasikan fragmen dalam file layout aktivitas.
+
Dalam hal ini, Anda bisa +menetapkan properti layout fragmen seakan-akan sebuah tampilan. Misalnya, berikut ini adalah file +layout untuk aktivitas dengan dua fragmen:
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <fragment android:name="com.example.news.ArticleListFragment" + android:id="@+id/list" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="match_parent" /> + <fragment android:name="com.example.news.ArticleReaderFragment" + android:id="@+id/viewer" + android:layout_weight="2" + android:layout_width="0dp" + android:layout_height="match_parent" /> +</LinearLayout> +
+Atribut {@code android:name} dalam {@code <fragment>} menetapkan kelas {@link +android.app.Fragment} untuk dibuat instance-nya dalam layout.
+ +Saat sistem membuat layout aktivitas, sistem membuat instance setiap fragmen sebagaimana yang ditetapkan dalam layout +dan memanggil metode {@link android.app.Fragment#onCreateView onCreateView()} masing-masing, +untuk mengambil setiap fragmen. Sistem akan menyisipkan {@link android.view.View} yang dikembalikan langsung oleh fragmen, + menggantikan elemen {@code <fragment>}.
+ +++Catatan: Setiap fragmen memerlukan identifier +unik yang bisa digunakan sistem untuk memulihkan fragmen jika aktivitas dimulai kembali (dan identifier yang bisa digunakan menangkap +fragmen untuk melakukan transaksi, seperti menghapusnya). Ada tiga cara untuk memberikan +ID bagi fragmen:
+-
+
- Memberikan atribut {@code android:id} bersama ID unik. +
- Memberikan atribut {@code android:tag} bersama string unik. +
- Jika Anda tidak memberikan dua hal tersebut, sistem akan menggunakan ID +tampilan kontainer. +
+
+ - Atau, secara programatis tambahkan fragmen ke {@link android.view.ViewGroup} yang ada.
+
Kapan saja saat aktivitas berjalan, Anda bisa menambahkan fragmen ke layout aktivitas. Anda +cukup menetapkan {@link +android.view.ViewGroup} di tempat memasukkan fragmen.
+Untuk membuat transaksi fragmen dalam aktivitas (seperti menambah, menghapus, atau mengganti +fragmen), Anda harus menggunakan API dari {@link android.app.FragmentTransaction}. Anda bisa mengambil instance + {@link android.app.FragmentTransaction} dari {@link android.app.Activity} seperti ini:
+ ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()} +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +
+ +Selanjutnya Anda bisa menambahkan fragmen menggunakan metode {@link +android.app.FragmentTransaction#add(int,Fragment) add()}, dengan menetapkan fragmen yang akan ditambahkan dan +tampilan tempat menyisipkannya. Misalnya:
+ ++ExampleFragment fragment = new ExampleFragment(); +fragmentTransaction.add(R.id.fragment_container, fragment); +fragmentTransaction.commit(); +
+ +Argumen pertama yang diteruskan ke {@link android.app.FragmentTransaction#add(int,Fragment) add()} + adalah {@link android.view.ViewGroup} tempat fragmen harus dimasukkan, yang ditetapkan oleh +ID sumber daya, dan parameter kedua merupakan fragmen yang akan ditambahkan.
+Setelah membuat perubahan dengan +{@link android.app.FragmentTransaction}, Anda harus + memanggil {@link android.app.FragmentTransaction#commit} untuk menerapkan perubahan.
+
+
Menambahkan fragmen tanpa UI
+ +Contoh di atas menampilkan cara menambahkan fragmen ke aktivitas untuk menyediakan UI. Akan tetapi, +Anda juga bisa menggunakan fragmen untuk menyediakan perilaku latar belakang bagi aktivitas tanpa menampilkan UI +tambahan.
+ +Untuk menambahkan fragmen tanpa UI, tambahkan fragmen dari aktivitas menggunakan {@link +android.app.FragmentTransaction#add(Fragment,String)} (dengan menyediakan string unik "tag" untuk fragmen +, bukan ID tampilan). Ini akan menambahkan fragmen, namun, karena tidak dikaitkan dengan tampilan +dalam layout aktivitas, ini tidak akan menerima panggilan ke {@link +android.app.Fragment#onCreateView onCreateView()}. Jadi Anda tidak perlu mengimplementasikan metode itu.
+ +Menyediakan tag string untuk fragmen tidak hanya untuk fragmen non-UI—Anda juga bisa +menyediakan tag string untuk fragmen yang memiliki UI—namun jika fragmen tidak memiliki UI +, maka tag string adalah satu-satunya cara untuk mengidentifikasinya. Jika Anda ingin mendapatkan fragmen dari +aktivitas nantinya, Anda perlu menggunakan {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()}.
+ +Untuk contoh aktivitas yang menggunakan fragmen sebagai pekerja latar belakang, tanpa UI, lihat sampel {@code
+FragmentRetainInstance.java}, yang disertakan dalam sampel SDK (tersedia melalui
+Android SDK Manager) dan terletak di sistem Anda sebagai
+<sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java
.
Mengelola Fragmen
+ +Untuk mengelola fragmen dalam aktivitas, Anda perlu menggunakan {@link android.app.FragmentManager}. Untuk +mendapatkannya, panggil {@link android.app.Activity#getFragmentManager()} dari aktivitas Anda.
+ +Beberapa hal yang dapat Anda lakukan dengan {@link android.app.FragmentManager} antara lain:
+ +-
+
- Dapatkan fragmen yang ada di aktivitas dengan {@link +android.app.FragmentManager#findFragmentById findFragmentById()} (untuk fragmen yang menyediakan UI dalam +layout aktivitas) atau {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()} (untuk fragmen yang menyediakan atau tidak menyediakan UI). +
- Tarik fragmen dari back-stack, dengan {@link +android.app.FragmentManager#popBackStack()} (mensimulasikan perintah Back oleh pengguna). +
- Daftarkan listener untuk perubahan pada back-stack, dengan {@link +android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}. +
Untuk informasi selengkapnya tentang metode ini dan hal lainnya, lihat dokumentasi kelas {@link +android.app.FragmentManager}.
+ +Seperti yang ditunjukkan di bagian sebelumnya, Anda juga bisa menggunakan {@link android.app.FragmentManager} +untuk membuka {@link android.app.FragmentTransaction}, sehingga Anda bisa melakukan transaksi, seperti +menambah dan menghapus fragmen.
+ + +Melakukan Transaksi Fragmen
+ +Fitur menarik terkait penggunaan fragmen di aktivitas adalah kemampuan menambah, menghapus, mengganti, +dan melakukan tindakan lain dengannya, sebagai respons atas interaksi pengguna. Setiap set perubahan +yang Anda lakukan untuk aktivitas disebut transaksi dan Anda bisa melakukan transaksi menggunakan API di {@link +android.app.FragmentTransaction}. Anda juga bisa menyimpan setiap transaksi ke back-stack yang dikelola +aktivitas, sehingga pengguna bisa mengarah mundur melalui perubahan fragmen (mirip mengarah +mundur melalui aktivitas).
+ +Anda bisa mengambil instance {@link android.app.FragmentTransaction} dari {@link +android.app.FragmentManager} seperti ini:
+ ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}; +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; ++ +
Setiap transaksi merupakan serangkaian perubahan yang ingin dilakukan pada waktu yang sama. Anda bisa +mengatur semua perubahan yang ingin dilakukan untuk transaksi mana saja menggunakan metode seperti {@link +android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()}, +dan {@link android.app.FragmentTransaction#replace replace()}. Kemudian, untuk menerapkan transaksi +pada aktivitas, Anda harus memanggil {@link android.app.FragmentTransaction#commit()}.
+ + +Akan tetapi, sebelum memanggil {@link +android.app.FragmentTransaction#commit()}, Anda mungkin perlu memanggil {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, untuk menambahkan transaksi +ke back-stack dari transaksi fragmen. Back-stack ini dikelola oleh aktivitas dan memungkinkan +pengguna kembali ke status fragmen sebelumnya, dengan menekan tombol Back.
+ +Misalnya, berikut ini cara mengganti satu fragmen dengan yang fragmen yang lain, dan mempertahankan +status sebelumnya di back-stack:
+ ++// Create new fragment and transaction +Fragment newFragment = new ExampleFragment(); +FragmentTransaction transaction = getFragmentManager().beginTransaction(); + +// Replace whatever is in the fragment_container view with this fragment, +// and add the transaction to the back stack +transaction.replace(R.id.fragment_container, newFragment); +transaction.addToBackStack(null); + +// Commit the transaction +transaction.commit(); ++ +
Dalam contoh ini, {@code newFragment} menggantikan fragmen apa saja (jika ada) yang saat ini berada dalam +kontainer layout yang diidentifikasi oleh ID {@code R.id.fragment_container}. Dengan memanggil @link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, transaksi yang diganti +disimpan ke back-stack sehingga pengguna bisa membalikkan transaksi dan mengembalikan fragmen +sebelumnya dengan menekan tombol Back.
+ +Jika Anda menambahkan beberapa perubahan pada transaksi (seperti {@link +android.app.FragmentTransaction#add add()} atau {@link android.app.FragmentTransaction#remove +remove()}) dan panggil {@link +android.app.FragmentTransaction#addToBackStack addToBackStack()}, maka semua perubahan akan diterapkan +sebelum Anda memanggil {@link android.app.FragmentTransaction#commit commit()} akan ditambahkan ke +back-stack sebagai satu transaksi dan tombol Back akan membalikannya semua.
+ +Urutan menambahkan perubahan pada {@link android.app.FragmentTransaction} tidak berpengaruh, +kecuali:
+-
+
- Anda harus memanggil {@link android.app.FragmentTransaction#commit()} paling akhir +
- Jika Anda menambahkan beberapa fragmen ke kontainer yang sama, maka +urutan penambahannya akan menentukan urutan munculnya dalam hierarki tampilan +
Jika Anda tidak memanggil {@link android.app.FragmentTransaction#addToBackStack(String) +addToBackStack()} saat melakukan transaksi yang menghapus fragmen, maka fragmen itu +akan dimusnahkan bila transaksi diikat dan pengguna tidak bisa mengarah kembali ke sana. Sedangkan, jika +Anda memanggil {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} saat +menghapus fragmen, maka fragmen itu akan dihentikan dan akan dilanjutkan jika pengguna mengarah +kembali.
+ +Tip: Untuk setiap transaksi fragmen, Anda bisa menerapkan animasi +transisi, dengan memanggil {@link android.app.FragmentTransaction#setTransition setTransition()} sebelum +mengikatnya.
+ +Memanggil {@link android.app.FragmentTransaction#commit()} tidak akan langsung menjalankan +transaksi. Namun sebuah jadwal akan dibuat untuk dijalankan pada thread UI aktivitas (thread "utama") +begitu thread bisa melakukannya. Akan tetapi, jika perlu Anda bisa memanggil {@link +android.app.FragmentManager#executePendingTransactions()} dari thread UI untuk segera +mengeksekusi transaksi yang diserahkan oleh {@link android.app.FragmentTransaction#commit()}. Hal itu +biasanya tidak perlu kecuali jika transaksi merupakan dependensi bagi pekerjaan dalam thread lain.
+ +Perhatian: Anda bisa mengikat transaksi menggunakan {@link +android.app.FragmentTransaction#commit commit()} hanya sebelum aktivitas menyimpan +statusnya (saat pengguna meninggalkan aktivitas). Jika Anda mencoba mengikatnya setelah itu, +eksepsi akan dilontarkan. Ini karena status setelah pengikatan bisa hilang jika aktivitas +perlu dipulihkan. Untuk situasi yang memperbolehkan Anda meniadakan pengikatan (commit), gunakan {@link +android.app.FragmentTransaction#commitAllowingStateLoss()}.
+ + + + +Berkomunikasi dengan Aktivitas
+ +Meskipun {@link android.app.Fragment} diimplementasikan sebagai objek yang tidak bergantung pada +{@link android.app.Activity} dan bisa digunakan dalam banyak aktivitas, instance tertentu +dari fragmen secara langsung terkait dengan aktivitas yang dimuatnya.
+ +Khususnya, fragmen bisa mengakses instance {@link android.app.Activity} dengan {@link +android.app.Fragment#getActivity()} dan dengan mudah melakukan tugas-tugas seperti mencari tampilan dalam + layout aktivitas:
+ ++View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list); ++ +
Demikian pula, aktivitas Anda bisa memanggil metode di fragmen dengan meminta acuan ke +{@link android.app.Fragment} dari {@link android.app.FragmentManager}, menggunakan {@link +android.app.FragmentManager#findFragmentById findFragmentById()} atau {@link +android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. Misalnya:
+ ++ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment); ++ + +
Membuat callback kejadian pada aktivitas
+ +Dalam beberapa kasus, Anda mungkin perlu fragmen untuk berbagi kejadian dengan aktivitas. Cara yang baik untuk melakukannya +adalah mendefinisikan antarmuka callback di dalam fragmen dan mengharuskan aktivitas host +mengimplementasikannya. Saat aktivitas menerima callback melalui antarmuka, aktivitas akan bisa berbagi informasi itu +dengan fragmen lain dalam layout jika perlu.
+ +Misalnya, jika sebuah aplikasi berita memiliki dua fragmen dalam aktivitas—satu untuk menampilkan daftar +artikel (fragmen A) dan satu lagi untuk menampilkan artikel (fragmen B)—maka fragmen A harus +memberi tahu aktivitas bila item daftar dipilih sehingga aktivitas bisa memberi tahu fragmen B untuk menampilkan artikel. Dalam +hal ini, antarmuka {@code OnArticleSelectedListener} dideklarasikan di dalam fragmen A:
+ ++public static class FragmentA extends ListFragment { + ... + // Container Activity must implement this interface + public interface OnArticleSelectedListener { + public void onArticleSelected(Uri articleUri); + } + ... +} ++ +
Selanjutnya aktivitas yang menjadi host fragmen akan mengimplementasikan antarmuka {@code OnArticleSelectedListener} + dan +mengesampingkan {@code onArticleSelected()} untuk memberi tahu fragmen B mengenai kejadian dari fragmen A. Untuk memastikan +bahwa aktivitas host mengimplementasikan antarmuka ini, metode callback fragmen A {@link +android.app.Fragment#onAttach onAttach()} (yang dipanggil sistem saat menambahkan +fragmen ke aktivitas) membuat instance {@code OnArticleSelectedListener} dengan +membuat {@link android.app.Activity} yang diteruskan ke {@link android.app.Fragment#onAttach +onAttach()}:
+ ++public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnArticleSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); + } + } + ... +} ++ +
Jika aktivitas belum mengimplementasikan antarmuka, maka fragmen akan melontarkan +{@link java.lang.ClassCastException}. +Jika berhasil, anggota {@code mListener} yang menyimpan acuan ke implementasi aktivitas +{@code OnArticleSelectedListener}, sehingga fragmen A bisa berbagi kejadian dengan aktivitas, dengan memanggil metode +yang didefinisikan oleh antarmuka {@code OnArticleSelectedListener}. Misalnya, jika fragmen A adalah +ekstensi dari {@link android.app.ListFragment}, maka setiap kali +pengguna mengklik item daftar, sistem akan memanggil {@link android.app.ListFragment#onListItemClick +onListItemClick()} di fragmen, yang selanjutnya memanggil {@code onArticleSelected()} untuk berbagi +kejadian dengan aktivitas:
+ ++public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + // Append the clicked item's row ID with the content provider Uri + Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id); + // Send the event and Uri to the host activity + mListener.onArticleSelected(noteUri); + } + ... +} ++ +
Parameter {@code id} yang diteruskan ke {@link +android.app.ListFragment#onListItemClick onListItemClick()} merupakan ID baris dari item yang diklik, +yang digunakan aktivitas (atau fragmen lain) untuk mengambil artikel dari {@link +android.content.ContentProvider} aplikasi.
+ +Informasi selengkapnya tentang +menggunakan penyedia konten tersedia dalam dokumen Penyedia Konten.
+ + + +Menambahkan item ke Action-Bar
+ +Fragmen Anda bisa menyumbangkan item menu ke Menu Opsi aktivitas (dan, konsekuensinya, Action-Bar) dengan mengimplementasikan +{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. Agar +metode ini bisa menerima panggilan, Anda harus memanggil {@link +android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} selama {@link +android.app.Fragment#onCreate(Bundle) onCreate()}, untuk menunjukkan bahwa fragmen +ingin menambahkan item ke Menu Opsi (jika tidak, fragmen tidak akan menerima panggilan ke +{@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).
+ +Setiap item yang selanjutnya Anda tambahkan ke Menu Opsi dari fragmen akan ditambahkan ke item menu +yang ada. Fragmen juga menerima callback ke {@link +android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} bila item menu +dipilih.
+ +Anda juga bisa mendaftarkan tampilan dalam layout fragmen untuk menyediakan menu konteks dengan memanggil {@link +android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. Bila pengguna +membuka menu konteks, fragmen akan menerima panggilan ke {@link +android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) +onCreateContextMenu()}. Bila pengguna memilih item, fragmen akan menerima panggilan ke @link +android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.
+ +Catatan: Walaupun fragmen menerima callback pada item yang dipilih +untuk setiap item menu yang ditambahkannya, aktivitaslah yang pertama kali menerima masing-masing callback saat pengguna +memilih item menu. Jika implementasi aktivitas dari callback bila-item-dipilih, +tidak menangani item yang dipilih, maka kejadian akan diteruskan ke callback fragmen. Ini berlaku +untuk Menu Opsi dan menu konteks.
+ +Untuk informasi selengkapnya tentang menu, lihat panduan pengembang Menu dan Action-Bar.
+ + + + +Menangani Daur Hidup Fragmen
+ +Mengelola daur hidup fragmen mirip sekali dengan mengelola daur hidup aktivitas. Seperti +aktivitas, fragmen bisa berada dalam tiga status:
+ +-
+
- Dilanjutkan +
- Fragmen terlihat dalam aktivitas yang berjalan. + +
- Dihentikan sementara +
- Aktivitas lain berada di latar depan dan memiliki fokus, namun aktivitas tempat fragmen berada +masih terlihat (aktivitas latar depan sebagian terlihat atau tidak menutupi +seluruh layar). + +
- Dihentikan +
- Fragmen tidak terlihat. Aktivitas host telah dihentikan atau +fragmen telah dihapus dari aktivitas namun ditambahkan ke back-stack. Fragmen yang dihentikan +masih hidup (semua status dan informasi anggota masih disimpan oleh sistem). Akan tetapi, fragmen +tidak terlihat lagi oleh pengguna dan akan dimatikan jika aktivitas dimatikan. +
Seperti halnya aktivitas, Anda bisa mempertahankan status fragmen menggunakan {@link +android.os.Bundle}, jika proses aktivitas dimatikan dan Anda harus memulihkan status +fragmen bila aktivitas dibuat kembali. Anda bisa menyimpan status selama callback {@link +android.app.Fragment#onSaveInstanceState onSaveInstanceState()} fragmen dan memulihkannya selama +{@link android.app.Fragment#onCreate onCreate()}, {@link +android.app.Fragment#onCreateView onCreateView()}, atau {@link +android.app.Fragment#onActivityCreated onActivityCreated()}. Untuk informasi selengkapnya tentang menyimpan +status, lihat dokumen Aktivitas +.
+ +Perbedaan paling signifikan dalam daur hidup antara aktivitas dan fragmen ada +pada cara penyimpanannya dalam back-stack masing-masing. Aktivitas ditempatkan ke back-stack aktivitas +yang dikelola oleh sistem saat dihentikan, secara default (sehingga pengguna bisa mengarah kembali +ke aktivitas dengan tombol Back, seperti yang dibahas dalam Tugas dan Back-Stack). +Akan tetapi, fragmen yang ditempatkan ke back-stack dikelola oleh aktivitas host hanya saat +Anda secara eksplisit meminta agar instance disimpan dengan memanggil {@link +android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} selama transaksi yang +menghapus fragmen.
+ +Jika tidak, pengelolaan daur hidup fragmen mirip sekali dengan mengelola daur hidup +aktivitas. Jadi, praktik yang sama untuk mengelola daur hidup +aktivitas juga berlaku untuk fragmen. Namun yang perlu juga Anda pahami adalah bagaimana hidup +aktivitas memengaruhi hidup fragmen.
+ +Perhatian: Jika Anda memerlukan objek {@link android.content.Context} + dalam {@link android.app.Fragment}, Anda bisa memanggil {@link android.app.Fragment#getActivity()}. +Akan tetapi, berhati-hatilah memanggil {@link android.app.Fragment#getActivity()} hanya bila fragmen +terkait dengan aktivitas. Bila fragmen belum terkait, atau terlepas selama akhir daur +hidupnya, {@link android.app.Fragment#getActivity()} akan kembali nol.
+ + +Mengoordinasi dengan daur hidup aktivitas
+ +Daur hidup aktivitas tempat fragmen berada akan memengaruhi langsung siklus hidup +fragmen sedemikian rupa sehingga setiap callback daur hidup aktivitas menghasilkan callback yang sama untuk masing-masing +fragmen. Misalnya, bila aktivitas menerima {@link android.app.Activity#onPause}, masing-masing +fragmen dalam aktivitas akan menerima {@link android.app.Fragment#onPause}.
+ +Namun fragmen memiliki beberapa callback daur hidup ekstra, yang menangani interaksi +unik dengan aktivitas untuk melakukan tindakan seperti membangun dan memusnahkan UI fragmen. Metode callback +tambahan ini adalah:
+ +-
+
- {@link android.app.Fragment#onAttach onAttach()} +
- Dipanggil bila fragmen telah dikaitkan dengan aktivitas ({@link +android.app.Activity} diteruskan di sini). +
- {@link android.app.Fragment#onCreateView onCreateView()} +
- Dipanggil untuk membuat hierarki tampilan yang dikaitkan dengan fragmen. +
- {@link android.app.Fragment#onActivityCreated onActivityCreated()} +
- Dipanggil bila metode {@link android.app.Activity#onCreate +onCreate()} aktivitas telah dikembalikan. +
- {@link android.app.Fragment#onDestroyView onDestroyView()} +
- Dipanggil bila hierarki tampilan yang terkait dengan fragmen dihapus. +
- {@link android.app.Fragment#onDetach onDetach()} +
- Dipanggil bila fragmen diputuskan dari aktivitas. +
Aliran daur hidup fragmen, karena dipengaruhi oleh aktivitas host-nya, diilustrasikan oleh +gambar 3. Dalam gambar ini, Anda bisa melihat bagaimana setiap status aktivitas menentukan +metode callback mana yang mungkin diterima fragmen. Misalnya, saat aktivitas menerima call back {@link +android.app.Activity#onCreate onCreate()}, fragmen dalam aktivitas akan menerima tidak lebih +dari callback {@link android.app.Fragment#onActivityCreated onActivityCreated()}.
+ +Setelah status aktivitas diteruskan kembali, Anda bisa bebas menambah dan menghapus fragmen untuk +aktivitas tersebut. Sehingga, hanya saat aktivitas berada dalam status dilanjutkan, daur hidup fragmen bisa +berubah secara independen.
+ +Akan tetapi, saat aktivitas meninggalkan status dilanjutkan, fragmen akan kembali didorong +melalui daur hidupnya oleh aktivitas.
+ + + + +Contoh
+ +Untuk merangkum semua yang telah dibahas dalam dokumen ini, berikut ini contoh aktivitas +yang menggunakan dua fragmen untuk membuat layout dua panel. Aktivitas di bawah ini menyertakan satu fragmen untuk +menampilkan daftar putar Shakespeare dan fragmen lainnya menampilkan rangkuman pemutaran bila dipilih dari +daftar. Aktivitas ini juga menunjukkan cara menyediakan konfigurasi fragmen berbeda, +berdasarkan konfigurasi layar.
+ +Catatan: Kode sumber lengkap untuk aktivitas ini tersedia di +{@code +FragmentLayout.java}.
+ +Aktivitas utama akan menerapkan layout seperti biasa, selama {@link +android.app.Activity#onCreate onCreate()}:
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main} + +Layout yang diterapkan adalah {@code fragment_layout.xml}:
+ +{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout} + +Dengan layout ini, sistem akan membuat instance {@code TitlesFragment} (yang mencantumkan +judul) segera setelah aktivitas memuat layout, sementara {@link android.widget.FrameLayout} + (lokasi penempatan fragmen untuk menampilkan rangkuman pemutaran) menempati ruang di sisi kanan +layar, namun pada awalnya masih kosong. Seperti yang akan Anda lihat di bawah ini, sampai pengguna memilih item +dari daftar maka fragmen baru akan ditempatkan ke dalam {@link android.widget.FrameLayout}.
+ +Akan tetapi, tidak semua konfigurasi layar cukup lebar untuk menampilkan +daftar putar dan rangkuman secara berdampingan. Sehingga, layout di atas hanya digunakan untuk konfigurasi +layar mendatar, dengan menyimpannya di {@code res/layout-land/fragment_layout.xml}.
+ +Sehingga, bila layar berada dalam orientasi tegak, sistem akan menerapkan layout berikut, yang +tersimpan di {@code res/layout/fragment_layout.xml}:
+ +{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} + +Layout ini hanya menyertakan {@code TitlesFragment}. Ini artinya saat perangkat berada dalam +orientasi tegak, hanya judul daftar putar yang terlihat. Jadi, saat pengguna mengklik item +daftar dalam konfigurasi ini, aplikasi akan memulai aktivitas baru untuk menampilkan rangkuman, +sebagai ganti pemuatan fragmen kedua.
+ +Berikutnya, Anda bisa melihat bagaimana hal ini dilakukan dalam kelas fragmen. Pertama adalah {@code +TitlesFragment}, yang menampilkan judul daftar putar Shakespeare. Fragmen ini membuat ekstensi {@link +android.app.ListFragment} dan mengandalkannya itu untuk menangani sebagian besar pekerjaan tampilan daftar.
+ +Saat Anda memeriksa kode ini, perhatikan bahwa ada dua kemungkinan perilaku saat pengguna mengklik +item daftar: bergantung pada layout mana yang aktif, bisa membuat dan menampilkan fragmen +baru untuk menampilkan detail dalam aktivitas yang sama (menambahkan fragmen ke {@link +android.widget.FrameLayout}), atau memulai aktivitas baru (tempat fragmen ditampilkan).
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles} + +Fragmen kedua, {@code DetailsFragment} menampilkan rangkuman pemutaran untuk item yang dipilih dari +daftar dari {@code TitlesFragment}:
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details} + +Ingatlah dari kelas {@code TitlesFragment}, bahwa, jika pengguna mengklik item daftar dan +layout saat ini tidak menyertakan tampilan {@code R.id.details} (yaitu tempat +{@code DetailsFragment} berada), maka aplikasi memulai aktivitas {@code DetailsActivity} +untuk menampilkan konten item.
+ +Berikut ini adalah {@code DetailsActivity}, yang hanya menanamkan {@code DetailsFragment} untuk menampilkan rangkuman pemutaran +yang dipilih saat layar dalam orientasi tegak:
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java +details_activity} + +Perhatikan bahwa aktivitas ini selesai sendiri jika konfigurasi mendatar, sehingga aktivitas utama +bisa mengambil alih dan menampilkan {@code DetailsFragment} bersama {@code TitlesFragment}. +Ini bisa terjadi jika pengguna memulai {@code DetailsActivity} saat dalam orientasi tegak, namun kemudian +memutarnya menjadi mendatar (yang akan memulai lagi aktivitas saat ini).
+ + +Untuk contoh lainnya mengenai penggunaan fragmen (dan file sumber lengkap untuk contoh ini), +lihat aplikasi contoh Demo API yang tersedia di +ApiDemos (bisa diunduh dari Komponen contoh SDK).
+ + diff --git a/docs/html-intl/intl/in/guide/components/fundamentals.jd b/docs/html-intl/intl/in/guide/components/fundamentals.jd new file mode 100644 index 0000000000000000000000000000000000000000..bd9a500f77a5c608557ab62134bc7400a24f241c --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/fundamentals.jd @@ -0,0 +1,480 @@ +page.title=Dasar-Dasar Aplikasi +@jd:body + +Dalam dokumen ini
+ +Aplikasi Android ditulis dalam bahasa pemrograman Java. Android SDK Tools mengkompilasi +kode Anda—bersama data dan file sumber daya —ke dalam APK: Paket Android, +yaitu file arsip berekstensi {@code .apk}. Satu file APK berisi semua konten +aplikasi Android dan merupakan file yang digunakan perangkat berbasis Android untuk menginstal aplikasi.
+ +Setelah diinstal di perangkat, setiap aplikasi Android tinggal di sandbox keamanannya sendiri:
+ +-
+
- Sistem operasi Android merupakan sistem Linux multi-pengguna yang di dalamnya setiap +aplikasi adalah pengguna berbeda. + +
- Secara default, sistem menetapkan ID pengguna Linux unik kepada setiap aplikasi (ID ini hanya + digunakan oleh sistem dan tidak diketahui aplikasi). Sistem menetapkan izin +bagi semua file dalam aplikasi sehingga hanya ID pengguna yang diizinkan yang bisa mengaksesnya. + +
- Setiap proses memiliki mesin virtual (VM) sendiri, sehingga kode aplikasi yang berjalan secara terisolasi dari +aplikasi lainnya. + +
- Secara default, setiap aplikasi berjalan dalam proses Linux-nya sendiri. Android memulai proses +bila ada komponen aplikasi yang perlu dijalankan, kemudian mematikan proses bila tidak lagi diperlukan +atau bila sistem harus memulihkan memori untuk digunakan aplikasi lain. +
Dengan cara ini, sistem Android mengimplementasikan prinsip privilese minim. Ini berarti, +secara default aplikasi hanya memiliki akses ke komponen yang diperlukannya untuk melakukan pekerjaannya dan +tidak lebih dari itu. Hal ini menghasilkan lingkungan yang sangat aman sehingga aplikasi tidak bisa mengakses bagian +sistem bila tidak diberi izin.
+ +Akan tetapi, ada beberapa cara bagi aplikasi untuk berbagi data dengan aplikasi lain dan bagi aplikasi +untuk mengakses layanan sistem:
+ +-
+
- Dua aplikasi bisa diatur untuk menggunakan ID pengguna Linux yang sama, +dalam hal ini keduanya bisa saling mengakses file masing-masing. Untuk menghemat sumber daya sistem, aplikasi dengan ID +pengguna yang sama juga bisa diatur agar berjalan dalam proses Linux yang sama dan menggunakan VM yang sama ( +aplikasi juga harus ditandatangani dengan sertifikat yang sama). +
- Aplikasi bisa meminta izin akses ke data perangkat seperti kontak +pengguna, pesan SMS, penyimpanan lepas-pasang (kartu SD), kamera, Bluetooth, dan lainnya. Semua +izin aplikasi harus diberikan oleh pengguna saat menginstal. +
Hal tersebut mencakup dasar-dasar tentang cara aplikasi Android berada di dalam sistem. Bagian dokumen +selanjutnya memperkenalkan Anda pada:
+-
+
- Komponen kerangka kerja inti yang mendefinisikan aplikasi. +
- File manifes tempat Anda mendeklarasikan komponen dan fitur yang diperlukan perangkat +untuk aplikasi. +
- Sumber daya yang terpisah dari kode aplikasi dan memungkinkan +aplikasi mengoptimalkan perilakunya untuk beragam konfigurasi perangkat. +
Komponen Aplikasi
+ +Komponen aplikasi adalah blok pembangun penting dari aplikasi Android. +Setiap komponen merupakan titik berbeda yang digunakan sistem untuk memasuki aplikasi. Tidak semua komponen +merupakan titik masuk sebenarnya bagi pengguna dan sebagian saling bergantung, namun masing-masing komponen tersedia +sebagai kesatuan sendiri dan memainkan peran tertentu—masing-masing merupakan +blok pembangun unik yang mendefinisikan perilaku aplikasi secara keseluruhan.
+ +Ada empat macam tipe komponen aplikasi. Setiap tipe memiliki kegunaan tersendiri +dan daur hidupnya sendiri yang mendefinisikan cara komponen dibuat dan dimusnahkan.
+ +Berikut ini empat tipe komponen aplikasi:
+ +-
+
+
- Aktivitas + +
- Sebuah aktivitas mewakili satu layar dengan antarmuka pengguna. Misalnya,
+aplikasi email mungkin memiliki satu aktivitas yang menampilkan daftar email
+baru, aktivitas lain untuk menulis email, dan aktivitas satunya lagi untuk membaca email. Walaupun
+semua aktivitas bekerja sama untuk membentuk pengalaman pengguna yang kohesif dalam aplikasi email,
+masing-masing tidak saling bergantung. Karenanya, aplikasi berbeda bisa memulai
+salah satu aktivitas ini (jika aplikasi email mengizinkannya). Misalnya, aplikasi kamera bisa memulai
+aktivitas dalam aplikasi email yang membuat email baru agar pengguna bisa berbagi gambar.
+
+
Aktivitas diimplementasikan sebagai subkelas {@link android.app.Activity} dan Anda bisa mengetahui selengkapnya +tentang hal ini dalam panduan pengembang Aktivitas +.
+
+
+
+ - Layanan + +
- Sebuah layanan adalah komponen yang berjalan di latar belakang untuk melakukan
+operasi yang berjalan lama atau untuk melakukan pekerjaan bagi proses jarak jauh. Layanan
+tidak menyediakan antarmuka pengguna. Misalnya, sebuah layanan bisa memutar musik di latar belakang sementara
+pengguna berada dalam aplikasi lain, atau layanan bisa menarik data lewat jaringan tanpa
+memblokir interaksi pengguna dengan aktivitas. Komponen lain, seperti aktivitas, bisa memulai
+layanan dan membiarkannya berjalan atau mengikat layanan untuk berinteraksi dengannya.
+
+
Layanan diimplementasikan sebagai subkelas {@link android.app.Service} dan Anda bisa mengetahui selengkapnya +tentang hal ini dalam panduan +pengembang Layanan.
+
+
+
+ - Penyedia konten + +
- Sebuah penyedia konten mengelola seperangkat data-bersama aplikasi. Anda bisa menyimpan data
+dalam sistem file, database SQLite, di web, atau lokasi penyimpanan permanen lainnya
+yang bisa diakses aplikasi. Melalui penyedia konten, aplikasi lain bisa melakukan query atau bahkan
+memodifikasi data (jika penyedia konten mengizinkannya). Misalnya, sistem Android menyediakan penyedia
+konten yang mengelola informasi kontak pengguna. Karenanya, setiap aplikasi
+dengan izin yang sesuai bisa melakukan query mengenai bagian dari penyedia konten (seperti {@link
+android.provider.ContactsContract.Data}) untuk membaca dan menulis informasi tentang orang tertentu.
+
+
Penyedia konten juga berguna untuk membaca dan menulis data privat ke aplikasi Anda +dan tidak dibagikan. Misalnya, aplikasi contoh Note Pad menggunakan +penyedia konten untuk menyimpan catatan.
+ +Penyedia konten diimplementasikan sebagai subkelas {@link android.content.ContentProvider} +dan harus mengimplementasikan seperangkat standar API yang memungkinkan aplikasi +lain melakukan transaksi. Untuk informasi selengkapnya, lihat panduan pengembang +Penyedia Konten.
+
+
+
+ - Penerima siaran + +
- Sebuah penerima siaran adalah komponen yang merespons pengumuman siaran dalam lingkup
+sistem. Banyak siaran yang berasal dari sistem—misalnya, siaran yang mengumumkan bahwa
+layar telah dimatikan, baterai lemah, atau gambar telah direkam.
+Aplikasi juga bisa memulai siaran—misalnya untuk menginformasikan ke
+aplikasi lain bahwa sebagian data telah diunduh ke perangkat dan bisa digunakan aplikasi lain tersebut. Walaupun penerima
+siaran tidak menampilkan antarmuka pengguna, penerima bisa membuat pemberitahuan baris status
+untuk memberi tahu pengguna kapan kejadian siaran dilakukan. Meskipun penerima siaran umumnya cuma menjadi
+"gerbang" untuk komponen lain dan dimaksudkan untuk melakukan pekerjaan dalam jumlah sangat minim. Misalnya
+, penerima siaran bisa menjalankan layanan untuk melakukan beberapa pekerjaan berdasarkan kejadian.
+
+
Penerima siaran diimplementasikan sebagai subkelas {@link android.content.BroadcastReceiver} +dan setiap siaran dikirim sebagai objek {@link android.content.Intent}. Untuk informasi selengkapnya, +lihat kelas {@link android.content.BroadcastReceiver}.
+
+
+
Aspek unik dari desain sistem Android adalah aplikasi mana pun bisa memulai +komponen aplikasi lain. Misalnya, jika Anda menginginkan pengguna mengambil +foto dengan kamera perangkat, bisa saja aplikasi lain yang melakukannya dan aplikasi +Anda bisa menggunakannya, sebagai ganti mengembangkan aktivitas sendiri untuk mengambil foto. Anda tidak +harus menyatukan atau bahkan menautkan ke kode dari aplikasi kamera. +Sebagai gantinya, Anda tinggal memulai aktivitas di aplikasi kamera yang akan mengambil +foto. Bila selesai, foto akan dikembalikan ke aplikasi sehingga Anda bisa menggunakannya. Bagi pengguna, +kamera seakan menjadi bagian dari aplikasi Anda.
+ +Saat sistem memulai komponen, sistem akan memulai proses untuk aplikasi itu (jika +belum berjalan) dan membuat instance kelas yang diperlukan untuk komponen. Misalnya, jika aplikasi Anda +memulai aktivitas dalam aplikasi kamera yang mengambil foto, aktivitas itu akan +berjalan dalam proses yang dimiliki oleh aplikasi kamera, bukan dalam proses aplikasi Anda. +Karenanya, tidak seperti aplikasi di sebagian besar sistem lain, aplikasi Android tidak memiliki titik +masuk tunggal (misalnya tidak ada fungsi {@code main()}).
+ +Karena sistem menjalankan setiap aplikasi dalam proses terpisah dengan izin file yang +membatasi akses ke aplikasi lain, aplikasi Anda tidak bisa langsung mengaktifkan komponen dari aplikasi lain. Akan tetapi, sistem +Android bisa melakukannya. Jadi, untuk mengaktifkan +komponen dalam aplikasi lain, Anda harus mengirim pesan ke sistem yang menetapkan intent Anda untuk memulai +komponen tertentu. Selanjutnya sistem akan mengaktifkan komponen untuk Anda.
+ + +Mengaktifkan Komponen
+ +Tiga dari empat tipe komponen—aktivitas, layanan, dan +penerima siaran—diaktifkan oleh pesan asinkron yang disebut intent. +Intent saling mengikat setiap komponen saat runtime (Anda bisa menganggapnya +sebagai pembawa pesan yang meminta tindakan dari komponen lain), baik komponen itu milik aplikasi Anda +atau milik aplikasi lain.
+ +Intent dibuat dengan objek {@link android.content.Intent}, yang mendefinisikan pesan untuk +mengaktifkan komponen tertentu atau komponen tipe komponen tertentu—masing-masing intent +bisa eksplisit atau implisit.
+ +Untuk aktivitas dan layanan, intent mendefinisikan tindakan yang akan dilakukan (misalnya, untuk "melihat" atau +"mengirim" sesuatu) dan mungkin menetapkan URI data untuk ditindaklanjuti (salah satu hal yang mungkin perlu diketahui +oleh komponen yang akan dimulai). Misalnya, intent mungkin menyampaikan permintaan suatu +aktivitas untuk menampilkan gambar atau membuka halaman web. Dalam beberapa kasus, Anda bisa memulai +aktivitas untuk menerima hasil, dalam hal ini, aktivitas juga akan mengembalikan hasil +dalam {@link android.content.Intent} (misalnya Anda bisa mengeluarkan intent agar +pengguna bisa memilih kontak pribadi dan memintanya dikembalikan kepada Anda—intent yang dikembalikan menyertakan URI yang +menunjuk ke kontak yang dipilih).
+ +Untuk penerima siaran, intent hanya mendefinisikan +pengumuman yang sedang disiarkan (misalnya, siaran untuk menunjukkan baterai perangkat hampir habis +hanya menyertakan string tindakan yang menunjukkan "baterai hampir habis").
+ +Tipe komponen lainnya dan penyedia konten, tidak diaktifkan oleh intent. Melainkan +diaktifkan saat ditargetkan oleh permintaan dari {@link android.content.ContentResolver}. Resolver +konten menangani semua transaksi langsung dengan penyedia konten sehingga komponen yang melakukan +transaksi dengan penyedia tidak perlu dan sebagai gantinya memanggil metode pada objek {@link +android.content.ContentResolver}. Ini membuat lapisan abstraksi antara penyedia +konten dan komponen yang meminta informasi (demi keamanan).
+ +Ada beberapa metode terpisah untuk mengaktifkan masing-masing tipe komponen:
+-
+
- Anda bisa memulai aktivitas (atau memberinya pekerjaan baru) dengan +meneruskan {@link android.content.Intent} ke {@link android.content.Context#startActivity +startActivity()} atau {@link android.app.Activity#startActivityForResult startActivityForResult()} +(bila Anda ingin aktivitas mengembalikan hasil). +
- Anda bisa memulai layanan (atau memberikan instruksi baru ke layanan yang sedang berlangsung) dengan +meneruskan {@link android.content.Intent} ke {@link android.content.Context#startService +startService()}. Atau Anda bisa mengikat ke layanan dengan meneruskan {@link android.content.Intent} ke +{@link android.content.Context#bindService bindService()}. +
- Anda bisa memulai siaran dengan meneruskan {@link android.content.Intent} ke metode seperti +{@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, {@link +android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}, atau {@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()}. +
- Anda bisa melakukan query ke penyedia konten dengan memanggil {@link +android.content.ContentProvider#query query()} pada {@link android.content.ContentResolver}. +
Untuk informasi selengkapnya tentang menggunakan intent, lihat dokumen Intent dan Filter + Intent. Informasi selengkapnya tentang mengaktifkan komponen +tertentu juga tersedia dalam dokumen berikut: Aktivitas, Layanan, {@link +android.content.BroadcastReceiver} dan Penyedia Konten.
+ + +File Manifes
+ +Sebelum sistem Android bisa memulai komponen aplikasi, sistem harus mengetahui +keberadaan komponen dengan membaca file {@code AndroidManifest.xml} aplikasi (file +"manifes"). Aplikasi Anda harus mendeklarasikan semua komponennya dalam file ini, yang harus menjadi akar +dari direktori proyek aplikasi.
+ +Manifes melakukan banyak hal selain mendeklarasikan komponen aplikasi, +seperti:
+-
+
- Mengidentifikasi izin pengguna yang diperlukan aplikasi, seperti akses Internet atau +akses-baca ke kontak pengguna. +
- Mendeklarasikan API Level + minimum yang diperlukan aplikasi, berdasarkan API yang digunakan aplikasi. +
- Mendeklarasikan fitur perangkat keras dan perangkat lunak yang diperlukan aplikasi, seperti kamera, +layanan Bluetooth, atau layar multisentuh. +
- Pustaka API aplikasi perlu ditautkan (selain +API kerangka kerja Android), seperti pustaka +Google Maps. +
- Dan lainnya +
Mendeklarasikan komponen
+ +Tugas utama manifes adalah menginformasikan komponen aplikasi pada sistem. Misalnya, +file manifes bisa mendeklarasikan aktivitas sebagai berikut:
+ ++<?xml version="1.0" encoding="utf-8"?> +<manifest ... > + <application android:icon="@drawable/app_icon.png" ... > + <activity android:name="com.example.project.ExampleActivity" + android:label="@string/example_label" ... > + </activity> + ... + </application> +</manifest>+ +
Dalam elemen <application>
+, atribut {@code android:icon} menunjuk ke sumber daya untuk ikon yang mengidentifikasi
+aplikasi.
Dalam elemen <activity>
,
+atribut {@code android:name} menetapkan nama kelas yang sepenuhnya memenuhi syarat subkelas {@link
+android.app.Activity} dan atribut {@code android:label} menetapkan string yang akan
+digunakan sebagai label yang terlihat oleh pengguna untuk aktivitas tersebut.
Anda harus mendeklarasikan semua komponen aplikasi dengan cara ini:
+-
+
- Elemen
<activity>
untuk +aktivitas
+ - Elemen
<service>
untuk +layanan
+ - Elemen
<receiver>
untuk +penerima siaran
+ - Elemen
<provider>
untuk +penyedia konten
+
Aktivitas, layanan, dan penyedia konten yang Anda sertakan dalam kode sumber, namun tidak +dideklarasikan dalam manifes, tidak akan terlihat pada sistem dan, akibatnya, tidak pernah bisa berjalan. Akan tetapi, +penerima siaran +bisa dideklarasikan dalam manifes atau dibuat secara dinamis dalam kode (sebagai objek +{@link android.content.BroadcastReceiver}) dan didaftarkan pada sistem dengan memanggil +{@link android.content.Context#registerReceiver registerReceiver()}.
+ +Untuk informasi selengkapnya tentang cara menstrukturkan file manifes untuk aplikasi Anda, +lihat dokumentasi File AndroidManifest.xml.
+ + + +Mendeklarasikan kemampuan komponen
+ +Seperti telah dibahas di atas, dalam Mengaktifkan Komponen, Anda bisa menggunakan +{@link android.content.Intent} untuk memulai aktivitas, layanan, dan penerima siaran. Anda bisa +melakukannya dengan menamai komponen sasaran secara eksplisit (menggunakan nama kelas komponen) dalam intent. Akan tetapi, +kemampuan intent sebenarnya ada pada konsep intent implisit. Intent implisit +cuma menjelaskan tipe tindakan yang akan dilakukan (dan, secara opsional, data tempat Anda ingin +melakukan tindakan) dan memungkinkan sistem untuk menemukan komponen pada perangkat yang bisa melakukan +tindakan tersebut dan memulainya. Jika ada banyak komponen yang bisa melakukan tindakan yang dijelaskan oleh intent, +maka pengguna bisa memilih komponen yang akan digunakan.
+ +Cara sistem mengidentifikasi komponen yang bisa merespons intent adalah dengan membandingkan +intent yang diterima dengan filter intent yang disediakan dalam file manifes aplikasi lainnya pada +perangkat.
+ +Bila mendeklarasikan aktivitas dalam manifes aplikasi, secara opsional Anda bisa menyertakan +filter intent yang mendeklarasikan kemampuan aktivitas agar bisa merespons intent dari +aplikasi lain. Anda bisa mendeklarasikan filter intent untuk komponen dengan +menambahkan elemen {@code +<intent-filter>} sebagai anak elemen deklarasi komponen.
+ +Misalnya, jika Anda telah membangun aplikasi email dengan aktivitas untuk menulis email baru, Anda bisa +mendeklarasikan filter intent untuk merespons intent "kirim" (untuk mengirim email baru) seperti ini:
++<manifest ... > + ... + <application ... > + <activity android:name="com.example.project.ComposeEmailActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <data android:type="*/*" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> ++ +
Kemudian, jika aplikasi lain membuat intent dengan tindakan {@link +android.content.Intent#ACTION_SEND} dan meneruskannya ke {@link android.app.Activity#startActivity +startActivity()}, sistem bisa memulai aktivitas Anda agar pengguna bisa menulis draf dan mengirim +email.
+ +Untuk informasi selengkapnya tentang membuat filter intent, lihat dokumen Intent dan Filter Intent. +
+ + + +Mendeklarasikan kebutuhan aplikasi
+ +Ada berbagai macam perangkat yang didukung oleh Android dan tidak +semuanya menyediakan fitur dan kemampuan yang sama. Agar aplikasi Anda tidak dihapus pada perangkat yang tidak memiliki +fitur yang diperlukan aplikasi, Anda harus jelas mendefinisikan profil mengenai +tipe perangkat yang didukung aplikasi dengan mendeklarasikan kebutuhan perangkat dan perangkat lunak dalam file +manifes. Kebanyakan deklarasi ini hanya bersifat informasi dan sistem tidak +membacanya, namun layanan eksternal seperti Google Play akan membacanya untuk menyediakan +penyaringan bagi pengguna saat mereka mencari aplikasi dari perangkat.
+ +Misalnya, jika aplikasi memerlukan kamera dan menggunakan API yang disediakan dalam Android 2.1 (API Level 7) +, Anda harus mendeklarasikannya sebagai kebutuhan dalam file manifes seperti ini:
+ ++<manifest ... > + <uses-feature android:name="android.hardware.camera.any" + android:required="true" /> + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> + ... +</manifest> ++ +
Sekarang, perangkat yang tidak memiliki kamera dan menggunakan +Android versi lebih rendah dari 2.1 tidak bisa menginstal aplikasi Anda dari Google Play.
+ +Akan tetapi, bisa juga mendeklarasikan bahwa aplikasi Anda menggunakan kamera, namun tidak +mengharuskannya. Dalam hal itu, aplikasi Anda harus mengatur atribut {@code required} + ke {@code "false"} dan memeriksa saat runtime apakah +perangkat memiliki kamera dan menonaktifkan setiap fitur kamera yang sesuai.
+ +Informasi selengkapnya tentang cara mengelola kompatibilitas aplikasi dengan +perangkat yang berbeda disediakan dalam dokumen +Kompatibilitas Perangkat.
+ + + +Sumber Daya Aplikasi
+ +Aplikasi Android tidak hanya terdiri dari kode—Aplikasi memerlukan sumber daya yang +terpisah dari kode sumber, seperti gambar, file audio, dan apa saja yang berkaitan dengan +presentasi visual dari aplikasi. Misalnya, Anda harus mendefinisikan animasi, menu, gaya, warna, +dan layout antarmuka pengguna aktivitas dengan file XML. Penggunaan sumber daya aplikasi +mempermudah pembaruan berbagai karakteristik aplikasi Anda tanpa memodifikasi kode dan—dengan menyediakan +seperangkat sumber daya alternatif—memungkinkan Anda mengoptimalkan aplikasi untuk berbagai konfigurasi +perangkat berbeda (seperti bahasa dan ukuran layar yang berbeda).
+ +Untuk setiap sumber daya yang Anda sertakan dalam proyek Android, alat bawaan SDK akan mendefinisikan ID integer +unik, yang bisa Anda gunakan untuk mengacu sumber daya dari kode aplikasi atau dari sumber daya lainnya yang +didefinisikan dalam XML. Misalnya, jika aplikasi berisi file gambar bernama {@code +logo.png} (disimpan dalam direktori {@code res/drawable/}), alat SDK akan menghasilkan ID sumber daya +bernama {@code R.drawable.logo}, yang bisa Anda gunakan untuk mengacu gambar dan memasukkannya dalam +antarmuka pengguna.
+ +Salah satu aspek paling penting dari penyediaan sumber daya yang terpisah dari +kode sumber adalah kemampuan Anda menyediakan sumber daya alternatif untuk konfigurasi perangkat +yang berbeda. Misalnya, dengan mendefinisikan string UI dalam XML, Anda bisa menerjemahkan string ke dalam +bahasa lain dan menyimpan string itu dalam file terpisah. Kemudian, berdasarkan qualifier +bahasa yang ditambahkan ke nama direktori sumber daya (seperti {@code res/values-fr/} untuk nilai +string Prancis) dan pengaturan bahasa pengguna, sistem Android akan menerapkan string bahasa yang sesuai +untuk UI Anda.
+ +Android mendukung banyak qualifier berbeda untuk sumber daya alternatif Anda. Qualifier +adalah string pendek yang Anda sertakan dalam nama direktori sumber +daya untuk mendefinisikan konfigurasi perangkat yang harus digunakan sumber daya tersebut. Contoh lainnya, +Anda harus sering membuat layout berbeda untuk aktivitas, bergantung pada +orientasi layar dan ukuran perangkat. Misalnya, saat layar perangkat dalam orientasi +tegak, Anda mungkin ingin layout tombolnya vertikal, tetapi saat layar dalam orientasi +mendatar, tombolnya harus sejajar horizontal. Untuk mengubah layout +sesuai orientasi, Anda bisa mendefinisikan dua layout berbeda dan menerapkan qualifier yang +tepat untuk setiap nama direktori layout. Kemudian, sistem secara otomatis menerapkan +layout yang tepat sesuai dengan orientasi perangkat saat ini.
+ +Untuk informasi selengkapnya tentang berbagai jenis sumber daya yang bisa disertakan dalam aplikasi dan cara +membuat sumber daya alternatif untuk konfigurasi perangkat berbeda, bacalah Menyediakan Sumber Daya.
+ + + +Teruskan membaca tentang:
+-
+
- Intent dan Filter Intent + +
- Informasi tentang cara menggunakan API {@link android.content.Intent} untuk + mengaktifkan komponen aplikasi, seperti aktivitas dan layanan, dan cara menyediakan komponen aplikasi + untuk digunakan oleh aplikasi lain. +
- Aktivitas +
- Informasi tentang cara membuat instance kelas {@link android.app.Activity}, +yang menyediakan layar tersendiri dalam aplikasi bersama antarmuka pengguna. +
- Menyediakan Sumber Daya +
- Informasi tentang cara aplikasi Android disusun untuk memisahkan sumber daya aplikasi dari +kode aplikasi, termasuk cara Anda bisa menyediakan sumber daya alternatif untuk +konfigurasi perangkat tertentu. + +
Anda juga mungkin tertarik dengan:
+-
+
- Kompatibilitas Perangkat +
- Informasi tentang cara kerja Android pada berbagai tipe perangkat dan +pengenalan mengenai cara mengoptimalkan aplikasi untuk setiap perangkat atau membatasi ketersediaan aplikasi Anda untuk +perangkat berbeda. +
- Izin Sistem +
- Informasi tentang cara Android membatasi akses aplikasi pada API tertentu dengan sistem izin +yang mengharuskan persetujuan pengguna agar aplikasi dapat menggunakan API tersebut. +
Artikel Blog
+ + +Menggunakan DialogFragments
+Dalam posting ini, saya akan menunjukkan cara menggunakan DialogFragments dengan pustaka dukungan v4 (untuk kompatibilitas mundur pada perangkat sebelum Honeycomb) untuk menunjukkan dialog edit sederhana dan mengembalikan hasil ke Aktivitas pemanggil menggunakan antarmuka.
+ + + +Fragmen Untuk Semua
+Hari ini kami telah merilis pustaka statis yang memperlihatkan API Fragment yang sama (serta LoaderManager baru dan beberapa kelas lain) agar aplikasi yang kompatibel dengan Android 1.6 atau yang lebih baru bisa menggunakan fragmen untuk membuat antarmuka pengguna yang kompatibel dengan tablet.
+ + + +Multithreading untuk Kinerja
+Praktik yang baik dalam membuat aplikasi yang responsif adalah memastikan thread UI utama Anda +melakukan pekerjaan minimum. Setiap tugas yang berpotensi lama dan dapat membuat aplikasi mogok harus +ditangani di thread berbeda.
+ +Pelatihan
+ + +Mengelola Daur Hidup Aktivitas
+Bagian ini menjelaskan pentingnya metode callback daur hidup yang diterima setiap instance Aktivitas +dan cara menggunakannya sehingga aktivitas Anda melakukan yang diharapkan pengguna dan tidak menghabiskan sumber daya sistem +saat aktivitas tidak membutuhkannya.
+ + + +Membangun UI Dinamis dengan Fragmen
+Bagian ini menunjukkan kepada Anda cara membuat pengalaman pengguna yang dinamis dengan fragmen dan mengoptimalkan +pengalaman pengguna aplikasi Anda dengan berbagai ukuran layar, sekaligus terus mendukung +perangkat yang menjalankan versi sebelumnya, sesudah versi Android 1.6.
+ + + +Berbagi Konten
+Bagian ini membahas beberapa cara umum untuk mengirim dan menerima konten antar +aplikasi menggunakan API Intent dan objek ActionProvider.
+ +Dalam dokumen ini
+-
+
- Tipe Intent +
- Membangun Intent + + +
- Menerima Intent Implisit
+
-
+
- Contoh filter +
+ - Menggunakan Intent Tertunda +
- Resolusi Intent + + +
Lihat juga
+ + +{@link android.content.Intent} merupakan objek pertukaran pesan yang bisa Anda gunakan untuk meminta tindakan +dari komponen aplikasi lain. +Walaupun intent memudahkan komunikasi antarkomponen dalam beberapa cara, ada tiga +kasus-penggunaan dasar:
+ +-
+
- Untuk memulai aktivitas:
+
{@link android.app.Activity} menyatakan satu layar dalam aplikasi. Anda bisa memulai instance +baru {@link android.app.Activity} dengan meneruskan {@link android.content.Intent} +ke {@link android.content.Context#startActivity startActivity()}. {@link android.content.Intent} +menjelaskan aktivitas yang akan dimulai dan membawa data yang diperlukan.
+ +Jika Anda ingin menerima hasil dari aktivitas bila selesai, +panggil {@link android.app.Activity#startActivityForResult +startActivityForResult()}. Aktivitas Anda menerima hasil +sebagai objek {@link android.content.Intent} terpisah dalam callback {@link +android.app.Activity#onActivityResult onActivityResult()} aktivitas Anda. +Untuk informasi selengkapnya, lihat panduan Aktivitas.
+
+ - Untuk memulai layanan:
+
{@link android.app.Service} adalah komponen yang melakukan operasi di latar belakang +tanpa antarmuka pengguna. Anda bisa memulai layanan untuk melakukan operasi satu-kali +(misalnya mengunduh file) dengan meneruskan {@link android.content.Intent} +ke {@link android.content.Context#startService startService()}. {@link android.content.Intent} +menjelaskan layanan yang akan dimulai dan membawa data yang diperlukan.
+ +Jika layanan didesain dengan antarmuka pengguna klien-server, Anda bisa mengikat ke layanan +dari komponen lain dengan meneruskan {@link android.content.Intent} ke {@link +android.content.Context#bindService bindService()}. Untuk informasi selengkapnya, lihat panduan Layanan.
+
+ - Untuk mengirim siaran:
+
Siaran adalah pesan yang bisa diterima aplikasi apa saja. Sistem menyampaikan beragam siaran +untuk kejadian sistem, misalnya saat sistem booting atau saat perangkat mulai mengisi daya. +Anda bisa mengirim siaran ke aplikasi lain dengan meneruskan {@link android.content.Intent} +ke {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}, +{@link android.content.Context#sendOrderedBroadcast(Intent, String) +sendOrderedBroadcast()}, atau {@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.
+
+
Tipe Intent
+ +Ada dua tipe intent:
+ +-
+
- Intent eksplisit menetapkan komponen untuk memulai dengan nama ( +nama kelas yang sepenuhnya memenuhi syarat). Anda biasanya akan menggunakan intent eksplisit untuk memulai sebuah komponen +dalam aplikasi sendiri, karena Anda mengetahui nama kelas dari aktivitas atau layanan yang ingin dimulai. +Misalnya, mulai aktivitas baru sebagai respons terhadap tindakan pengguna atau mulai layanan untuk mengunduh +file di latar belakang. + +
- Intent implisit tidak menetapkan komponen tertentu, melainkan mendeklarasikan tindakan umum +yang dilakukan, yang memungkinkan komponen aplikasi lain untuk menanganinya. Misalnya, jika Anda ingin +menampilkan sebuah lokasi di peta pada pengguna, Anda bisa menggunakan intent implisit untuk meminta aplikasi lain +yang mampu untuk menunjukkan lokasi yang telah ditetapkan di peta tersebut. +
Saat Anda membuat intent eksplisit untuk memulai aktivitas atau layanan, sistem akan segera +memulai komponen aplikasi yang telah ditetapkan dalam objek {@link android.content.Intent}.
+ +Bila Anda membuat intent implisit, sistem Android akan menemukan komponen yang sesuai untuk memulai +dengan membandingkan konten intent dengan filter intent yang dideklarasikan dalam file manifes aplikasi lain di +perangkat. Jika intent cocok dengan filter intent, sistem akan memulai komponen tersebut dan mengiriminya +objek {@link android.content.Intent}. Jika banyak filter intent yang kompatibel, sistem +menampilkan dialog sehingga pengguna bisa memilih aplikasi yang akan digunakan.
+ +Filter intent adalah ekspresi dalam file manifes aplikasi yang +menetapkan tipe intent yang akan diterima +komponen. Misalnya, dengan mendeklarasikan intent filter untuk aktivitas, +Anda akan memungkinkan aplikasi lain untuk langsung memulai aktivitas Anda dengan intent tertentu. +Demikian pula, jika Anda tidak mendeklarasikan filter intent untuk suatu aktivitas, maka aktivitas tersebut hanya bisa dimulai +dengan intent eksplisit.
+ +Perhatian: Untuk memastikan aplikasi Anda aman, selalu gunakan intent +eksplisit saat memulai {@link android.app.Service} dan jangan +mendeklarasikan filter intent untuk layanan. Menggunakan intent implisit untuk memulai layanan akan menimbulkan +bahaya keamanan karena Anda tidak bisa memastikan layanan apa yang akan merespons intent, +dan pengguna tidak bisa melihat layanan mana yang dimulai. Mulai dari Android 5.0 (API level 21), sistem +melontarkan eksepsi jika Anda memanggil {@link android.content.Context#bindService bindService()} +dengan intent implisit.
+ + + + + +Membangun Intent
+ +Objek {@link android.content.Intent} membawa informasi yang digunakan sistem Android +untuk menentukan komponen mana yang akan dimulai (misalnya nama persis dari suatu komponen atau kategori +komponen yang seharusnya menerima intent), ditambah informasi yang digunakan komponen penerima untuk +melakukan tindakan dengan benar (misalnya tindakan yang harus dilakukan dan data yang harus diolah).
+ + +Informasi utama yang dimuat dalam {@link android.content.Intent} adalah sebagai berikut:
+ +-
+
+
- Nama komponen +
- Nama komponen yang akan dimulai.
+
+
Ini opsional, namun merupakan bagian informasi penting yang membuat intent +menjadi eksplisit, yaitu intent harus dikirim hanya ke komponen aplikasi +yang didefinisikan oleh nama komponen. Tanpa nama komponen, intent menjadi implisit dan +sistem akan memutuskan komponen mana yang harus menerima intent berdasarkan informasi intent lain +(misalnya tindakan, data, dan kategori—yang dijelaskan di bawah ini). Jadi jika Anda ingin memulai komponen +tertentu dalam aplikasi, Anda harus menetapkan nama komponen tersebut.
+ +Catatan: Saat memulai {@link android.app.Service}, Anda harus +selalu menetapkan nama komponen. Jika tidak, maka Anda tidak bisa memastikan layanan apa +yang akan merespons intent tersebut, dan pengguna tidak bisa melihat layanan mana yang dimulai.
+ +Bidang {@link android.content.Intent} ini adalah objek +{@link android.content.ComponentName}, yang bisa Anda tetapkan menggunakan +nama kelas yang sepenuhnya memenuhi syarat dari komponen target, termasuk nama paket aplikasi. Misalnya, +{@code com.example.ExampleActivity}. Anda bisa mengatur nama komponen dengan {@link +android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass +setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, atau dengan konstruktor +{@link android.content.Intent}.
+ +
+
+ - Tindakan +
- String yang menetapkan tindakan generik untuk dilakukan (misalnya lihat atau pilih).
+
+
Dalam hal intent siaran, ini adalah tindakan yang terjadi dan dilaporkan. +Tindakan ini sangat menentukan bagaimana keseluruhan intent disusun—terutama +apa yang dimuat dalam data dan ekstra. + +
Anda bisa menetapkan tindakan sendiri yang akan digunakan oleh intent dalam aplikasi Anda (atau digunakan oleh aplikasi +lain untuk memanggil komponen dalam aplikasi Anda), namun Anda harus menggunakan konstanta tindakan +yang didefinisikan oleh kelas {@link android.content.Intent} atau kelas kerangka kerja lain. Berikut ini adalah beberapa +tindakan umum untuk memulai sebuah aktivitas:
+ +-
+
- {@link android.content.Intent#ACTION_VIEW} +
- Gunakan tindakan ini dalam intent dengan {@link + android.content.Context#startActivity startActivity()} saat Anda memiliki beberapa informasi yang + bisa ditampilkan aktivitas kepada pengguna, misalnya foto yang bisa dilihat dalam aplikasi galeri, atau alamat + yang bisa dilihat dalam aplikasi peta. + +
- {@link android.content.Intent#ACTION_SEND} +
- Juga dikenal dengan intent "berbagi", Anda harus menggunakannya dalam intent dengan {@link + android.content.Context#startActivity startActivity()} bila Anda memiliki data yang bisa digunakan pengguna untuk + berbagi melalui aplikasi lain, misalnya aplikasi email atau aplikasi jaringan sosial. +
Lihat referensi kelas {@link android.content.Intent} untuk konstanta +selengkapnya yang mendefinisikan tindakan generik. Tindakan lain yang didefinisikan +di tempat lain dalam kerangka kerja Android, misalnya dalam {@link android.provider.Settings} untuk tindakan +yang membuka layar tertentu dalam aplikasi Settings di sistem.
+ +Anda bisa menetapkan tindakan untuk sebuah intent dengan {@link android.content.Intent#setAction +setAction()} atau dengan konstruktor {@link android.content.Intent}.
+ +Jika mendefinisikan tindakan Anda sendiri, pastikan untuk memasukkan nama paket aplikasi Anda +sebagai awalan. Misalnya:
+static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
+
+
+ - Data +
- URI (objek {@link android.net.Uri}) yang mengacu data untuk diolah dan/atau
+tipe MIME dari data tersebut. Tipe data yang disediakan umumnya didikte oleh tindakan intent.
+Misalnya, jika tindakan merupakan {@link android.content.Intent#ACTION_EDIT}, data harus berisi
+URI dari dokumen untuk diedit.
+
+
Saat membuat intent, +seringkali tipe data (tipe MIME-nya) selain URI perlu ditetapkan. +Misalnya, aktivitas yang mampu menampilkan gambar mungkin tidak mampu +memutar file audio, walaupun format URI mungkin serupa. +Jadi menetapkan tipe MIME data Anda akan membantu sistem +Android menemukan komponen terbaik untuk diterima intent. +Akan tetapi, tipe MIME seringkali bisa diambil dari URI—terutama saat datanya merupakan URI +{@code content:}, yang menunjukkan data tersebut berada di perangkat dan dikontrol oleh +{@link android.content.ContentProvider}, yang membuat data tipe MIME terlihat di sistem.
+ +Untuk mengatur data URI saja, panggil {@link android.content.Intent#setData setData()}. +Untuk mengatur tipe MIME saja, panggil {@link android.content.Intent#setType setType()}. Jika perlu, Anda +bisa mengatur keduanya secara eksplisit dengan {@link +android.content.Intent#setDataAndType setDataAndType()}.
+ +Perhatian: Jika ingin mengatur tipe URI dan MIME, +jangan panggil {@link android.content.Intent#setData setData()} dan +{@link android.content.Intent#setType setType()} karena mereka saling menghapuskan nilai satu sama lain. +Selalu gunakan {@link android.content.Intent#setDataAndType setDataAndType()} untuk mengatur +tipe URI maupun MIME.
+
+
+ - Kategori +
- String yang berisi informasi tambahan tentang jenis komponen
+yang harus menangani intent. Keterangan kategori dalam jumlah berapa pun bisa
+dimasukkan dalam intent, namun sebagian besar intent tidak memerlukan kategori.
+Berikut ini adalah beberapa kategori umum:
+
+
-
+
- {@link android.content.Intent#CATEGORY_BROWSABLE} +
- Aktivitas target memungkinkannya dimulai oleh browser web untuk menampilkan data +yang diacu oleh tautan—misalnya gambar atau pesan e-mail. + +
- {@link android.content.Intent#CATEGORY_LAUNCHER} +
- Aktivitas tersebut adalah aktivitas awal dari sebuah tugas dan dicantumkan dalam + launcher aplikasi sistem. + +
Lihat keterangan kelas {@link android.content.Intent} untuk mengetahui daftar lengkap +kategori.
+ +Anda bisa menetapkan kategori dengan {@link android.content.Intent#addCategory addCategory()}.
+
+
Properti yang tercantum di atas (nama komponen, tindakan, data, dan kategori) menyatakan +karakteristik yang mendefinisikan intent. Dengan membaca properti ini, sistem Android +mampu memutuskan komponen aplikasi yang harus dimulainya.
+ +Akan tetapi, intent bisa membawa informasi tambahan yang tidak memengaruhi +cara intent ditetapkan pada komponen aplikasi. Intent juga bisa menyediakan:
+ +-
+
- Ekstra +
- Pasangan nilai-kunci yang membawa informasi yang diperlukan untuk menghasilkan tindakan yang diminta.
+Seperti halnya beberapa tindakan menggunakan jenis tertentu URI data, beberapa tindakan juga menggunakan ekstra tertentu.
+
+
Anda bisa menambahkan data ekstra dengan beragam metode {@link android.content.Intent#putExtra putExtra()}, +masing-masing menerima dua parameter: nama kunci dan nilainya. +Anda juga bisa membuat objek {@link android.os.Bundle} dengan semua data ekstra, kemudian memasukkan +{@link android.os.Bundle} dalam {@link android.content.Intent} dengan {@link +android.content.Intent#putExtras putExtras()}.
+ +Misalnya, saat membuat intent yang akan dikirimkan bersama email +{@link android.content.Intent#ACTION_SEND}, Anda bisa menetapkan penerima "kepada" dengan kunci +{@link android.content.Intent#EXTRA_EMAIL}, dan menetapkan "subjek" dengan kunci +{@link android.content.Intent#EXTRA_SUBJECT}.
+ +Kelas {@link android.content.Intent} menetapkan beberapa konstanta {@code EXTRA_*} +untuk tipe data standar. Jika Anda ingin mendeklarasikan kunci ekstra sendiri (untuk intent yang +diterima aplikasi Anda), pastikan untuk memasukkan nama paket aplikasi +sebagai awalan. Misalnya:
+static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
+
+
+ - Flag +
- Flag didefinisikan dalam kelas {@link android.content.Intent} yang berfungsi sebagai metadata untuk
+intent. Flag menginstruksikan cara meluncurkan aktivitas (misalnya,
+tugas mana yang harus dimiliki suatu aktivitas
+) dan cara memperlakukannya setelah diluncurkan (misalnya, apakah aktivitas tersebut masuk ke dalam daftar aktivitas
+terbaru) pada sistem Android.
+
+
Untuk informasi selengkapnya, lihat metode {@link android.content.Intent#setFlags setFlags()} .
+
+
+
Contoh intent eksplisit
+ +Intent eksplisit adalah intent yang Anda gunakan untuk meluncurkan komponen aplikasi tertentu, seperti +aktivitas tertentu atau layanan dalam aplikasi Anda. Untuk membuat intent eksplisit, definisikan +nama komponen untuk objek {@link android.content.Intent} —semua +properti intent lain bersifat opsional.
+ +Misalnya, jika Anda ingin membangun layanan dalam aplikasi Anda, bernama {@code DownloadService}, +yang didesain untuk mengunduh file dari web, Anda bisa memulainya dengan kode berikut ini:
+ ++// Executed in an Activity, so 'this' is the {@link android.content.Context} +// The fileUrl is a string URL, such as "http://www.example.com/image.png" +Intent downloadIntent = new Intent(this, DownloadService.class); +downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl)); +startService(downloadIntent); ++ +
Konstruktor {@link android.content.Intent#Intent(Context,Class)} + menyediakan {@link android.content.Context} aplikasi dan +objek {@link java.lang.Class} pada komponen. Dengan demikian, +intent ini memulai secara eksplisit kelas {@code DownloadService} dalam aplikasi.
+ +Untuk informasi selengkapnya tentang membangun dan memulai layanan, lihat panduan +Layanan.
+ + + + +Contoh intent implisit
+ +Intent implisit menetapkan tindakan yang bisa memanggil aplikasi pada perangkat yang mampu +melakukan tindakan. Menggunakan intent implisit berguna bila aplikasi Anda tidak bisa melakukan +tindakan, namun aplikasi lain mungkin bisa melakukannya dan Anda ingin pengguna untuk memilih aplikasi mana yang ingin digunakan.
+ +Misalnya, jika memiliki konten yang Anda ingin agar pengguna berbagi konten itu dengan orang lain, buatlah intent +dengan tindakan {@link android.content.Intent#ACTION_SEND} +dan tambahkan ekstra yang menetapkan konten yang akan dibagikan. Bila Anda memanggil +{@link android.content.Context#startActivity startActivity()} dengan intent tersebut, pengguna bisa +memilih aplikasi yang akan digunakan untuk berbagi konten.
+ +Perhatian: Ada kemungkinan pengguna tidak memiliki suatu +aplikasi yang menangani intent implisit yang Anda kirimkan ke {@link android.content.Context#startActivity +startActivity()}. Jika itu terjadi, panggilan akan gagal dan aplikasi Anda akan crash. Untuk memeriksa +apakah aktivitas bisa menerima intent, panggil {@link android.content.Intent#resolveActivity +resolveActivity()} pada objek {@link android.content.Intent} Anda. Jika hasilnya bukan nol, +berarti setidaknya ada satu aplikasi yang bisa menangani intent tersebut dan aman untuk memanggil +{@link android.content.Context#startActivity startActivity()}. Jika hasilnya nol, +Anda tidak boleh menggunakan intent tersebut dan, jika memungkinkan, Anda harus menonaktifkan fitur yang mengeluarkan +intent tersebut.
+ + ++// Create the text message with a string +Intent sendIntent = new Intent(); +sendIntent.setAction(Intent.ACTION_SEND); +sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); +sendIntent.setType("text/plain"); + +// Verify that the intent will resolve to an activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(sendIntent); +} ++ +
Catatan: Dalam hal ini, URI tidak digunakan, namun tipe data intent +dideklarasikan untuk menetapkan konten yang dibawa oleh ekstra.
+ + +Saat {@link android.content.Context#startActivity startActivity()} dipanggil, sistem akan +memeriksa semua aplikasi yang terinstal untuk menentukan aplikasi mana yang bisa menangani intent jenis ini ( +intent dengan tindakan {@link android.content.Intent#ACTION_SEND} dan yang membawa data +"teks/polos"). Jika hanya ada satu aplikasi yang bisa menanganinya, aplikasi tersebut akan langsung terbuka dan diberi +intent tersebut. Jika banyak aktivitas menerima intent, sistem akan +menampilkan dialog sehingga pengguna bisa memilih aplikasi mana yang digunakan.
+ + +Memaksakan pemilih aplikasi
+ +Bila ada lebih dari satu aplikasi yang merespons intent implisit Anda, +pengguna bisa memilih aplikasi mana yang digunakan dan membuat aplikasi tersebut pilihan default untuk +tindakan tersebut. Ini sangat membantu saat melakukan tindakan di mana pengguna +mungkin ingin menggunakan aplikasi yang sama untuk seterusnya, seperti saat membuka halaman web (pengguna +biasanya memilih hanya satu browser web).
+ +Akan tetapi, jika ada banyak aplikasi yang bisa merespons intent tersebut dan pengguna mungkin ingin menggunakan aplikasi +yang berbeda untuk setiap kalinya, Anda harus menampilkan dialog pemilih secara eksplisit. Dialog pemilih akan meminta +pengguna memilih aplikasi yang akan digunakan untuk tindakan tertentu setiap kali (pengguna tidak bisa memilih aplikasi default untuk +tindakan tersebut). Misalnya, saat aplikasi Anda melakukan "berbagi" dengan tindakan {@link +android.content.Intent#ACTION_SEND}, pengguna mungkin ingin berbagi menggunakan aplikasi berbeda sesuai +dengan situasi mereka saat itu, jadi Anda harus selalu menggunakan dialog pemilih, seperti yang ditampilkan dalam gambar 2.
+ + + + +Untuk menampilkan pemilih, buatlah {@link android.content.Intent} menggunakan {@link +android.content.Intent#createChooser createChooser()} dan teruskan ke {@link +android.app.Activity#startActivity startActivity()}. Misalnya:
+ ++Intent sendIntent = new Intent(Intent.ACTION_SEND); +... + +// Always use string resources for UI text. +// This says something like "Share this photo with" +String title = getResources().getString(R.string.chooser_title); +// Create intent to show the chooser dialog +Intent chooser = Intent.createChooser(sendIntent, title); + +// Verify the original intent will resolve to at least one activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(chooser); +} ++ +
Ini menampilkan dialog dengan daftar aplikasi yang merespons intent yang diteruskan ke metode {@link +android.content.Intent#createChooser createChooser()} dan menggunakan teks yang disediakan sebagai +judul dialog.
+ + + + + + + + + +Menerima Intent Implisit
+ +Untuk mengiklankan intent implisit yang bisa diterima aplikasi Anda, deklarasikan satu atau beberapa filter intent untuk +tiap komponen aplikasi dengan elemen {@code <intent-filter>} +dalam file manifes Anda. +Tiap filter intent menetapkan tipe intent yang diterimanya berdasarkan tindakan intent, +data, dan kategori. Sistem akan mengirim intent implisit ke komponen aplikasi Anda hanya jika +intent tersebut bisa diteruskan melalui salah satu filter intent.
+ +Catatan: Intent eksplisit selalu dikirimkan ke targetnya, +apa pun filter intent yang dideklarasikan komponen.
+ +Komponen aplikasi harus mendeklarasikan filter terpisah untuk setiap pekerjaan unik yang bisa dilakukannya. +Misalnya, satu aktivitas dalam aplikasi galeri gambar bisa memiliki dua filter: satu filter +untuk melihat gambar, dan filter lainnya untuk mengedit gambar. Bila aktivitas dimulai, +aktivitas akan memeriksa {@link android.content.Intent} dan menentukan cara berperilaku berdasarkan informasi +dalam {@link android.content.Intent} (misalnya menampilkan kontrol editor atau tidak).
+ +Tiap filter intent didefinisikan oleh elemen {@code <intent-filter>} +dalam file manifes aplikasi, yang tersarang dalam komponen aplikasi terkait (seperti +elemen {@code <activity>} +). Di dalam {@code <intent-filter>}, +Anda bisa menetapkan tipe intent yang akan diterima dengan menggunakan salah satu atau beberapa +dari tiga elemen ini:
+ +-
+
- {@code <action>} +
- Mendeklarasikan tindakan intent yang diterima, dalam atribut {@code name}. Nilai + haruslah nilai string literal dari tindakan, bukan konstanta kelas. +
- {@code <data>} +
- Mendeklarasikan tipe data yang diterima, menggunakan salah satu atau beberapa atribut yang menetapkan beragam
+ aspek URI data (
scheme
,host
,port
, +path
, dll.) dan tipe MIME.
+ - {@code <category>} +
- Mendeklarasikan kategori intent yang diterima, dalam atribut {@code name}. Nilai
+ haruslah nilai string literal dari tindakan, bukan konstanta kelas.
+
+
Catatan: Untuk menerima intent implisit, Anda + harus menyertakan kategori +{@link android.content.Intent#CATEGORY_DEFAULT} dalam filter intent. Metode + {@link android.app.Activity#startActivity startActivity()}dan + {@link android.app.Activity#startActivityForResult startActivityForResult()} memperlakukan semua intent + seolah-olah mendeklarasikan kategori {@link android.content.Intent#CATEGORY_DEFAULT}. + Jika tidak mendeklarasikan kategori ini dalam filter intent Anda, tidak ada intent implisit yang ditetapkan untuk + aktivitas Anda.
+
+
Misalnya, ini adalah deklarasi aktivitas dengan filter intent yang diterima intent +{@link android.content.Intent#ACTION_SEND} bila tipe data berupa teks:
+ ++<activity android:name="ShareActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + </intent-filter> +</activity> ++ +
Anda bisa membuat filter yang menyertakan lebih dari satu instance +{@code <action>}, +{@code <data>}, atau +{@code <category>}. +Jika Anda melakukannya, Anda hanya perlu memastikan bahwa komponen bisa menangani semua kombinasi +elemen filter tersebut.
+ +Bila ingin menangani beragam jenis intent, namun hanya dalam kombinasi +tindakan, data, dan tipe kategori tertentu, maka Anda harus membuat banyak filter intent.
+ + +Membatasi akses ke komponen
+Menggunakan filter intent bukanlah cara yang aman untuk mencegah aplikasi lain memulai +komponen Anda. Walaupun filter intent membatasi komponen agar hanya merespons +jenis intent implisit tertentu, aplikasi lain bisa saja memulai komponen aplikasi Anda +dengan menggunakan intent eksplisit jika pengembangnya menentukan nama komponen Anda. +Jika perlu hanya aplikasi Anda sendiri yang mampu memulai salah satu komponen, +atur atribut {@code +exported} ke {@code "false"} untuk komponen itu. +
+Intent implisit diuji terhadap filter dengan membandingkan intent dengan masing-masing +dari ketiga elemen. Agar dikirim ke komponen, intent harus lolos ketiga pengujian tersebut. +Jika intent gagal dalam salah satu pengujian, sistem Android tidak akan mengirim intent ke +komponen. Akan tetapi, karena sebuah komponen dapat memiliki beberapa filter intent, intent yang tidak +lolos melalui salah satu filter komponen mungkin akan lolos di filter lain. +Informasi selengkapnya tentang cara sistem menetapkan intent disediakan dalam bagian di bawah ini +tentang Resolusi Intent.
+ +Perhatian: Untuk menghindari menjalankan +{@link android.app.Service} aplikasi yang berbeda secara tidak sengaja, selalu gunakan intent eksplisit untuk memulai layanan Anda sendiri dan jangan +deklarasikan filter intent untuk layanan Anda.
+ +Catatan: +Untuk semua aktivitas, Anda harus mendeklarasikan filter intent dalam file manifes. +Akan tetapi, filter untuk penerima siaran bisa didaftarkan secara dinamis dengan memanggil +{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String, +Handler) registerReceiver()}. Anda nanti bisa mencabut pendaftaran penerima dengan {@link +android.content.Context#unregisterReceiver unregisterReceiver()}. Dengan begitu aplikasi Anda +bisa mendengarkan siaran tertentu hanya selama periode waktu yang telah ditetapkan saat aplikasi Anda +berjalan.
+ + + + + + + +Contoh filter
+ +Untuk lebih memahami beberapa perilaku filter intent, lihatlah cuplikan berikut +dari file manifes aplikasi berbagi di jaringan sosial.
+ ++<activity android:name="MainActivity"> + <!-- This activity is the main entry, should appear in app launcher --> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> + +<activity android:name="ShareActivity"> + <!-- This activity handles "SEND" actions with text data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + </intent-filter> + <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <action android:name="android.intent.action.SEND_MULTIPLE"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="application/vnd.google.panorama360+jpg"/> + <data android:mimeType="image/*"/> + <data android:mimeType="video/*"/> + </intent-filter> +</activity> ++ +
Aktivitas pertama, {@code MainActivity}, merupakan titik masuk utama aplikasi—aplikasi yang +terbuka saat pengguna meluncurkan aplikasi dengan ikon launcher:
+-
+
- Tindakan {@link android.content.Intent#ACTION_MAIN} + menunjukkan ini adalah titik masuk utama dan tidak mengharapkan data intent apa pun. +
- Kategori {@link android.content.Intent#CATEGORY_LAUNCHER} menunjukjkan bahwa ikon + aktivitas ini harus ditempatkan dalam launcher aplikasi sistem. Jika elemen {@code <activity>} + tidak menetapkan ikon dengan{@code icon}, maka sistem akan menggunakan ikon dari elemen +{@code <application>}. +
Keduanya harus dipasangkan bersama agar aktivitas muncul dalam launcher aplikasi.
+ +Aktivitas kedua, {@code ShareActivity}, dimaksudkan untuk memudahkan berbagi teks dan konten +media. Walaupun pengguna mungkin memasuki aktivitas ini dengan mengarah ke aktivitas dari {@code MainActivity}, +pengguna juga bisa memasukkan {@code ShareActivity} secara langsung dari aplikasi lain yang mengeluarkan intent +implisit yang cocok dengan salah satu dari kedua filter intent.
+ +Catatan: Tipe MIME, +{@code +application/vnd.google.panorama360+jpg}, merupakan tipe data khusus yang menetapkan +foto panorama, yang bisa Anda tangani dengan API panorama +Google.
+ + + + + + + + + + + + + +Menggunakan Intent Tertunda
+ +Objek {@link android.app.PendingIntent} merupakan pembungkus objek {@link +android.content.Intent}. Tujuan utama {@link android.app.PendingIntent} +adalah memberikan izin pada aplikasi asing +untuk menggunakan {@link android.content.Intent} yang termuat seolah-olah dieksekusi dari +proses aplikasi Anda sendiri.
+ +Kasus penggunaan utama untuk intent tertunda antara lain:
+-
+
- Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan Pemberitahuan + ({@link android.app.NotificationManager} + sistem Android akan mengeksekusi {@link android.content.Intent}) Anda. +
- Mendeklarasikan intent untuk dieksekusi saat pengguna melakukan tindakan dengan +App Widget + (aplikasi layar Home mengeksekusi {@link android.content.Intent}). +
- Mendeklarasikan intent untuk dieksekusi di waktu yang telah ditetapkan di masa mendatang +({@link android.app.AlarmManager} sistem Android akan mengeksekusi {@link android.content.Intent}). +
Karena setiap objek {@link android.content.Intent} didesain untuk ditangani oleh tipe +tertentu dari komponen aplikasi (baik {@link android.app.Activity}, {@link android.app.Service}, maupun + {@link android.content.BroadcastReceiver}), jadi {@link android.app.PendingIntent} harus +dibuat dengan pertimbangan yang sama. Saat menggunakan intent tertunda, aplikasi Anda tidak akan +mengeksekusi intent dengan panggilan seperti {@link android.content.Context#startActivity +startActivity()}. Anda harus mendeklarasikan tipe komponen yang dimaksud saat membuat +{@link android.app.PendingIntent} dengan memanggil metode kreator masing-masing:
+ +-
+
- {@link android.app.PendingIntent#getActivity PendingIntent.getActivity()} untuk + {@link android.content.Intent} yang memulai {@link android.app.Activity}. +
- {@link android.app.PendingIntent#getService PendingIntent.getService()} untuk + {@link android.content.Intent} yang memulai {@link android.app.Service}. +
- {@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} untuk + {@link android.content.Intent} yang memulai {@link android.content.BroadcastReceiver}. +
Kecuali jika aplikasi Anda menerima intent tertunda dari aplikasi lain, +metode di atas untuk membuat {@link android.app.PendingIntent} menjadi satu-satunya metode +{@link android.app.PendingIntent} yang mungkin Anda butuhkan.
+ +Tiap metode mengambil {@link android.content.Context} aplikasi saat itu, +{@link android.content.Intent} yang ingin Anda bungkus, dan satu atau beberapa flag yang menetapkan +cara penggunaan intent (misalnya apakah intent bisa digunakan lebih dari sekali).
+ +Informasi selengkapnya tentang intent tertunda disediakan pada dokumentasi untuk setiap +kasus penggunaan yang bersangkutan, seperti dalam panduan API Notifications +dan App Widgets.
+ + + + + + + +Resolusi Intent
+ + +Saat sistem menerima intent implisit yang memulai suatu aktivitas, sistem tersebut akan mencari +aktivitas terbaik untuk intent dengan membandingkan intent dengan filter intent berdasarkan tiga aspek:
+ +-
+
- Tindakan intent +
- Data intent (baik URI maupun tipe data) +
- Kategori intent +
Bagian berikut menjelaskan cara pencocokan intent dengan komponen yang sesuai +sehubungan dengan cara pendeklarasian filter intent dalam file manifes aplikasi.
+ + +Pengujian tindakan
+ +Untuk menetapkan tindakan intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen +{@code +<action>}. Misalnya:
+ ++<intent-filter> + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.VIEW" /> + ... +</intent-filter> ++ +
Untuk melewati filter ini, tindakan yang ditetapkan dalam {@link android.content.Intent} +harus sesuai dengan salah satu tindakan yang tercantum dalam filter.
+ +Jika filter tidak mencantumkan tindakan apa pun, maka tidak ada intent +yang dicocokkan, jadi semua intent gagal dalam pengujian. Akan tetapi, jika sebuah {@link android.content.Intent} +tidak menetapkan suatu tindakan, maka akan lolos pengujian (asalkan filter +berisi setidaknya satu tindakan).
+ + + +Pengujian kategori
+ +Untuk menetapkan kategori intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen +{@code +<category>}. Misalnya:
+ ++<intent-filter> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + ... +</intent-filter> ++ +
Agar intent bisa lolos pengujian kategori, setiap kategori dalam {@link android.content.Intent} +harus sesuai dengan kategori dalam filter. Kebalikannya tidak diperlukan—filter intent bisa +mendeklarasikan kategori lebih banyak daripada yang ditetapkan dalam {@link android.content.Intent} dan +{@link android.content.Intent} tetap akan lolos. Oleh karena itu, intent tanpa kategori harus +selalu lolos pengujian ini, kategori apa pun yang dideklarasikan dalam filter.
+ +Catatan: +Android secara otomatis menerapkan kategori {@link android.content.Intent#CATEGORY_DEFAULT} +untuk semua intent implisit yang diteruskan ke {@link +android.content.Context#startActivity startActivity()} dan {@link +android.app.Activity#startActivityForResult startActivityForResult()}. +Jadi jika ingin aktivitas Anda menerima intent implisit, aktivitas tersebut harus +menyertakan kategori untuk{@code "android.intent.category.DEFAULT"} dalam filter intent (seperti +yang ditampilkan dalam contoh{@code <intent-filter>} sebelumnya.
+ + + +Pengujian data
+ +Untuk menetapkan data intent yang diterima, filter intent bisa mendeklarasikan nol atau beberapa elemen +{@code +<data>}. Misalnya:
+ ++<intent-filter> + <data android:mimeType="video/mpeg" android:scheme="http" ... /> + <data android:mimeType="audio/mpeg" android:scheme="http" ... /> + ... +</intent-filter> ++ +
Tiap elemen <data>
+bisa menetapkan struktur URI dan tipe data (tipe media MIME). Ada atribut
+terpisah — {@code scheme}, {@code host}, {@code port},
+dan {@code path} — untuk setiap bagian URI:
+
{@code <scheme>://<host>:<port>/<path>}
+ ++Misalnya: +
+ +{@code content://com.example.project:200/folder/subfolder/etc}
+ +Dalam URI ini, skemanya adalah {@code content}, host-nya adalah {@code com.example.project}, +port-nya adalah {@code 200}, dan path-nya adalah {@code folder/subfolder/etc}. +
+ +Tiap atribut bersifat opsional dalam elemen {@code <data>}, +namun ada dependensi linear:
+-
+
- Jika skema tidak ditetapkan, host akan diabaikan. +
- Jika host tidak ditetapkan, port akan diabaikan. +
- Jika skema dan host tidak ditetapkan, path akan diabaikan. +
Bila URI dalam intent dibandingkan dengan spesifikasi URI dalam filter, +pembandingannya hanya dengan bagian URI yang disertakan dalam filter. Misalnya:
+-
+
- Jika sebuah filter menetapkan hanya satu skema, semua URI dengan skema tersebut akan cocok +dengan filter. +
- Jika sebuah filter menetapkan satu skema dan satu otoritas namun tanpa path, semua URI +dengan skema dan otoritas yang sama akan lolos dari filter, apa pun path-nya. +
- Jika sebuah filter menetapkan satu skema, otoritas dan path, hanya URI dengan skema, +otoritas, dan path sama yang bisa lolos dari filter. +
Catatan: Spesifikasi path bisa berisi +wildcard bintang (*) untuk hanya mencocokkan nama path secara parsial.
+ +Pengujian data membandingkan URI maupun tipe MIME dalam intent dengan URI +dan tipe MIME yang ditetapkan dalam filter. Aturannya adalah sebagai berikut: +
+ +-
+
- Intent yang tidak berisi URI maupun tipe MIME hanya akan lolos +pengujian jika filter tersebut tidak menetapkan URI atau tipe MIME apa pun. + +
- Intent yang berisi URI namun tidak berisi tipe MIME (baik secara eksplisit maupun tidak langsung dari +URI) hanya akan lolos pengujian jika URI-nya cocok dengan format URI filter +dan filternya juga tidak menetapkan tipe MIME. + +
- Intent yang berisi tipe MIME namun tidak berisi URI hanya akan lolos pengujian +jika filter mencantumkan tipe MIME yang sama dan tidak menetapkan format URI. + +
- Intent yang berisi URI maupun tipe MIME (baik secara eksplisit maupun tidak langsung dari +URI) hanya akan lolos pengujian bagian tipe MIME jika +tipe tersebut cocok dengan tipe yang dicantumkan dalam filter. Ini akan lolos pengujian bagian URI +jika URI-nya cocok dengan URI dalam filter atau memiliki {@code content:} +atau URI {@code file:} dan filter tidak menetapkan URI. Dengan kata lain, +komponen dianggap mendukung data {@code content:} dan {@code file:} jika +filternya hanya mencantumkan tipe MIME. +
+Aturan terakhir ini, aturan (d), mencerminkan harapan +bahwa komponen mampu mendapatkan data lokal dari file atau penyedia konten. +Oleh karena itu, filter mereka mencatumkan tipe data saja dan tidak secara eksplisit +harus menamai skema {@code content:} dan {@code file:}. +Ini adalah kasus umum. Elemen {@code <data>} +seperti berikut ini, misalnya, memberi tahu Android bahwa komponen bisa mengambil data gambar dari penyedia +konten dan menampilkannya: +
+ ++<intent-filter> + <data android:mimeType="image/*" /> + ... +</intent-filter>+ +
+Karena sebagian besar data yang tersedia dikeluarkan oleh penyedia konten, filter yang +menetapkan tipe data namun bukan URI mungkin adalah yang paling umum. +
+ ++Konfigurasi umum yang lain adalah filter dengan skema dan tipe data. Misalnya +, elemen {@code <data>} + seperti berikut ini akan memberi tahu Android bahwa +komponen bisa mengambil data video dari jaringan untuk melakukan tindakan: +
+ ++<intent-filter> + <data android:scheme="http" android:type="video/*" /> + ... +</intent-filter>+ + + +
Pencocokan intent
+ +Intent dicocokkan dengan filter intent selain untuk menemukan komponen +target yang akan diaktifkan, juga untuk menemukan sesuatu tentang rangkaian +komponen pada perangkat. Misalnya, aplikasi Home akan menempatkan launcher aplikasi +dengan mencari semua aktivitas dengan filter intent yang menetapkan tindakan +{@link android.content.Intent#ACTION_MAIN} dan +kategori {@link android.content.Intent#CATEGORY_LAUNCHER}.
+ +Aplikasi Anda bisa menggunakan pencocokan intent dengan cara serupa. +{@link android.content.pm.PackageManager} memiliki seperangkat metode {@code query...()} +yang mengembalikan semua komponen yang bisa menerima intent tertentu, dan +serangkaian metode{@code resolve...()} serupa yang menentukan komponen +terbaik untuk merespons intent. Misalnya, +{@link android.content.pm.PackageManager#queryIntentActivities +queryIntentActivities()} akan mengembalikan daftar semua aktivitas yang bisa melakukan +intent yang diteruskan sebagai argumen, dan {@link +android.content.pm.PackageManager#queryIntentServices +queryIntentServices()} akan mengembalikan daftar layanan serupa. +Tidak ada metode yang akan mengaktifkan komponen; mereka hanya mencantumkan komponen yang +bisa merespons. Ada metode serupa, +{@link android.content.pm.PackageManager#queryBroadcastReceivers +queryBroadcastReceivers()}, untuk penerima siaran. +
+ + + + diff --git a/docs/html-intl/intl/in/guide/components/loaders.jd b/docs/html-intl/intl/in/guide/components/loaders.jd new file mode 100644 index 0000000000000000000000000000000000000000..cd0379bf1cd99b5fc97325fad1e8749f07f991d5 --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/loaders.jd @@ -0,0 +1,494 @@ +page.title=Aktivitas +parent.title=Loader +parent.link=activities.html +@jd:body +Dalam dokumen ini
+-
+
- Rangkuman Loader API +
- Menggunakan Loader dalam Aplikasi + + +
- Contoh + + +
Kelas-kelas utama
+-
+
- {@link android.app.LoaderManager} +
- {@link android.content.Loader} + +
Contoh-contoh terkait
+-
+
- +LoaderCursor +
- +LoaderThrottle +
Diperkenalkan di Android 3.0, loader memudahkan pemuatan data asinkron +dalam aktivitas atau fragmen. Loader memiliki karakteristik ini:
+-
+
- Loader tersedia untuk setiap {@link android.app.Activity} dan {@link +android.app.Fragment}. +
- Loader menyediakan pemuatan data asinkron. +
- Loader memantau sumber data mereka dan memberikan hasil baru bila +konten berubah. +
- Loader secara otomatis menghubungkan kembali ke kursor loader lalu saat +dibuat kembali setelah perubahan konfigurasi. Karena itu, loader tidak perlu melakukan query ulang +datanya. +
Rangkuman Loader API
+ +Ada beberapa kelas dan antarmuka yang mungkin dilibatkan dalam menggunakan +loader pada aplikasi. Semuanya dirangkum dalam tabel ini:
+ +Kelas/Antarmuka | +Keterangan | +
---|---|
{@link android.app.LoaderManager} | +Kelas abstrak yang dikaitkan dengan {@link android.app.Activity} atau
+{@link android.app.Fragment} untuk mengelola satu atau beberapa instance {@link
+android.content.Loader}. Ini membantu aplikasi mengelola
+operasi berjalan lebih lama bersamaan dengan daur hidup {@link android.app.Activity}
+atau {@link android.app.Fragment}; penggunaan paling umumnya adalah dengan
+{@link android.content.CursorLoader}, akan tetapi aplikasi bebas menulis loader-nya
+ sendiri untuk memuat tipe data lainnya.
+ + + Hanya ada satu {@link android.app.LoaderManager} per aktivitas atau fragmen. Namun {@link android.app.LoaderManager} bisa memiliki +beberapa loader. |
+
{@link android.app.LoaderManager.LoaderCallbacks} | +Antarmuka callback untuk klien berinteraksi dengan {@link +android.app.LoaderManager}. Misalnya, Anda menggunakan metode callback {@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} +untuk membuat loader baru. | +
{@link android.content.Loader} | +Kelas abstrak yang melakukan pemuatan data asinkron. Ini +adalah kelas dasar untuk loader. Biasanya Anda akan menggunakan {@link +android.content.CursorLoader}, namun Anda bisa menerapkan subkelas sendiri. Selagi +loader aktif, loader harus memantau sumber datanya dan memberikan hasil +baru bila konten berubah. | +
{@link android.content.AsyncTaskLoader} | +Loader abstrak yang menyediakan {@link android.os.AsyncTask} untuk melakukan pekerjaan. | +
{@link android.content.CursorLoader} | +Subkelas {@link android.content.AsyncTaskLoader} yang meng-query +{@link android.content.ContentResolver} dan mengembalikan {@link +android.database.Cursor}. Kelas ini mengimplementasikan protokol {@link +android.content.Loader} dengan cara standar untuk query kursor, +yang dibuat berdasarkan {@link android.content.AsyncTaskLoader} untuk melakukan query kursor +pada thread latar belakang agar tidak memblokir UI aplikasi. Menggunakan loader +ini merupakan cara terbaik untuk memuat data secara asinkron dari {@link +android.content.ContentProvider}, sebagai ganti melakukan query terkelola melalui +fragmen atau API aktivitas. | +
Kelas dan antarmuka dalam tabel di atas merupakan komponen +esensial yang akan Anda gunakan untuk mengimplementasikan loader dalam aplikasi Anda. Anda tidak memerlukan semuanya +untuk setiap loader yang dibuat, namun Anda akan selalu memerlukan acuan ke {@link +android.app.LoaderManager} untuk memulai loader dan implementasi +kelas {@link android.content.Loader} seperti {@link +android.content.CursorLoader}. Bagian berikut ini menunjukkan kepada Anda cara menggunakan +kelas dan antarmuka ini dalam aplikasi.
+ +Menggunakan Loader dalam Aplikasi
+Bagian ini menjelaskan cara menggunakan loader dalam aplikasi Android. Aplikasi +yang menggunakan loader biasanya berisi yang berikut ini:
+-
+
- {@link android.app.Activity} atau {@link android.app.Fragment}. +
- Instance {@link android.app.LoaderManager}. +
- {@link android.content.CursorLoader} akan memuat data yang didukung oleh {@link +android.content.ContentProvider}. Atau, Anda dapat mengimplementasikan subkelas sendiri + dari {@link android.content.Loader} atau {@link android.content.AsyncTaskLoader} untuk +memuat data dari beberapa sumber lain. +
- Implementasi untuk {@link android.app.LoaderManager.LoaderCallbacks}. +Di sinilah Anda membuat loader baru dan mengelola acuan bagi loader +yang ada. +
- Cara menampilkan data loader, seperti {@link +android.widget.SimpleCursorAdapter}. +
- Sumber data, seperti {@link android.content.ContentProvider}, saat menggunakan +{@link android.content.CursorLoader}. +
Memulai Loader
+ +{@link android.app.LoaderManager} mengelola satu atau beberapa instance {@link +android.content.Loader} dalam {@link android.app.Activity} atau +{@link android.app.Fragment}. Hanya ada satu {@link +android.app.LoaderManager} per aktivitas atau fragmen.
+ +Anda biasanya +memulai {@link android.content.Loader} dalam metode {@link +android.app.Activity#onCreate onCreate()} aktivitas, atau dalam metode +{@link android.app.Fragment#onActivityCreated onActivityCreated()} fragmen. Anda +melakukannya dengan cara berikut ini:
+ +// Prepare the loader. Either re-connect with an existing one, +// or start a new one. +getLoaderManager().initLoader(0, null, this);+ +
Metode {@link android.app.LoaderManager#initLoader initLoader()} mengambil +parameter berikut:
+-
+
- ID unik yang mengidentifikasi loader. Dalam contoh ini, ID-nya adalah 0. +
- Argumen opsional untuk dipasok ke loader
+pada saat pembuatan (dalam contoh ini
null
).
+
+ - Implementasi {@link android.app.LoaderManager.LoaderCallbacks}, yang +akan dipanggil {@link android.app.LoaderManager} untuk melaporkan kejadian loader. Dalam contoh +ini, kelas lokal mengimplementasikan antarmuka {@link +android.app.LoaderManager.LoaderCallbacks}, sehingga meneruskan acuan +ke dirinya sendiri, {@code this}. +
Panggilan {@link android.app.LoaderManager#initLoader initLoader()} memastikan bahwa loader +telah dimulai dan aktif. Ia memiliki dua kemungkinan hasil:
+-
+
- Jika loader yang disebutkan oleh ID sudah ada, loader yang dibuat terakhir akan digunakan +kembali. +
- Jika loader yang disebutkan oleh ID tidak ada, +{@link android.app.LoaderManager#initLoader initLoader()} akan memicu metode +{@link android.app.LoaderManager.LoaderCallbacks} {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. +Di sinilah Anda mengimplementasikan kode untuk membuat instance dan mengembalikan loader baru. +Untuk diskusi selengkapnya, lihat bagian onCreateLoader. +
Dalam hal ini, implementasi {@link android.app.LoaderManager.LoaderCallbacks} +yang ditentukan akan dikaitkan dengan loader, dan akan dipanggil bila +status loader berubah. Jika saat panggilan ini status pemanggil sudah +dimulai, dan loader yang diminta sudah ada dan telah menghasilkan +datanya, maka sistem segera memanggil {@link +android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} +(selama {@link android.app.LoaderManager#initLoader initLoader()}), +sehingga Anda harus siap bila hal ini terjadi. Lihat +onLoadFinished untuk diskusi selengkapnya mengenai callback ini
+ +Perhatikan bahwa metode {@link android.app.LoaderManager#initLoader initLoader()} +mengembalikan {@link android.content.Loader} yang dibuat, namun Anda tidak +perlu menangkap acuan ke sana. {@link android.app.LoaderManager} mengelola +masa hidup loader secara otomatis. {@link android.app.LoaderManager} +memulai dan menghentikan pemuatan jika perlu, dan menjaga status loader +dan konten terkaitnya. Seperti yang tersirat di sini, Anda akan jarang berinteraksi dengan loader +secara langsung (meskipun misalnya menggunakan metode loader untuk menyempurnakan perilaku +loader, lihat contoh LoaderThrottle). +Anda paling sering akan menggunakan metode {@link +android.app.LoaderManager.LoaderCallbacks} untuk mengintervensi proses +pemuatan saat terjadi kejadian tertentu. Untuk diskusi selengkapnya mengenai topik ini, lihat Menggunakan Callback LoaderManager.
+ +Me-restart Loader
+ +Bila Anda menggunakan {@link android.app.LoaderManager#initLoader initLoader()}, seperti +ditampilkan di atas, loader yang ada akan digunakan dengan ID yang ditetapkan jika ada. +Jika tidak ada, ID akan dibuat. Namun kadang-kadang Anda perlu membuang data lama +dan mulai dari awal.
+ +Untuk membuang data lama, gunakan {@link +android.app.LoaderManager#restartLoader restartLoader()}. Misalnya, implementasi +{@link android.widget.SearchView.OnQueryTextListener} ini akan me-restart +bila query pengguna berubah. Loader perlu di-restart +agar dapat menggunakan filter pencarian yang telah direvisi untuk melakukan query baru:
+ ++public boolean onQueryTextChanged(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; +}+ +
Menggunakan Callback LoaderManager
+ +{@link android.app.LoaderManager.LoaderCallbacks} adalah antarmuka callback +yang memungkinkan klien berinteraksi dengan {@link android.app.LoaderManager}.
+Loader, khususnya {@link android.content.CursorLoader}, diharapkan +mempertahankan datanya setelah dihentikan. Ini memungkinkan aplikasi mempertahankan +datanya di aktivitas atau metode {@link android.app.Activity#onStop +onStop()} fragmen dan {@link android.app.Activity#onStart onStart()}, sehingga +bila pengguna kembali ke aplikasi, mereka tidak harus menunggu data +dimuat kembali. Anda menggunakan metode {@link android.app.LoaderManager.LoaderCallbacks} +untuk mengetahui waktu membuat loader baru, dan memberi tahu aplikasi kapan +berhenti menggunakan data loader.
+ +{@link android.app.LoaderManager.LoaderCallbacks} berisi metode +ini:
+-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — +Membuat instance dan mengembalikan {@link android.content.Loader} baru untuk ID yang diberikan. +
-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} +— Dipanggil bila loader yang dibuat sebelumnya selesai dimuat. +
-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} + — Dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya +tidak tersedia. + +
Metode ini dijelaskan lebih detail dalam bagian berikutnya.
+ +onCreateLoader
+ +Saat Anda mencoba mengakses loader (misalnya, melalui {@link +android.app.LoaderManager#initLoader initLoader()}), ia akan memeriksa untuk mengetahui adanya +loader yang ditetapkan oleh ID. Jika tidak ada, ia akan memicu metode {@link +android.app.LoaderManager.LoaderCallbacks} {@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Di +sinilah Anda membuat loader baru. Biasanya ini adalah {@link +android.content.CursorLoader}, namun Anda bisa mengimplementasikan sendiri subkelas {@link +android.content.Loader}.
+ +Dalam contoh ini, metode callback {@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} + akan membuat {@link android.content.CursorLoader}. Anda harus membuat +{@link android.content.CursorLoader} menggunakan metode konstruktornya, yang +memerlukan set informasi lengkap untuk melakukan query ke {@link +android.content.ContentProvider}. Secara khusus, ia memerlukan:
+-
+
- uri — URI untuk konten yang akan diambil. +
- projection — Daftar berisi kolom yang akan dikembalikan. Meneruskan
+
null
akan mengembalikan semua kolom, jadi tidak efisien.
+ - selection — Filter yang mendeklarasikan baris yang akan dikembalikan,
+diformat sebagai klausa SQL WHERE (tidak termasuk WHERE itu sendiri). Meneruskan
+
null
akan mengembalikan semua baris untuk URI yang diberikan.
+ - selectionArgs — Anda dapat menyertakan ?s dalam pilihan, yang akan +digantikan dengan nilai dari selectionArgs, agar muncul dalam +pilihan. Nilai-nilai akan diikat sebagai String. +
- sortOrder — Cara menyusun baris, diformat sebagai klausa SQL
+ORDER BY (tidak termasuk ORDER BY itu sendiri). Meneruskan
null
akan +menggunakan urutan sortir default, yang mungkin tidak berurutan.
+
Misalnya:
++ // If non-null, this is the current filter the user has provided. +String mCurFilter; +... +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); +}+
onLoadFinished
+ +Metode ini dipanggil bila loader yang dibuat sebelumnya selesai dimuat. +Metode ini dijamin dipanggil sebelum pelepasan data terakhir +yang disediakan untuk loader ini. Di titik ini Anda harus menyingkirkan semua penggunaan +data lama (karena akan segera dilepas), namun jangan melepas sendiri +data tersebut karena loader memilikinya dan akan menanganinya.
+ + +Loader akan melepas data setelah mengetahui bahwa aplikasi tidak +lagi menggunakannya. Misalnya, jika data adalah kursor dari {@link +android.content.CursorLoader}, Anda tidak boleh memanggil {@link +android.database.Cursor#close close()} sendiri. Jika kursor ditempatkan +dalam {@link android.widget.CursorAdapter}, Anda harus menggunakan metode {@link +android.widget.SimpleCursorAdapter#swapCursor swapCursor()} agar +{@link android.database.Cursor} lama tidak ditutup. Misalnya:
+ ++// This is the Adapter being used to display the list's data.+ +
SimpleCursorAdapter mAdapter; +... + +public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); +}
onLoaderReset
+ +Metode ini dipanggil bila loader yang dibuat sebelumnya sedang di-reset, sehingga datanya +tidak tersedia. Callback ini memungkinkan Anda mengetahui +kapan data akan dilepas sehingga dapat menghapus acuannya ke callback.
+Implementasi ini memanggil
+{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()}
+dengan nilai null
:
+// This is the Adapter being used to display the list's data. +SimpleCursorAdapter mAdapter; +... + +public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); +}+ + +
Contoh
+ +Sebagai contoh, berikut ini adalah implementasi penuh {@link +android.app.Fragment} yang menampilkan {@link android.widget.ListView} berisi +hasil query terhadap penyedia konten kontak. Ia menggunakan {@link +android.content.CursorLoader} untuk mengelola query pada penyedia.
+ +Agar aplikasi dapat mengakses kontak pengguna, seperti yang ditampilkan dalam contoh ini, +manifesnya harus menyertakan izin +{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.
+ ++public static class CursorLoaderListFragment extends ListFragment + implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { + + // This is the Adapter being used to display the list's data. + SimpleCursorAdapter mAdapter; + + // If non-null, this is the current filter the user has provided. + String mCurFilter; + + @Override public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText("No phone numbers"); + + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + // Create an empty adapter we will use to display the loaded data. + mAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_list_item_2, null, + new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, + new int[] { android.R.id.text1, android.R.id.text2 }, 0); + setListAdapter(mAdapter); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // Place an action bar item for searching. + MenuItem item = menu.add("Search"); + item.setIcon(android.R.drawable.ic_menu_search); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + SearchView sv = new SearchView(getActivity()); + sv.setOnQueryTextListener(this); + item.setActionView(sv); + } + + public boolean onQueryTextChange(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; + } + + @Override public boolean onQueryTextSubmit(String query) { + // Don't care about this. + return true; + } + + @Override public void onListItemClick(ListView l, View v, int position, long id) { + // Insert desired behavior here. + Log.i("FragmentComplexList", "Item clicked: " + id); + } + + // These are the Contacts rows that we will retrieve. + static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { + Contacts._ID, + Contacts.DISPLAY_NAME, + Contacts.CONTACT_STATUS, + Contacts.CONTACT_PRESENCE, + Contacts.PHOTO_ID, + Contacts.LOOKUP_KEY, + }; + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); + } + + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + } + + public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } +}+
Contoh Selengkapnya
+ +Ada beberapa contoh berbeda dalam ApiDemos yang +mengilustrasikan cara menggunakan loader:
+-
+
- +LoaderCursor — Versi lengkap dari +cuplikan yang ditampilkan di atas. +
- LoaderThrottle — Contoh cara penggunaan throttling untuk +mengurangi jumlah query dari penyedia konten saat datanya berubah. +
Untuk informasi tentang mengunduh dan menginstal contoh SDK, lihat Mendapatkan +Contoh.
+ diff --git a/docs/html-intl/intl/in/guide/components/processes-and-threads.jd b/docs/html-intl/intl/in/guide/components/processes-and-threads.jd new file mode 100644 index 0000000000000000000000000000000000000000..44051bf492e0acf8eba217fc29d482a48cf90a73 --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/processes-and-threads.jd @@ -0,0 +1,411 @@ +page.title=Proses dan Thread +page.tags=daur hidup,latar belakang + +@jd:body + +Dalam dokumen ini
+-
+
- Proses + + +
- Thread + + +
- Komunikasi antarproses +
Bila komponen aplikasi dimulai dan tidak ada komponen aplikasi lain yang +berjalan, sistem Android akan memulai proses Linux baru untuk aplikasi dengan satu thread +eksekusi. Secara default, semua komponen aplikasi yang sama berjalan dalam proses dan +thread yang sama (disebut thread "utama"). Jika komponen aplikasi dimulai dan sudah ada +proses untuk aplikasi itu (karena komponen lain dari aplikasi itu sudah ada), maka komponen +akan dimulai dalam proses itu dan menggunakan thread eksekusi yang sama. Akan tetapi, Anda bisa +mengatur komponen berbeda di aplikasi agar berjalan di proses terpisah, dan Anda bisa membuat thread tambahan untuk +setiap proses.
+ +Dokumen ini membahas cara kerja proses dan thread di aplikasi Android.
+ + +Proses
+ +Secara default, semua komponen aplikasi yang sama berjalan dalam proses yang sama dan kebanyakan +aplikasi tidak boleh mengubah ini. Akan tetapi, jika Anda merasa perlu mengontrol proses milik +komponen tertentu, Anda dapat melakukannya dalam file manifes.
+ +Entri manifes untuk setiap tipe elemen komponen—{@code +<activity>}, {@code +<service>}, {@code +<receiver>}, dan {@code +<provider>}—mendukung atribut {@code android:process} yang bisa menetapkan +dalam proses mana komponen harus dijalankan. Anda bisa mengatur atribut ini agar setiap komponen +berjalan dalam prosesnya sendiri atau agar beberapa komponen menggunakan proses yang sama sementara yang lainnya tidak. Anda juga bisa mengatur +{@code android:process} agar komponen aplikasi yang berbeda berjalan dalam proses yang sama +—sepanjang aplikasi menggunakan ID Linux yang sama dan ditandatangani +dengan sertifikat yang sama.
+ +Elemen {@code +<application>} juga mendukung atribut {@code android:process}, untuk mengatur +nilai default yang berlaku bagi semua komponen.
+ +Android bisa memutuskan untuk mematikan proses pada waktu tertentu, bila memori tinggal sedikit dan diperlukan oleh +proses lain yang lebih mendesak untuk melayani pengguna. Komponen +aplikasi yang berjalan dalam proses yang dimatikan maka sebagai konsekuensinya juga akan dimusnahkan. Proses dimulai +kembali untuk komponen itu bila ada lagi pekerjaan untuk mereka lakukan.
+ +Saat memutuskan proses yang akan dimatikan, sistem Android akan mempertimbangkan kepentingan relatifnya bagi +pengguna. Misalnya, sistem lebih mudah menghentikan proses yang menjadi host aktivitas yang tidak + lagi terlihat di layar, dibandingkan dengan proses yang menjadi host aktivitas yang terlihat. Karena itu, keputusan +untuk menghentikan proses bergantung pada keadaan komponen yang berjalan dalam proses tersebut. Aturan +yang digunakan untuk menentukan proses yang akan dihentikan dibahas di bawah ini.
+ + +Daur hidup proses
+ +Sistem Android mencoba mempertahankan proses aplikasi selama mungkin, namun +pada akhirnya perlu menghapus proses lama untuk mengambil kembali memori bagi proses baru atau yang lebih penting. Untuk +menentukan proses yang akan +dipertahankan dan yang harus dimatikan, sistem menempatkan setiap proses ke dalam "hierarki prioritas" berdasarkan +komponen yang berjalan dalam proses dan status komponen tersebut. Proses yang memiliki +prioritas terendah akan dimatikan terlebih dahulu, kemudian yang terendah berikutnya, dan seterusnya, jika perlu +untuk memulihkan sumber daya sistem.
+ +Ada lima tingkatan dalam hierarki prioritas. Daftar berikut berisi beberapa +tipe proses berdasarkan urutan prioritas (proses pertama adalah yang terpenting dan +dimatikan terakhir):
+ +-
+
- Proses latar depan
+
Proses yang diperlukan untuk aktivitas yang sedang dilakukan pengguna. Proses +dianggap berada di latar depan jika salah satu kondisi berikut terpenuhi:
+ +-
+
- Proses menjadi host {@link android.app.Activity} yang berinteraksi dengan pengguna dengan metode ({@link +android.app.Activity}{@link android.app.Activity#onResume onResume()} telah +dipanggil). + +
- Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang sedang berinteraksi dengan +pengguna. + +
- Proses menjadi host {@link android.app.Service} yang berjalan "di latar depan"— +layanan telah memanggil{@link android.app.Service#startForeground startForeground()}. + +
- Proses menjadi host {@link android.app.Service} yang menjalankan salah satu callback +daur hidupnya ({@link android.app.Service#onCreate onCreate()}, {@link android.app.Service#onStart +onStart()}, atau {@link android.app.Service#onDestroy onDestroy()}). + +
- Proses menjadi host {@link android.content.BroadcastReceiver} yang menjalankan metode {@link + android.content.BroadcastReceiver#onReceive onReceive()}-nya. +
Secara umum, hanya ada beberapa proses latar depan pada waktu yang diberikan. Proses dimatikan hanya sebagai +upaya terakhir— jika memori hampir habis sehingga semuanya tidak bisa terus berjalan. Pada umumnya, pada +titik itu, perangkat dalam keadaan memory paging, sehingga menghentikan beberapa proses latar depan +diperlukan agar antarmuka pengguna tetap responsif.
+
+ - Proses yang terlihat
+
Proses yang tidak memiliki komponen latar depan, namun masih bisa +memengaruhi apa yang dilihat pengguna di layar. Proses dianggap terlihat jika salah satu kondisi +berikut terpenuhi:
+ +-
+
- Proses ini menjadi host {@link android.app.Activity} yang tidak berada di latar depan, namun masih +terlihat oleh penggunanya (metode {@link android.app.Activity#onPause onPause()} telah dipanggil). +Ini bisa terjadi, misalnya, jika aktivitas latar depan memulai dialog, sehingga +aktivitas sebelumnya terlihat berada di belakangnya. + +
- Proses menjadi host {@link android.app.Service} yang terikat dengan aktivitas yang terlihat (atau latar +depan) +
Proses yang terlihat dianggap sangat penting dan tidak akan dimatikan kecuali jika hal itu +diperlukan agar semua proses latar depan tetap berjalan.
+
+
+ - Proses layanan
+
Proses yang menjalankan layanan yang telah dimulai dengan metode {@link +android.content.Context#startService startService()} dan tidak termasuk dalam salah satu dari dua kategori +yang lebih tinggi. Walaupun proses pelayanan tidak langsung terkait dengan semua yang dilihat oleh pengguna, proses ini +umumnya melakukan hal-hal yang dipedulikan pengguna (seperti memutar musik di latar belakang +atau mengunduh data di jaringan), jadi sistem membuat proses tetap berjalan kecuali memori tidak cukup untuk +mempertahankannya bersama semua proses latar depan dan proses yang terlihat.
+
+
+ - Proses latar belakang
+
Proses yang menampung aktivitas yang saat ini tidak terlihat oleh pengguna (metode +{@link android.app.Activity#onStop onStop()} aktivitas telah dipanggil). Proses ini tidak memiliki dampak +langsung pada pengalaman pengguna, dan sistem bisa menghentikannya kapan saja untuk memperoleh kembali memori bagi +proses latar depan, proses yang terlihat, +atau proses layanan. Biasanya ada banyak proses latar belakang yang berjalan, sehingga disimpan +dalam daftar LRU (least recently used atau paling sedikit digunakan) untuk memastikan bahwa proses dengan aktivitas yang paling baru +terlihat oleh pengguna sebagai yang terakhir untuk dimatikan. Jika aktivitas mengimplementasikan metode + daur hidupnya dengan benar, dan menyimpan statusnya saat ini, menghentikan prosesnya tidak akan memiliki efek +yang terlihat pada pengalaman pengguna, karena ketika pengguna kembali ke aktivitas, aktivitas itu memulihkan +semua statusnya yang terlihat. Lihat dokumen Aktivitas + untuk mendapatkan informasi tentang menyimpan dan memulihkan status.
+
+
+ - Proses kosong
+
Sebuah proses yang tidak berisi komponen aplikasi aktif apa pun. Alasan satu-satunya mempertahankan proses +seperti ini tetap hidup adalah untuk keperluan caching, meningkatkan waktu mulai (startup) bila +nanti komponen perlu dijalankan di dalamnya. Sistem sering menghentikan proses ini untuk menyeimbangkan sumber +daya sistem secara keseluruhan antara proses cache dan cache kernel yang mendasarinya.
+
+
Android sebisa mungkin memeringkat proses setinggi +mungkin, berdasarkan prioritas komponen yang sedang aktif dalam proses. Misalnya, jika suatu proses menjadi host sebuah layanan dan +aktivitas yang terlihat, proses akan diperingkat sebagai proses yang terlihat, bukan sebagai proses layanan.
+ +Selain itu, peringkat proses dapat meningkat karena adanya proses lain yang bergantung padanya +—proses yang melayani proses lain tidak bisa diperingkat lebih rendah daripada proses yang +sedang dilayaninya. Misalnya, jika penyedia konten dalam proses A melayani klien dalam proses B, atau +jika layanan dalam proses A terikat dengan komponen dalam proses B, proses A selalu dipertimbangkan sebagai paling rendah +prioritasnya dibandingkan dengan proses B.
+ +Karena proses yang menjalankan layanan diperingkat lebih tinggi daripada aktivitas latar belakang, +aktivitas yang memulai operasi yang berjalan lama mungkin lebih baik memulai layanan untuk operasi itu, daripada hanya +membuat thread pekerja—khususnya jika operasi mungkin akan berlangsung lebih lama daripada aktivitas. + Misalnya, aktivitas yang mengunggah gambar ke situs web harus memulai layanan +untuk mengunggah sehingga unggahan bisa terus berjalan di latar belakang meskipun pengguna meninggalkan aktivitas tersebut. +Menggunakan layanan akan memastikan operasi paling tidak memiliki prioritas "proses layanan", +apa pun yang terjadi pada aktivitas. Ini menjadi alasan yang sama yang membuat penerima siaran harus +menjalankan layanan daripada hanya menempatkan operasi yang menghabiskan waktu di thread.
+ + + + +Thread
+ +Bila aplikasi diluncurkan, sistem akan membuat thread eksekusi untuk aplikasi tersebut, yang diberi nama, +"main". Thread ini sangat penting karena bertugas mengirim kejadian ke widget +antarmuka pengguna yang sesuai, termasuk kejadian menggambar. Ini juga merupakan thread yang +membuat aplikasi berinteraksi dengan komponen dari Android UI toolkit (komponen dari paket {@link +android.widget} dan {@link android.view}). Karena itu, thread 'main' juga terkadang +disebut thread UI.
+ +Sistem ini tidak membuat thread terpisah untuk setiap instance komponen. Semua +komponen yang berjalan di proses yang sama akan dibuat instance-nya dalam thread UI, dan sistem akan memanggil +setiap komponen yang dikirim dari thread itu. Akibatnya, metode yang merespons callback sistem + (seperti {@link android.view.View#onKeyDown onKeyDown()} untuk melaporkan tindakan pengguna atau metode callback daur hidup) + selalu berjalan di thread UI proses.
+ +Misalnya saat pengguna menyentuh tombol pada layar, thread UI aplikasi akan mengirim kejadian +sentuh ke widget, yang selanjutnya menetapkan status ditekan dan mengirim permintaan yang tidak divalidasi ke +antrean kejadian. Thread UI akan menghapus antrean permintaan dan memberi tahu widget bahwa widget harus menggambar +dirinya sendiri.
+ +Saat aplikasi melakukan pekerjaan intensif sebagai respons terhadap interaksi pengguna, model +thread tunggal ini bisa menghasilkan kinerja yang buruk kecuali jika Anda mengimplementasikan aplikasi dengan benar. Khususnya jika + semua terjadi di thread UI, melakukan operasi yang panjang seperti akses ke jaringan atau query +database akan memblokir seluruh UI. Bila thread diblokir, tidak ada kejadian yang bisa dikirim, +termasuk kejadian menggambar. Dari sudut pandang pengguna, aplikasi +tampak mogok (hang). Lebih buruk lagi, jika thread UI diblokir selama lebih dari beberapa detik +(saat ini sekitar 5 detik) pengguna akan ditampilkan dialog "aplikasi tidak +merespons" (ANR) yang populer karena reputasi buruknya. Pengguna nanti bisa memutuskan untuk keluar dari aplikasi dan menghapus aplikasi +jika mereka tidak suka.
+ +Selain itu, toolkit Android UI bukan thread-safe. Jadi, Anda tidak harus memanipulasi +UI dari thread pekerja—Anda harus melakukan semua manipulasi pada antarmuka pengguna dari thread +UI. Sehingga hanya ada dua aturan untuk model thread tunggal Android:
+ +-
+
- Jangan memblokir thread UI +
- Jangan mengakses toolkit Android UI dari luar thread UI +
Thread pekerja
+ +Karena model thread tunggal yang dijelaskan di atas, Anda dilarang memblokir thread +UI demi daya respons UI aplikasi. Jika memiliki operasi untuk dijalankan +yang tidak seketika, Anda harus memastikan untuk melakukannya di thread terpisah (thread "latar belakang" atau +thread "pekerja").
+ +Misalnya, berikut ini beberapa kode untuk listener klik yang mengunduh gambar dari +thread terpisah dan menampilkannya dalam {@link android.widget.ImageView}:
+ ++public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + Bitmap b = loadImageFromNetwork("http://example.com/image.png"); + mImageView.setImageBitmap(b); + } + }).start(); +} ++ +
Awalnya hal ini tampak bekerja dengan baik, karena menciptakan thread baru untuk menangani +operasi jaringan. Akan tetapi, hal tersebut melanggar aturan kedua model thread tunggal: jangan mengakses + toolkit Android UI dari luar thread UI—sampel ini memodifikasi {@link +android.widget.ImageView} dari thread pekerja sebagai ganti thread UI. Ini bisa +mengakibatkan perilaku yang tidak terdefinisi dan tidak diharapkan, yang bisa menyulitkan dan menghabiskan waktu untuk melacaknya.
+ +Untuk memperbaiki masalah ini, Android menawarkan beberapa cara untuk mengakses thread UI dari +thread lainnya. Berikut ini daftar metode yang bisa membantu:
+ +-
+
- {@link android.app.Activity#runOnUiThread(java.lang.Runnable) +Activity.runOnUiThread(Runnable)} +
- {@link android.view.View#post(java.lang.Runnable) View.post(Runnable)} +
- {@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable, +long)} +
Misalnya, Anda bisa memperbaiki kode di atas dengan menggunakan metode {@link +android.view.View#post(java.lang.Runnable) View.post(Runnable)}:
+ ++public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); + mImageView.post(new Runnable() { + public void run() { + mImageView.setImageBitmap(bitmap); + } + }); + } + }).start(); +} ++ +
Kini implementasi ini thread-safe: operasi jaringan dilakukan terpisah dari thread + sementara {@link android.widget.ImageView} dimanipulasi dari thread UI.
+ +Akan tetapi, karena operasi semakin kompleks, jenis kode seperti ini bisa semakin rumit +dan sulit dipertahankan. Untuk menangani interaksi yang lebih kompleks dengan thread pekerja, Anda bisa mempertimbangkan + penggunaan {@link android.os.Handler}di thread pekerja, untuk memproses pesan yang dikirim dari + thread UI. Mungkin solusi terbaiknya adalah memperpanjang kelas {@link android.os.AsyncTask}, +yang akan menyederhanakan eksekusi tugas-tugas thread pekerja yang perlu berinteraksi dengan UI.
+ + +Menggunakan AsyncTask
+ +Dengan {@link android.os.AsyncTask}, Anda bisa melakukan pekerjaan asinkron pada antarmuka +pengguna. AsyncTask memblokir operasi di thread pekerja kemudian mempublikasikan hasilnya +di thread UI, tanpa mengharuskan Anda untuk menangani sendiri thread dan/atau handler sendiri.
+ +Untuk menggunakannya, Anda harus menempatkan {@link android.os.AsyncTask} sebagai subkelas dan mengimplementasikan metode callback {@link +android.os.AsyncTask#doInBackground doInBackground()} yang berjalan di kumpulan +thread latar belakang. Untuk memperbarui UI, Anda harus mengimplementasikan {@link +android.os.AsyncTask#onPostExecute onPostExecute()}, yang memberikan hasil dari {@link +android.os.AsyncTask#doInBackground doInBackground()} dan berjalan di thread UI, jadi Anda bisa +memperbarui UI dengan aman. Selanjutnya Anda bisa menjalankan tugas dengan memanggil {@link android.os.AsyncTask#execute execute()} +dari thread UI.
+ +Misalnya, Anda bisa mengimplementasikan contoh sebelumnya menggunakan {@link android.os.AsyncTask} dengan cara +ini:
+ ++public void onClick(View v) { + new DownloadImageTask().execute("http://example.com/image.png"); +} + +private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { + /** The system calls this to perform work in a worker thread and + * delivers it the parameters given to AsyncTask.execute() */ + protected Bitmap doInBackground(String... urls) { + return loadImageFromNetwork(urls[0]); + } + + /** The system calls this to perform work in the UI thread and delivers + * the result from doInBackground() */ + protected void onPostExecute(Bitmap result) { + mImageView.setImageBitmap(result); + } +} ++ +
Kini UI aman dan kode jadi lebih sederhana, karena memisahkan pekerjaan ke +dalam bagian-bagian yang harus dilakukan pada thread pekerja dan thread UI.
+ +Anda harus membaca acuan {@link android.os.AsyncTask} untuk memahami sepenuhnya +cara menggunakan kelas ini, namun berikut ini ikhtisar singkat cara kerjanya:
+ +-
+
- Anda bisa menetapkan tipe parameter, nilai kemajuan, dan nilai + akhir tugas, dengan menggunakan generik +
- Metode {@link android.os.AsyncTask#doInBackground doInBackground()} berjalan secara otomatis pada +thread pekerja +
- {@link android.os.AsyncTask#onPreExecute onPreExecute()}, {@link +android.os.AsyncTask#onPostExecute onPostExecute()}, dan {@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()} semuanya dipanggil pada thread UI +
- Nilai yang dikembalikan oleh {@link android.os.AsyncTask#doInBackground doInBackground()} akan dikirim ke +{@link android.os.AsyncTask#onPostExecute onPostExecute()} +
- Anda bisa memangil {@link android.os.AsyncTask#publishProgress publishProgress()} setiap saat di {@link +android.os.AsyncTask#doInBackground doInBackground()} untuk mengeksekusi {@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()} pada thread UI +
- Anda bisa membatalkan tugas ini kapan saja, dari thread mana saja +
Perhatian: Masalah lain yang mungkin Anda temui saat menggunakan +thread pekerja adalah restart tak terduga dalam aktivitas karena perubahan konfigurasi runtime + (seperti saat pengguna mengubah orientasi layar), yang bisa memusnahkan thread pekerja. Untuk +melihat cara mempertahankan tugas selama restart ini dan cara membatalkan +tugas dengan benar saat aktivitas dimusnahkan, lihat kode sumber untuk aplikasi sampel Shelves.
+ + +Metode thread-safe
+ +Dalam beberapa situasi, metode yang Anda implementasikan bisa dipanggil dari lebih dari satu thread, +dan karena itu harus ditulis agar menjadi thread-safe.
+ +Ini terutama terjadi untuk metode yang bisa dipanggil dari jauh —seperti metode dalam layanan terikat. Bila sebuah panggilan pada +metode yang dijalankan dalam {@link android.os.IBinder} berasal dari proses yang sama di mana +{@link android.os.IBinder IBinder} berjalan, metode ini akan dieksekusi di thread pemanggil. +Akan tetapi, bila panggilan berasal proses lain, metode akan dieksekusi dalam thread yang dipilih dari + kumpulan (pool) thread yang dipertahankan sistem dalam proses yang sama seperti{@link android.os.IBinder +IBinder} (tidak dieksekusi dalam thread UI proses). Misalnya, karena metode +{@link android.app.Service#onBind onBind()} layanan akan dipanggil dari thread UI +proses layanan, metode yang diimplementasikan dalam objek yang dikembalikan {@link android.app.Service#onBind +onBind()} (misalnya, subkelas yang mengimplementasikan metode RPC) akan dipanggil dari thread +di pool. Karena layanan bisa memiliki lebih dari satu klien, maka lebih dari satu pool thread bisa melibatkan + metode {@link android.os.IBinder IBinder} yang sama sekaligus. Metode {@link android.os.IBinder +IBinder} karenanya harus diimplementasikan sebagai thread-safe.
+ +Penyedia konten juga bisa menerima permintaan data yang berasal dalam proses lain. +Meskipun kelas {@link android.content.ContentResolver} dan {@link android.content.ContentProvider} + menyembunyikan detail cara komunikasi antarproses dikelola, metode {@link +android.content.ContentProvider} yang merespons permintaan itu—metode {@link +android.content.ContentProvider#query query()}, {@link android.content.ContentProvider#insert +insert()}, {@link android.content.ContentProvider#delete delete()}, {@link +android.content.ContentProvider#update update()}, dan {@link android.content.ContentProvider#getType +getType()}— dipanggil dari pool thread pada proses penyedia konten, bukan thread UI +untuk proses tersebut. Mengingat metode ini bisa dipanggil dari thread mana pun +sekaligus, metode-metode ini juga harus diimplementasikan sebagai thread-safe.
+ + +Komunikasi Antarproses
+ +Android menawarkan mekanisme komunikasi antarproses (IPC) menggunakan panggilan prosedur jauh + (RPC), yang mana metode ini dipanggil oleh aktivitas atau komponen aplikasi lain, namun dieksekusi dari +jauh (di proses lain), bersama hasil yang dikembalikan ke +pemanggil. Ini mengharuskan penguraian panggilan metode dan datanya ke tingkat yang bisa +dipahami sistem operasi, mentransmisikannya dari proses lokal dan ruang alamat untuk proses jauh +dan ruang proses, kemudian merakit kembali dan menetapkannya kembali di sana. Nilai-nilai yang dikembalikan +akan ditransmisikan dalam arah berlawanan. Android menyediakan semua kode untuk melakukan transaksi IPC + ini, sehingga Anda bisa fokus pada pendefinisian dan implementasi antarmuka pemrograman RPC.
+ +Untuk melakukan IPC, aplikasi Anda harus diikat ke layanan, dengan menggunakan {@link +android.content.Context#bindService bindService()}. Untuk informasi selengkapnya, lihat panduan pengembang Layanan.
+ + + diff --git a/docs/html-intl/intl/in/guide/components/recents.jd b/docs/html-intl/intl/in/guide/components/recents.jd new file mode 100644 index 0000000000000000000000000000000000000000..dcfcda7a7d5f9d64e41b392a2eacf7607577f100 --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/recents.jd @@ -0,0 +1,256 @@ +page.title=Layar Ikhtisar +page.tags="recents","overview" + +@jd:body + +Dalam dokumen ini
+-
+
- Menambahkan Tugas ke Layar Ikhtisar + + +
- Menghapus Tugas + + +
Kelas-kelas utama
+-
+
- {@link android.app.ActivityManager.AppTask} +
- {@link android.content.Intent} +
Kode contoh
+ + +Layar ikhtisar (juga disebut sebagai layar terbaru, daftar tugas terbaru, atau aplikasi terbaru) +UI tingkat sistem yang mencantumkan +aktivitas dan tugas yang baru saja diakses. Pengguna +bisa menyusuri daftar ini dan memilih satu tugas untuk dilanjutkan, atau pengguna bisa menghapus tugas dari +daftar dengan gerakan mengusap. Dengan dirilisnya Android 5.0 (API level 21), beberapa instance aktivitas yang +sama yang berisi dokumen berbeda dapat muncul sebagai tugas di layar ikhtisar. Misalnya, +Google Drive mungkin memiliki satu tugas untuk setiap beberapa dokumen Google. Setiap dokumen muncul sebagai +tugas dalam layar ikhtisar.
+ + + + +Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan
+aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.
+Akan tetapi, aplikasi Anda dapat menentukan cara dan waktu munculnya aktivitas di layar ikhtisar. Kelas
+{@link android.app.ActivityManager.AppTask} memungkinkan Anda mengelola tugas, dan flag
+ aktivitas kelas {@link android.content.Intent} memungkinkan Anda menentukan kapan aktivitas ditambahkan atau dihapus dari
+layar ikhtisar. Selain itu, atribut
+<activity>
memungkinkan Anda menetapkan perilaku di manifes.
Menambahkan Tugas ke Layar Ikhtisar
+ +Penggunaan flag kelas {@link android.content.Intent} untuk menambahkan tugas memberi kontrol lebih besar
+atas waktu dan cara dokumen dibuka atau dibuka kembali di layar ikhtisar. Bila menggunakan atribut
+<activity>
+, Anda dapat memilih antara selalu membuka dokumen dalam tugas baru atau menggunakan kembali tugas
+yang ada untuk dokumen tersebut.
Menggunakan flag Intent untuk menambahkan tugas
+ +Bila membuat dokumen baru untuk aktivitas, Anda memanggil metode +{@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()} + dari kelas {@link android.app.ActivityManager.AppTask}, dengan meneruskannya ke intent yang +menjalankan aktivitas tersebut. Untuk menyisipkan jeda logis agar sistem memperlakukan aktivitas Anda sebagai tugas +baru di layar ikhtisar, teruskan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} +dalam metode {@link android.content.Intent#addFlags(int) addFlags()} dari {@link android.content.Intent} +yang memulai aktivitas itu.
+ +Catatan: Flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} +menggantikan flag {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET}, +yang tidak digunakan lagi pada Android 5.0 (API level 21).
+ +Jika Anda menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} saat membuat +dokumen baru, sistem akan selalu membuat tugas baru dengan aktivitas target sebagai akar. +Dengan pengaturan ini, dokumen yang sama dapat dibuka di lebih dari satu tugas. Kode berikut memperagakan +cara aktivitas utama melakukannya:
+ + ++public void createNewDocument(View view) { + final Intent newDocumentIntent = newDocumentIntent(); + if (useMultipleTasks) { + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + } + startActivity(newDocumentIntent); + } + + private Intent newDocumentIntent() { + boolean useMultipleTasks = mCheckbox.isChecked(); + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; + } + + private static int incrementAndGet() { + Log.d(TAG, "incrementAndGet(): " + mDocumentCounter); + return mDocumentCounter++; + } +} ++ +
Catatan: Aktivitas yang dimulai dengan flag {@code FLAG_ACTIVITY_NEW_DOCUMENT} + harus telah menetapkan nilai atribut {@code android:launchMode="standard"} (default) dalam +manifes.
+ +Bila aktivitas utama memulai aktivitas baru, sistem akan mencari tugas yang intent +-nya cocok dengan nama komponen intent dalam tugas-tugas yang sudah ada dan mencari aktivitas dalam data Intent. Jika tugas +tidak ditemukan, atau intent ada dalam flag {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} +, tugas baru akan dibuat dengan aktivitas tersebut sebagai akarnya. Jika ditemukan, sistem akan +mengedepankan tugas itu dan meneruskan intent baru ke {@link android.app.Activity#onNewIntent onNewIntent()}. +Aktivitas baru akan mendapatkan intent dan membuat dokumen baru di layar ikhtisar, seperti dalam +contoh berikut:
+ + ++@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_new_document); + mDocumentCount = getIntent() + .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0); + mDocumentCounterTextView = (TextView) findViewById( + R.id.hello_new_document_text_view); + setDocumentCounterText(R.string.hello_new_document_counter); +} + +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity + is reused to create a new document. + */ + setDocumentCounterText(R.string.reusing_document_counter); +} ++ + +
Menggunakan atribut Aktivitas untuk menambahkan tugas
+ +Aktivitas juga dapat menetapkan dalam manifesnya agar selalu dimulai ke dalam tugas baru dengan menggunakan
+atribut <activity>
+,
+{@code android:documentLaunchMode}. Atribut ini memiliki empat nilai yang menghasilkan efek berikut
+bila pengguna membuka dokumen dengan aplikasi:
-
+
- "{@code intoExisting}" +
- Aktivitas menggunakan kembali tugas yang ada untuk dokumen tersebut. Ini sama dengan mengatur flag + {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} tanpa mengatur flag + {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, seperti dijelaskan dalam + Menggunakan flag Intent untuk menambahkan tugas, di atas. + +
- "{@code always}" +
- Aktivitas ini membuat tugas baru untuk dokumen, meski dokumen sudah dibuka. Menggunakan + nilai ini sama dengan menetapkan flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} + maupun {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. + +
- "{@code none”}" +
- Aktivitas ini tidak membuat tugas baru untuk dokumen. Layar ikhtisar memperlakukan + aktivitas seperti itu secara default: satu tugas ditampilkan untuk aplikasi, yang +dilanjutkan dari aktivitas apa pun yang terakhir dipanggil pengguna. + +
- "{@code never}" +
- Aktivitas ini tidak membuat tugas baru untuk dokumen. Mengatur nilai ini akan mengesampingkan + perilaku flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} + dan {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}, jika salah satunya ditetapkan di +intent, dan layar ikhtisar menampilkan satu tugas untuk aplikasi, yang dilanjutkan dari + aktivitas apa pun yang terakhir dipanggil pengguna. +
Catatan: Untuk nilai selain {@code none} dan {@code never}, +aktivitas harus didefinisikan dengan {@code launchMode="standard"}. Jika atribut ini tidak ditetapkan, maka +{@code documentLaunchMode="none"} akan digunakan.
+ +Menghapus Tugas
+ +Secara default, tugas dokumen secara otomatis dihapus dari layar ikhtisar bila aktivitasnya
+selesai. Anda bisa mengesampingkan perilaku ini dengan kelas {@link android.app.ActivityManager.AppTask},
+dengan flag {@link android.content.Intent} atau atribut
+<activity>
.
Kapan saja Anda bisa mengecualikan tugas dari layar ikhtisar secara keseluruhan dengan menetapkan atribut
+<activity>
+,
+{@code android:excludeFromRecents} hingga {@code true}.
Anda bisa menetapkan jumlah maksimum tugas yang dapat disertakan aplikasi Anda dalam layar ikhtisar dengan menetapkan
+atribut <activity>
+ {@code android:maxRecents}
+ ke satu nilai integer. Nilai default-nya adalah 16. Bila telah mencapai jumlah maksimum, tugas yang terakhir
+digunakan akan dihapus dari layar ikhtisar. Nilai maksimum {@code android:maxRecents}
+ adalah 50 (25 pada perangkat dengan memori sedikit); nilai yang kurang dari 1 tidak berlaku.
Menggunakan kelas AppTask untuk menghapus tugas
+ +Dalam aktivitas yang membuat tugas baru di layar ikhtisar, Anda bisa +menetapkan kapan menghapus tugas dan menyelesaikan semua aktivitas yang terkait dengannya +dengan memanggil metode {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()}.
+ + ++public void onRemoveFromRecents(View view) { + // The document is no longer needed; remove its task. + finishAndRemoveTask(); +} ++ +
Catatan: Penggunaan metode +{@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()} +akan mengesampingkan penggunaan tag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, seperti +dibahas di bawah ini.
+ +Mempertahankan tugas yang telah selesai
+ +Jika Anda ingin mempertahankan tugas di layar ikhtisar, sekalipun aktivitas sudah selesai, teruskan +flag {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} dalam metode +{@link android.content.Intent#addFlags(int) addFlags()} dari Intent yang memulai aktivitas itu.
+ + ++private Intent newDocumentIntent() { + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; +} ++ +
Untuk memperoleh efek yang sama, tetapkan atribut
+<activity>
+
+{@code android:autoRemoveFromRecents} hingga {@code false}. Nilai default-nya adalah {@code true}
+untuk aktivitas dokumen, dan {@code false} untuk aktivitas biasa. Penggunaan atribut ini akan mengesampingkan flag
+{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}, yang telah dibahas sebelumnya.
-
+
- Dasar-Dasar + +
- Membuat Layanan yang Sudah Dimulai + + +
- Membuat Layanan Terikat +
- Mengirim Pemberitahuan ke Pengguna +
- Menjalankan Layanan di Latar Depan +
- Mengelola Daur Hidup Layanan + + +
- {@link android.app.Service} +
- {@link android.app.IntentService} +
Dalam dokumen ini
+-
+
Kelas-kelas utama
+-
+
Contoh
+ + +Lihat juga
+ + +{@link android.app.Service} adalah sebuah komponen aplikasi yang bisa melakukan +operasi yang berjalan lama di latar belakang dan tidak menyediakan antarmuka pengguna. Komponen +aplikasi lain bisa memulai layanan dan komponen aplikasi tersebut akan terus berjalan +di latar belakang walaupun pengguna beralih ke aplikasi lain. Selain itu, komponen bisa mengikat ke layanan +untuk berinteraksi dengannya dan bahkan melakukan komunikasi antarproses (IPC). Misalnya, layanan mungkin +menangani transaksi jaringan, memutar musik, melakukan file I/O, atau berinteraksi dengan penyedia konten +dari latar belakang.
+ +Ada dua bentuk dasar layanan:
+ +-
+
- Sudah Dimulai +
- Layanan "sudah dimulai" bila komponen aplikasi (misalnya aktivitas) memulainya dengan +memanggil {@link android.content.Context#startService startService()}. Sesudah dimulai, layanan +bisa berjalan terus-menerus di latar belakang walaupun komponen yang memulainya telah dimusnahkan. Biasanya, +layanan yang sudah dimulai akan melakukan operasi tunggal dan tidak mengembalikan hasil ke pemanggilnya. +Misalnya, layanan bisa mengunduh atau mengunggah file melalui jaringan. Bila operasi selesai, +layanan seharusnya berhenti sendiri. +
- Terikat +
- Layanan "terikat" bila komponen aplikasi mengikat kepadanya dengan memanggil {@link +android.content.Context#bindService bindService()}. Layanan terikat menawarkan antarmuka +klien-server yang memungkinkan komponen berinteraksi dengan layanan tersebut, mengirim permintaan, mendapatkan hasil dan bahkan +melakukannya pada sejumlah proses dengan komunikasi antarproses (IPC). Layanan terikat hanya berjalan selama +ada komponen aplikasi lain yang terikat padanya. Sejumlah komponen bisa terikat pada layanan secara bersamaan, +namun bila semuanya melepas ikatan, layanan tersebut akan dimusnahkan. +
Walaupun dokumentasi ini secara umum membahas kedua jenis layanan secara terpisah, layanan +Anda bisa menggunakan keduanya—layanan bisa dimulai (untuk berjalan terus-menerus) sekaligus memungkinkan pengikatan. +Cukup mengimplementasikan dua metode callback: {@link +android.app.Service#onStartCommand onStartCommand()} untuk memungkinkan komponen memulainya dan {@link +android.app.Service#onBind onBind()} untuk memungkinkan pengikatan.
+ +Apakah aplikasi Anda sudah dimulai, terikat, atau keduanya, semua komponen aplikasi +bisa menggunakan layanan (bahkan dari aplikasi terpisah), demikian pula semua komponen bisa menggunakan +suatu aktivitas—dengan memulainya dengan {@link android.content.Intent}. Akan tetapi, Anda bisa mendeklarasikan +layanan sebagai privat, pada file manifes, dan memblokir akses dari aplikasi lain. Hal ini +dibahas selengkapnya di bagian tentang Mendeklarasikan layanan dalam +manifes.
+ +Perhatian: Layanan berjalan di +thread utama proses yang menjadi host-nya—layanan tidak membuat thread-nya sendiri +dan tidak berjalan pada proses terpisah (kecuali bila Anda tentukan demikian). Artinya, +jika layanan Anda akan melakukan pekerjaan yang membutuhkan tenaga CPU besar atau operasi yang memblokir (seperti +pemutaran MP3 atau jaringan), Anda perlu membuat thread baru dalam layanan untuk melakukan pekerjaan tersebut. Dengan menggunakan +thread terpisah, Anda mengurangi risiko terjadinya kesalahan Aplikasi Tidak Merespons (Application Not Responding/ANR) dan +thread utama aplikasi bisa tetap dikhususkan pada interaksi pengguna dengan aktivitas Anda.
+ + +Dasar-Dasar
+ +Haruskah menggunakan layanan atau thread?
+Layanan sekadar komponen yang bisa berjalan di latar belakang walaupun pengguna sedang tidak +berinteraksi dengan aplikasi Anda. Sehingga, Anda harus membuat layanan bila memang itu +yang dibutuhkan.
+Bila Anda perlu melakukan pekerjaan di luar thread utama, namun hanya bila pengguna sedang berinteraksi +dengan aplikasi, maka Anda harus membuat thread baru sebagai ganti layanan baru. Misalnya, +bila Anda ingin memutar musik, namun hanya saat aktivitas Anda berjalan, Anda bisa membuat +thread dalam {@link android.app.Activity#onCreate onCreate()}, mulai menjalankannya di {@link +android.app.Activity#onStart onStart()}, kemudian menghentikannya di {@link android.app.Activity#onStop +onStop()}. Pertimbangkan juga untuk menggunakan {@link android.os.AsyncTask} atau {@link android.os.HandlerThread}, +sebagai ganti kelas {@link java.lang.Thread} yang lazim digunakan. Lihat dokumen Proses dan +Threading untuk informasi selengkapnya tentang thread.
+Ingatlah jika menggunakan layanan, layanan tersebut tetap berjalan di thread utama aplikasi Anda secara +default, jadi Anda harus tetap membuat thread baru dalam layanan bila layanan tersebut melakukan operasi yang intensif +atau operasi yang memblokir.
+Untuk membuat layanan, Anda harus membuat subkelas {@link android.app.Service} (atau +salah satu dari subkelasnya yang ada). Dalam implementasi, Anda perlu mengesampingkan sebagian metode callback yang +menangani aspek utama daur hidup layanan dan memberikan mekanisme bagi komponen untuk mengikat +pada layanan, bila dibutuhkan. Metode callback terpenting yang perlu Anda kesampingkan adalah:
+ +-
+
- {@link android.app.Service#onStartCommand onStartCommand()} +
- Sistem akan memanggil metode ini bila komponen lain, misalnya aktivitas, +meminta dimulainya layanan, dengan memanggil {@link android.content.Context#startService +startService()}. Setelah metode ini dieksekusi, layanan akan dimulai dan bisa berjalan di +latar belakang terus-menerus. Jika mengimplementasikan ini, Anda bertanggung jawab menghentikan layanan bila +bila pekerjaannya selesai, dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau {@link +android.content.Context#stopService stopService()}. (Jika hanya ingin menyediakan pengikatan, Anda tidak +perlu mengimplementasikan metode ini.) +
- {@link android.app.Service#onBind onBind()} +
- Sistem akan memanggil metode ini bila komponen lain ingin mengikat pada +layanan (misalnya untuk melakukan RPC), dengan memanggil {@link android.content.Context#bindService +bindService()}. Dalam mengimplementasikan metode ini, Anda harus menyediakan antarmuka yang digunakan +klien untuk berkomunikasi dengan layanan, dengan mengembalikan {@link android.os.IBinder}. Anda harus selalu +mengimplementasikan metode ini, namun jika tidak ingin mengizinkan pengikatan, Anda perlu mengembalikan null. +
- {@link android.app.Service#onCreate()} +
- Sistem memanggil metode ini bila layanan dibuat untuk pertama kalinya, untuk melakukan prosedur +penyiapan satu kali (sebelum memanggil {@link android.app.Service#onStartCommand onStartCommand()} atau +{@link android.app.Service#onBind onBind()}). Bila layanan sudah berjalan, metode ini tidak +dipanggil. +
- {@link android.app.Service#onDestroy()} +
- Sistem memanggil metode ini bila layanan tidak lagi digunakan dan sedang dimusnahkan. +Layanan Anda perlu mengimplementasikannya untuk membersihkan sumber daya seperti thread, listener +terdaftar, penerima, dll. Ini adalah panggilan terakhir yang diterima layanan. +
Bila komponen memulai layanan dengan memanggil {@link +android.content.Context#startService startService()} (yang menyebabkan panggilan ke {@link +android.app.Service#onStartCommand onStartCommand()}), maka layanan +terus berjalan hingga terhenti sendiri dengan {@link android.app.Service#stopSelf()} atau bila komponen +lain menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.
+ +Bila komponen memanggil +{@link android.content.Context#bindService bindService()} untuk membuat layanan (dan {@link +android.app.Service#onStartCommand onStartCommand()} tidak dipanggil), maka layanan hanya berjalan +selama komponen terikat kepadanya. Setelah layanan dilepas ikatannya dari semua klien, +sistem akan menghancurkannya.
+ +Sistem Android akan menghentikan paksa layanan hanya bila memori tinggal sedikit dan sistem harus memulihkan +sumber daya sistem untuk aktivitas yang mendapatkan fokus pengguna. Jika layanan terikat pada suatu aktivitas yang mendapatkan +fokus pengguna, layanan tersebut lebih kecil kemungkinannya untuk dimatikan, dan jika layanan dideklarasikan untuk berjalan di latar depan (akan dibahas kemudian), maka sudah hampir pasti ia tidak akan dimatikan. +Sebaliknya, bila layanan sudah dimulai dan berjalan lama, maka sistem akan menurunkan posisinya +dalam daftar tugas latar belakang seiring waktu dan layanan akan sangat rentan untuk +dimatikan—bila layanan Anda dimulai, maka Anda harus mendesainnya agar bisa menangani restart +oleh sistem dengan baik. Jika sistem mematikan layanan Anda, layanan akan dimulai kembali begitu sumber daya +kembali tersedia (tetapi ini juga bergantung pada nilai yang Anda kembalikan dari {@link +android.app.Service#onStartCommand onStartCommand()}, sebagaimana akan dibahas nanti). Untuk informasi selengkapnya +tentang kapan sistem mungkin akan memusnahkan layanan, lihat dokumen +Proses dan Threading.
+ +Dalam bagian selanjutnya, Anda akan melihat bagaimana membuat masing-masing tipe layanan dan cara menggunakannya +dari komponen aplikasi lain.
+ + + +Mendeklarasikan layanan dalam manifes
+ +Sebagaimana aktivitas (dan komponen lainnya), Anda harus mendeklarasikan semua layanan dalam file manifes +aplikasi Anda.
+ +Untuk mendeklarasikan layanan Anda, tambahkan sebuah elemen {@code <service>} +sebagai anak +elemen {@code <application>}. Misalnya:
+ ++<manifest ... > + ... + <application ... > + <service android:name=".ExampleService" /> + ... + </application> +</manifest> ++ +
Lihat acuan elemen {@code <service>} +untuk informasi selengkapnya tentang cara mendeklarasikan layanan Anda dalam manifes.
+ +Ada atribut lain yang bisa Anda sertakan dalam elemen {@code <service>} untuk +mendefinisikan properti seperti izin yang dibutuhkan untuk memulai layanan dan proses +tempat berjalannya layanan. {@code android:name} adalah satu-satunya atribut yang diperlukan +—atribut tersebut menetapkan nama kelas layanan. Setelah +mempublikasikan aplikasi, Anda tidak boleh mengubah nama ini, karena jika melakukannya, Anda bisa merusak +kode karena dependensi terhadap intent eksplisit untuk memulai atau mengikat layanan (bacalah posting blog berjudul Things +That Cannot Change). + +
Untuk memastikan aplikasi Anda aman, selalu gunakan intent eksplisit saat memulai atau mengikat +{@link android.app.Service} Anda dan jangan mendeklarasikan filter intent untuk layanan. Jika +Anda perlu membiarkan adanya ambiguitas tentang layanan mana yang dimulai, Anda bisa +menyediakan filter intent bagi layanan dan tidak memasukkan nama komponen pada {@link +android.content.Intent}, namun Anda juga harus menyesuaikan paket bagi intent tersebut dengan {@link +android.content.Intent#setPackage setPackage()}, yang memberikan klarifikasi memadai bagi +target layanan.
+ +Anda juga bisa memastikan layanan tersedia hanya bagi aplikasi Anda dengan +menyertakan atribut {@code android:exported} +dan mengaturnya ke {@code "false"}. Hal ini efektif menghentikan aplikasi lain agar tidak memulai +layanan Anda, bahkan saat menggunakan intent eksplisit.
+ + + + +Membuat Layanan yang Sudah Dimulai
+ +Layanan yang sudah dimulai adalah layanan yang dimulai komponen lain dengan memanggil {@link +android.content.Context#startService startService()}, yang menyebabkan panggilan ke metode +{@link android.app.Service#onStartCommand onStartCommand()} layanan.
+ +Bila layanan sudah dimulai, layanan tersebut memiliki daur hidup yang tidak bergantung pada +komponen yang memulainya dan bisa berjalan terus-menerus di latar belakang walaupun +komponen yang memulainya dimusnahkan. Dengan sendirinya, layanan akan berhenti sendiri bila pekerjaannya +selesai dengan memanggil {@link android.app.Service#stopSelf stopSelf()}, atau komponen lain bisa menghentikannya +dengan memanggil {@link android.content.Context#stopService stopService()}.
+ +Komponen aplikasi seperti aktivitas bisa memulai layanan dengan memanggil {@link +android.content.Context#startService startService()} dan meneruskan {@link android.content.Intent} +yang menetapkan layanan dan menyertakan data untuk digunakan layanan. Layanan menerima +{@link android.content.Intent} ini dalam metode {@link android.app.Service#onStartCommand +onStartCommand()}.
+ +Sebagai contoh, anggaplah aktivitas perlu menyimpan data ke database online. Aktivitas tersebut bisa +memulai layanan pendamping dan mengiriminya data untuk disimpan dengan meneruskan intent ke {@link +android.content.Context#startService startService()}. Layanan akan menerima intent dalam {@link +android.app.Service#onStartCommand onStartCommand()}, menghubungkan ke Internet dan melakukan +transaksi database. Bila transaksi selesai, layanan akan berhenti sendiri dan +dimusnahkan.
+ +Perhatian: Layanan berjalan dalam proses yang sama dengan aplikasi +tempatnya dideklarasikan dan dalam thread utama aplikasi tersebut, secara default. Jadi, bila layanan Anda +melakukan operasi yang intensif atau operasi pemblokiran saat pengguna berinteraksi dengan aktivitas dari +aplikasi yang sama, layanan akan memperlambat kinerja aktivitas. Agar tidak memengaruhi +kinerja aplikasi, Anda harus memulai thread baru di dalam layanan.
+ +Biasanya, ada dua kelas yang bisa Anda perluas untuk membuat layanan yang sudah dimulai:
+-
+
- {@link android.app.Service} +
- Ini adalah kelas dasar untuk semua layanan. Bila memperluas kelas ini, Anda perlu +membuat thread baru sebagai tempat melaksanakan semua pekerjaan layanan tersebut, karena layanan +menggunakan thread utama aplikasi Anda secara default, dan hal ini bisa memperlambat +kinerja aktivitas yang dijalankan aplikasi Anda. +
- {@link android.app.IntentService} +
- Ini adalah subkelas {@link android.app.Service} yang menggunakan thread pekerja untuk menangani +semua permintaan memulai, satu per satu. Ini adalah pilihan terbaik jika Anda tidak mengharuskan layanan +menangani beberapa permintaan sekaligus. Anda cukup mengimplementasikan {@link +android.app.IntentService#onHandleIntent onHandleIntent()}, yang menerima intent untuk setiap +permintaan memulai agar bisa melakukan pekerjaan latar belakang. +
Bagian selanjutnya membahas cara mengimplementasikan layanan Anda menggunakan +salah satu dari kelas-kelas ini.
+ + +Memperluas kelas IntentService
+ +Mengingat kebanyakan layanan yang sudah dimulai tidak perlu menangani beberapa permintaan +sekaligus (yang bisa berupa skenario multi-threading berbahaya), mungkin Anda sebaiknya mengimplementasikan +layanan menggunakan kelas {@link android.app.IntentService}.
+ +Berikut ini yang dilakukan {@link android.app.IntentService}:
+ +-
+
- Membuat thread pekerja default yang menjalankan semua intent yang disampaikan ke {@link +android.app.Service#onStartCommand onStartCommand()} terpisah dari thread utama aplikasi +Anda. +
- Membuat antrean pekerjaan yang meneruskan intent satu per satu ke implementasi {@link +android.app.IntentService#onHandleIntent onHandleIntent()}, sehingga Anda tidak perlu +mengkhawatirkan multi-threading. +
- Menghentikan layanan setelah semua permintaan memulai telah ditangani, jadi Anda tidak perlu memanggil +{@link android.app.Service#stopSelf}. +
- Menyediakan implementasi default {@link android.app.IntentService#onBind onBind()} yang +mengembalikan null. +
- Menyediakan implementasi default {@link android.app.IntentService#onStartCommand +onStartCommand()} yang mengirimkan intent ke antrean pekerjaan kemudian ke implementasi {@link +android.app.IntentService#onHandleIntent onHandleIntent()} Anda. +
Oleh karena itu, Anda hanya perlu mengimplementasikan {@link +android.app.IntentService#onHandleIntent onHandleIntent()} untuk melakukan pekerjaan yang diberikan oleh +klien. (Akan tetapi, Anda juga perlu menyediakan konstruktor kecil bagi layanan.)
+ +Berikut ini contoh implementasi {@link android.app.IntentService}:
+ ++public class HelloIntentService extends IntentService { + + /** + * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} + * constructor with a name for the worker thread. + */ + public HelloIntentService() { + super("HelloIntentService"); + } + + /** + * The IntentService calls this method from the default worker thread with + * the intent that started the service. When this method returns, IntentService + * stops the service, as appropriate. + */ + @Override + protected void onHandleIntent(Intent intent) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + } +} ++ +
Anda hanya memerlukan: konstruktor dan implementasi {@link +android.app.IntentService#onHandleIntent onHandleIntent()}.
+ +Jika Anda memutuskan untuk juga mengesampingkan metode callback lain, seperti {@link +android.app.IntentService#onCreate onCreate()}, {@link +android.app.IntentService#onStartCommand onStartCommand()}, atau {@link +android.app.IntentService#onDestroy onDestroy()}, pastikan memanggil implementasi super, sehingga +{@link android.app.IntentService} bisa menangani hidup thread pekerja dengan baik.
+ +Misalnya, {@link android.app.IntentService#onStartCommand onStartCommand()} harus mengembalikan +implementasi default (yang merupakan cara penyampaian intent ke {@link +android.app.IntentService#onHandleIntent onHandleIntent()}):
+ ++@Override +public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + return super.onStartCommand(intent,flags,startId); +} ++ +
Selain {@link android.app.IntentService#onHandleIntent onHandleIntent()}, satu-satunya metode lain +yang tidak mengharuskan Anda memanggil super kelas adalah {@link android.app.IntentService#onBind +onBind()} (namun Anda hanya perlu mengimplementasikannya bila layanan mengizinkan pengikatan).
+ +Dalam bagian berikutnya, Anda akan melihat bagaimana layanan serupa diimplementasikan saat +memperluas kelas {@link android.app.Service} basis, yang membutuhkan kode lebih banyak lagi, namun mungkin +cocok jika Anda perlu menangani beberapa permintaan memulai sekaligus.
+ + +Memperluas kelas Layanan
+ +Seperti telah Anda lihat di bagian sebelumnya, menggunakan {@link android.app.IntentService} membuat +implementasi layanan yang sudah dimulai jadi sangat sederhana. Namun, bila Anda mengharuskan layanan untuk +melakukan multi-threading (sebagai ganti memproses permintaan memulai melalui antrean pekerjaan), maka Anda +bisa memperluas kelas {@link android.app.Service} untuk menangani masing-masing intent.
+ +Sebagai perbandingan, contoh kode berikut ini adalah implementasi kelas {@link +android.app.Service} yang melakukan pekerjaan yang persis sama dengan contoh di atas menggunakan {@link +android.app.IntentService}. Artinya, untuk setiap permintaan memulai, kode tersebut akan menggunakan thread pekerja +untuk melakukan pekerjaan dan memproses permintaan satu per satu.
+ ++public class HelloService extends Service { + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, restart + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + } +} ++ +
Seperti yang bisa Anda lihat, ini membutuhkan lebih banyak pekerjaan daripada menggunakan {@link android.app.IntentService}.
+ +Akan tetapi, karena Anda menangani sendiri setiap panggilan ke {@link android.app.Service#onStartCommand +onStartCommand()}, Anda bisa melakukan beberapa permintaan sekaligus. Itu bukan yang +dilakukan contoh ini, namun jika itu yang diinginkan, Anda bisa membuat thread baru untuk setiap +permintaan dan langsung menjalankannya (sebagai ganti menunggu permintaan sebelumnya selesai).
+ +Perhatikan bahwa metode {@link android.app.Service#onStartCommand onStartCommand()} harus mengembalikan +integer. Integer tersebut merupakan nilai yang menjelaskan cara sistem melanjutkan layanan dalam +kejadian yang dimatikan oleh sistem (sebagaimana dibahas di atas, implementasi default {@link +android.app.IntentService} menangani hal ini untuk Anda, walaupun Anda bisa memodifikasinya). Nilai yang dikembalikan +dari {@link android.app.Service#onStartCommand onStartCommand()} harus berupa salah satu +konstanta berikut ini:
+ +-
+
- {@link android.app.Service#START_NOT_STICKY} +
- Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand +onStartCommand()} dikembalikan, jangan membuat lagi layanan tersebut, kecuali jika ada intent +tertunda yang akan disampaikan. Inilah pilihan teraman untuk menghindari menjalankan layanan Anda +bila tidak diperlukan dan bila aplikasi Anda bisa me-restart pekerjaan yang belum selesai. +
- {@link android.app.Service#START_STICKY} +
- Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand +onStartCommand()} dikembalikan, buat kembali layanan dan panggil {@link +android.app.Service#onStartCommand onStartCommand()}, namun jangan menyampaikan ulang intent terakhir. +Sebagai gantinya, sistem akan memanggil {@link android.app.Service#onStartCommand onStartCommand()} dengan +intent null, kecuali jika ada intent tertunda untuk memulai layanan, dan dalam hal ini, +intent tersebut disampaikan. Ini cocok bagi pemutar media (atau layanan serupa) yang tidak +mengeksekusi perintah, namun berjalan terus-menerus dan menunggu pekerjaan. +
- {@link android.app.Service#START_REDELIVER_INTENT} +
- Jika sistem mematikan layanan setelah {@link android.app.Service#onStartCommand +onStartCommand()} kembali, buat kembali layanan dan panggil {@link +android.app.Service#onStartCommand onStartCommand()} dengan intent terakhir yang disampaikan ke +layanan. Intent yang tertunda akan disampaikan pada gilirannya. Ini cocok bagi layanan yang +aktif melakukan pekerjaan yang harus segera dilanjutkan, misalnya mengunduh file. +
Untuk detail selengkapnya tentang nilai pengembalian ini, lihat dokumentasi acuan untuk setiap +konstanta.
+ + + +Memulai Layanan
+ +Anda bisa memulai layanan dari aktivitas atau komponen aplikasi lain dengan meneruskan +{@link android.content.Intent} (yang menetapkan layanan yang akan dimulai) ke {@link +android.content.Context#startService startService()}. Sistem Android akan memanggil metode {@link +android.app.Service#onStartCommand onStartCommand()} layanan dan meneruskan {@link +android.content.Intent} padanya. (Jangan sekali-kali memanggil {@link android.app.Service#onStartCommand +onStartCommand()} secara langsung.)
+ +Misalnya, aktivitas bisa memulai contoh layanan di bagian sebelumnya ({@code +HelloSevice}) menggunakan intent eksplisit dengan {@link android.content.Context#startService +startService()}:
+ ++Intent intent = new Intent(this, HelloService.class); +startService(intent); ++ +
Metode {@link android.content.Context#startService startService()} segera kembali dan +sistem Android akan memanggil metode {@link android.app.Service#onStartCommand +onStartCommand()} layanan. Jika layanan belum berjalan, sistem mula-mula memanggil {@link +android.app.Service#onCreate onCreate()}, kemudian memanggil {@link android.app.Service#onStartCommand +onStartCommand()}.
+ +Jika layanan juga tidak menyediakan pengikatan, intent yang disampaikan dengan {@link +android.content.Context#startService startService()} adalah satu-satunya mode komunikasi antara +komponen aplikasi dan layanan. Akan tetapi, jika Anda ingin agar layanan mengirimkan hasilnya kembali, maka +klien yang memulai layanan bisa membuat {@link android.app.PendingIntent} untuk siaran +(dengan {@link android.app.PendingIntent#getBroadcast getBroadcast()}) dan menyampaikannya ke layanan +dalam {@link android.content.Intent} yang memulai layanan. Layanan kemudian bisa menggunakan +siaran untuk menyampaikan hasil.
+ +Beberapa permintaan untuk memulai layanan menghasilkan beberapa panggilan pula ke +{@link android.app.Service#onStartCommand onStartCommand()} layanan. Akan tetapi, hanya satu permintaan untuk menghentikan +layanan (dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link +android.content.Context#stopService stopService()}) dibutuhkan untuk menghentikannya.
+ + +Menghentikan layanan
+ +Layanan yang sudah dimulai harus mengelola daur hidupnya sendiri. Artinya, sistem tidak menghentikan atau +memusnahkan layanan kecuali jika harus memulihkan memori sistem dan layanan +terus berjalan setelah {@link android.app.Service#onStartCommand onStartCommand()} kembali. Jadi, +layanan tersebut harus berhenti sendiri dengan memanggil {@link android.app.Service#stopSelf stopSelf()} atau +komponen lain bisa menghentikannya dengan memanggil {@link android.content.Context#stopService stopService()}.
+ +Setelah diminta untuk berhenti dengan {@link android.app.Service#stopSelf stopSelf()} atau {@link +android.content.Context#stopService stopService()}, sistem akan menghapus layanan +secepatnya.
+ +Akan tetapi, bila layanan Anda menangani beberapa permintaan ke {@link
+android.app.Service#onStartCommand onStartCommand()} sekaligus, Anda tidak boleh menghentikan
+layanan bila Anda baru selesai memproses permintaan memulai, karena setelah itu mungkin Anda sudah menerima permintaan memulai
+yang baru (berhenti pada permintaan pertama akan menghentikan permintaan kedua). Untuk menghindari
+masalah ini, Anda bisa menggunakan {@link android.app.Service#stopSelf(int)} untuk memastikan bahwa permintaan
+Anda untuk menghentikan layanan selalu berdasarkan pada permintaan memulai terbaru. Artinya, bila Anda memanggil {@link
+android.app.Service#stopSelf(int)}, Anda akan meneruskan ID permintaan memulai (startId
+yang disampaikan ke {@link android.app.Service#onStartCommand onStartCommand()}) yang terkait dengan permintaan berhenti
+Anda. Kemudian jika layanan menerima permintaan memulai baru sebelum Anda bisa memanggil {@link
+android.app.Service#stopSelf(int)}, maka ID tidak akan sesuai dan layanan tidak akan berhenti.
Perhatian: Aplikasi Anda perlu menghentikan layanannya +bila selesai bekerja untuk menghindari pemborosan sumber daya sistem dan tenaga baterai. Jika perlu, +komponen lain bisa menghentikan layanan secara eksplisit dengan memanggil {@link +android.content.Context#stopService stopService()}. Bahkan jika Anda mengaktifkan pengikatan bagi layanan, +Anda harus selalu menghentikan layanan sendiri jika layanan tersebut menerima panggilan ke {@link +android.app.Service#onStartCommand onStartCommand()}.
+ +Untuk informasi selengkapnya tentang daur hidup layanan, lihat bagian di bawah ini tentang Mengelola Daur Hidup Layanan.
+ + + +Membuat Layanan Terikat
+ +Layanan terikat adalah layanan yang memungkinkan komponen aplikasi untuk mengikatnya dengan memanggil {@link +android.content.Context#bindService bindService()} guna membuat koneksi yang berlangsung lama +(dan umumnya tidak mengizinkan komponen untuk memulainya dengan memanggil {@link +android.content.Context#startService startService()}).
+ +Anda sebaiknya membuat layanan terikat bila ingin berinteraksi dengan layanan dari aktivitas +dan komponen lain dalam aplikasi Anda atau mengeskpos sebagian fungsionalitas aplikasi Anda ke +ke aplikasi lain, melalui komunikasi antarproses (IPC).
+ +Untuk membuat layanan terikat, Anda harus mengimplementasikan metode callback {@link +android.app.Service#onBind onBind()} untuk mengembalikan {@link android.os.IBinder} yang +mendefinisikan antarmuka bagi komunikasi dengan layanan. Komponen aplikasi lain kemudian bisa memanggil +{@link android.content.Context#bindService bindService()} untuk mengambil antarmuka dan +mulai memanggil metode pada layanan. Layanan hanya hidup untuk melayani komponen aplikasi yang +terikat padanya, jadi bila tidak ada komponen yang terikat pada layanan, sistem akan memusnahkannya +(Anda tidak perlu menghentikan layanan terikat seperti halnya bila layanan dimulai +melalui {@link android.app.Service#onStartCommand onStartCommand()}).
+ +Untuk membuat layanan terikat, hal yang perlu dilakukan pertama kali adalah mendefinisikan antarmuka yang menetapkan +cara klien berkomunikasi dengan layanan. Antarmuka antara layanan +dan klien ini harus berupa implementasi {@link android.os.IBinder} dan yang harus dikembalikan +layanan Anda dari metode callback {@link android.app.Service#onBind +onBind()}. Setelah menerima {@link android.os.IBinder}, klien bisa mulai +berinteraksi dengan layanan melalui antarmuka tersebut.
+ +Beberapa klien bisa mengikat ke layanan sekaligus. Bila klien selesai berinteraksi dengan +layanan, klien akan memanggil {@link android.content.Context#unbindService unbindService()} untuk melepas ikatan. Bila +tidak ada klien yang terikat pada layanan, sistem akan menghapus layanan tersebut.
+ +Ada beberapa cara untuk mengimplementasikan layanan terikat dan implementasinya lebih +rumit daripada layanan yang sudah dimulai, jadi layanan terikat dibahas dalam dokumen +terpisah tentang Layanan Terikat.
+ + + +Mengirim Pemberitahuan ke Pengguna
+ +Setelah berjalan, layanan bisa memberi tahu pengguna tentang suatu kejadian menggunakan Pemberitahuan Toast atau Pemberitahuan Baris Status.
+ +Pemberitahuan Toast adalah pesan yang muncul sebentar pada permukaan jendela saat ini +kemudian menghilang, sementara pemberitahuan baris status memberikan ikon di baris status dengan +pesan yang bisa dipilih oleh pengguna untuk melakukan suatu tindakan (misalnya memulai suatu aktivitas).
+ +Biasanya, pemberitahuan baris status adalah teknik terbaik bila ada pekerjaan latar belakang yang sudah selesai +(misalnya file selesai +diunduh) dan pengguna kini bisa menggunakannya. Bila pengguna memilih pemberitahuan dari +tampilan diperluas, pemberitahuan akan bisa memulai aktivitas (misalnya menampilkan file yang baru diunduh).
+ +Lihat panduan pengembang Pemberitahuan Toast atau Pemberitahuan Baris Status +untuk informasi selengkapnya.
+ + + +Menjalankan Layanan di Latar Depan
+ +Layanan latar depan adalah layanan yang dianggap sebagai sesuatu yang +diketahui secara aktif oleh pengguna, jadi bukan sesuatu yang akan dihapus oleh sistem bila memori menipis. Sebuah +layanan latar depan harus memberikan pemberitahuan bagi baris status, yang ditempatkan pada +heading "Ongoing" yang artinya pemberitahuan tersebut tidak bisa diabaikan kecuali jika layanan +dihentikan atau dihapus dari latar depan.
+ +Misalnya, pemutar musik yang memutar musik dari suatu layanan harus diatur untuk berjalan di +latar depan, karena pengguna mengetahui operasi tersebut +secara eksplisit. Pemberitahuan di baris status bisa menunjukkan lagu saat ini dan memungkinkan +pengguna untuk menjalankan suatu aktivitas untuk berinteraksi dengan pemutar musik.
+ +Untuk meminta agar layanan Anda berjalan di latar depan, panggil {@link +android.app.Service#startForeground startForeground()}. Metode ini memerlukan dua parameter: sebuah integer +yang mengidentifikasi pemberitahuan secara unik dan {@link +android.app.Notification} untuk baris status. Misalnya:
+ ++Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), + System.currentTimeMillis()); +Intent notificationIntent = new Intent(this, ExampleActivity.class); +PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); +notification.setLatestEventInfo(this, getText(R.string.notification_title), + getText(R.string.notification_message), pendingIntent); +startForeground(ONGOING_NOTIFICATION_ID, notification); ++ +
Perhatian: ID integer yang Anda berikan ke {@link +android.app.Service#startForeground startForeground()} tidak boleh 0.
+ + +Untuk menghapus layanan dari latar depan, panggil {@link +android.app.Service#stopForeground stopForeground()}. Metode ini memerlukan boolean, yang menunjukkan +apakah pemberitahuan baris status juga akan dihapus. Metode ini tidak menghentikan +layanan. Akan tetapi, jika Anda menghentikan layanan saat masih berjalan di latar depan +maka pemberitahuan juga akan dihapus.
+ +Untuk informasi selengkapnya tentang pemberitahuan, lihat Membuat Pemberitahuan +Baris Status.
+ + + +Mengelola Daur Hidup Layanan
+ +Daur hidup layanan jauh lebih sederhana daripada daur hidup aktivitas. Akan tetapi, lebih penting lagi adalah +memerhatikan dengan cermat bagaimana layanan Anda dibuat dan dimusnahkan, karena suatu layanan +bisa berjalan di latar belakang tanpa disadari oleh pengguna.
+ +Daur hidup layanan—dari saat dibuat hingga dimusnahkan—bisa mengikuti +dua path berbeda:
+ +-
+
- Layanan yang sudah dimulai
+
Layanan dibuat bila komponen lain memanggil {@link +android.content.Context#startService startService()}. Layanan kemudian berjalan terus-menerus dan harus +berhenti sendiri dengan memanggil {@link +android.app.Service#stopSelf() stopSelf()}. Komponen lain juga bisa menghentikan +layanan dengan memanggil {@link android.content.Context#stopService +stopService()}. Bila layanan dihentikan, sistem akan menghancurkannya.
+
+ - Layanan terikat
+
Layanan dibuat bila komponen lain (klien) memanggil {@link +android.content.Context#bindService bindService()}. Klien kemudian berkomunikasi dengan layanan +melalui antarmuka {@link android.os.IBinder}. Klien bisa menutup koneksi dengan memanggil +{@link android.content.Context#unbindService unbindService()}. Sejumlah klien bisa mengikat pada +layanan yang sama dan bila semuanya melepas ikatan, sistem akan memusnahkan layanan tersebut. (Layanan +tidak perlu berhenti sendiri.)
+
Kedua path tersebut tidak benar-benar terpisah. Artinya, Anda bisa mengikat ke layanan yang sudah +dimulai dengan {@link android.content.Context#startService startService()}. Misalnya, layanan +musik latar belakang bisa dimulai dengan memanggil {@link android.content.Context#startService +startService()} dengan {@link android.content.Intent} yang mengidentifikasi musik yang akan diputar. Kemudian, +mungkin saat pengguna ingin mengontrol pemutar musik atau mendapatkan informasi +tentang lagu yang diputar, aktivitas bisa mengikat ke layanan dengan memanggil {@link +android.content.Context#bindService bindService()}. Dalam kasus seperti ini, {@link +android.content.Context#stopService stopService()} atau {@link android.app.Service#stopSelf +stopSelf()} tidak menghentikan layanan sampai semua klien melepas ikatan.
+ + +Mengimplementasikan callback daur hidup
+ +Seperti halnya aktivitas, layanan memiliki metode callback daur hidup yang bisa Anda implementasikan +untuk memantau perubahan status layanan dan melakukan pekerjaan pada waktu yang tepat. Layanan skeleton +berikut memperagakan setiap metode daur hidup:
+ ++public class ExampleService extends Service { + int mStartMode; // indicates how to behave if the service is killed + IBinder mBinder; // interface for clients that bind + boolean mAllowRebind; // indicates whether onRebind should be used + + @Override + public void {@link android.app.Service#onCreate onCreate}() { + // The service is being created + } + @Override + public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { + // The service is starting, due to a call to {@link android.content.Context#startService startService()} + return mStartMode; + } + @Override + public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()} + return mBinder; + } + @Override + public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { + // All clients have unbound with {@link android.content.Context#unbindService unbindService()} + return mAllowRebind; + } + @Override + public void {@link android.app.Service#onRebind onRebind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()}, + // after onUnbind() has already been called + } + @Override + public void {@link android.app.Service#onDestroy onDestroy}() { + // The service is no longer used and is being destroyed + } +} ++ +
Catatan: Tidak seperti metode callback daur hidup aktivitas, Anda +tidak perlu memanggil implementasi superkelas metode callback tersebut.
+ + + + +Dengan mengimplementasikan metode-metode ini, Anda bisa memantau dua loop tersarang (nested loop) daur hidup layanan:
+ +-
+
- Seluruh masa pakai layanan terjadi antara saat {@link
+android.app.Service#onCreate onCreate()} dipanggil dan saat {@link
+android.app.Service#onDestroy} kembali. Seperti halnya aktivitas, layanan melakukan penyiapan awal di
+{@link android.app.Service#onCreate onCreate()} dan melepaskan semua sisa sumber daya yang ada di {@link
+android.app.Service#onDestroy onDestroy()}. Misalnya,
+layanan pemutar musik bisa membuat thread tempat musik akan diputar dalam {@link
+android.app.Service#onCreate onCreate()}, kemudian menghentikan thread tersebut dalam {@link
+android.app.Service#onDestroy onDestroy()}.
+
+
Metode {@link android.app.Service#onCreate onCreate()} dan {@link android.app.Service#onDestroy +onDestroy()} diperlukan semua layanan, baik yang +dibuat oleh {@link android.content.Context#startService startService()} maupun {@link +android.content.Context#bindService bindService()}.
+
+ - Masa pakai aktif layanan dimulai dengan panggilan ke {@link
+android.app.Service#onStartCommand onStartCommand()} atau {@link android.app.Service#onBind onBind()}.
+Masing-masing metode diberikan {@link
+android.content.Intent} yang diteruskan ke {@link android.content.Context#startService
+startService()} atau {@link android.content.Context#bindService bindService()}.
+
Jika layanan telah dimulai, masa pakai aktif akan berakhir pada saat yang sama dengan +berakhirnya seluruh masa pakai (layanan masih aktif bahkan setelah {@link android.app.Service#onStartCommand +onStartCommand()} kembali). Jika layanan tersebut terikat, masa pakai aktifnya akan berakhir bila {@link +android.app.Service#onUnbind onUnbind()} kembali.
+
+
Catatan: Meskipun layanan yang sudah dimulai dihentikan dengan panggilan ke +{@link android.app.Service#stopSelf stopSelf()} atau {@link +android.content.Context#stopService stopService()}, tidak ada callback tersendiri bagi +layanan tersebut (tidak ada callback {@code onStop()}). Jadi, kecuali jika layanan terikat ke klien, +sistem akan memusnahkannya bila layanan dihentikan—{@link +android.app.Service#onDestroy onDestroy()} adalah satu-satunya callback yang diterima.
+ +Gambar 2 mengilustrasikan metode callback yang lazim bagi suatu layanan. Walaupun gambar tersebut memisahkan +layanan yang dibuat oleh {@link android.content.Context#startService startService()} dari layanan +yang dibuat oleh {@link android.content.Context#bindService bindService()}, ingatlah +bahwa suatu layanan, bagaimana pun dimulainya, bisa memungkinkan klien mengikat padanya. +Jadi, suatu layanan yang awalnya dimulai dengan {@link android.app.Service#onStartCommand +onStartCommand()} (oleh klien yang memanggil {@link android.content.Context#startService startService()}) +masih bisa menerima panggilan ke {@link android.app.Service#onBind onBind()} (bila klien memanggil +{@link android.content.Context#bindService bindService()}).
+ +Untuk informasi selengkapnya tentang membuat layanan yang menyediakan pengikatan, lihat dokumen Layanan Terikat, +yang menyertakan informasi selengkapnya tentang metode callback {@link android.app.Service#onRebind onRebind()} +di bagian tentang Mengelola Daur Hidup +Layanan Terikat.
+ + + diff --git a/docs/html-intl/intl/in/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/in/guide/components/tasks-and-back-stack.jd new file mode 100644 index 0000000000000000000000000000000000000000..279442f2ab381e511ecedbd383718e71ddfdfb2f --- /dev/null +++ b/docs/html-intl/intl/in/guide/components/tasks-and-back-stack.jd @@ -0,0 +1,578 @@ +page.title=Tugas dan Back-Stack +parent.title=Aktivitas +parent.link=activities.html +@jd:body + +Dalam dokumen ini
+ + +Artikel
+ + +Lihat juga
+ +Sebuah aplikasi biasanya berisi beberapa aktivitas. Setiap aktivitas +harus didesain dengan jenis tindakan tertentu yang bisa dilakukan pengguna dan bisa memulai aktivitas +lain. Misalnya, aplikasi email mungkin memiliki satu aktivitas untuk menampilkan daftar pesan baru. +Bila pengguna memilih sebuah pesan, aktivitas baru akan terbuka untuk melihat pesan tersebut.
+ +Aktivitas bahkan bisa memulai aktivitas yang ada dalam aplikasi lain di perangkat. Misalnya +, jika aplikasi Anda ingin mengirim pesan email, Anda bisa mendefinisikan intent untuk melakukan tindakan +"kirim" dan menyertakan sejumlah data, seperti alamat email dan pesan. Aktivitas dari aplikasi +lain yang mendeklarasikan dirinya untuk menangani jenis intent ini akan terbuka. Dalam hal ini, intent +tersebut untuk mengirim email, sehingga aktivitas "menulis" pada aplikasi email akan dimulai (jika beberapa aktivitas +mendukung intent yang sama, maka sistem akan memungkinkan pengguna memilih mana yang akan digunakan). Bila email telah +dikirim, aktivitas Anda akan dilanjutkan dan seolah-olah aktivitas email adalah bagian dari aplikasi Anda. Meskipun +aktivitas mungkin dari aplikasi yang berbeda, Android akan tetap mempertahankan pengalaman pengguna yang mulus +dengan menjalankan kedua aktivitas dalam tugas yang sama.
+ +Tugas adalah kumpulan aktivitas yang berinteraksi dengan pengguna +saat melakukan pekerjaan tertentu. Aktivitas tersebut diatur dalam tumpukan (back-stack), dalam +urutan membuka setiap aktivitas.
+ + + +Layar Home perangkat adalah tempat memulai hampir semua tugas. Bila pengguna menyentuh ikon di launcher +aplikasi +(atau pintasan pada layar Home), tugas aplikasi tersebut akan muncul pada latar depan. Jika tidak ada +tugas untuk aplikasi (aplikasi tidak digunakan baru-baru ini), maka tugas baru +akan dibuat dan aktivitas "utama" untuk aplikasi tersebut akan terbuka sebagai aktivitas akar dalam back-stack.
+ +Bila aktivitas saat ini dimulai lagi, aktivitas baru akan didorong ke atas back-stack dan +mengambil fokus. Aktivitas sebelumnya tetap dalam back-stack, namun dihentikan. Bila aktivitas +dihentikan, sistem akan mempertahankan status antarmuka penggunanya saat ini. Bila pengguna menekan tombol +Back +, aktivitas saat ini akan dikeluarkan dari atas back-stack (aktivitas dimusnahkan) dan + aktivitas sebelumnya dilanjutkan (status UI sebelumnya dipulihkan). Aktivitas dalam back-stack +tidak pernah disusun ulang, hanya didorong dan dikeluarkan dari back-stack—yang didorong ke back-stack saat dimulai oleh +aktivitas saat ini dan dikeluarkan bila pengguna meninggalkannya menggunakan tombol Back. Dengan demikian, +back-stack +beroperasi sebagai struktur objek "masuk terakhir, keluar pertama". Gambar 1 melukiskan perilaku +ini dengan jangka waktu yang menunjukkan kemajuan antar aktivitas beserta +back-stack pada setiap waktu.
+ + + + + +Jika pengguna terus menekan Back, maka setiap aktivitas dalam back-stack akan dikeluarkan untuk +menampilkan +yang sebelumnya, sampai pengguna kembali ke layar Home (atau aktivitas mana pun yang sedang dijalankan saat tugas +dimulai. Bila semua aktivitas telah dihapus dari back-stack, maka tugas tidak akan ada lagi.
+ +Gambar 2. Dua tugas: Tugas B menerima interaksi pengguna +di latar depan, sedangkan Tugas A di latar belakang, menunggu untuk dilanjutkan.
+Gambar 3. Satu aktivitas dibuat instance-nya beberapa kali.
+Tugas adalah unit kohesif yang bisa dipindahkan ke "latar belakang" bila pengguna memulai tugas baru atau masuk ke +layar Home, melalui tombolHome. Sementara di latar belakang, semua aktivitas dalam +tugas +dihentikan, namun back-stack untuk tugas tidak berubah—tugas kehilangan fokus saat +tugas lain berlangsung, seperti yang ditampilkan dalam gambar 2. Kemudian, tugas bisa kembali ke "latar depan" agar pengguna +bisa melanjutkan tugas di tempat menghentikannya. Anggaplah, misalnya, tugas saat ini (Tugas A) memiliki tiga +aktivitas dalam back-stack—dua pada aktivitas saat ini. Pengguna menekan tombol Home +, kemudian +memulai aplikasi baru dari launcher aplikasi. Bila muncul layar Home, Tugas A akan beralih +ke latar belakang. Bila aplikasi baru dimulai, sistem akan memulai tugas untuk aplikasi tersebut +(Tugas B) dengan back-stack aktivitas sendiri. Setelah berinteraksi dengan aplikasi +tersebut, pengguna akan kembali ke Home lagi dan memilih aplikasi yang semula +memulai Tugas A. Sekarang, Tugas A muncul di +latar depan—ketiga aktivitas dalam back-stack tidak berubah dan aktivitas di atas +back-stack akan dilanjutkan. Pada +titik ini pengguna juga bisa beralih kembali ke Tugas B dengan masuk ke Home dan memilih ikon aplikasi +yang memulai tugas tersebut (atau dengan memilih tugas aplikasi dari +layar ikhtisar). +Ini adalah contoh dari melakukan multitasking di Android.
+ +Catatan: Beberapa tugas bisa berlangsung di latar belakang secara bersamaan. +Akan tetapi, jika pengguna menjalankan banyak tugas di latar belakang sekaligus, sistem mungkin mulai +menghapus aktivitas latar belakang untuk memulihkan memori, yang akan menyebabkan status aktivitas hilang. +Lihat bagian berikut tentang Status aktivitas.
+ +Karena aktivitas di back-stack tidak pernah diatur ulang, jika aplikasi Anda memungkinkan +pengguna untuk memulai aktivitas tertentu dari lebih dari satu aktivitas, instance baru +aktivitas tersebut akan dibuat dan didorong ke back-stack (bukannya memunculkan instance sebelumnya dari +aktivitas ke atas). Dengan demikian, satu aktivitas pada aplikasi Anda mungkin dibuat beberapa +kali (bahkan dari beberapa tugas), seperti yang ditampilkan dalam gambar 3. Dengan demikian, jika pengguna mengarahkan mundur +menggunakan tombol Back, setiap instance aktivitas ini akan ditampilkan dalam urutan saat +dibuka (masing-masing +dengan status UI sendiri). Akan tetapi, Anda bisa memodifikasi perilaku ini jika tidak ingin aktivitas +dibuat instance-nya lebih dari sekali. Caranya dibahas di bagian selanjutnya tentang Mengelola Tugas.
+ + +Untuk meringkas perilaku default aktivitas dan tugas:
+ +-
+
- Bila Aktivitas A memulai Aktivitas B, Aktivitas A dihentikan, namun sistem mempertahankan statusnya +(seperti posisi gulir dan teks yang dimasukkan ke dalam formulir). +Jika pengguna menekan tombol Back saat dalam Aktivitas B, Aktivitas A akan dilanjutkan dengan status +yang dipulihkan. +
- Bila pengguna meninggalkan tugas dengan menekan tombol Home aktivitas saat ini akan +dihentikan dan +tugas beralih ke latar belakang. Sistem akan mempertahankan status setiap aktivitas dalam tugas. Jika +nanti pengguna melanjutkan tugas dengan memilih ikon launcher yang memulai tugas, tugas tersebut akan +beralih ke latar depan dan melanjutkan aktivitas di atas back-stack. +
- Jika pengguna menekan tombol Back, aktivitas saat ini akan dikeluarkan dari back-stack +dan +dimusnahkan. Aktivitas sebelumnya dalam back-stack akan dilanjutkan. Bila suatu aktivitas dimusnahkan, sistem +tidak akanmempertahankan status aktivitas. +
- Aktivitas bisa dibuat instance-nya beberapa kali, bahkan dari tugas-tugas lainnya. +
Desain Navigasi
+Untuk mengetahui selengkapnya tentang cara kerja navigasi aplikasi di Android, baca panduan Navigasi Desain Android.
+Menyimpan Status Aktivitas
+ +Seperti dibahas di atas, perilaku default sistem akan mempertahankan status aktivitas bila +dihentikan. Dengan cara ini, bila pengguna mengarah kembali ke aktivitas sebelumnya, antarmuka pengguna akan muncul +seperti saat ditinggalkan. Akan tetapi, Anda bisa—dan harus—secara proaktif mempertahankan +status aktivitas menggunakan metode callback, jika aktivitas ini dimusnahkan dan harus +dibuat kembali.
+ +Bila sistem menghentikan salah satu aktivitas (seperti saat aktivitas baru dimulai atau tugas +dipindah ke latar belakang), sistem mungkin memusnahkan aktivitas sepenuhnya jika perlu memulihkan +memori sistem. Bila hal ini terjadi, informasi tentang status aktivitas akan hilang. Jika hal ini terjadi, sistem +masih +mengetahui bahwa aktivitas memiliki tempat di back-stack, namun saat aktivitas tersebut dibawa ke bagian teratas +back-stack, sistem harus membuatnya kembali (bukan melanjutkannya). Untuk +menghindari hilangnya pekerjaan pengguna, Anda harus secara proaktif mempertahankannya dengan menerapkan metode callback +{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} +dalam aktivitas.
+ +Untuk informasi selengkapnya tentang cara menyimpan status aktivitas Anda, lihat dokumen +Aktivitas.
+ + + +Mengelola Tugas
+ +Cara Android mengelola tugas dan back-stack, seperti yang dijelaskan di atas—dengan menempatkan semua +aktivitas yang dimulai secara berurutan dalam tugas yang sama dan dalam back-stack "masuk terakhir, keluar pertama"—berfungsi +dengan baik untuk kebanyakan aplikasi dan Anda tidak perlu khawatir tentang cara mengaitkan aktivitas +dengan tugas atau cara penempatannya di back-stack. Akan tetapi, Anda bisa memutuskan apakah ingin menyela +perilaku normal. Mungkin Anda ingin agar suatu aktivitas dalam aplikasi untuk memulai tugas baru bila telah +dimulai (sebagai ganti menempatkannya dalam tugas saat ini); atau, bila memulai aktivitas, Anda ingin +memajukan instance yang ada (sebagai ganti membuat instance +baru pada bagian teratas back-stack); atau, Anda ingin back-stack dihapus dari semua +aktivitas selain untuk aktivitas akar bila pengguna meninggalkan tugas.
+ +Anda bisa melakukan semua ini dan lainnya, dengan atribut dalam elemen manifes +{@code <activity>} +dan dengan flag pada intent yang Anda teruskan ke +{@link android.app.Activity#startActivity startActivity()}.
+ +Dalam hal ini, atribut +{@code <activity>} utama yang bisa Anda gunakan adalah:
+ +-
+
- + {@code taskAffinity} +
- + {@code launchMode} +
- + {@code allowTaskReparenting} +
- + {@code clearTaskOnLaunch} +
- + {@code alwaysRetainTaskState} +
- + {@code finishOnTaskLaunch} +
Dan flag intent utama yang bisa Anda gunakan adalah:
+ +-
+
- {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} +
- {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} +
- {@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP} +
Dalam bagian berikut, Anda akan melihat cara menggunakan beberapa atribut manifes ini dan flag +intent untuk mendefinisikan cara mengaitkan aktivitas dengan tugas dan cara perilakunya di back-stack.
+ +Juga, pertimbangan cara menyatakan dan mengelola tugas dan aktivitas +dibahas secara terpisah di layar ikhtisar. Lihat Layar Ikhtisar +untuk informasi selengkapnya. Biasanya Anda harus mengizinkan sistem mendefinisikan cara menyatakan tugas dan +aktivitas di layar ikhtisar, dan Anda tidak perlu memodifikasi perilaku ini.
+ +Perhatian: Kebanyakan aplikasi tidak harus menyela perilaku +default untuk aktivitas dan tugas. Jika merasa bahwa aktivitas Anda perlu memodifikasi +perilaku default, lakukan dengan hati-hati dan pastikan menguji kegunaan aktivitas selama +dijalankan dan saat mengarahkan kembali ke sana dari aktivitas dan tugas lain dengan tombol Back. +Pastikan menguji perilaku navigasi yang mungkin bertentangan dengan perilaku yang diharapkan pengguna.
+ + +Mendefinisikan mode peluncuran
+ +Mode peluncuran memungkinkan Anda mendefinisikan cara mengaitkan instance baru dari suatu aktivitas dengan +tugas saat ini. Anda bisa mendefinisikan beragam mode peluncuran dalam dua cara:
+-
+
- Menggunakan file manifes
+
Bila Anda mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas +dengan tugas-tugas saat mulai.
+ - Menggunakan flag intent
+
Saat memanggil{@link android.app.Activity#startActivity startActivity()}, +Anda bisa menyertakan flag dalam {@link android.content.Intent} yang menyatakan cara (atau +apakah) aktivitas baru tersebut harus dikaitkan dengan tugas saat ini.
+
Dengan demikian, jika Aktivitas A memulai Aktivitas B, Aktivitas B bisa mendefinisikan dalam manifesnya cara +mengaitkan dengan tugas saat ini (jika sama sekali) dan Aktivitas A juga bisa meminta cara mengaitkan Aktivitas B +dengan tugas saat ini. Jika kedua aktivitas mendefinisikan cara mengaitkan Aktivitas B +dengan tugas, maka permintaan Aktivitas A (sebagaimana didefinisikan dalam intent) lebih dihargai daripada +permintaan Aktivitas B (sebagaimana didefinisikan dalam manifesnya).
+ +Catatan: Beberapa mode peluncuran yang tersedia untuk file manifes +tidak tersedia sebagai flag untuk intent dan, juga, beberapa mode peluncuran yang tersedia sebagai flag +untuk intent tidak bisa didefinisikan dalam manifest.
+ + +Menggunakan file manifes
+ +Saat mendeklarasikan aktivitas dalam file manifes, Anda bisa menetapkan cara mengaitkan aktivitas +dengan tugas menggunakan {@code <activity>} +melalui atribut {@code +launchMode} elemen.
+ +Atribut {@code
+launchMode} menetapkan instruksi tentang cara meluncurkan aktivitas
+ke dalam tugas. Ada empat macam mode peluncuran yang bisa Anda tetapkan ke atribut
+launchMode
+:
-
+
- {@code "standard"} (mode default) +
- Default. Sistem membuat instance baru aktivitas dalam tugas yang +akan menjadi tempat memulainya dan mengarahkan intent ke sana. Aktivitas ini bisa dibuat instance-nya beberapa kali, +masing-masing instance bisa dimiliki oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance. +
- {@code "singleTop"} +
- Jika instance aktivitas sudah ada di bagian teratas tugas saat ini, sistem
+akan mengarahkan intent ke instance tersebut melalui panggilan ke metode {@link
+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru dari
+aktivitas tersebut. Aktivitas bisa dibuat instance-nya beberapa kali, masing-masing instance bisa dimiliki
+oleh tugas berbeda, dan satu tugas bisa memiliki beberapa instance (namun hanya jika
+aktivitas di bagian teratas back-stack bukan instance yang ada dari aktivitas tersebut).
+
Misalnya, anggaplah back-stack tugas terdiri dari aktivitas A akar dengan aktivitas B, C, +dan D di bagian teratas (back-stack adalah A-B-C-D; D yang teratas). Intent masuk untuk aktivitas tipe D. +Jika D memiliki mode peluncuran {@code "standard"} default, instance baru dari kelas ini akan diluncurkan dan +back-stack menjadi A-B-C-D-D. Namun, jika mode peluncuran D adalah {@code "singleTop"}, instance +yang ada dari D akan menerima intent melalui {@link +android.app.Activity#onNewIntent onNewIntent()}, karena ada di bagian teratas back-stack— +back-stack tetap A-B-C-D. Akan tetapi, jika intent masuk untuk aktivitas tipe B, maka +instance B baru akan ditambahkan ke back-stack, sekalipun mode peluncuran adalah{@code "singleTop"}.
+Catatan: Bila instance dari aktivitas baru telah dibuat, +pengguna bisa menekan tombol Back untuk kembali ke aktivitas sebelumnya. Namun bila instance +yang ada dari +aktivitas menangani intent baru, pengguna tidak bisa menekan tombol Back untuk kembali ke +status +aktivitas sebelum intent baru masuk di {@link android.app.Activity#onNewIntent +onNewIntent()}.
+
+
+ - {@code "singleTask"} +
- Sistem membuat tugas baru dan membuat instance aktivitas di akar tugas baru.
+Akan tetapi, jika instance aktivitas sudah ada dalam tugas terpisah, sistem akan mengarahkan
+intent ke instance yang ada melalui panggilan ke metode {@link
+android.app.Activity#onNewIntent onNewIntent()}, bukan membuat instance baru. Hanya
+boleh ada satu instance aktivitas untuk setiap kalinya.
+
Catatan: Meskipun aktivitas dimulai di tugas baru, tombol +Back tetap akan mengembalikan pengguna ke aktivitas sebelumnya.
+ - {@code "singleInstance"}. +
- Sama seperti {@code "singleTask"}, namun sistem tidak meluncurkan aktivitas lain ke +tugas yang menyimpan instance. Aktivitas selalu satu dan satu-satunya anggota dari tugasnya; +aktivitas apa pun yang dimulai dengan ini akan dibuka di tugas yang terpisah. +
Sebagai contoh lainnya, aplikasi Browser Android mendeklarasikan bahwa aktivitas browser web harus +selalu dibuka dalam tugasnya sendiri—dengan menetapkan mode pembuka {@code singleTask} dalam elemen{@code <activity>}. +Ini berarti bahwa jika aplikasi Anda mengeluarkan +intent untuk membuka Browser Android, aktivitasnya tidak akan ditempatkan dalam tugas +yang sama seperti aplikasi Anda. Sebagai gantinya, tugas baru akan dimulai untuk Browser atau, jika Browser +sudah memiliki tugas yang berjalan di latar belakang, tugas tersebut akan dimajukan untuk menangani intent +baru.
+ +Baik aktivitas dimulai dalam tugas baru atau maupun dalam tugas yang sama seperti aktivitas yang memulainya, tombol +Back selalu membawa pengguna ke aktivitas sebelumnya. Akan tetapi, jika +Anda memulai aktivitas yang menetapkan mode pembuka {@code singleTask}, maka jika instance +aktivitas tersebut ada dalam tugas latar belakang, seluruh tugas tersebut akan dibawa ke latar depan. Pada titik +ini, back-stack sekarang menyertakan semua aktivitas dari tugas yang dimajukan, di atas +back-stack. Gambar 4 mengilustrasikan tipe skenario ini.
+ + + + +Untuk informasi selengkapnya tentang menggunakan mode pembuka dalam file manifes, lihat dokumentasi elemen
+<activity>
+, di mana atribut {@code launchMode} dan nilai-nilai yang diterima
+akan dibahas selengkapnya.
Catatan: Perilaku yang Anda tentukan untuk aktivitas dengan atribut {@code launchMode} +bisa dikesampingkan dengan flag yang disertakan bersama intent yang memulai aktivitas Anda, seperti dibahas dalam +bagian berikutnya.
+ + + +Menggunakan flag Intent
+ +Saat memulai aktivitas, Anda bisa memodifikasi asosiasi default aktivitas pada tugasnya + dengan menyertakan flag dalam intent yang Anda kirimkan ke {@link +android.app.Activity#startActivity startActivity()}. Flag yang bisa Anda gunakan untuk memodifikasi perilaku default +adalah:
+ ++
Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTask"} {@code launchMode} +yang dibahas di bagian sebelumnya.
Ini menghasilkan perilaku yang sama dengan nilai {@code "singleTop"} {@code launchMode} +yang dibahas di bagian sebelumnya.
Tidak ada nilai untuk atribut {@code launchMode} + yang menghasilkan perilaku ini.
+{@code FLAG_ACTIVITY_CLEAR_TOP} paling sering digunakan bersama dengan + {@code FLAG_ACTIVITY_NEW_TASK}. +Bila digunakan bersama-sama, flag ini adalah cara penempatan aktivitas yang ada +dalam tugas lain dan meletakkannya dalam posisi yang memungkinkannya merespons intent.
+Catatan: Jika mode pembuka aktivitas yang didesain adalah +{@code "standard"}, +ini juga akan dihapus dari back-stack dan instance baru akan diluncurkan di tempatnya untuk menangani +intent yang masuk. Itu karena instance baru selalu dibuat untuk intent baru bila +mode peluncuran adalah {@code "standard"}.
+Menangani afinitas
+ +Afinitas menunjukkan tugas mana yang disukai aktivitas untuk dimiliki. Secara default, semua +aktivitas aplikasi yang sama memiliki afinitas untuk satu sama lain. Jadi, secara default, semua +aktivitas dalam aplikasi yang sama lebih menyukai berada dalam tugas yang sama. Akan tetapi, Anda bisa memodifikasi +afinitas default untuk suatu aktivitas. Aktivitas yang didefinisikan dalam +aplikasi yang berbeda bisa berbagi afinitas, atau aktivitas yang didefinisikan dalam aplikasi yang sama bisa +diberi afinitas tugas yang berbeda.
+ +Anda bisa memodifikasi afinitas untuk setiap yang diberikan +dengan atribut {@code taskAffinity} +elemen {@code <activity>}.
+ +Atribut {@code taskAffinity} +mengambil nilai string, yang harus unik dari nama paket default +yang dideklarasikan dalam elemen +{@code <manifest>} +, karena sistem menggunakan nama untuk mengidentifikasi afinitas +tugas default untuk aplikasi.
+ +Afinitas berperan dalam dua keadaan:
+-
+
- Bila intent yang meluncurkan aktivitas berisi flag
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}
+.
+
+
Aktivitas baru, secara default, diluncurkan ke dalam tugas aktivitas +yang disebut {@link android.app.Activity#startActivity startActivity()}. Ini didorong ke back-stack +yang sama seperti caller. Akan tetapi, jika intent yang diteruskan ke +{@link android.app.Activity#startActivity startActivity()} +berisi flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} +, maka sistem akan mencari tugas yang berbeda untuk menampung aktivitas baru. Sering kali, itu adalah tugas baru. +Akan tetapi, tidak harus demikian. Jika sudah ada tugas lama dengan afinitas yang sama seperti +aktivitas baru, aktivitas ini akan diluncurkan ke dalam tugas tersebut. Jika tidak, tugas baru akan dimulai.
+ +Jika flag ini menyebabkan aktivitas memulai tugas baru dan pengguna menekan tombol Home +untuk meninggalkannya, +harus ada cara bagi pengguna untuk mengarahkan kembali ke tugas. Beberapa entitas (seperti +notification manager) selalu memulai aktivitas dalam tugas eksternal, tidak pernah sebagai bagian dari miliknya sendiri, jadi +selalu menempatkan {@code FLAG_ACTIVITY_NEW_TASK} dalam intent yang diteruskan ke +{@link android.app.Activity#startActivity startActivity()}. +Jika Anda memiliki aktivitas yang bisa dipanggil melalui +entitas eksternal yang mungkin menggunakan flag ini, hati-hatilah karena pengguna memiliki cara independen untuk kembali +ke tugas yang telah dimulai, seperti dengan ikon launcher (aktivitas akar dari tugas +memiliki filter intent {@link android.content.Intent#CATEGORY_LAUNCHER}; lihat bagian Memulai tugas di bawah ini).
+
+
+ - Bila aktivitas memiliki atribut
+{@code allowTaskReparenting} sendiri yang diatur ke {@code "true"}.
+
Dalam hal ini, aktivitas bisa berpindah dari tugas yang dimulainya ke tugas yang afinitasnya +dimilikinya, bila tugas tersebut di bawa ke latar depan.
+Misalnya, anggaplah sebuah aktivitas melaporkan kondisi cuaca di sejumlah kota terpilih +yang didefinisikan sebagai bagian dari aplikasi perjalanan. Aktivitas memiliki afinitas yang sama dengan aktivitas lain dalam aplikasi +yang sama (afinitas aplikasi default) dan aktivitas ini memungkinkan re-parenting dengan atribut ini. +Bila salah satu aktivitas Anda memulai aktivitas laporan cuaca, awalnya aktivitas ini dimiliki oleh tugas +yang sama dengan aktivitas Anda. Akan tetapi, bila tugas aplikasi perjalanan di bawa ke latar depan, +aktivitas laporan cuaca akan ditetapkan kembali ke tugas itu dan ditampilkan di dalamnya.
+
+
Tip: Jika file {@code .apk} berisi lebih dari satu "aplikasi" +dari sudut pandang pengguna, Anda mungkin perlu menggunakan atribut {@code taskAffinity} + untuk menetapkan afinitas berbeda pada aktivitas yang terkait dengan setiap "aplikasi".
+ + + +Menghapus back-stack
+ +Jika pengguna meninggalkan tugas dalam waktu yang lama, sistem akan menghapus tugas semua aktivitas kecuali +aktivitas akar. Bila pengguna kembali ke tugas itu lagi, hanya aktivitas akar yang akan dipulihkan. +Sistem berperilaku seperti ini, karena, setelah sekian waktu, pengguna mungkin telah mengabaikan +apa yang mereka kerjakan sebelum dan kembali ke tugas itu untuk memulai sesuatu yang baru.
+ +Ada beberapa atribut aktivitas yang bisa Anda gunakan untuk memodifikasi perilaku ini:
+ +-
+
alwaysRetainTaskState
+
+- Jika atribut ini ditetapkan ke {@code "true"} dalam aktivitas akar tugas, +perilaku default yang baru dijelaskan tidak akan terjadi. + Tugas akan mempertahankan semua aktivitas dalam back-stack bahkan setelah sekian lama. + +
clearTaskOnLaunch
+- Jika atribut ini diatur ke {@code "true"} dalam aktivitas akar tugas, back- +stack akan dihapus hingga aktivitas akar bila pengguna meninggalkan tugas +dan kembali lagi. Dengan kata lain, ini adalah lawan dari + +{@code alwaysRetainTaskState}. Pengguna selalu kembali ke tugas dengan +status awalnya, walaupun hanya sebentar meninggalkan tugas. + +
finishOnTaskLaunch
+
+- Atribut ini seperti {@code clearTaskOnLaunch}, +namun beroperasi pada +satu aktivitas, bukan pada seluruh tugas. Hal ini juga bisa menyebabkan aktivitas +hilang, termasuk aktivitas akar. Bila ini diatur ke {@code "true"}, +aktivitas akan tetap menjadi bagian dari tugas hanya untuk sesi saat ini. Jika pengguna +keluar dan kemudian kembali ke tugas tersebut, tugas tidak akan ada lagi. +
Memulai tugas
+ +Anda bisa mengatur aktivitas sebagai titik masuk untuk tugas dengan memberikan filter intent dengan +{@code "android.intent.action.MAIN"} sebagai tindakan yang ditetapkan dan +{@code "android.intent.category.LAUNCHER"} +sebagai kategori yang ditetapkan. Misalnya:
+ ++<activity ... > + <intent-filter ... > + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + ... +</activity> ++ +
Filter intent semacam ini akan menyebabkan ikon dan label untuk +aktivitas ditampilkan dalam launcher aplikasi, yang akan memberi cara kepada pengguna untuk meluncurkan aktivitas dan +kembali ke tugas yang dibuatnya kapan saja setelah ia telah diluncurkan. +
+ +Kemampuan kedua ini penting: Pengguna harus bisa meninggalkan tugas dan kemudian kembali ke tugas tersebut +nanti dengan menggunakan launcher aktivitas ini. Karena itu, kedua mode +pembuka yang menandai aktivitas selalu memulai tugas, {@code "singleTask"} dan +{@code "singleInstance"}, hanya boleh digunakan bila aktivitas memiliki filter +{@link android.content.Intent#ACTION_MAIN} +dan {@link android.content.Intent#CATEGORY_LAUNCHER}. Bayangkan, misalnya, apa yang akan +terjadi jika filter tidak ada: Intent meluncurkan aktivitas{@code "singleTask"}, memulai +tugas yang baru, dan pengguna menghabiskan lebih banyak waktu mengerjakan tugas tersebut. Pengguna kemudian menekan tombol +Home. Tugas kini dikirim ke latar belakang dan tidak terlihat. Sekarang pengguna tidak memiliki cara untuk kembali +ke tugas tersebut, karena tidak dinyatakan dalam launcher aplikasi.
+ +Untuk kasus-kasus di mana Anda tidak ingin pengguna bisa kembali ke aktivitas, atur dalam
+<activity>
+ pada
+{@code finishOnTaskLaunch}
+elemen ke {@code "true"} (lihat Menghapus back-stack).
Informasi lebih jauh tentang cara menyatakan dan mengelola tugas dan aktivitas dalam +layar ikhtisar tersedia dalam +Layar Ikhtisar.
+ + diff --git a/docs/html-intl/intl/in/guide/index.jd b/docs/html-intl/intl/in/guide/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..f24fab690ed98c407ddbf363f3ce0358d3df341c --- /dev/null +++ b/docs/html-intl/intl/in/guide/index.jd @@ -0,0 +1,74 @@ +page.title=Pengantar Android + +@jd:body + + +Untuk mempelajari cara kerja aplikasi, mulailah dengan +Dasar-Dasar Aplikasi.
+Untuk langsung memulai pemrograman, bacalah Membangun Aplikasi Pertama Anda.
+Android menyediakan kerangka kerja aplikasi yang kaya dan memungkinkan Anda membangun aplikasi dan permainan +inovatif untuk perangkat seluler di lingkungan bahasa pemrograman Java. Dokumen yang tercantum di navigasi +sebelah kiri menyediakan detail tentang cara membangun aplikasi menggunakan berbagai API Android.
+ +Jika Anda masih baru dengan pengembangan Android, Anda perlu memahami +konsep dasar berikut mengenai kerangka kerja aplikasi Android:
+ + +Aplikasi menyediakan beberapa titik masuk
+ +Aplikasi Android dibangun sebagai kombinasi beragam komponen yang bisa dipanggil +satu per satu. Misalnya, satu aktivitas individual menyediakan satu +layar untuk antarmuka pengguna, dan layanan yang secara terpisah melakukan +tugas di latar belakang.
+ +Dari satu komponen Anda dapat memulai komponen lainnya menggunakan intent. Anda bahkan dapat memulai +satu komponen dalam aplikasi berbeda, seperti aktivitas dalam aplikasi peta untuk menampilkan alamat. Model ini +menyediakan beberapa titik masuk untuk aplikasi tunggal dan memungkinkan setiap aplikasi untuk berfungsi sebagai "default" +pengguna bagi tindakan yang dapat dipanggil aplikasi lain.
+ + +Ketahui selengkapnya:
+ + +Aplikasi beradaptasi dengan perangkat berbeda
+ +Android menyediakan kerangka kerja aplikasi adaptif yang memungkinkan Anda menyediakan sumber daya unik +bagi konfigurasi perangkat yang berbeda-beda. Misalnya, Anda bisa membuat berbagai file layout +XML untuk ukuran layar yang berbeda-beda dan sistem akan menentukan +layout yang akan diterapkan berdasarkan ukuran layar perangkat yang ada saat ini.
+ +Anda dapat melakukan query ketersediaan fitur perangkat saat dijalankan (runtime) jika ada fitur aplikasi yang memerlukan +perangkat keras spesifik seperti kamera. Jika diperlukan, Anda juga bisa mendeklarasikan fitur yang dibutuhkan aplikasi +agar pasar aplikasi seperti Google Play Store tidak mengizinkan instalasi pada perangkat yang tidak +mendukung fitur itu.
+ + +Ketahui selengkapnya:
+ + +Dalam dokumen ini
+-
+
- Struktur File Manifes +
- Konvensi File +
- Fitur File
+
-
+
- Filter Intent +
- Ikon dan Label +
- Izin +
- Pustaka +
+
+ Setiap aplikasi harus memiliki file AndroidManifest.xml (bernama persis seperti ini) di direktori akar. + File manifes + menyediakan informasi penting tentang aplikasi ke sistem Android, + informasi yang harus dimiliki sistem agar bisa menjalankan setiap kode +aplikasi. Di antaranya, manifes melakukan hal berikut ini: +
+ +-
+
- Menamai paket Java untuk aplikasi. +Nama paket berfungsi sebagai identifier unik untuk aplikasi. + +
- Menjelaskan berbagai komponen aplikasi—aktivitas, + layanan, penerima siaran, dan penyedia konten +yang membentuk aplikasi. Menamai kelas yang mengimplementasikan setiap komponen dan +mempublikasikan kemampuannya (misalnya, pesan {@link android.content.Intent +Intent} mana yang bisa ditanganinya). Deklarasi ini memberi tahu sistem Android mengenai +komponennya dan dalam kondisi apa bisa diluncurkan. + +
- Menentukan proses yang akan menjadi host komponen aplikasi. + +
- Mendeklarasikan izin aplikasi mana yang harus dimiliki untuk +mengakses bagian yang dilindungi pada API dan berinteraksi dengan aplikasi lain. + +
- Juga mendeklarasikan izin lain yang harus dimiliki untuk +untuk berinteraksi dengan komponen aplikasi. + +
- Mencantumkan daftar kelas {@link android.app.Instrumentation} yang memberikan +profil dan informasi lain saat aplikasi berjalan. Deklarasi ini +hanya ada di manifes saat aplikasi dibuat dan diuji; + deklarasi dihapus sebelum aplikasi dipublikasikan. + +
- Mendeklarasikan tingkat minimum API Android yang diperlukan +aplikasi. + +
- Mencantumkan daftar pustaka yang harus ditautkan aplikasi. +
Struktur File Manifes
+ ++Diagram di bawah ini menampilkan struktur umum file manifes dan setiap +elemen yang bisa ditampungnya. Setiap elemen, bersama +atributnya, didokumentasikan secara lengkap dalam file terpisah. Untuk melihat +informasi terperinci tentang setiap elemen, klik nama elemen dalam diagram, +dalam daftar abjad elemen yang mengikuti diagram, atau penyebutan nama +elemen lainnya. +
+ ++<?xml version="1.0" encoding="utf-8"?> + +<manifest> + + <uses-permission /> + <permission /> + <permission-tree /> + <permission-group /> + <instrumentation /> + <uses-sdk /> + <uses-configuration /> + <uses-feature /> + <supports-screens /> + <compatible-screens /> + <supports-gl-texture /> + + <application> + + <activity> + <intent-filter> + <action /> + <category /> + <data /> + </intent-filter> + <meta-data /> + </activity> + + <activity-alias> + <intent-filter> . . . </intent-filter> + <meta-data /> + </activity-alias> + + <service> + <intent-filter> . . . </intent-filter> + <meta-data/> + </service> + + <receiver> + <intent-filter> . . . </intent-filter> + <meta-data /> + </receiver> + + <provider> + <grant-uri-permission /> + <meta-data /> + <path-permission /> + </provider> + + <uses-library /> + + </application> + +</manifest> ++ +
+Semua elemen yang bisa muncul dalam file manifes tercantum di bawah ini +dalam urutan abjad. Ini adalah satu-satunya elemen legal; Anda tidak bisa +menambahkan elemen atau atribut sendiri. +
+ +
+<action>
+<activity>
+<activity-alias>
+<application>
+<category>
+<data>
+<grant-uri-permission>
+<instrumentation>
+<intent-filter>
+<manifest>
+<meta-data>
+<permission>
+<permission-group>
+<permission-tree>
+<provider>
+<receiver>
+<service>
+<supports-screens>
+<uses-configuration>
+<uses-feature>
+<uses-library>
+<uses-permission>
+<uses-sdk>
+
Konvensi File
+ ++Sebagian konvensi dan aturan berlaku secara umum untuk semua elemen +dan atribut di manifes: +
+ +-
+
- Elemen +
- Hanya elemen
+
<manifest>
dan +<application>
+yang diwajibkan, masing-masing harus ada dan hanya boleh terjadi sekali. +Umumnya elemen lain bisa terjadi berkali-kali atau sama sekali tidak terjadi — meskipun +setidaknya sebagian dari elemen itu harus ada untuk agar manifes mencapai sesuatu yang +berarti. + ++Jika elemen tidak berisi apa pun, berarti elemen itu berisi elemen lain. +Semua nilai diatur melalui atribut, bukan sebagai data karakter dalam elemen. +
+ ++Elemen yang sama tingkatan umumnya tidak diurutkan. Misalnya, elemen +
<activity>
, +<provider>
, dan +<service>
+bisa dicampur dalam urutan apa pun. (Elemen +<activity-alias>
+ merupakan eksepsi untuk aturan ini: Elemen ini harus mengikuti +<activity>
+ini aliasnya.) +
+
+ - Atribut +
- Secara formal, semua atribut opsional. Akan tetapi, ada sebagian
+yang harus ditetapkan agar elemen bisa mencapai tujuannya. Gunakan
+dokumentasi sebagai panduan. Bagi atribut yang benar-benar opsional, ini menyebutkan
+nilai default atau menyatakan apa yang terjadi jika tidak ada spesifikasi.
+
+
Selain untuk beberapa atribut elemen akar +
<manifest>
, + semua nama atribut dimulai dengan awalan {@code android:} — +misalnya, {@code android:alwaysRetainTaskState}. Karena awalan ini universal, dokumentasi umumnya meniadakannya saat mengacu atribut +dengan nama. +
+
+ - Mendeklarasikan nama kelas +
- Banyak elemen berhubungan dengan objek Java, termasuk elemen
+aplikasi itu sendiri (elemen
+
<application>
+) dan aktivitas komponen — utamanya +(<activity>
), +layanan +(<service>
), +penerima siaran +(<receiver>
), +dan penyedia konten +(<provider>
). + ++Jika mendefinisikan subkelas, seperti yang selalu Anda definisikan untuk kelas komponen +({@link android.app.Activity}, {@link android.app.Service}, +{@link android.content.BroadcastReceiver}, dan {@link android.content.ContentProvider}), +subkelas dideklarasikan melalui atribut {@code name}. Nama harus menyertakan tujuan +paket lengkap. +Misalnya, subkelas {@link android.app.Service} mungkin dideklarasikan sebagai berikut: +
+ +<manifest . . . > + <application . . . > + <service android:name="com.example.project.SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest>
+ ++Akan tetapi, sebagai shorthand, jika karakter pertama string adalah titik, +string akan ditambahkan ke nama paket aplikasi (seperti yang ditetapkan dalam elemen +
+ +<manifest>
+ melalui atribut +package
+). Penetapan berikut sama dengan di atas: +<manifest package="com.example.project" . . . > + <application . . . > + <service android:name=".SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest>
+ ++Saat memulai komponen, Android akan membuat instance subkelas yang diberi nama. +Jika subkelas tidak ditetapkan, maka akak dibuat instance kelas dasar. +
+
+ - Banyak nilai +
- Jika lebih dari satu nilai yang dapat ditetapkan, elemen ini hampir selalu
+diulangi, bukan menampilkan daftar banyak nilai dalam satu elemen.
+Misalnya, filter intent dapat mencantumkan beberapa tindakan:
+
+
<intent-filter . . . > + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.INSERT" /> + <action android:name="android.intent.action.DELETE" /> + . . . +</intent-filter>
+
+ - Nilai sumber daya +
- Beberapa atribut memiliki nilai yang bisa ditampilkan kepada pengguna — misalnya
+, label dan ikon aktivitas. Nilai atribut ini
+harus dilokalkan dan karenanya ditetapkan dari sumber daya atau tema. Nilai sumber
+daya dinyatakan dalam format berikut,
+
+
{@code @[package:]type:name}
+ ++dalam hal ini nama package boleh dihilangkan jika sumber daya ada dalam paket yang sama dengan +dengan aplikasi, type adalah tipe sumber daya — seperti "string" atau +"drawable" — dan name adalah nama yang mengidentifikasi sumber daya tertentu. +Misalnya: +
+ +<activity android:icon="@drawable/smallPic" . . . >
+ ++Nilai tema diekspresikan dengan cara yang sama, namun dengan awal '{@code ?}' +dan bukan '{@code @}': +
+ +{@code ?[package:]type:name} +
+
+ - Nilai-nilai string +
- Bila nilai atribut adalah string, dua garis miring kiri ('{@code \\}') +harus digunakan untuk meninggalkan karakter — misalnya, '{@code \\n}' untuk +baris baru atau '{@code \\uxxxx}' untuk karakter Unicode. +
Fitur File
+ ++Bagian berikut menjelaskan cara menerapkan sebagian fitur Android +dalam file manifest. +
+ + +Filter Intent
+ ++Komponen inti dari aplikasi (aktivitasnya, layanannya, dan penerima +siaran) diaktifkan oleh intent. Intent adalah +sekumpulan informasi (objek {@link android.content.Intent}) yang menjelaskan +tindakan yang diinginkan — termasuk data yang akan ditindaklanjuti, kategori +komponen yang harus melakukan tindakan, dan petunjuk terkait lainnya. +Android mencari komponen yang sesuai untuk merespons intent, meluncurkan +instance komponen baru jika diperlukan, dan meneruskannya ke +objek Intent. +
+ +
+Komponen mengiklankan kemampuannya — jenis intent yang bisa diresponsnya
+ — melalui filter intent. Karena sistem Android
+harus mempelajari intent yang dapat ditangani komponen sebelum meluncurkan komponen,
+filter intent ditetapkan dalam manifes sebagai elemen
+<intent-filter>
+. Sebuah komponen dapat memiliki filter dalam jumlah berapa saja, masing-masing menjelaskan
+kemampuan yang berbeda.
+
+Intent yang secara eksplisit menamai komponen target akan mengaktifkan komponen itu; +filter tidak berperan. Namun intent yang tidak menetapkan target +dengan nama dapat mengaktifkan komponen hanya jika dapat melewati salah satu filter +komponen. +
+ ++Untuk informasi tentang cara objek Intent diuji terhadap filter intent, +lihat dokumen terpisah, +Intent +dan Filter Intent. +
+ + +Ikon dan Label
+ +
+Sejumlah elemen memiliki atribut {@code icon} dan {@code label} untuk
+ikon kecil dan label teks yang bisa ditampilkan kepada pengguna. Sebagian ada juga yang memiliki atribut
+{@code description}untuk teks penjelasan yang lebih panjang yang juga bisa
+ditampilkan pada layar. Misalnya, elemen
+<permission>
+ memiliki ketiga atribut ini, jadi saat pengguna ditanya apakah akan
+memberi izin bagi aplikasi yang memintanya, ikon yang mewakili
+izin, nama izin, dan keterangan yang
+mengikutinya bisa ditampilkan kepada pengguna.
+
+Dalam setiap kasus, ikon dan label yang ditetapkan dalam elemen yang memuatnya menjadi
+{@code icon} default dan pengaturan {@code label} untuk semua subelemen kontainer ini.
+Karena itu, ikon dan label yang ditetapkan dalam elemen
+<application>
+adalah ikon dan label default untuk setiap komponen aplikasi.
+Demikian pula, ikon dan label yang ditetapkan untuk komponen — misalnya, elemen
+<activity>
+— adalah pengaturan default untuk setiap elemen komponen
+<intent-filter>
+. Jika elemen
+<application>
+menetapkan label, namun suatu aktivitas dan filter intent-nya tidak menetapkan label,
+maka label aplikasi akan dianggap sama-sama sebagai label aktvitas dan
+filter intent.
+
+Ikon dan label yang ditetapkan untuk filter intent digunakan untuk mewakili komponen +kapan saja komponen ditampilkan kepada pengguna saat memenuhi fungsi yang +diiklankan oleh filter. Misalnya, filter dengan pengaturan +"{@code android.intent.action.MAIN}" dan +"{@code android.intent.category.LAUNCHER}" mengiklankan aktivitas +sebagai aktivitas yang memulai aplikasi—, yaitu +sebagai salah satu aktivitas yang harus ditampilkan dalam launcher aplikasi. Ikon dan label yang +diatur dalam filter karenanya adalah ikon dan label yang ditampilkan dalam launcher. +
+ + +Izin
+ ++Sebuah izin adalah pembatasan yang membatasi akses ke bagian +kode atau ke data pada perangkat. Pembatasan diberlakukan untuk melindungi data dan kode +penting yang bisa disalahgunakan untuk mengganggu atau merusak pengalaman pengguna. +
+ ++Setiap izin diidentifikasi melalui label yang unik. Sering kali, label menunjukkan +tindakan yang dibatasi. Misalnya, berikut ini adalah beberapa izin yang didefinisikan +oleh Android: +
+ +{@code android.permission.CALL_EMERGENCY_NUMBERS}
+
{@code android.permission.READ_OWNER_DATA}
+
{@code android.permission.SET_WALLPAPER}
+
{@code android.permission.DEVICE_POWER}
+Sebuah fitur bisa dilindungi paling banyak oleh satu izin. +
+ +
+Jika aplikasi memerlukan akses ke fitur yang dilindungi oleh izin,
+aplikasi harus mendeklarasikan bahwa aplikasi memerlukan izin itu dengan elemen
+<uses-permission>
+ dalam manifes. Kemudian, bila aplikasi telah diinstal pada
+perangkat, installer akan menentukan apakah izin yang diminta akan diberikan atau tidak
+dengan memeriksa otoritas yang menandatangani
+sertifikat aplikasi dan, dalam beberapa kasus, bertanya pada pengguna.
+Jika izin diberikan, aplikasi tersebut bisa menggunakan
+fitur yang dilindungi. Jika tidak, upaya aplikasi untuk mengakses fitur tersebut akan gagal
+tanpa ada pemberitahuan apa pun kepada pengguna.
+
+Aplikasi juga bisa melindungi komponennya sendiri (aktivitas, layanan,
+penerima siaran, dan penyedia konten) dengan izin. Aplikasi bisa menerapkan
+izin mana pun yang didefinisikan oleh Android (tercantum dalam
+{@link android.Manifest.permission android.Manifest.permission}) atau dideklarasikan
+oleh aplikasi lain. Atau aplikasi bisa mendefinisikannya sendiri. Izin baru dideklarasikan
+dengan elemen
+<permission>
+. Misalnya, aktivitas dapat dilindungi sebagai berikut:
+
+<manifest . . . > + <permission android:name="com.example.project.DEBIT_ACCT" . . . /> + <uses-permission android:name="com.example.project.DEBIT_ACCT" /> + . . . + <application . . .> + <activity android:name="com.example.project.FreneticActivity" + android:permission="com.example.project.DEBIT_ACCT" + . . . > + . . . + </activity> + </application> +</manifest> ++ +
+Perhatikan, dalam contoh ini izin {@code DEBIT_ACCT} tidak hanya
+dideklarasikan dengan elemen
+<permission>
+, penggunaannya juga diminta dengan elemen
+<uses-permission>
+. Penggunaannya harus diminta agar komponen
+aplikasi lainnya bisa menjalankan aktivitas yang dilindungi, meskipun perlindungan itu
+diberlakukan oleh aplikasi itu sendiri.
+
+Dalam contoh yang sama, jika atribut {@code permission} ditetapkan
+untuk izin yang dideklarasikan di tempat lain
+lain (seperti {@code android.permission.CALL_EMERGENCY_NUMBERS}, maka atribut
+tidak perlu mendeklarasikannya lagi dengan elemen
+<permission>
+. Akan tetapi, penggunaannya masih perlu dengan
+<uses-permission>
.
+
+Elemen
+<permission-tree>
+mendeklarasikan namespace untuk grup izin yang akan didefinisikan dalam
+kode. Dan
+<permission-group>
+mendefinisikan label untuk seperangkat izin (yang sama-sama dideklarasikan dalam manifes dengan elemen
+<permission>
+dan yang dideklarasikan di tempat lain). Ini hanya memengaruhi cara izin
+dikelompokkan saat ditampilkan kepada pengguna. Elemen
+<permission-group>
+ tidak menetapkan izin mana dimiliki grup;
+elemen hanya memberi nama grup. Izin ditempatkan dalam grup
+dengan memberikan nama grup ke elemen
+<permission>
+ melalui atribut
+permissionGroup
+.
+
Pustaka
+ ++Setiap aplikasi ditautkan dengan pustaka default Android, yang +menyertakan paket dasar untuk membangun aplikasi (dengan kelas umum +seperti Activity, Service, Intent, View, Button, Application, ContentProvider, +dan sebagainya). +
+ +
+Akan tetapi, sebagian paket berada dalam pustakanya sendiri. Jika aplikasi Anda
+menggunakan kode salah satu paket ini, aplikasi secara eksplisit meminta untuk ditautkan dengan
+paket tersebut. Manifes harus berisi elemen
+<uses-library>
yang
+terpisah untuk menamai setiap pustaka. (Nama pustaka bisa ditemukan
+dalam dokumentasi paket.)
+
Dalam dokumen ini
+-
+
- Dasar-Dasar +
- Izin Pengguna +
- Tabel kalender + + +
- Tabel Events + + +
- Tabel peserta + + +
- Tabel pengingat + + +
- Tabel Instances + +
- Intent Kalender + + + +
- Adaptor Sinkronisasi +
Kelas-kelas utama
+-
+
- {@link android.provider.CalendarContract.Calendars} +
- {@link android.provider.CalendarContract.Events} +
- {@link android.provider.CalendarContract.Attendees} +
- {@link android.provider.CalendarContract.Reminders} +
Penyedia Kalender adalah repository untuk kejadian kalender seorang pengguna. API +Penyedia Kalender memungkinkan Anda melakukan query, menyisipkan, memperbarui, dan menghapus +pada kalender, kejadian, peserta, pengingat, dan seterusnya.
+ + +API Penyedia Kalender bisa digunakan oleh aplikasi dan adaptor sinkronisasi. Aturannya +bervariasi menurut tipe program yang membuat panggilan. Dokumen ini +terutama berfokus pada penggunaan API Penyedia Kalender sebagai sebuah aplikasi. Untuk +pembahasan ragam adaptor sinkronisasi, lihat +Adaptor Sinkronisasi.
+ + +Biasanya, untuk membaca atau menulis data kalender, manifes aplikasi harus +berisi izin yang sesuai, yang dijelaskan dalam Izin +Pengguna. Untuk mempermudah dilakukannya operasi umum, +Penyedia Kalender menyediakan satu set intent, seperti dijelaskan dalam Intent +Kalender. Semua intent ini membawa pengguna ke aplikasi Kalender untuk menyisipkan, menampilkan, +dan mengedit kejadian. Pengguna berinteraksi dengan aplikasi Kalender kemudian +kembali ke aplikasi semula. Jadi, aplikasi Anda tidak perlu meminta izin, +juga tidak perlu menyediakan antarmuka pengguna untuk menampilkan atau membuat kejadian.
+ +Dasar-Dasar
+ +Penyedia konten menyimpan data dan menjadikannya bisa diakses oleh +aplikasi. Penyedia konten yang ditawarkan oleh platform Android (termasuk Penyedia Kalender) biasanya mengekspos data sebagai satu set tabel berdasarkan +model database relasional, dengan tiap baris berupa record dan tiap kolom berupa data +yang memiliki tipe dan arti tertentu. Melalui API Penyedia Kalender, aplikasi +dan adaptor sinkronisasi bisa mendapatkan akses baca/tulis ke tabel-tabel database yang menyimpan +data kalender seorang pengguna.
+ +Setiap penyedia konten membuka sebuah URI publik (yang dibungkus sebagai objek
+{@link android.net.Uri}
+) yang mengidentifikasikan set datanya secara unik. Penyedia konten yang mengontrol
+ beberapa set data (beberapa tabel) mengekspos URI terpisah untuk tiap set. Semua
+URI untuk penyedia diawali dengan string "content://". String ini
+mengidentifikasi data sebagai dikontrol oleh penyedia konten. Penyedia Kalender
+mendefinisikan konstanta untuk URI masing-masing kelas (tabel). URI ini
+memiliki format <class>.CONTENT_URI
. Misalnya,
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
Gambar 1 menampilkan representasi grafis model data Penyedia Kalender. Gambar ini menampilkan +tabel dan bidang utama yang saling berkaitan.
+ + + + +Seorang pengguna bisa memiliki beberapa kalender, dan kalender yang berbeda bisa dikaitkan dengan tipe akun yang berbeda (Google Calendar, Exchange, dan seterusnya).
+ +{@link android.provider.CalendarContract} mendefinisikan model data dari informasi yang terkait dengan kalender dan kejadian. Data ini disimpan di sejumlah tabel, yang dicantumkan di bawah ini.
+ +Tabel (Kelas) | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.Calendars} |
+
+ Tabel ini menyimpan +informasi khusus kalender. Tiap baris dalam tabel ini berisi data untuk +satu kalender, seperti nama, warna, informasi sinkronisasi, dan seterusnya. | +
{@link android.provider.CalendarContract.Events} | + +Tabel ini menyimpan +informasi khusus kejadian. Tiap baris dalam tabel ini berisi informasi untuk satu +kejadian—misalnya, judul kejadian, lokasi, waktu mulai, waktu +selesai, dan seterusnya. Kejadian bisa terjadi satu kali atau bisa berulang beberapa kali. Peserta, +pengingat, dan properti perluasan disimpan dalam tabel terpisah. +Masing-masing memiliki sebuah {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} +yang mengacu {@link android.provider.BaseColumns#_ID} dalam tabel Events. | + +
{@link android.provider.CalendarContract.Instances} | + +Tabel ini menyimpan +waktu mulai dan waktu selesai setiap bentuk kejadian. Tiap baris dalam tabel ini +mewakili satu bentuk kejadian. Untuk kejadian satu kali ada pemetaan 1:1 +antara instance dan kejadian. Untuk kejadian berulang, beberapa baris akan dibuat +secara otomatis yang sesuai dengan beberapa kejadian itu. | +
{@link android.provider.CalendarContract.Attendees} | + +Tabel ini menyimpan +informasi peserta (tamu) kejadian. Tiap baris mewakili satu tamu +kejadian. Ini menetapkan tipe tamu dan respons kehadiran tamu +untuk kejadian. | +
{@link android.provider.CalendarContract.Reminders} | + +Tabel ini menyimpan +data peringatan/pemberitahuan. Tiap baris mewakili satu peringatan untuk sebuah kejadian. Sebuah +kejadian bisa memiliki beberapa pengingat. Jumlah maksimum pengingat per kejadian +ditetapkan dalam +{@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS}, +yang diatur oleh adaptor sinkronisasi yang +memiliki kalender yang diberikan. Pengingat ditetapkan dalam menit sebelum kejadian +dan memiliki metode yang menentukan cara pengguna akan diperingatkan. | +
API Penyedia Kalender didesain agar luwes dan tangguh. Sementara itu +, Anda perlu memberikan pengalaman pengguna akhir yang baik dan +melindungi integritas kalender dan datanya. Untuk mencapainya, berikut ini adalah +beberapa hal yang harus diingat saat menggunakan API ini:
+ +-
+
+
- Menyisipkan, memperbarui, dan menampilkan kejadian kalender. Untuk menyisipkan, mengubah, dan membaca kejadian secara langsung dari Penyedia Kalender, Anda memerlukan izin yang sesuai. Akan tetapi, jika Anda tidak sedang membuat aplikasi atau adaptor sinkronisasi kalender berfitur lengkap, maka tidak perlu meminta izin. Sebagai gantinya, Anda bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Bila menggunakan intent, aplikasi Anda akan mengirim pengguna ke aplikasi Kalender untuk melakukan operasi yang diinginkan +dalam sebuah formulir yang sudah diisi. Setelah operasi selesai, formulir dikembalikan ke aplikasi Anda. +Dengan mendesain aplikasi untuk melakukan operasi umum melalui Kalender, +Anda akan memberi pengguna sebuah antarmuka pengguna yang konsisten dan tangguh. Inilah +pendekatan yang disarankan. Untuk informasi selengkapnya, lihat Intent +Kalender. + + +
- Adaptor sinkronisasi. Adaptor sinkronisasi menyinkronkan data kalender +pada perangkat pengguna dengan server atau sumber data lain. Dalam tabel +{@link android.provider.CalendarContract.Calendars} dan +{@link android.provider.CalendarContract.Events}, +ada kolom yang dicadangkan untuk digunakan adaptor sinkronisasi. +Penyedia dan aplikasi tidak boleh memodifikasinya. Sebenarnya, tabel-tabel itu tidak +terlihat kecuali jika diakses sebagai adaptor sinkronisasi. Untuk informasi selengkapnya tentang +adaptor sinkronisasi, lihat Adaptor Sinkronisasi. + +
Izin Pengguna
+ +Untuk membaca data kalender, aplikasi harus menyertakan izin {@link +android.Manifest.permission#READ_CALENDAR} dalam file manifesnya. File +harus menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR} +untuk menghapus, menyisipkan, atau memperbarui data kalender:
+ ++<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"...> + <uses-sdk android:minSdkVersion="14" /> + <uses-permission android:name="android.permission.READ_CALENDAR" /> + <uses-permission android:name="android.permission.WRITE_CALENDAR" /> + ... +</manifest> ++ + +
Tabel Kalender
+ +Tabel {@link android.provider.CalendarContract.Calendars} berisi data +untuk tiap kalender. Kolom-kolom +berikut ini bisa ditulisi oleh aplikasi maupun adaptor sinkronisasi. +Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat +acuan {@link android.provider.CalendarContract.Calendars}.
+Konstanta | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.Calendars#NAME} | +Nama kalender. | +
{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME} | +Nama kalender ini yang ditampilkan kepada pengguna. | +
{@link android.provider.CalendarContract.Calendars#VISIBLE} | + +Sebuah boolean yang menunjukkan apakah kalender dipilih untuk ditampilkan. Nilai +0 menunjukkan bahwa kejadian yang terkait dengan kalender ini tidak boleh +ditampilkan. Nilai 1 menunjukkan bahwa kejadian yang terkait dengan kalender ini harus +ditampilkan. Nilai ini memengaruhi pembuatan baris dalam tabel {@link +android.provider.CalendarContract.Instances}. | + + +
{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS} | + +Sebuah boolean yang menunjukkan apakah kalender harus disinkronkan dan apakah +kejadiannya harus disimpan pada perangkat. Nilai 0 berarti jangan menyinkronkan kalender ini atau +simpan kejadiannya pada perangkat. Nilai 1 berarti menyinkronkan kejadian untuk kalender ini +dan simpan kejadiannya pada perangkat. | +
Membuat query kalender
+ +Berikut ini adalah contoh yang menampilkan cara mendapatkan kalender yang dimiliki oleh +pengguna tertentu. Untuk memudahkan, dalam contoh ini, operasi query ditampilkan dalam +thread antarmuka pengguna ("thread utama"). Dalam praktiknya, hal ini harus dilakukan dalam +thread asinkron, sebagai ganti pada thread utama. Untuk diskusi selengkapnya, lihat +Loader. Jika Anda tidak sekadar +membaca data melainkan memodifikasinya, lihat {@link android.content.AsyncQueryHandler}. +
+ + ++// Projection array. Creating indices for this array instead of doing +// dynamic lookups improves performance. +public static final String[] EVENT_PROJECTION = new String[] { + Calendars._ID, // 0 + Calendars.ACCOUNT_NAME, // 1 + Calendars.CALENDAR_DISPLAY_NAME, // 2 + Calendars.OWNER_ACCOUNT // 3 +}; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1; +private static final int PROJECTION_DISPLAY_NAME_INDEX = 2; +private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;+ + +
Mengapa Anda harus menyertakan +ACCOUNT_TYPE?
Jika Anda membuat query pada {@link
+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
+Calendars.ACCOUNT_NAME}, Anda juga harus menyertakan
+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
+dalam pemilihan. Itu karena akun yang bersangkutan
+hanya dianggap unik mengingat ACCOUNT_NAME
dan
+ACCOUNT_TYPE
-nya. ACCOUNT_TYPE
adalah string yang sesuai dengan
+autentikator akun yang digunakan bila akun didaftarkan dengan
+{@link android.accounts.AccountManager}. Ada juga sebuah tipe akun khusus yang disebut {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} untuk kalender
+yang tidak terkait dengan akun perangkat. Akun {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} tidak
+disinkronkan.
Di bagian berikutnya pada contoh ini, Anda akan membuat query. Pemilihan
+akan menetapkan kriteria untuk query. Dalam contoh ini, query mencari
+kalender yang memiliki ACCOUNT_NAME
+"sampleuser@google.com", ACCOUNT_TYPE
+"com.google", dan OWNER_ACCOUNT
+"sampleuser@google.com". Jika Anda ingin melihat semua kalender yang
+telah ditampilkan pengguna, bukan hanya kalender yang dimiliki pengguna, hilangkan OWNER_ACCOUNT
.
+Query tersebut akan menghasilkan objek {@link android.database.Cursor}
+yang bisa Anda gunakan untuk menyusuri set hasil yang dikembalikan oleh
+query database. Untuk diskusi selengkapnya tentang penggunaan query dalam penyedia konten,
+lihat Penyedia Kalender.
// Run query +Cursor cur = null; +ContentResolver cr = getContentResolver(); +Uri uri = Calendars.CONTENT_URI; +String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND (" + + Calendars.ACCOUNT_TYPE + " = ?) AND (" + + Calendars.OWNER_ACCOUNT + " = ?))"; +String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google", + "sampleuser@gmail.com"}; +// Submit the query and get a Cursor object back. +cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);+ +
Bagian berikutnya ini menggunakan kursor untuk merunut set hasil. Bagian ini menggunakan +konstanta yang disiapkan pada awal contoh ini untuk menghasilkan nilai-nilai +bagi tiap bidang.
+ +// Use the cursor to step through the returned records +while (cur.moveToNext()) { + long calID = 0; + String displayName = null; + String accountName = null; + String ownerName = null; + + // Get the field values + calID = cur.getLong(PROJECTION_ID_INDEX); + displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX); + accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX); + ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX); + + // Do something with the values... + + ... +} ++ +
Memodifikasi kalender
+ +Untuk melakukan pembaruan kalender, Anda bisa menyediakan {@link
+android.provider.BaseColumns#_ID} kalender itu baik sebagai ID yang ditambahkan ke
+URI
+
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+atau sebagai item pemilihan pertama. Pemilihan
+harus diawali dengan "_id=?"
, dan
+selectionArg
pertama harus berupa {@link
+android.provider.BaseColumns#_ID} kalender.
+Anda juga bisa melakukan pembaruan dengan menuliskan kode ID dalam URI. Contoh ini mengubah
+nama tampilan kalender dengan pendekatan
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+:
private static final String DEBUG_TAG = "MyActivity"; +... +long calID = 2; +ContentValues values = new ContentValues(); +// The new display name for the calendar +values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar"); +Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows);+ +
Menyisipkan kalender + +
Kalender didesain untuk dikelola terutama oleh sebuah adaptor sinkronisasi, sehingga Anda +hanya boleh menyisipkan kalender baru sebagai adaptor sinkronisasi. Biasanya, +aplikasi hanya bisa membuat perubahan semu pada kalender, misalnya mengubah nama tampilan. Jika +perlu membuat sebuah kalender lokal, aplikasi bisa melakukannya dengan melakukan +penyisipan kalender sebagai adaptor sinkronisasi, menggunakan {@link +android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} dari {@link +android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}. +{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} +adalah sebuah tipe akun khusus untuk kalender yang tidak +terkait dengan akun perangkat. Kalender tipe ini tidak disinkronkan dengan server. Untuk +diskusi tentang adaptor sinkronisasi, lihat Adaptor Sinkronisasi.
+ +Tabel Events
+ +Tabel {@link android.provider.CalendarContract.Events} berisi detail +untuk tiap kejadian. Untuk menambah, memperbarui, atau menghapus kejadian, aplikasi harus +menyertakan izin {@link android.Manifest.permission#WRITE_CALENDAR} dalam +file manifesnya.
+ +Kolom-kolom Events berikut ini bisa ditulis oleh aplikasi maupun +adaptor sinkronisasi. Untuk mengetahui daftar lengkap bidang-bidang yang didukung, lihat acuan {@link +android.provider.CalendarContract.Events}.
+ +Konstanta | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID} | +{@link android.provider.BaseColumns#_ID} kalender yang dimiliki kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#ORGANIZER} | +Email pengatur (pemilik) kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#TITLE} | +Judul kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION} | +Tempat kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION} | +Keterangan kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#DTSTART} | +Waktu mulai kejadian dalam milidetik UTC sejak waktu patokan. | +
{@link android.provider.CalendarContract.EventsColumns#DTEND} | +Waktu selesai kejadian dalam milidetik UTC sejak waktu patokan. | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE} | +Zona waktu kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE} | +Zona waktu untuk waktu selesai kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#DURATION} | + +Durasi kejadian dalam format RFC5545.
+Misalnya, nilai "PT1H" menyatakan bahwa kejadian
+akan berlangsung satu jam, dan nilai "P2W" menunjukkan
+durasi 2 minggu. |
+
+
+
{@link android.provider.CalendarContract.EventsColumns#ALL_DAY} | + +Nilai 1 menunjukkan kejadian ini memakan waktu sehari penuh, seperti yang didefinisikan oleh +zona waktu lokal. Nilai 0 menunjukkan kejadian adalah kejadian biasa yang mungkin dimulai +dan selesai pada sembarang waktu selama suatu hari. | + + +
{@link android.provider.CalendarContract.EventsColumns#RRULE} | + +Aturan perulangan untuk format kejadian. Misalnya,
+"FREQ=WEEKLY;COUNT=10;WKST=SU" . Anda bisa menemukan
+contoh selengkapnya di sini. |
+
+
{@link android.provider.CalendarContract.EventsColumns#RDATE} | +Tanggal perulangan kejadian. + Anda biasanya menggunakan {@link android.provider.CalendarContract.EventsColumns#RDATE} + bersama dengan {@link android.provider.CalendarContract.EventsColumns#RRULE} + untuk mendefinisikan satu set agregat +kejadian berulang. Untuk diskusi selengkapnya, lihat Spesifikasi RFC5545. | +
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY} | + +Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa +dijadwalkan. | + +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY} | +Apakah tamu bisa memodifikasi kejadian atau tidak. | +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS} | +Apakah tamu bisa mengundang tamu lain atau tidak. | +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS} | +Apakah tamu bisa membaca daftar peserta atau tidak. | +
Menambahkan Kejadian
+ +Bila aplikasi Anda menyisipkan kejadian baru, sebaiknya Anda menggunakan +Intent {@link android.content.Intent#ACTION_INSERT INSERT}, seperti dijelaskan dalam Menggunakan intent untuk menyisipkan kejadian. Akan tetapi, jika +perlu, Anda bisa menyisipkan kejadian secara langsung. Bagian ini menjelaskan +caranya.
+ + +Berikut ini adalah aturan untuk menyisipkan kejadian baru:
+-
+
+
- Anda harus menyertakan {@link +android.provider.CalendarContract.EventsColumns#CALENDAR_ID} dan {@link +android.provider.CalendarContract.EventsColumns#DTSTART}. + +
- Anda harus menyertakan {@link +android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}. Untuk mendapatkan daftar +ID zona waktu yang diinstal pada sistem, gunakan {@link +java.util.TimeZone#getAvailableIDs()}. Perhatikan bahwa aturan ini tidak berlaku jika +Anda menyisipkan kejadian melalui Intent {@link +android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam Menggunakan intent untuk menyisipkan kejadian—dalam +skenario itu, sebuah zona waktu default akan diberikan. + +
- Untuk kejadian tidak-berulang, Anda harus menyertakan {@link +android.provider.CalendarContract.EventsColumns#DTEND}. + + +
- Untuk kejadian berulang, Anda harus menyertakan sebuah {@link +android.provider.CalendarContract.EventsColumns#DURATION} selain {@link +android.provider.CalendarContract.EventsColumns#RRULE} atau {@link +android.provider.CalendarContract.EventsColumns#RDATE}. Perhatikan bahwa aturan ini tidak berlaku jika +Anda menyisipkan kejadian melalui Intent {@link +android.content.Intent#ACTION_INSERT INSERT}, yang dijelaskan dalam Menggunakan intent untuk menyisipkan kejadian—dalam +skenario itu, Anda bisa menggunakan {@link +android.provider.CalendarContract.EventsColumns#RRULE} bersama {@link android.provider.CalendarContract.EventsColumns#DTSTART} dan {@link android.provider.CalendarContract.EventsColumns#DTEND}, dan aplikasi Calendar +akan mengubahnya menjadi durasi secara otomatis. + +
Berikut ini adalah contoh penyisipan kejadian. Penyisipan ini dilakukan dalam thread UI +demi kemudahan. Dalam praktiknya, penyisipan dan pembaruan harus dilakukan di +thread asinkron untuk memindahkan tindakan ke dalam thread latar belakang. Untuk +informasi selengkapnya, lihat {@link android.content.AsyncQueryHandler}.
+ + ++long calID = 3; +long startMillis = 0; +long endMillis = 0; +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 9, 14, 7, 30); +startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 9, 14, 8, 45); +endMillis = endTime.getTimeInMillis(); +... + +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Events.DTSTART, startMillis); +values.put(Events.DTEND, endMillis); +values.put(Events.TITLE, "Jazzercise"); +values.put(Events.DESCRIPTION, "Group workout"); +values.put(Events.CALENDAR_ID, calID); +values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles"); +Uri uri = cr.insert(Events.CONTENT_URI, values); + +// get the event ID that is the last element in the Uri +long eventID = Long.parseLong(uri.getLastPathSegment()); +// +// ... do something with event ID +// +//+ +
Catatan: Perhatikan cara contoh ini menangkap ID kejadian +setelah kejadian dibuat. Inilah cara termudah untuk mendapatkan ID kejadian. Anda akan sering +memerlukan ID kejadian untuk melakukan operasi kalender lainnya—misalnya, untuk menambahkan +peserta atau pengingat ke kejadian.
+ + +Memperbarui Kejadian
+ +Bila aplikasi Anda ingin memperbolehkan pengguna mengedit kejadian, sebaiknya
+gunakan Intent {@link android.content.Intent#ACTION_EDIT EDIT}, seperti
+dijelaskan dalam Menggunakan intent untuk mengedit kejadian.
+Akan tetapi, jika perlu, Anda bisa mengedit kejadian secara langsung. Untuk melakukan pembaruan
+suatu kejadian, Anda bisa memberikan _ID
+kejadian itu sebagai ID yang ditambahkan ke URI ({@link
+android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+atau sebagai item pemilihan pertama.
+Pemilihan harus dimulai dengan "_id=?"
, dan
+selectionArg
yang pertama harus berupa _ID
kejadian. Anda juga bisa
+melakukan pembaruan dengan menggunakan pemilihan tanpa ID. Berikut ini adalah contoh pembaruan
+kejadian. Contoh ini mengubah judul kejadian dengan pendekatan
+{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}
+:
private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 188; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri updateUri = null; +// The new title for the event +values.put(Events.TITLE, "Kickboxing"); +updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows);+ +
Menghapus Kejadian
+ +Anda bisa menghapus kejadian dengan {@link +android.provider.BaseColumns#_ID} sebagai ID yang ditambahkan pada URI, atau dengan +pemilihan standar. Jika Anda menggunakan ID yang ditambahkan, Anda tidak bisa melakukan pemilihan. +Ada dua versi penghapusan: sebagai aplikasi dan sebagai adaptor sinkronisasi. Penghapusan +aplikasi mengatur kolom yang dihapus ke 1. Flag ini yang memberi tahu +adaptor sinkronisasi bahwa baris telah dihapus dan bahwa penghapusan ini harus +diberitahukan ke server. Penghapusan adaptor sinkronisasi menghapus kejadian dari +database bersama semua data terkaitnya. Berikut ini adalah contoh aplikasi +yang menghapus kejadian melalui {@link android.provider.BaseColumns#_ID}-nya:
+ + +private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 201; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri deleteUri = null; +deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().delete(deleteUri, null, null); +Log.i(DEBUG_TAG, "Rows deleted: " + rows); ++ +
Tabel Peserta
+ +Tiap baris tabel {@link android.provider.CalendarContract.Attendees} +mewakili satu peserta atau tamu dari sebuah kejadian. Memanggil +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} +akan menghasilkan daftar peserta untuk +kejadian dengan {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan. +{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} ini +harus cocok dengan {@link +android.provider.BaseColumns#_ID} kejadian tertentu.
+ +Tabel berikut mencantumkan
+bidang-bidang yang bisa ditulis. Saat menyisipkan peserta baru, Anda harus menyertakan semuanya
+kecuali ATTENDEE_NAME
.
+
Konstanta | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} | +ID kejadian. | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME} | +Nama peserta. | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL} | +Alamat email peserta. | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP} | +Hubungan peserta dengan kejadian. Salah satu dari: +
|
+
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE} | +Tipe peserta. Salah satu dari: +
|
+
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS} | +Status kehadiran peserta. Salah satu dari: +
|
+
Menambahkan Peserta
+ +Berikut ini adalah contoh yang menambahkan satu peserta ke kejadian. Perhatikan bahwa +{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} +diperlukan:
+ ++long eventID = 202; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Attendees.ATTENDEE_NAME, "Trevor"); +values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com"); +values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); +values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL); +values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); +values.put(Attendees.EVENT_ID, eventID); +Uri uri = cr.insert(Attendees.CONTENT_URI, values); ++ +
Tabel Pengingat
+ +Tiap baris tabel {@link android.provider.CalendarContract.Reminders} +mewakili satu pengingat untuk sebuah kejadian. Memanggil +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} akan menghasilkan daftar pengingat untuk +kejadian dengan +{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} yang diberikan.
+ + +Tabel berikut mencantumkan bidang-bidang yang bisa ditulis untuk pengingat. Semua bidang harus +disertakan saat menyisipkan pengingat baru. Perhatikan bahwa adaptor sinkronisasi menetapkan +tipe pengingat yang didukungnya dalam tabel {@link +android.provider.CalendarContract.Calendars}. Lihat +{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS} +untuk detailnya.
+ + +Konstanta | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID} | +ID kejadian. | +
{@link android.provider.CalendarContract.RemindersColumns#MINUTES} | +Menit yang ditunggu untuk memicu kejadian pengingat. | +
{@link android.provider.CalendarContract.RemindersColumns#METHOD} | +Metode alarm, seperti yang diatur pada server. Salah satu dari: +
|
+
Menambahkan Pengingat
+ +Contoh ini menambahkan pengingat ke kejadian. Pengingat dipicu 15 +menit sebelum kejadian.
++long eventID = 221; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Reminders.MINUTES, 15); +values.put(Reminders.EVENT_ID, eventID); +values.put(Reminders.METHOD, Reminders.METHOD_ALERT); +Uri uri = cr.insert(Reminders.CONTENT_URI, values);+ +
Tabel Instances
+ +Tabel +{@link android.provider.CalendarContract.Instances} menyimpan +waktu mulai dan waktu selesai kejadian. Tiap baris dalam tabel ini +mewakili satu bentuk kejadian. Tabel instance tidak bisa ditulis dan hanya +menyediakan sebuah cara untuk membuat query kejadian.
+ +Tabel berikut mencantumkan beberapa bidang yang bisa Anda query untuk suatu instance. Perhatikan +bahwa zona waktu didefinisikan oleh +{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE} +dan +{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.
+ + +Konstanta | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.Instances#BEGIN} | +Waktu mulai instance, dalam milidetik UTC. | +
{@link android.provider.CalendarContract.Instances#END} | +Waktu selesai instance, dalam milidetik UTC. | +
{@link android.provider.CalendarContract.Instances#END_DAY} | + +Hari selesai Julian dari instance, relatif terhadap +zona waktu Kalender. + + | +
{@link android.provider.CalendarContract.Instances#END_MINUTE} | + +Menit selesai dari instance yang diukur dari tengah malam di zona waktu +Kalender. | + +
{@link android.provider.CalendarContract.Instances#EVENT_ID} | +Kejadian _ID untuk instance ini. |
+
{@link android.provider.CalendarContract.Instances#START_DAY} | +Hari mulai Julian dari instance, relatif terhadap zona waktu Kalender. + | +
{@link android.provider.CalendarContract.Instances#START_MINUTE} | + +Menit mulai dari instance yang diukur dari tengah malam, relatif terhadap +zona waktu Kalender. + | + +
Membuat query tabel Instance
+ +Untuk membuat query tabel Instances, Anda perlu menetapkan rentang waktu query +dalam URI. Dalam contoh ini, {@link android.provider.CalendarContract.Instances} +mendapatkan akses ke bidang {@link +android.provider.CalendarContract.EventsColumns#TITLE} melalui +implementasi antarmuka {@link android.provider.CalendarContract.EventsColumns}-nya. +Dengan kata lain, {@link +android.provider.CalendarContract.EventsColumns#TITLE} dihasilkan melalui +tampilan database, bukan melalui query terhadap tabel {@link +android.provider.CalendarContract.Instances} mentah.
+ ++private static final String DEBUG_TAG = "MyActivity"; +public static final String[] INSTANCE_PROJECTION = new String[] { + Instances.EVENT_ID, // 0 + Instances.BEGIN, // 1 + Instances.TITLE // 2 + }; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_BEGIN_INDEX = 1; +private static final int PROJECTION_TITLE_INDEX = 2; +... + +// Specify the date range you want to search for recurring +// event instances +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2011, 9, 23, 8, 0); +long startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2011, 10, 24, 8, 0); +long endMillis = endTime.getTimeInMillis(); + +Cursor cur = null; +ContentResolver cr = getContentResolver(); + +// The ID of the recurring event whose instances you are searching +// for in the Instances table +String selection = Instances.EVENT_ID + " = ?"; +String[] selectionArgs = new String[] {"207"}; + +// Construct the query with the desired date range. +Uri.Builder builder = Instances.CONTENT_URI.buildUpon(); +ContentUris.appendId(builder, startMillis); +ContentUris.appendId(builder, endMillis); + +// Submit the query +cur = cr.query(builder.build(), + INSTANCE_PROJECTION, + selection, + selectionArgs, + null); + +while (cur.moveToNext()) { + String title = null; + long eventID = 0; + long beginVal = 0; + + // Get the field values + eventID = cur.getLong(PROJECTION_ID_INDEX); + beginVal = cur.getLong(PROJECTION_BEGIN_INDEX); + title = cur.getString(PROJECTION_TITLE_INDEX); + + // Do something with the values. + Log.i(DEBUG_TAG, "Event: " + title); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(beginVal); + DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime())); + } + }+ +
Intent Kalender
+Aplikasi Anda tidak memerlukan izin untuk membaca dan menulis data kalender. Sebagai gantinya, aplikasi bisa menggunakan intent yang didukung oleh aplikasi Kalender Android untuk menyerahkan operasi baca dan tulis ke aplikasi itu. Tabel berikut mencantumkan intent yang didukung oleh Penyedia Kalender:
+Tindakan | +URI | + +Keterangan | +Ekstra | +
---|---|---|---|
+ {@link android.content.Intent#ACTION_VIEW VIEW} |
+
|
+ Membuka kalender pada waktu yang ditetapkan oleh <ms_since_epoch> . |
+ Tidak ada. | +
{@link android.content.Intent#ACTION_VIEW VIEW} + + |
+
|
+ Menampilkan kejadian yang ditetapkan oleh <event_id> . |
+
+ {@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} + + + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
+
{@link android.content.Intent#ACTION_EDIT EDIT} | +
|
+ Mengedit kejadian yang ditetapkan oleh <event_id> . |
+
+ {@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} + + + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
+
{@link android.content.Intent#ACTION_EDIT EDIT} + + {@link android.content.Intent#ACTION_INSERT INSERT} |
+
|
+
+ Membuat sebuah kejadian. | +Ekstra apa saja yang tercantum dalam tabel di bawah. | +
Tabel berikut mencantumkan ekstra intent yang didukung oleh Penyedia Kalender: +
+Ekstra Intent | +Keterangan | +
---|---|
{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE} | +Nama kejadian. | +
{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME +CalendarContract.EXTRA_EVENT_BEGIN_TIME} | +Waktu mulai kejadian dalam milidetik sejak waktu patokan. | +
{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME +CalendarContract.EXTRA_EVENT_END_TIME} | + +Waktu selesai kejadian dalam milidetik sejak waktu patokan. | +
{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY +CalendarContract.EXTRA_EVENT_ALL_DAY} | + +Sebuah boolean yang menunjukkan bahwa kejadian sehari penuh. Nilai bisa
+true atau false . |
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION +Events.EVENT_LOCATION} | + +Lokasi kejadian. | +
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION +Events.DESCRIPTION} | + +Keterangan kejadian. | +
+ {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} | +Alamat email mereka yang harus diundang berupa daftar yang dipisahkan koma. | +
+ {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE} | +Aturan perulangan kejadian. | +
+ {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL +Events.ACCESS_LEVEL} | + +Apakah kejadian bersifat privat atau publik. | +
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY +Events.AVAILABILITY} | + +Jika kejadian ini dihitung sebagai waktu sibuk atau waktu bebas yang bisa dijadwalkan. | + +
Bagian berikut menjelaskan cara menggunakan semua intent ini.
+ + +Menggunakan intent untuk menyisipkan kejadian
+ +Penggunaan Intent {@link android.content.Intent#ACTION_INSERT INSERT} +akan memungkinkan aplikasi Anda menyerahkan tugas penyisipan kejadian ke Kalender itu sendiri. +Dengan pendekatan ini, aplikasi Anda bahkan tidak perlu menyertakan izin {@link +android.Manifest.permission#WRITE_CALENDAR} dalam file manifesnya.
+ + +Bila pengguna menjalankan aplikasi yang menggunakan pendekatan ini, aplikasi akan mengirim +izin ke Kalender untuk menyelesaikan penambahan kejadian. Intent {@link +android.content.Intent#ACTION_INSERT INSERT} menggunakan bidang-bidang ekstra +untuk mengisi formulir lebih dahulu dengan detail kejadian dalam Kalender. Pengguna nanti bisa +membatalkan kejadian, mengedit formulir sebagaimana diperlukan, atau menyimpan kejadian ke +kalender mereka.
+ + + +Berikut ini adalah cuplikan kode yang menjadwalkan kejadian pada tanggal 19 Januari 2012, yang berjalan +dari 7:30 pagi hingga 8:30 pagi Perhatikan hal-hal berikut tentang cuplikan kode ini:
+ +-
+
- Cuplikan kode ini menetapkan {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} + sebagai URI-nya. + +
- Cuplikan kode ini menggunakan bidang-bidang ekstra {@link +android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME +CalendarContract.EXTRA_EVENT_BEGIN_TIME} dan {@link +android.provider.CalendarContract#EXTRA_EVENT_END_TIME +CalendarContract.EXTRA_EVENT_END_TIME} untuk mengisi dahulu formulir +dengan waktu kejadian. Nilai-nilai untuk waktu ini harus dalam milidetik UTC +sejak waktu patokan. + +
- Cuplikan kode ini menggunakan bidang ekstra {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} +untuk memberikan daftar undangan yang dipisah koma, yang ditetapkan melalui alamat email. + +
+Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 0, 19, 7, 30); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 0, 19, 8, 30); +Intent intent = new Intent(Intent.ACTION_INSERT) + .setData(Events.CONTENT_URI) + .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()) + .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()) + .putExtra(Events.TITLE, "Yoga") + .putExtra(Events.DESCRIPTION, "Group class") + .putExtra(Events.EVENT_LOCATION, "The gym") + .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY) + .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com"); +startActivity(intent); ++ +
Menggunakan intent untuk mengedit kejadian
+ +Anda bisa memperbarui kejadian secara langsung, seperti dijelaskan dalam Memperbarui kejadian. Namun penggunaan Intent {@link +android.content.Intent#ACTION_EDIT EDIT} memungkinkan aplikasi yang +tidak memiliki izin untuk menyerahkan pengeditan kejadian ke aplikasi Kalender. +Bila pengguna selesai mengedit kejadian dalam Kalender, pengguna akan dikembalikan ke +aplikasi semula.
Berikut ini adalah contoh intent yang mengatur +judul baru bagi kejadian yang ditetapkan dan memungkinkan pengguna mengedit kejadian dalam Kalender.
+ + +long eventID = 208; +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_EDIT) + .setData(uri) + .putExtra(Events.TITLE, "My New Title"); +startActivity(intent);+ +
Menggunakan intent untuk menampilkan data kalender
+Penyedia Kalender menyediakan dua cara menggunakan Intent {@link android.content.Intent#ACTION_VIEW VIEW}:
+-
+
- Untuk membuka Kalender pada tanggal tertentu. +
- Untuk menampilkan sebuah kejadian. + +
Berikut ini adalah contoh yang menampilkan cara membuka Kalender pada tanggal tertentu:
+// A date-time specified in milliseconds since the epoch. +long startMillis; +... +Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); +builder.appendPath("time"); +ContentUris.appendId(builder, startMillis); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(builder.build()); +startActivity(intent);+ +
Berikut ini adalah contoh yang menampilkan cara membuka kejadian untuk menampilkan:
+long eventID = 208; +... +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(uri); +startActivity(intent); ++ + +
Adaptor Sinkronisasi
+ + +Hanya ada perbedaan kecil dalam cara aplikasi dan adaptor sinkronisasi +mengakses Penyedia Kalender:
+ +-
+
- Adaptor sinkronisasi perlu menetapkan bahwa dirinya sebuah adaptor sinkronisasi dengan mengatur {@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} ke
true
.
+
+
+ - Adaptor sinkronisasi perlu memberikan {@link +android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} dan {@link +android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} sebagai parameter query dalam URI. + +
- Adaptor sinkronisasi memiliki akses tulis ke lebih banyak kolom daripada aplikasi atau widget.
+ Misalnya, aplikasi hanya bisa mengubah sedikit karakteristik kalender,
+ misalnya nama, nama tampilan, pengaturan visibilitas, dan apakah kalender
+ disinkronkan atau tidak. Sebagai perbandingan, adaptor sinkronisasi bisa mengakses bukan hanya kolom-kolom itu, namun banyak kolom lainnya,
+ misalnya warna kalender, zona waktu, tingkat akses, lokasi, dan seterusnya.
+Akan tetapi, adaptor sinkronisasi dibatasi pada
ACCOUNT_NAME
dan +ACCOUNT_TYPE
yang ditetapkannya.
Berikut ini adalah metode pembantu yang bisa Anda gunakan untuk menghasilkan URI bagi penggunaan dengan adaptor sinkronisasi:
+static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } ++
Untuk contoh implementasi adaptor sinkronisasi (yang tidak terkait secara khusus dengan Kalender), lihat +SampleSyncAdapter. diff --git a/docs/html-intl/intl/in/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/in/guide/topics/providers/contacts-provider.jd new file mode 100644 index 0000000000000000000000000000000000000000..994c56b5300b0d144f63987f39b9c027a2948434 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/providers/contacts-provider.jd @@ -0,0 +1,2356 @@ +page.title=Penyedia Kontak +@jd:body +
Tampilan Cepat
+-
+
- Repository informasi Android tentang orang. +
- + Sinkronisasi dengan web. + +
- + Mengintegrasikan data aliran sosial. + +
Dalam dokumen ini
+-
+
- + Organisasi Penyedia Kontak + +
- + Kontak mentah + +
- + Data + +
- + Kontak + +
- + Data Dari Adaptor Sinkronisasi + +
- + Izin yang Diperlukan + +
- + Profil Pengguna + +
- + Metadata Penyedia Kontak + +
- + Akses Penyedia Kontak +
- + +
- + Adaptor Sinkronisasi Penyedia Kontak + +
- + Data Aliran Sosial + +
- + Fitur Tambahan Penyedia Kontak + +
Kelas-kelas utama
+-
+
- {@link android.provider.ContactsContract.Contacts} +
- {@link android.provider.ContactsContract.RawContacts} +
- {@link android.provider.ContactsContract.Data} +
- {@code android.provider.ContactsContract.StreamItems} +
Contoh-Contoh Terkait
+-
+
- + + Contact Manager + + +
- + + Contoh Adaptor Sinkronisasi + +
Lihat Juga
+-
+
- + + Dasar-Dasar Penyedia Konten + + +
+ Penyedia Kontak adalah komponen Android yang tangguh dan fleksibel dalam mengelola + repository data pusat tentang orang di perangkat. Penyedia Kontak adalah sumber data + yang Anda lihat dalam aplikasi kontak perangkat, dan Anda juga bisa mengakses datanya dalam aplikasi + Anda sendiri serta mentransfer data antara perangkat dan layanan online. Penyedia mengakomodasi + berbagai sumber data dan mencoba mengelola data sebanyak mungkin untuk setiap orang, sehingga + organisasinya menjadi kompleks. Karena itu, API penyedia menyertakan + satu set kelas kontrak dan antarmuka ekstensif yang membantu pengambilan dan + modifikasi data. +
++ Panduan ini menjelaskan hal-hal berikut: +
+-
+
- + Struktur penyedia dasar. + +
- + Cara mengambil data dari penyedia. + +
- + Cara memodifikasi data di penyedia. + +
- + Cara menulis adaptor sinkronisasi untuk menyinkronkan data dari server Anda ke + Penyedia Kontak. + +
+ Panduan ini beranggapan bahwa Anda mengetahui dasar-dasar penyedia konten Android. Untuk mengetahui selengkapnya + tentang penyedia konten Android, bacalah + panduan + Dasar-Dasar Penyedia Konten. Contoh aplikasi + Sample Sync Adapter + adalah contoh penggunaan adaptor sinkronisasi untuk mentransfer data antara Penyedia Kontak + dan contoh aplikasi yang memiliki host di Google Web Services. +
+Organisasi Penyedia Kontak
++ Penyedia Kontak adalah komponen penyedia konten Android. Komponen ini memelihara tiga tipe + data tentang seseorang, masing-masing disesuaikan dengan tabel yang ditawarkan oleh penyedia, seperti + yang terlihat dalam gambar 1: +
+ + ++ Ketiga tabel disebut secara umum menurut nama kelas kontrak. Kelas + mendefinisikan konstanta untuk URI konten, nama kolom, dan nilai kolom yang digunakan oleh tabel-tabel: +
+-
+
- + Tabel {@link android.provider.ContactsContract.Contacts} + +
- + Baris mewakili orang yang berbeda, berdasarkan agregrasi baris kontak mentah. + +
- + Tabel {@link android.provider.ContactsContract.RawContacts} + +
- + Baris berisi rangkuman data seseorang, untuk tipe dan akun pengguna tertentu. + +
- + Tabel {@link android.provider.ContactsContract.Data} + +
- + Baris berisi data untuk kontak mentah, seperti alamat email atau nomor telepon. + +
+ Tabel lain yang diwakili oleh kelas kontrak dalam {@link android.provider.ContactsContract} + adalah tabel tambahan yang digunakan Penyedia Kontak untuk mengelola operasinya atau mendukung + fungsi tertentu dalam kontak atau aplikasi telepon perangkat. +
+Kontak mentah
++ Kontak mentah mewakili data seseorang yang berasal dari satu tipe akun dan nama + akun. Karena Penyedia Kontak memungkinkan lebih dari satu layanan online sebagai sumber + data untuk satu orang, Penyedia Kontak memungkinkan multikontak mentah untuk orang yang sama. + Multikontak mentah juga memungkinkan seorang pengguna mengombinasikan data seseorang dari lebih dari satu akun + bertipe akun yang sama. +
++ Sebagian besar data untuk kontak mentah tidak disimpan dalam + tabel {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, data tersebut disimpan dalam satu atau beberapa baris + dalam tabel {@link android.provider.ContactsContract.Data}. Setiap baris data memiliki kolom + {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} yang + berisi nilai {@code android.provider.BaseColumns#_ID RawContacts._ID} dari + baris {@link android.provider.ContactsContract.RawContacts} induknya. +
+Kolom-kolom kontak mentah yang penting
++ Kolom-kolom penting dalam tabel {@link android.provider.ContactsContract.RawContacts} + tercantum pada tabel 1. Bacalah catatan yang diberikan setelah tabel: +
+ +Nama kolom | +Kegunaan | +Catatan | +
---|---|---|
+ {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME} + | ++ Nama akun untuk tipe akun yang merupakan sumber kontak mentah ini. + Misalnya, nama akun dari akun Google adalah salah satu alamat Gmail + pemilik perangkat. Lihat entri berikutnya untuk + {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} untuk informasi + selengkapnya. + | ++ Format nama ini khusus untuk tipe akun ini. Format ini tidak + harus alamat email. + | +
+ {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} + | +
+ Tipe akun yang merupakan sumber kontak mentah ini. Misalnya, tipe
+ akun dari akun Google adalah com.google . Selalu batasi tipe akun Anda
+ dengan identifier domain untuk domain yang Anda miliki atau kontrol. Hal ini akan memastikan bahwa tipe
+ akun Anda bersifat unik.
+ |
+ + Tipe akun yang menawarkan data kontak biasanya memiliki adaptor sinkronisasi terkait yang + menyinkronkan dengan Penyedia Kontak. + |
+ {@link android.provider.ContactsContract.RawContactsColumns#DELETED} + | ++ Flag "deleted" untuk kontak mentah. + | ++ Flag ini memungkinkan Penyedia Kontak memelihara baris secara internal hingga adaptor + sinkronisasi bisa menghapus baris dari server mereka dan akhirnya menghapus baris + dari repository. + | +
Catatan
++ Berikut ini adalah catatan penting tentang + tabel {@link android.provider.ContactsContract.RawContacts}: +
+-
+
- + Nama kontak mentah tidak disimpan di barisnya dalam + {@link android.provider.ContactsContract.RawContacts}. Sebagai gantinya, nama tersebut disimpan dalam + tabel {@link android.provider.ContactsContract.Data}, pada + baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName}. Kontak mentah + hanya memiliki satu baris dari tipe ini dalam tabel {@link android.provider.ContactsContract.Data}. + +
-
+ Perhatian: Untuk menggunakan data akun sendiri dalam baris kontak mentah, akun harus
+ didaftarkan lebih dahulu dengan {@link android.accounts.AccountManager}. Caranya, mintalah
+ pengguna untuk menambahkan tipe akun dan nama akun ke dalam daftar akun. Jika Anda tidak
+ melakukannya, Penyedia Kontak secara otomatis akan menghapus baris kontak mentah Anda.
+
+ Misalnya, Anda menginginkan aplikasi memelihara data kontak untuk layanan berbasis web + dengan domain {@code com.example.dataservice}, dan akun pengguna untuk layanan Anda + adalah {@code becky.sharp@dataservice.example.com}, pengguna harus menambahkan lebih dahulu "type" + akun ({@code com.example.dataservice}) dan "name" akun + ({@code becky.smart@dataservice.example.com}) sebelum aplikasi Anda bisa menambahkan baris kontak mentah. + Anda bisa menjelaskan ketentuan ini kepada pengguna dalam dokumentasi, atau meminta + pengguna untuk menambahkan tipe dan nama, atau keduanya. Tipe akun dan nama akun + dijelaskan lebih detail di bagian berikutnya. +
+
Sumber data kontak mentah
++ Untuk memahami cara kerja kontak mentah, perhatikan pengguna "Emily Dickinson" yang mendefinisikan + tiga akun pengguna berikut pada perangkatnya: +
+-
+
emily.dickinson@gmail.com
+ emilyd@gmail.com
+ - Akun Twitter "belle_of_amherst" +
+ Pengguna ini telah mengaktifkan Sync Contacts untuk ketiga akun dalam pengaturan + Accounts. +
+
+ Anggaplah Emily Dickinson membuka jendela browser, masuk ke Gmail sebagai
+ emily.dickinson@gmail.com
, membuka
+ Contacts, dan menambahkan "Thomas Higginson". Kemudian, ia masuk ke Gmail sebagai
+ emilyd@gmail.com
dan mengirimkan email kepada "Thomas Higginson", yang
+ menambahkan Thomas secara otomatis sebagai kontak. Ia juga mengikuti "colonel_tom" (ID Twitter Thomas Higginson) di
+ Twitter.
+
+ Penyedia Kontak membuat tiga kontak mentah akibat pekerjaan ini: +
+-
+
-
+ Kontak mentah untuk "Thomas Higginson" yang dikaitkan dengan
emily.dickinson@gmail.com
. + Tipe akun penggunanya adalah Google. +
+ -
+ Kontak mentah kedua untuk "Thomas Higginson" yang dikaitkan dengan
emilyd@gmail.com
. + Tipe akun pengguna juga Google. Ada kontak mentah kedua + meskipun nama tersebut identik dengan nama sebelumnya karena orang bersangkutan ditambahkan untuk + akun pengguna yang berbeda. +
+ - + Kontak mentah ketiga untuk "Thomas Higginson" yang dikaitkan dengan "belle_of_amherst". Tipe + akun penggunanya adalah Twitter. + +
Data
+
+ Seperti yang telah disebutkan, data untuk kontak mentah disimpan dalam
+ baris {@link android.provider.ContactsContract.Data} yang ditautkan dengan nilai
+ _ID
kontak mentah. Cara ini memungkinkan satu kontak mentah memiliki beberapa instance tipe data
+ yang sama dengan alamat email atau nomor telepon. Misalnya, jika
+ "Thomas Higginson" untuk {@code emilyd@gmail.com} (baris kontak mentah untuk Thomas Higginson
+ yang dikaitkan dengan akun Google emilyd@gmail.com
) memiliki alamat email rumah
+ thigg@gmail.com
dan alamat email kerja
+ thomas.higginson@gmail.com
, Penyedia Kontak akan menyimpan dua baris alamat
+ email dan menautkan keduanya ke kontak mentah.
+
+ Perhatikan bahwa tipe data yang berbeda disimpan dalam satu tabel ini. Baris-baris nama tampilan, + nomor telepon, email, alamat surat, foto, dan data situs web semuanya bisa ditemukan dalam + tabel {@link android.provider.ContactsContract.Data}. Untuk membantu mengelola ini, + tabel {@link android.provider.ContactsContract.Data} memiliki beberapa kolom dengan nama deskriptif, + dalam kolom lain dengan nama generik. Konten kolom bernama deskriptif memiliki arti yang sama + terlepas dari tipe data dalam barisnya, sedangkan konten kolom bernama generik memiliki + arti yang berbeda-beda sesuai dengan tipe data. +
+Nama kolom deskriptif
++ Beberapa contoh nama kolom deskriptif adalah: +
+-
+
- + {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID} + +
-
+ Nilai kolom
_ID
kontak mentah untuk data ini. +
+ - + {@link android.provider.ContactsContract.Data#MIMETYPE} + +
- + Tipe data yang disimpan dalam baris ini, dinyatakan berupa tipe MIME custom. Penyedia Kontak + menggunakan tipe MIME yang didefinisikan dalam subkelas + {@link android.provider.ContactsContract.CommonDataKinds}. Tipe MIME ini adalah sumber terbuka, + dan bisa digunakan oleh setiap aplikasi atau adaptor sinkronisasi yang bisa digunakan bersama Penyedia Kontak. + +
- + {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} + +
- + Jika tipe baris data ini bisa terjadi lebih dari satu kali untuk suatu kontak mentah, + kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} + menandai baris data yang berisi data utama untuk tipe itu. Misalnya, jika + pengguna menekan lama sebuah nomor telepon untuk kontak dan memilih Set default, + maka baris {@link android.provider.ContactsContract.Data} yang berisi angka itu + mengatur kolom {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY}-nya ke suatu + nilai bukan nol. + +
Nama kolom generik
+
+ Ada 15 kolom generik bernama DATA1
hingga
+ DATA15
yang tersedia secara umum dan empat kolom generik
+ tambahan SYNC1
hingga SYNC4
yang harus digunakan hanya oleh adaptor
+ sinkronisasi. Konstanta nama kolom generik selalu berfungsi, terlepas dari tipe
+ data dalam baris .
+
+ Kolom DATA1
diindeks. Penyedia Kontak selalu menggunakan kolom ini untuk
+ data yang diharapkan penyedia akan menjadi target yang paling sering dari suatu query. Misalnya,
+ dalam baris email, kolom ini berisi alamat email sebenarnya.
+
+ Sesuai konvensi, kolom DATA15
dicadangkan untuk menyimpan data Binary Large Object
+ (BLOB) seperti thumbnail foto.
+
Nama kolom bertipe spesifik
++ Guna memudahkan pekerjaan dengan kolom untuk tipe baris tertentu, Penyedia Kontak + juga menyediakan konstanta nama kolom bertipe spesifik, yang didefinisikan dalam subkelas + {@link android.provider.ContactsContract.CommonDataKinds}. Konstanta cuma memberikan nama + konstanta yang berbeda ke nama kolom yang sama, yang membantu Anda mengakses data dalam baris + bertipe spesifik. +
++ Misalnya, kelas {@link android.provider.ContactsContract.CommonDataKinds.Email} mendefinisikan + konstanta nama kolom bertipe spesifik untuk baris {@link android.provider.ContactsContract.Data} + yang memiliki tipe MIME + {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE + Email.CONTENT_ITEM_TYPE}. Kelas ini berisi konstanta + {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} untuk kolom + alamat email. Nilai sesungguhnya dari + {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} adalah "data1", yang + sama dengan nama generik kolom. +
+
+ Perhatian: Jangan tambahkan data custom Anda sendiri ke
+ tabel {@link android.provider.ContactsContract.Data} dengan menggunakan baris yang memiliki salah satu
+ tipe MIME yang telah didefinisikan penyedia. Jika melakukannya, Anda bisa kehilangan data atau menyebabkan penyedia
+ gagal berfungsi. Misalnya, Anda seharusnya tidak menambahkan baris bertipe MIME
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+ Email.CONTENT_ITEM_TYPE} yang berisi nama pengguna sebagai ganti alamat email dalam
+ kolom DATA1
. Jika Anda menggunakan tipe MIME custom sendiri untuk baris bersangkutan, maka Anda bebas
+ untuk mendefinisikan nama kolom bertipe spesifik dan menggunakan kolom sekehendak Anda.
+
+ Gambar 2 menampilkan cara kolom deskriptif dan kolom data muncul dalam + baris {@link android.provider.ContactsContract.Data}, dan cara nama kolom bertipe spesifik "melapisi" + nama kolom generik +
+ + +Kelas nama kolom bertipe spesifik
++ Tabel 2 berisi daftar kelas nama kolom bertipe spesifik yang paling umum digunakan: +
+ +Kelas pemetaan | +Tipe data | +Catatan | +
---|---|---|
{@link android.provider.ContactsContract.CommonDataKinds.StructuredName} | +Data nama untuk kontak mentah yang dikaitkan dengan baris data ini. | +Kontak mentah hanya memiliki salah satu baris ini. | +
{@link android.provider.ContactsContract.CommonDataKinds.Photo} | +Foto utama untuk kontak mentah yang dikaitkan dengan baris data ini. | +Kontak mentah hanya memiliki salah satu baris ini. | +
{@link android.provider.ContactsContract.CommonDataKinds.Email} | +Alamat email untuk kontak mentah yang dikaitkan dengan baris data ini. | +Kontak mentah bisa memiliki beberapa alamat email. | +
{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal} | +Alamat pos untuk kontak mentah yang dikaitkan dengan baris data ini. | +Kontak mentah bisa memiliki beberapa alamat email. | +
{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} | +Identifier yang menautkan kontak mentah ke salah satu grup dalam Penyedia Kontak. | ++ Grup adalah fitur opsional pada tipe akun dan nama akun. Grup dijelaskan + lebih detail di bagian Grup kontak. + | +
Kontak
++ Penyedia Kontak mengombinasikan baris kontak mentah di semua tipe akun dan nama akun + untuk membentuk kontak. Hal ini memudahkan menampilkan dan memodifikasi semua data + yang telah dikumpulkan pengguna untuk seseorang. Penyedia Kontak mengelola pembuatan baris + kontak baru, dan agregasi kontak mentah dengan baris kontak yang ada. Baik aplikasi maupun adaptor sinkronisasi + tidak boleh menambahkan kontak dan sebagian kolom dalam baris kontak yang bersifat hanya baca. +
++ Catatan: Jika Anda mencoba menambahkan kontak ke Penyedia Kontak dengan + {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, Anda akan mendapatkan + eksepsi {@link java.lang.UnsupportedOperationException}. Jika Anda mencoba memperbarui sebuah kolom + yang tercantum sebagai "hanya-baca", pembaruan akan diabaikan. +
++ Penyedia Kontak membuat kontak baru untuk merespons penambahan kontak mentah baru + yang tidak cocok dengan kontak yang ada. Penyedia juga melakukan ini jika data + kontak mentah yang ada berubah sehingga tidak lagi cocok dengan kontak yang + sebelumnya dihubungkan. Jika aplikasi atau adaptor sinkronisasi membuat kontak mentah baru yang + memang cocok dengan kontak yang ada, kontak mentah baru akan diagregasikan ke kontak + yang ada. +
+
+ Penyedia Kontak menautkan baris kontak ke baris kontak mentahnya dengan kolom
+ _ID
dari baris kontak dalam tabel {@link android.provider.ContactsContract.Contacts Contacts}.
+ Kolom CONTACT_ID
tabel kontak mentah
+ {@link android.provider.ContactsContract.RawContacts} berisi nilai _ID
untuk
+ baris kontak yang dikaitkan dengan tiap baris kontak mentah.
+
+ Tabel {@link android.provider.ContactsContract.Contacts} juga memiliki kolom + {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} yang merupakan + tautan "permanen" ke baris kontak. Karena memelihara kontak + secara otomatis, Penyedia Kontak bisa mengubah nilai {@code android.provider.BaseColumns#_ID} baris kontak + untuk merespons agregasi atau sinkronisasi. Sekalipun ini terjadi, URI konten + {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} yang dikombinasikan dengan + {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} kontak akan tetap + menunjuk ke baris kontak itu, sehingga Anda bisa menggunakan + {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} + untuk memelihara tautan ke kontak "favorit", dan seterusnya. Kolom ini memiliki formatnya sendiri, yang + tidak terkait dengan format kolom {@code android.provider.BaseColumns#_ID}. +
++ Gambar 3 menampilkan cara ketiga tabel utama terkait satu sama lain. +
+ + +Data Dari Adaptor Sinkronisasi
++ Pengguna memasukkan data kontak secara langsung ke dalam perangkat, namun data juga mengalir masuk ke Penyedia Kontak + dari layanan web melalui adaptor sinkronisasi, yang mengotomatiskan + transfer data antara perangkat dan layanan. Adaptor sinkronisasi berjalan di latar belakang + di bawah kontrol sistem, dan memanggil metode {@link android.content.ContentResolver} + untuk mengelola data. +
++ Di Android, layanan web yang digunakan adaptor sinkronisasi diidentifikasi melalui tipe akun. + Setiap adaptor sinkronisasi bekerja dengan satu tipe akun, tetapi bisa mendukung beberapa nama akun untuk + tipe itu. Tipe akun dan nama akun dijelaskan secara singkat di bagian + Sumber data kontak mentah. Definisi berikut menyediakan + detail selengkapnya, dan menjelaskan cara tipe dan nama akun berkaitan dengan adaptor sinkronisasi dan layanan. +
+-
+
- + Tipe akun + +
-
+ Mengidentifikasi layanan tempat pengguna menyimpan data. Sering kali, pengguna harus
+ mengautentikasi diri dengan layanan. Misalnya, Google Contacts adalah tipe akun, yang diidentifikasi
+ dengan kode
google.com
. Nilai ini sesuai dengan tipe akun yang digunakan oleh + {@link android.accounts.AccountManager}. +
+ - + Nama akun + +
- + Mengidentifikasi akun atau login tertentu untuk suatu tipe akun. Akun Google Contacts + sama dengan akun Google, yang memiliki alamat email sebagai nama akun. + Layanan lain mungkin menggunakan nama pengguna satu-kata atau identitas berupa angka. + +
+ Tipe akun tidak harus unik. Pengguna boleh mengonfigurasi beberapa akun Google Contacts + dan mengunduh data ke Penyedia Kontak; ini mungkin terjadi jika pengguna memiliki satu set + kontak pribadi untuk satu nama akun pribadi, dan satu set lagi untuk pekerjaan. Nama akun + biasanya unik. Bersama-sama, keduanya mengidentifikasi aliran data tertentu antara Penyedia Kontak dan + layanan eksternal. +
++ Jika Anda ingin mentransfer data layanan ke Penyedia Kontak, Anda perlu menulis + adaptor sinkronisasi sendiri. Hal ini dijelaskan lebih detail di bagian + Adaptor Sinkronisasi Penyedia Kontak. +
++ Gambar 4 menampilkan cara Penyedia Kontak dimasukkan ke dalam aliran data + tentang orang. Dalam kotak bertanda "sync adapters", setiap adaptor diberi label menurut tipe akunnya. +
+ + +Izin yang Diperlukan
++ Aplikasi yang ingin mengakses Penyedia Kontak harus meminta izin + berikut: +
+-
+
- Akses baca ke satu atau beberapa tabel +
-
+ {@link android.Manifest.permission#READ_CONTACTS}, yang ditetapkan dalam
+
AndroidManifest.xml
dengan elemen ++ <uses-permission>
sebagai +<uses-permission android:name="android.permission.READ_CONTACTS">
. +
+ - Akses tulis ke satu atau beberapa tabel +
-
+ {@link android.Manifest.permission#WRITE_CONTACTS}, yang ditetapkan dalam
+
AndroidManifest.xml
dengan elemen ++ <uses-permission>
sebagai +<uses-permission android:name="android.permission.WRITE_CONTACTS">
. +
+
+ Izin ini tidak diperluas ke data profil pengguna. Profil pengguna dan izin + yang diperlukan dibahas di bagian berikut, + Profil Pengguna. +
++ Ingatlah bahwa data kontak pengguna bersifat pribadi dan sensitif. Pengguna mempersoalkan + privasinya, sehingga tidak ingin aplikasi mengumpulkan data tentang diri atau kontak mereka. + Jika alasan Anda memerlukan izin untuk mengakses data kontak tidak jelas, pengguna mungkin memberi + aplikasi Anda peringkat rendah atau langsung menolak menginstalnya. +
+Profil Pengguna
+
+ Tabel {@link android.provider.ContactsContract.Contacts} berisi satu baris yang berisi
+ data profil untuk pengguna perangkat. Data ini menjelaskan data perangkat user
bukannya
+ salah satu kontak pengguna. Baris kontak profil ditautkan ke baris
+ kontak mentah untuk setiap sistem yang menggunakan profil.
+ Setiap baris kontak mentah profil bisa memiliki beberapa baris data. Konstanta untuk mengakses profil
+ pengguna tersedia dalam kelas {@link android.provider.ContactsContract.Profile}.
+
+ Akses ke profil pengguna memerlukan izin khusus. Selain itu, izin + {@link android.Manifest.permission#READ_CONTACTS} dan + {@link android.Manifest.permission#WRITE_CONTACTS} diperlukan untuk membaca dan menulis, akses + ke profil pengguna memerlukan masing-masing izin {@code android.Manifest.permission#READ_PROFILE} dan + {@code android.Manifest.permission#WRITE_PROFILE} untuk akses baca dan tulis. + +
++ Ingatlah bahwa Anda harus mempertimbangkan profil pengguna bersifat sensitif. Izin + {@code android.Manifest.permission#READ_PROFILE} memungkinkan Anda mengakses data yang mengidentifikasi secara pribadi + pengguna perangkat. Pastikan memberi tahu pengguna alasan + Anda memerlukan izin akses profil pengguna dalam keterangan aplikasi Anda. +
++ Untuk mengambil baris kontak berisi profil pengguna, + panggil {@link android.content.ContentResolver#query(Uri,String[], String, String[], String) + ContentResolver.query()}. Atur URI konten ke + {@link android.provider.ContactsContract.Profile#CONTENT_URI} dan jangan sediakan + kriteria pemilihan apa pun. Anda juga bisa menggunakan URI konten ini sebagai URI dasar untuk mengambil kontak + mentah atau data untuk profil. Misalnya, cuplikan kode ini mengambil data untuk profil: +
++// Sets the columns to retrieve for the user profile +mProjection = new String[] + { + Profile._ID, + Profile.DISPLAY_NAME_PRIMARY, + Profile.LOOKUP_KEY, + Profile.PHOTO_THUMBNAIL_URI + }; + +// Retrieves the profile from the Contacts Provider +mProfileCursor = + getContentResolver().query( + Profile.CONTENT_URI, + mProjection , + null, + null, + null); ++
+ Catatan: Jika Anda mengambil beberapa baris kontak, dan ingin menentukan apakah salah satu baris + adalah profil pengguna, uji + kolom {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} pada baris tersebut. Kolom ini + diatur ke "1" jika kontak adalah profil pengguna. +
+Metadata Penyedia Kontak
++ Penyedia Kontak mengelola data yang mencatat status data kontak dalam + repository. Metadata repository ini disimpan di berbagai tempat, termasuk baris-baris tabel + Raw Contacts, Data, dan Contacts, + tabel {@link android.provider.ContactsContract.Settings}, dan + tabel {@link android.provider.ContactsContract.SyncState}. Tabel berikut menampilkan + efek setiap potongan metadata ini: +
+ +Tabel | +Kolom | +Nilai | +Arti | +
---|---|---|---|
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#DIRTY} | +"0" - tidak berubah sejak sinkronisasi terakhir. | +
+ Menandai kontak mentah yang berubah pada perangkat dan telah disinkronkan kembali ke
+ server. Nilai diatur secara otomatis oleh Penyedia Kontak bila aplikasi
+ Android memperbarui baris.
+ + Adaptor sinkronisasi yang memodifikasi kontak mentah atau tabel data harus selalu menambahkan + string {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} ke + URI konten yang digunakannya. Ini mencegah penyedia menandai baris sebagai kotor. + Sebaliknya, modifikasi oleh adaptor sinkronisasi tampak seperti modifikasi lokal dan + dikirim ke server, meskipun server adalah sumber modifikasi. + + |
+
"1" - berubah sejak sinkronisasi terakhir, harus disinkronkan kembali ke server. | +|||
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#VERSION} | +Nomor versi baris ini. | ++ Penyedia Kontak menambahkan nilai ini secara otomatis bila baris atau + data terkaitnya berubah. + | +
{@link android.provider.ContactsContract.Data} | +{@link android.provider.ContactsContract.DataColumns#DATA_VERSION} | +Nomor versi baris ini. | ++ Penyedia Kontak menambahkan nilai ini secara otomatis bila baris data + berubah. + | +
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID} | ++ Nilai string yang mengidentifikasi secara unik kontak mentah ini ke akun tempat + kontak dibuat. + | +
+ Bila adaptor sinkronisasi membuat kontak mentah baru, kolom ini harus diatur ke
+ ID unik server untuk kontak mentah itu. Bila aplikasi Android membuat kontak mentah
+ baru, aplikasi harus membiarkan kolom ini kosong. Ini mengisyaratkan pada adaptor
+ sinkronisasi bahwa adaptor harus membuat kontak mentah baru pada server, dan mendapatkan
+ nilai untuk {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}.
+ + Khususnya, id sumber harus unik untuk setiap tipe + akun dan stabil di semua sinkronisasi: + +
|
+
{@link android.provider.ContactsContract.Groups} | +{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE} | +"0" - Kontak dalam grup ini tidak boleh terlihat dalam UI aplikasi Android. | ++ Kolom ini digunakan untuk kompatibilitas dengan server yang memungkinkan pengguna menyembunyikan kontak dalam + grup tertentu. + | +
"1" - Kontak dalam grup ini boleh terlihat dalam UI aplikasi. | +|||
{@link android.provider.ContactsContract.Settings} | ++ {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE} | ++ "0" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup + tidak akan terlihat pada UI aplikasi Android. + | ++ Secara default, kontak tidak terlihat jika tidak satu pun kontak mentahnya milik grup + (Keanggotaan grup untuk kontak mentah ditandai oleh satu atau beberapa baris + {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} + dalam tabel {@link android.provider.ContactsContract.Data}). + Dengan mengatur flag ini dalam baris tabel {@link android.provider.ContactsContract.Settings} + untuk tipe akun dan akun, Anda bisa memaksakan kontak tanpa grup agar terlihat. + Satu kegunaan flag ini adalah menampilkan kontak dari server yang tidak menggunakan grup. + | +
+ "1" - Untuk akun dan tipe akun ini, kontak yang bukan milik grup + akan terlihat pada UI aplikasi. + | + +|||
{@link android.provider.ContactsContract.SyncState} | +(semua) | ++ Gunakan tabel ini untuk menyimpan metadata bagi adaptor sinkronisasi Anda. + | ++ Dengan tabel ini, Anda bisa menyimpan status sinkronisasi dan data lain yang terkait dengan sinkronisasi secara persisten pada + perangkat. + | +
Akses Penyedia Kontak
++ Bagian ini menjelaskan panduan untuk mengakses data dari Penyedia Kontak, yang berfokus pada + hal-hal berikut: +
+-
+
- + Query entitas. + +
- + Modifikasi batch. + +
- + Pengambilan dan modifikasi dengan intent. + +
- + Integritas data. + +
+ Membuat modifikasi dari adaptor sinkronisasi juga secara lebih detail di bagian + Adaptor Sinkronisasi Penyedia Kontak. +
+Membuat query entitas
++ Karena disusun secara hierarki, tabel-tabel Penyedia Kontak sering kali berguna untuk + mengambil baris dan semua baris "anak" yang ditautkan dengannya. Misalnya, untuk menampilkan + semua informasi untuk satu orang, Anda mungkin ingin mengambil semua + baris {@link android.provider.ContactsContract.RawContacts} untuk satu baris + {@link android.provider.ContactsContract.Contacts}, atau semua + baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk satu baris + {@link android.provider.ContactsContract.RawContacts}. Untuk memudahkan hal ini, Penyedia Kontak + menawarkan konstruksi entitas, yang berfungsi seperti gabungan database di antara + tabel-tabel. +
++ Entitas adalah seperti tabel yang terdiri atas kolom-kolom terpilih dari tabel induk dan tabel anaknya. + Bila membuat query sebuah entitas, Anda memberikan proyeksi dan kriteria pencarian berdasarkan kolom-kolom + yang tersedia dari entitas itu. Hasilnya adalah sebuah {@link android.database.Cursor} yang + berisi satu baris untuk setiap baris tabel anak yang diambil. Misalnya, jika Anda membuat query + {@link android.provider.ContactsContract.Contacts.Entity} untuk satu nama kontak + dan semua baris {@link android.provider.ContactsContract.CommonDataKinds.Email} untuk semua + kontak mentah bagi nama itu, Anda akan mendapatkan kembali {@link android.database.Cursor} berisi satu baris + untuk setiap baris {@link android.provider.ContactsContract.CommonDataKinds.Email}. +
++ Entitas menyederhanakan query. Dengan entitas, Anda bisa mengambil semua data kontak untuk satu + kontak atau kontak mentah sekaligus, sebagai ganti harus membuat query tabel induk terlebih dahulu untuk mendapatkan + ID, lalu harus membuat query tabel anak dengan ID itu. Selain itu, Penyedia Kontak akan memproses + query terhadap entitas dalam satu transaksi, yang memastikan bahwa data yang diambil + konsisten secara internal. +
++ Catatan: Entitas biasanya tidak berisi semua kolom tabel induk dan + anak. Jika Anda mencoba menggunakan nama kolom yang tidak ada dalam daftar konstanta + nama kolom untuk entitas, Anda akan mendapatkan {@link java.lang.Exception}. +
++ Cuplikan berikut menampilkan cara mengambil semua baris kontak mentah untuk sebuah kontak. Cuplikan ini + adalah bagian dari aplikasi lebih besar yang memiliki dua aktivitas, "main" dan "detail". Aktivitas utama + menampilkan daftar baris kontak; bila pengguna memilih satu baris, aktivitas akan mengirimkan ID-nya ke aktivitas + detail. Aktivitas detail menggunakan{@link android.provider.ContactsContract.Contacts.Entity} + untuk menampilkan semua baris data dari semua kontak mentah yang dikaitkan dengan kontak + terpilih. +
++ Cuplikan ini diambil dari aktivitas "detail": +
++... + /* + * Appends the entity path to the URI. In the case of the Contacts Provider, the + * expected URI is content://com.google.contacts/#/entity (# is the ID value). + */ + mContactUri = Uri.withAppendedPath( + mContactUri, + ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); + + // Initializes the loader identified by LOADER_ID. + getLoaderManager().initLoader( + LOADER_ID, // The identifier of the loader to initialize + null, // Arguments for the loader (in this case, none) + this); // The context of the activity + + // Creates a new cursor adapter to attach to the list view + mCursorAdapter = new SimpleCursorAdapter( + this, // the context of the activity + R.layout.detail_list_item, // the view item containing the detail widgets + mCursor, // the backing cursor + mFromColumns, // the columns in the cursor that provide the data + mToViews, // the views in the view item that display the data + 0); // flags + + // Sets the ListView's backing adapter. + mRawContactList.setAdapter(mCursorAdapter); +... +@Override +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + + /* + * Sets the columns to retrieve. + * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. + * DATA1 contains the first column in the data row (usually the most important one). + * MIMETYPE indicates the type of data in the data row. + */ + String[] projection = + { + ContactsContract.Contacts.Entity.RAW_CONTACT_ID, + ContactsContract.Contacts.Entity.DATA1, + ContactsContract.Contacts.Entity.MIMETYPE + }; + + /* + * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw + * contact collated together. + */ + String sortOrder = + ContactsContract.Contacts.Entity.RAW_CONTACT_ID + + " ASC"; + + /* + * Returns a new CursorLoader. The arguments are similar to + * ContentResolver.query(), except for the Context argument, which supplies the location of + * the ContentResolver to use. + */ + return new CursorLoader( + getApplicationContext(), // The activity's context + mContactUri, // The entity content URI for a single contact + projection, // The columns to retrieve + null, // Retrieve all the raw contacts and their data rows. + null, // + sortOrder); // Sort by the raw contact ID. +} ++
+ Bila selesai dimuat, {@link android.app.LoaderManager} akan memicu callback ke + {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D) + onLoadFinished()}. Salah satu argumen masuk pada metode ini adalah + {@link android.database.Cursor} bersama hasil query. Dalam aplikasi Anda sendiri, Anda bisa memperoleh + data dari {@link android.database.Cursor} ini untuk menampilkannya atau menggunakannya lebih jauh. +
+Modifikasi batch
++ Bila memungkinkan, Anda harus menyisipkan, memperbarui, dan menghapus data dalam Penyedia Kontak dengan + "batch mode", dengan membuat {@link java.util.ArrayList} dari + objek-objek {@link android.content.ContentProviderOperation} dan memanggil + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena + Penyedia Kontak menjalankan semua operasi dalam satu + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} transaksi, + modifikasi Anda tidak akan pernah meninggalkan repository kontak dalam keadaan + tidak konsisten. Modifikasi batch juga memudahkan penyisipan kontak mentah dan data detailnya + sekaligus. +
++ Catatan: Untuk memodifikasi satu kontak mentah, pertimbangkan untuk mengirim intent ke + aplikasi kontak perangkat daripada menangani modifikasi dalam aplikasi Anda. + Cara ini dijelaskan lebih detail di bagian + Pengambilan dan modifikasi dengan intent. +
+Yield point
+
+ Modifikasi batch yang berisi operasi dalam jumlah besar bisa memblokir proses lain,
+ yang mengakibatkan pengalaman pengguna yang buruk secara keseluruhan. Untuk menata semua modifikasi yang ingin Anda
+ jalankan dalam sesedikit mungkin daftar terpisah, sambil mencegah modifikasi dari
+ memblokir sistem, Anda harus menetapkan yield point untuk satu atau beberapa operasi.
+ Yield point (titik hasil) adalah objek {@link android.content.ContentProviderOperation} yang mengatur
+ nilai {@link android.content.ContentProviderOperation#isYieldAllowed()}-nya ke
+ true
. Bila menemui yield point, Penyedia Kontak akan menghentikan pekerjaannya untuk
+ membiarkan proses lain berjalan dan menutup transaksi saat ini. Bila dimulai lagi, penyedia akan
+ melanjutkan dengan operasi berikutnya di {@link java.util.ArrayList} dan memulai transaksi
+ baru.
+
+ Yield point memang menyebabkan lebih dari satu transaksi per panggilan ke + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Karena + itu, Anda harus menetapkan yield point pada operasi terakhir untuk satu set baris terkait. + Misalnya, Anda harus menetapkan yield point pada operasi terakhir di satu set yang menambahkan + baris kontak mentah dan baris data terkait, atau operasi terakhir untuk satu set baris yang terkait + dengan satu kontak. +
++ Yield point juga merupakan unit operasi atomis. Semua akses antara dua yield point bisa + saja berhasil atau gagal sebagai satu unit. Jika Anda mengatur yield point, operasi + atomis terkecil adalah seluruh batch operasi. Jika menggunakan yield point, Anda akan mencegah + operasi menurunkan kinerja sistem, sekaligus memastikan subset + operasi bersifat atomis. +
+Acuan balik modifikasi
++ Saat Anda menyisipkan baris kontak mentah baru dan baris data terkaitnya sebagai satu set + objek {@link android.content.ContentProviderOperation}, Anda harus menautkan baris data ke + baris kontak mentah dengan memasukkan nilai + {@code android.provider.BaseColumns#_ID} kontak mentah sebagai + nilai {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Akan tetapi, nilai + ini tidak tersedia saat Anda membuat {@link android.content.ContentProviderOperation} + untuk baris data, karena Anda belum menerapkan + {@link android.content.ContentProviderOperation} untuk baris kontak mentah. Solusinya, + kelas {@link android.content.ContentProviderOperation.Builder} memiliki metode + {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}. + Metode ini memungkinkan Anda menyisipkan atau mengubah kolom dengan + hasil dari operasi sebelumnya. +
++ Metode {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} + memiliki dua argumen: +
+-
+
-
+
key
+
+ - + Kunci dari pasangan kunci-nilai. Nilai argumen ini harus berupa nama kolom + dalam tabel yang Anda modifikasi. + +
-
+
previousResult
+
+ -
+ Indeks berbasis 0 dari nilai pada larik
+ objek {@link android.content.ContentProviderResult} dari
+ {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Saat
+ operasi batch diterapkan, hasil tiap operasi akan disimpan dalam
+ larik hasil antara. Nilai
previousResult
adalah indeks + dari salah satu hasil ini, yang diambil dan disimpan bersama nilaikey
. + Cara ini memungkinkan Anda menyisipkan record kontak mentah baru dan mendapatkan kembali nilai + {@code android.provider.BaseColumns#_ID}-nya, lalu membuat "acuan balik" ke + nilai itu saat Anda menambahkan baris {@link android.provider.ContactsContract.Data}. ++ Seluruh larik hasil dibuat saat Anda memanggil + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} untuk pertama kali, + dengan ukuran setara dengan ukuran {@link java.util.ArrayList} dari + objek {@link android.content.ContentProviderOperation} yang Anda sediakan. Akan tetapi, semua + elemen dalam larik hasil diatur ke
+null
, dan jika Anda mencoba + melakukan acuan balik ke hasil untuk operasi yang belum diterapkan, +{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} + akan mengeluarkan {@link java.lang.Exception}. + +
+
+ Cuplikan kode berikut menampilkan cara menyisipkan kontak mentah baru dan data secara batch. Cuplikan kode ini
+ menyertakan kode yang menetapkan yield point dan menggunakan acuan balik. Cuplikan kode ini adalah
+ versi perluasan dari metodecreateContacEntry()
, yang merupakan bagian dari kelas
+ ContactAdder
dalam
+ aplikasi contoh
+ Contact Manager
.
+
+ Cuplikan pertama mengambil data kontak dari UI. Pada saat ini, pengguna sudah + memilih akun tempat kontak mentah baru harus ditambahkan. +
++// Creates a contact entry from the current UI values, using the currently-selected account. +protected void createContactEntry() { + /* + * Gets values from the UI + */ + String name = mContactNameEditText.getText().toString(); + String phone = mContactPhoneEditText.getText().toString(); + String email = mContactEmailEditText.getText().toString(); + + int phoneType = mContactPhoneTypes.get( + mContactPhoneTypeSpinner.getSelectedItemPosition()); + + int emailType = mContactEmailTypes.get( + mContactEmailTypeSpinner.getSelectedItemPosition()); ++
+ Cuplikan berikutnya membuat operasi untuk menyisipkan baris kontak mentah ke dalam + tabel {@link android.provider.ContactsContract.RawContacts}: +
++ /* + * Prepares the batch operation for inserting a new raw contact and its data. Even if + * the Contacts Provider does not have any data for this person, you can't add a Contact, + * only a raw contact. The Contacts Provider will then add a Contact automatically. + */ + + // Creates a new array of ContentProviderOperation objects. + ArrayList<ContentProviderOperation> ops = + new ArrayList<ContentProviderOperation>(); + + /* + * Creates a new raw contact with its account type (server type) and account name + * (user's account). Remember that the display name is not stored in this row, but in a + * StructuredName data row. No other data is required. + */ + ContentProviderOperation.Builder op = + ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); ++
+ Berikutnya, kode akan membuat baris data untuk baris-baris nama tampilan, telepon, dan email. +
++ Setiap objek pembangun operasi menggunakan + {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} + untuk mendapatkan + {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. Acuan menunjuk + balik ke objek {@link android.content.ContentProviderResult} dari operasi pertama, + yang menambahkan baris kontak mentah dan mengembalikan nilai {@code android.provider.BaseColumns#_ID} + barunya. Hasilnya, setiap data ditautkan secara otomatis oleh + {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}-nya + ke baris {@link android.provider.ContactsContract.RawContacts} baru yang memilikinya. +
++ Objek {@link android.content.ContentProviderOperation.Builder} yang menambahkan baris email + diberi flag {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean) + withYieldAllowed()}, yang mengatur yield point: +
++ // Creates the display name for the new raw contact, as a StructuredName data row. + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * withValueBackReference sets the value of the first argument to the value of + * the ContentProviderResult indexed by the second argument. In this particular + * call, the raw contact ID column of the StructuredName data row is set to the + * value of the result returned by the first operation, which is the one that + * actually adds the raw contact row. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to StructuredName + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + + // Sets the data row's display name to the name in the UI. + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified phone number and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Phone + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + + // Sets the phone number and type + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified email and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Email + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) + + // Sets the email address and type + .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) + .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); + + /* + * Demonstrates a yield point. At the end of this insert, the batch operation's thread + * will yield priority to other threads. Use after every set of operations that affect a + * single contact, to avoid degrading performance. + */ + op.withYieldAllowed(true); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); ++
+ Cuplikan terakhir menampilkan panggilan ke + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} yang + menyisipkan baris-baris kontak mentah dan data baru. +
++ // Ask the Contacts Provider to create a new contact + Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" + + mSelectedAccount.getType() + ")"); + Log.d(TAG,"Creating contact: " + name); + + /* + * Applies the array of ContentProviderOperation objects in batch. The results are + * discarded. + */ + try { + + getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + } catch (Exception e) { + + // Display a warning + Context ctx = getApplicationContext(); + + CharSequence txt = getString(R.string.contactCreationFailure); + int duration = Toast.LENGTH_SHORT; + Toast toast = Toast.makeText(ctx, txt, duration); + toast.show(); + + // Log exception + Log.e(TAG, "Exception encountered while inserting contact: " + e); + } +} ++
+ Operasi batch juga memungkinkan Anda menerapkan kontrol konkurensi optimistis, + sebuah metode yang menerapkan transaksi modifikasi tanpa harus mengunci repository yang mendasari. + Untuk menggunakan metode ini, terapkan transaksi dan periksa modifikasi lain yang + mungkin telah dibuat bersamaan. Jika ternyata modifikasi tidak konsisten, Anda + mengembalikan transaksi ke kondisi semula dan mencobanya kembali. +
++ Kontrol konkurensi optimistis berguna untuk perangkat seluler, apabila hanya ada satu pengguna setiap + kalinya, dan akses simultan ke repository data jarang terjadi. Karena penguncian tidak digunakan, + tidak ada waktu yang terbuang untuk memasang kunci atau menunggu transaksi lain untuk melepas kunci. +
++ Untuk menggunakan kontrol konkurensi optimistis saat memperbarui satu baris + {@link android.provider.ContactsContract.RawContacts}, ikuti langkah-langkah ini: +
+-
+
- + Ambil kolom {@link android.provider.ContactsContract.SyncColumns#VERSION} + kontak mentah bersama data lain yang Anda ambil. + +
- + Buat sebuah objek {@link android.content.ContentProviderOperation.Builder} yang cocok untuk + memberlakukan batasan, dengan menggunakan metode + {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. Untuk URI konten, + gunakan {@link android.provider.ContactsContract.RawContacts#CONTENT_URI + RawContacts.CONTENT_URI} + dengan {@code android.provider.BaseColumns#_ID} kontak mentah yang ditambahkan padanya. + +
- + Untuk objek {@link android.content.ContentProviderOperation.Builder}, panggil + {@link android.content.ContentProviderOperation.Builder#withValue(String, Object) + withValue()} untuk membandingkan kolom {@link android.provider.ContactsContract.SyncColumns#VERSION} + dengan nomor versi yang baru saja Anda ambil. + +
- + Untuk {@link android.content.ContentProviderOperation.Builder} yang sama, panggil + {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int) + withExpectedCount()} untuk memastikan bahwa hanya satu baris yang diuji oleh pernyataan ini. + +
- + Panggil {@link android.content.ContentProviderOperation.Builder#build()} untuk membuat + objek {@link android.content.ContentProviderOperation}, kemudian tambahkan objek ini sebagai + objek pertama di {@link java.util.ArrayList} yang Anda teruskan ke + {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. + +
- + Terapkan transaksi batch. + +
+ Jika baris kontak mentah diperbarui oleh operasi lain antara waktu Anda membaca baris dan + waktu Anda mencoba memodifikasinya, "asert" {@link android.content.ContentProviderOperation} + akan gagal, dan seluruh batch operasi akan dibatalkan. Anda nanti bisa memilih untuk mencoba ulang + batch atau melakukan tindakan lain. +
++ Cuplikan berikut memperagakan cara membuat "asert" + {@link android.content.ContentProviderOperation} setelah membuat query satu kontak mentah yang menggunakan + {@link android.content.CursorLoader}: +
++/* + * The application uses CursorLoader to query the raw contacts table. The system calls this method + * when the load is finished. + */ +public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { + + // Gets the raw contact's _ID and VERSION values + mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); + mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); +} + +... + +// Sets up a Uri for the assert operation +Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID); + +// Creates a builder for the assert operation +ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri); + +// Adds the assertions to the assert operation: checks the version and count of rows tested +assertOp.withValue(SyncColumns.VERSION, mVersion); +assertOp.withExpectedCount(1); + +// Creates an ArrayList to hold the ContentProviderOperation objects +ArrayList ops = new ArrayList<ContentProviderOperationg>; + +ops.add(assertOp.build()); + +// You would add the rest of your batch operations to "ops" here + +... + +// Applies the batch. If the assert fails, an Exception is thrown +try + { + ContentProviderResult[] results = + getContentResolver().applyBatch(AUTHORITY, ops); + + } catch (OperationApplicationException e) { + + // Actions you want to take if the assert operation fails go here + } ++
Pengambilan dan modifikasi dengan intent
++ Mengirimkan intent ke aplikasi kontak perangkat memungkinkan Anda mengakses Penyedia Kontak + secara tidak langsung. Intent akan memulai UI aplikasi kontak perangkat, tempat pengguna bisa + melakukan pekerjaan yang terkait dengan kontak. Dengan tipe akses ini, pengguna bisa: +
-
+
- Memilih kontak dari daftar dan meneruskannya ke aplikasi untuk pekerjaan lebih jauh. +
- Mengedit data kontak yang ada. +
- Memasukkan kontak mentah baru untuk akun mereka. +
- Menghapus kontak atau data kontak. +
+ Jika pengguna menyisipkan atau memperbarui data, Anda bisa mengumpulkan data lebih dahulu dan mengirimkannya sebagai + bagian dari intent. +
++ Bila Anda menggunakan intent untuk mengakses Penyedia Kontak melalui aplikasi kontak perangkat, Anda + tidak perlu menulis UI atau kode sendiri untuk mengakses penyedia. Anda juga tidak harus + meminta izin untuk membaca dari atau menulis ke penyedia. Aplikasi kontak perangkat bisa + mendelegasikan izin membaca untuk kontak kepada Anda, dan karena Anda membuat modifikasi pada + penyedia melalui aplikasi lain, Anda tidak perlu memiliki izin menulis. +
++ Proses umum pengiriman intent untuk mengakses penyedia dijelaskan secara detail dalam panduan + + Dasar-Dasar Penyedia Konten di bagian "Akses data melalui intent". Tindakan, + tipe MIME, dan nilai data yang Anda gunakan untuk tugas yang tersedia dirangkum dalam Tabel 4, sedangkan + nilai ekstra yang bisa Anda gunakan bersama + {@link android.content.Intent#putExtra(String, String) putExtra()} tercantum dalam + dokumentasi acuan untuk {@link android.provider.ContactsContract.Intents.Insert}: +
+ +Tugas | +Tindakan | +Data | +Tipe MIME | +Catatan | +
---|---|---|---|---|
Memilih kontak dari daftar | +{@link android.content.Intent#ACTION_PICK} | +
+ Salah satu dari:
+
|
+ + Tidak digunakan + | +
+ Menampilkan daftar kontak mentah atau daftar data dari kontak mentah, sesuai dengan tipe
+ URI konten yang Anda sediakan.
+
+ Panggil
+ {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()},
+ yang menghasilkan URI konten dari baris terpilih. Bentuk URI adalah
+ URI konten tabel dengan |
+
Menyisipkan kontak mentah baru | +{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION} | +N/A | ++ {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE + RawContacts.CONTENT_TYPE}, tipe MIME untuk satu set kontak mentah. + | ++ Menampilkan layar Add Contact aplikasi kontak perangkat. Nilai + ekstra yang Anda tambahkan ke intent akan ditampilkan. Jika dikirimkan bersama + {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}, + URI konten dari kontak mentah yang baru saja ditambahkan akan dikembalikan ke + {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} + metode callback aktivitas Anda pada argumen {@link android.content.Intent}, di + bidang "data". Untuk mendapatkan nilainya, panggil {@link android.content.Intent#getData()}. + | +
Mengedit kontak | +{@link android.content.Intent#ACTION_EDIT} | ++ {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} untuk + kontak. Aktivitas editor memungkinkan pengguna mengedit setiap data yang dikaitkan + dengan kontak ini. + | ++ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE + Contacts.CONTENT_ITEM_TYPE}, kontak tunggal. | ++ Menampilkan layar Edit Contact dalam aplikasi kontak. Nilai ekstra yang Anda tambahkan + ke intent akan ditampilkan. Bila pengguna mengklik Done untuk menyimpan + hasil edit, aktivitas Anda kembali ke latar depan. + | +
Menampilkan picker yang juga bisa menambahkan data. | +{@link android.content.Intent#ACTION_INSERT_OR_EDIT} | ++ N/A + | ++ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE} + | +
+ Intent ini selalu menampilkan layar picker aplikasi kontak. Pengguna bisa memilih
+ kontak untuk diedit, atau menambahkan kontak baru. Layar edit atau layar tambah
+ akan muncul, sesuai dengan pilihan pengguna, dan data ekstra yang Anda kirimkan dalam intent
+ akan ditampilkan. Jika aplikasi Anda menampilkan data kontak seperti email atau nomor telepon, gunakan
+ intent ini untuk memungkinkan pengguna menambahkan data ke kontak yang ada.
+
+ + Catatan: Tidak perlu mengirimkan nilai nama dalam ekstra intent ini, + karena pengguna selalu mengambil nama yang ada atau menambahkan nama baru. Lebih-lebih, + jika Anda mengirimkan nama, dan pengguna memilih untuk melakukan edit, aplikasi kontak akan + menampilkan nama yang Anda kirimkan, yang menimpa nilai sebelumnya. Jika pengguna tidak + menyadari hal ini dan menyimpan hasil edit, nilai lama akan hilang. + + |
+
+ Aplikasi kontak perangkat tidak memperbolehkan Anda menghapus kontak mentah atau datanya dengan + intent. Sebagai gantinya, untuk menghapus kontak mentah, gunakan + {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()} + atau {@link android.content.ContentProviderOperation#newDelete(Uri) + ContentProviderOperation.newDelete()}. +
++ Cuplikan berikut menampilkan cara menyusun dan mengirimkan intent yang menyisipkan kontak dan data + mentah baru: +
++// Gets values from the UI +String name = mContactNameEditText.getText().toString(); +String phone = mContactPhoneEditText.getText().toString(); +String email = mContactEmailEditText.getText().toString(); + +String company = mCompanyName.getText().toString(); +String jobtitle = mJobTitle.getText().toString(); + +// Creates a new intent for sending to the device's contacts application +Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); + +// Sets the MIME type to the one expected by the insertion activity +insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); + +// Sets the new contact name +insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); + +// Sets the new company and job title +insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); +insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); + +/* + * Demonstrates adding data rows as an array list associated with the DATA key + */ + +// Defines an array list to contain the ContentValues objects for each row +ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); + + +/* + * Defines the raw contact row + */ + +// Sets up the row as a ContentValues object +ContentValues rawContactRow = new ContentValues(); + +// Adds the account type and name to the row +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()); +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + +// Adds the row to the array +contactData.add(rawContactRow); + +/* + * Sets up the phone number data row + */ + +// Sets up the row as a ContentValues object +ContentValues phoneRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +phoneRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE +); + +// Adds the phone number and its type to the row +phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); + +// Adds the row to the array +contactData.add(phoneRow); + +/* + * Sets up the email data row + */ + +// Sets up the row as a ContentValues object +ContentValues emailRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +emailRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE +); + +// Adds the email address and its type to the row +emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); + +// Adds the row to the array +contactData.add(emailRow); + +/* + * Adds the array to the intent's extras. It must be a parcelable object in order to + * travel between processes. The device's contacts app expects its key to be + * Intents.Insert.DATA + */ +insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); + +// Send out the intent to start the device's contacts app in its add contact activity. +startActivity(insertIntent); ++
Integritas data
++ Karena repository kontak berisi data penting dan sensitif yang diharapkan pengguna agar + benar dan terbaru. Penyedia Kontak memiliki aturan yang didefinisikan dengan baik demi integritas data. Anda + bertanggung jawab untuk mematuhi aturan ini saat memodifikasi data kontak. Aturan-aturan penting itu + dicantumkan di sini: +
+-
+
- + Selalu tambahkan baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} + untuk setiap baris {@link android.provider.ContactsContract.RawContacts} yang Anda tambahkan. + +
- + Baris {@link android.provider.ContactsContract.RawContacts} tanpa + baris {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} dalam + tabel {@link android.provider.ContactsContract.Data} bisa menyebabkan masalah selama + agregasi. + +
- + Selalu tautkan baris {@link android.provider.ContactsContract.Data} baru ke baris + {@link android.provider.ContactsContract.RawContacts} induknya. + +
- + Baris {@link android.provider.ContactsContract.Data} yang tidak ditautkan ke + {@link android.provider.ContactsContract.RawContacts} tidak akan terlihat dalam aplikasi kontak + perangkat, dan itu bisa menimbulkan masalah dengan adaptor sinkronisasi. + +
- + Ubah data hanya untuk kontak mentah yang Anda miliki. + +
- + Ingatlah bahwa Penyedia Kontak biasanya mengelola data dari berbagai + tipe akun/layanan online. Anda harus memastikan bahwa aplikasi Anda hanya memodifikasi + atau menghapus data untuk baris milik Anda, dan bahwa aplikasi hanya menyisipkan data dengan + tipe akun dan nama yang Anda kontrol. + +
- + Selalu gunakan konstanta yang didefinisikan dalam {@link android.provider.ContactsContract} dan + subkelasnya untuk otoritas, URI konten, URI path, nama kolom, tipe MIME, dan + nilai {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE}. + +
- + Menggunakan konstanta ini membantu Anda menghindari kesalahan. Anda juga akan diberi tahu dengan peringatan + compiler jika salah satu konstanta sudah usang. + +
Baris data custom
++ Dengan membuat dan menggunakan tipe MIME custom sendiri, Anda bisa menyisipkan, mengedit, menghapus, dan mengambil + baris data sendiri dalam tabel {@link android.provider.ContactsContract.Data}. Baris Anda + dibatasi untuk menggunakan kolom yang didefinisikan dalam + {@link android.provider.ContactsContract.DataColumns}, meskipun Anda bisa memetakan nama kolom + bertipe spesifik sendiri ke nama kolom default. Dalam aplikasi kontak perangkat, + data untuk baris Anda ditampilkan, tetapi tidak bisa diedit atau dihapus, dan pengguna tidak bisa menambahkan + data lain. Untuk memudahkan pengguna mengubah baris data custom Anda, Anda harus menyediakan aktivitas + editor dalam aplikasi Anda sendiri. +
+
+ Untuk menampilkan data custom, sediakan file contacts.xml
berisi elemen
+ <ContactsAccountType>
dan satu atau beberapa elemen anak
+ <ContactsDataKind>
. Hal ini dijelaskan lebih detail di
+ bagian <ContactsDataKind> element
.
+
+ Untuk mengetahui selengkapnya tentang tipe MIME custom, bacalah panduan + + Membuat Penyedia Konten. +
+Adaptor Sinkronisasi Penyedia Kontak
++ Penyedia Kontak didesain khusus untuk menangani sinkronisasi + data kontak antara perangkat dan layanan online. Hal ini memungkinkan pengguna mengunduh + data yang ada dari perangkat baru dan mengunggah data yang ada ke akun baru. + Sinkronisasi juga memastikan bahwa pengguna memiliki data terbaru, apa pun + sumber penambahan dan perubahan itu. Keuntungan lain dari sinkronisasi adalah membuat + data kontak tersedia sekalipun perangkat tidak terhubung ke jaringan. +
++ Walaupun Anda bisa menerapkan sinkronisasi dengan berbagai cara, sistem Android menyediakan + kerangka kerja sinkronisasi plug-in yang mengotomatiskan tugas-tugas berikut: +
-
+
+
- + Memeriksa ketersediaan jaringan. + +
- + Menjadwalkan dan menjalankan sinkronisasi, berdasarkan preferensi pengguna. + +
- + Memulai kembali sinkronisasi yang telah berhenti. + +
+ Untuk menggunakan kerangka kerja ini, Anda harus menyediakan plug-in adaptor sinkronisasi. Setiap adaptor sinkronisasi bersifat unik bagi + layanan dan penyedia konten, tetapi mampu menangani beberapa nama akun untuk layanan yang sama. Kerangka + kerja ini juga memungkinkan beberapa adaptor sinkronisasi untuk layanan dan penyedia yang sama. +
+Kelas dan file adaptor sinkronisasi
++ Anda mengimplementasikan adaptor sinkronisasi sebagai subkelas + {@link android.content.AbstractThreadedSyncAdapter} dan menginstalnya sebagai bagian dari aplikasi + Android. Sistem akan mempelajari adaptor sinkronisasi dari elemen-elemen di manifes + aplikasi Anda dan dari file XML khusus yang ditunjuk oleh manifes. File XML mendefinisikan + tipe akun untuk layanan online dan otoritas untuk penyedia konten, yang bersama-sama + mengidentifikasi adaptor secara unik. Adaptor sinkronisasi tidak menjadi aktif hingga pengguna menambahkan + akun untuk tipe akun adaptor sinkronisasi dan memungkinkan sinkronisasi untuk penyedia + konten yang disinkronkan dengan adaptor sinkronisasi. Pada saat itu, sistem mulai mengelola adaptor, + memanggilnya seperlunya untuk menyinkronkan antara penyedia konten dan server. +
+
+ Catatan: Menggunakan tipe akun sebagai bagian dari identifikasi adaptor sinkronisasi memungkinkan
+ sistem mendeteksi dan menghimpun adaptor-adaptor sinkronisasi yang mengakses berbagai layanan dari
+ organisasi yang sama. Misalnya, adaptor sinkronisasi untuk semua layanan online Google semuanya memiliki tipe akun
+ yang sama com.google
. Bila pengguna menambahkan akun Google ke perangkatnya, semua
+ adaptor sinkronisasi yang terinstal untuk layanan Google akan dicantumkan bersama; setiap adaptor sinkronisasi
+ yang tercantum akan menyinkronkan diri dengan berbagai penyedia konten pada perangkat.
+
+ Karena sebagian besar layanan mengharuskan pengguna untuk memeriksa identitas sebelum mengakses + data, sistem Android menawarkan kerangka kerja autentikasi yang serupa dengan, dan sering kali + digunakan bersama, kerangka kerja adaptor sinkronisasi. Kerangka kerja autentikasi menggunakan + autentikator plug-in yang merupakan subkelas + {@link android.accounts.AbstractAccountAuthenticator}. Autentikator memeriksa + identitas pengguna dalam langkah-langkah berikut: +
-
+
- + Mengumpulkan nama pengguna, kata sandi, atau informasi serupa ( + kredensial pengguna). + +
- + Mengirimkan kredensial ke layanan + +
- + Memeriksa balasan layanan. + +
+ Jika layanan menerima kredensial, autentikator bisa + menyimpan kredensial itu untuk digunakan nanti. Karena kerangka kerja autentikator plug-in, + {@link android.accounts.AccountManager} bisa menyediakan akses ke setiap token autentikasi yang didukung suatu autentikator + dan dipilihnya untuk diekspos, seperti token autentikasi OAuth2. +
++ Meskipun autentikasi tidak diharuskan, sebagian besar layanan kontak menggunakannya. + Akan tetapi, Anda tidak wajib menggunakan kerangka kerja autentikasi Android untuk melakukan autentikasi. +
+Implementasi adaptor sinkronisasi
++ Untuk mengimplementasikan adaptor sinkronisasi bagi Penyedia Kontak, perlu Anda memulai dengan membuat + aplikasi Android yang berisi elemen-elemen berikut: +
+-
+
- + Komponen {@link android.app.Service} yang merespons permintaan sistem untuk + mengikat ke adaptor sinkronisasi. + +
-
+ Bila sistem ingin menjalankan sinkronisasi, sistem akan memanggil metode
+ {@link android.app.Service#onBind(Intent) onBind()} layanan untuk mendapatkan
+ {@link android.os.IBinder} bagi adaptor sinkronisasi. Hal ini memungkinkan sistem melakukan
+ panggilan lintas proses ke metode adaptor.
+
+ Dalam contoh aplikasi + Sample Sync Adapter, nama kelas layanan ini adalah +
+com.example.android.samplesync.syncadapter.SyncService
. +
+ - + Adaptor sinkronisasi yang sesungguhnya, diimplementasikan sebagai subkelas konkret dari + {@link android.content.AbstractThreadedSyncAdapter}. + +
-
+ Kelas ini melakukan pekerjaan mengunduh data dari server, mengunggah data ke
+ perangkat, dan menyelesaikan konflik. Pekerjaan utama adaptor
+ diselesaikan dengan metode {@link android.content.AbstractThreadedSyncAdapter#onPerformSync(
+ Account, Bundle, String, ContentProviderClient, SyncResult)
+ onPerformSync()}. Instance kelas ini harus dibuat sebagai singleton.
+
+ Dalam contoh aplikasi + Sample Sync Adapter, adaptor sinkronisasi didefinisikan dalam kelas +
+com.example.android.samplesync.syncadapter.SyncAdapter
. +
+ - + Subkelas {@link android.app.Application}. + +
- + Kelas ini berfungsi sebagai pabrik untuk singleton adaptor sinkronisasi. Gunakan + metode {@link android.app.Application#onCreate()} untuk membuat instance adaptor sinkronisasi , dan + menyediakan metode "getter" statis untuk mengembalikan singleton ke + metode {@link android.app.Service#onBind(Intent) onBind()} dari layanan + adaptor sinkronisasi. + +
- + Opsional: Komponen {@link android.app.Service} yang merespons + permintaan dari sistem untuk autentikasi pengguna. + +
-
+ {@link android.accounts.AccountManager} memulai layanan ini untuk memulai proses
+ autentikasi. Metode {@link android.app.Service#onCreate()} layanan membuat instance
+ objek autentikator. Bila sistem ingin mengautentikasi akun pengguna untuk
+ adaptor sinkronisasi aplikasi, sistem akan memanggil metode
+{@link android.app.Service#onBind(Intent) onBind()} layanan guna mendapatkan
+ {@link android.os.IBinder} bagi autentikator. Hal ini memungkinkan sistem melakukan
+ panggilan lintas proses ke metode autentikator.
+
+ Dalam contoh aplikasi + Sample Sync Adapter, nama kelas layanan ini adalah +
+com.example.android.samplesync.authenticator.AuthenticationService
. +
+ - + Opsional: Subkelas konkret + {@link android.accounts.AbstractAccountAuthenticator} yang menangani permintaan + autentikasi. + +
-
+ Kelas ini menyediakan metode yang dipicu {@link android.accounts.AccountManager}
+ untuk mengautentikasi kredensial pengguna dengan layanan. Detail
+ proses autentikasi sangat bervariasi, berdasarkan teknologi server yang digunakan. Anda harus
+ mengacu ke dokumentasi bagi perangkat lunak server untuk mengetahui selengkapnya tentang autentikasi.
+
+ Dalam contoh aplikasi + Sample Sync Adapter, autentikator didefinisikan dalam kelas +
+com.example.android.samplesync.authenticator.Authenticator
. +
+ - + File XML yang mendefinisikan adaptor sinkronisasi dan autentikator bagi sistem. + +
-
+ Komponen-komponen layanan adaptor sinkronisasi dan autentikator
+ didefinisikan dalam elemen-elemen
+
<service>
+ di manifes aplikasi. Elemen-elemen ini + berisi +<meta-data>
+elemen anak yang menyediakan data tertentu ke + sistem: +-
+
-
+ Elemen
+
<meta-data>
+ untuk layanan adaptor sinkronisasi menunjuk ke + file XMLres/xml/syncadapter.xml
. Pada gilirannya, file ini mendefinisikan + URI untuk layanan web yang akan disinkronkan dengan Penyedia Kontak, + dan tipe akun untuk layanan web. +
+ -
+ Opsional: Elemen
+
<meta-data>
+ untuk autentikator menunjuk ke file XML +res/xml/authenticator.xml
. Pada gilirannya, file ini menetapkan + tipe akun yang didukung autentikator, serta sumber daya UI yang + muncul selama proses autentikasi. Tipe akun yang ditetapkan dalam elemen ini + harus sama dengan tipe akun yang ditetapkan untuk adaptor + sinkronisasi. +
+
+ -
+ Elemen
+
Data Aliran Sosial
++ Tabel-tabel {@code android.provider.ContactsContract.StreamItems} dan + {@code android.provider.ContactsContract.StreamItemPhotos} + mengelola data yang masuk dari jaringan sosial. Anda bisa menulis adaptor sinkronisasi yang menambahkan data aliran + dari jaringan Anda sendiri ke tabel-tabel ini, atau Anda bisa membaca data aliran dari tabel-tabel ini dan + menampilkannya dalam aplikasi sendiri, atau keduanya. Dengan fitur-fitur ini, layanan dan aplikasi + jaringan sosial Anda bisa diintegrasikan ke dalam pengalaman jaringan sosial Android. +
+Teks aliran sosial
+
+ Item aliran selalu dikaitkan dengan kontak mentah.
+ {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} menautkan ke
+ nilai _ID
untuk kontak mentah. Tipe akun dan nama akun kontak
+ mentah juga disimpan dalam baris item aliran.
+
+ Simpanlah data dari aliran Anda dalam kolom-kolom berikut: +
+-
+
- + {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE} + +
- + Diperlukan. Tipe akun pengguna untuk kontak mentah yang dikaitkan dengan + item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran. + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME} + +
- + Diperlukan. Nama akun pengguna untuk kontak mentah yang dikaitkan dengan + item aliran ini. Ingatlah untuk mengatur nilai ini saat Anda menyisipkan item aliran. + +
- + Kolom identifier + +
-
+ Diperlukan. Anda harus memasukkan kolom identifier berikut saat
+ menyisipkan item aliran:
+
-
+
- + {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}: + Nilai {@code android.provider.BaseColumns#_ID} kontak yang dikaitkan dengan item aliran + ini. + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: + Nilai {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} + kontak yang dikaitkan dengan item aliran ini. + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}: + Nilai {@code android.provider.BaseColumns#_ID} kontak mentah yang dikaitkan dengan item aliran + ini. + +
+ - + {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS} + +
- + Opsional. Menyimpan informasi rangkuman yang bisa Anda tampilkan di awal item aliran. + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#TEXT} + +
- + Teks item aliran, baik konten yang diposting oleh sumber item, + maupun keterangan beberapa tindakan yang menghasilkan item aliran. Kolom ini bisa berisi + sembarang gambar sumber daya pemformatan dan tertanam yang bisa dirender oleh + {@link android.text.Html#fromHtml(String) fromHtml()}. Penyedia bisa memotong atau + menghapus konten yang panjang, tetapi penyedia akan mencoba menghindari memutus tag. + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} + +
- + String teks berisi waktu item aliran yang disisipkan atau diperbarui, berupa + milidetik sejak waktu patokan. Aplikasi yang menyisipkan atau memperbarui item aliran + bertanggung jawab memelihara kolom ini; aplikasi tidak dipelihara secara otomatis oleh + Penyedia Kontak. + +
+ Untuk menampilkan informasi pengidentifikasi item aliran Anda, gunakan + {@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON}, + {@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}, dan + {@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} untuk menautkan ke sumber daya + dalam aplikasi Anda. +
++ Tabel {@code android.provider.ContactsContract.StreamItems} juga berisi kolom-kolom + {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} hingga + {@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} untuk penggunaan eksklusif oleh + adaptor sinkronisasi. +
+Foto aliran sosial
++ Tabel {@code android.provider.ContactsContract.StreamItemPhotos} menyimpan foto-foto yang dikaitkan + dengan item aliran. Kolom +{@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} tabel ini + menautkan ke nilai dalam kolom {@code android.provider.BaseColumns#_ID} + tabel {@code android.provider.ContactsContract.StreamItems}. Acuan foto disimpan dalam + tabel pada kolom-kolom ini: +
+-
+
- + Kolom {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} (BLOB). + +
- + Representasi biner foto, yang diubah ukurannya oleh penyedia untuk penyimpanan dan tampilan. + Kolom ini tersedia untuk kompatibilitas ke belakang dengan versi Penyedia Kontak + sebelumnya yang menggunakannya untuk menyimpan foto. Akan tetapi, pada versi saat ini + Anda tidak boleh menggunakan kolom ini untuk menyimpan foto. Sebagai gantinya, gunakan + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} atau + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} (keduanya + dijelaskan dalam poin-poin berikut) untuk menyimpan foto di file. Kolom ini sekarang + berisi thumbnail foto, yang tersedia untuk dibaca. + +
- + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} + +
- + Identifier numerik foto untuk kontak mentah. Tambahkan nilai ini ke konstanta + {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI} + untuk mendapatkan URI konten yang menunjuk ke satu file foto, kemudian panggil + {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) + openAssetFileDescriptor()} untuk mendapatkan handle ke file foto. + +
- + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} + +
- + URI konten menunjuk langsung ke file foto untuk foto yang diwakili oleh baris ini. + Panggillah {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) + openAssetFileDescriptor()} dengan URI ini untuk mendapatkan handle ke file foto. + +
Menggunakan tabel aliran sosial
++ Tabel-tabel ini sama fungsinya dengan tabel-tabel utama lainnya dalam Penyedia Kontak, kecuali: +
+-
+
- + Tabel-tabel ini memerlukan izin akses tambahan. Untuk membaca dari tabel, aplikasi Anda + harus memiliki izin {@code android.Manifest.permission#READ_SOCIAL_STREAM}. Untuk memodifikasi + tabel, aplikasi Anda harus memiliki izin + {@code android.Manifest.permission#WRITE_SOCIAL_STREAM}. + +
-
+ Untuk tabel {@code android.provider.ContactsContract.StreamItems}, jumlah baris
+ yang disimpan bagi setiap kontak mentah adalah terbatas. Setelah batasnya tercapai,
+ Penyedia Kontak akan membuat ruang untuk baris item aliran baru dengan menghapus secara otomatis
+ baris yang memiliki
+ {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} terlama. Untuk mendapatkan
+ batas, keluarkan query ke URI konten
+ {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI}. Anda bisa membiarkan
+ semua argumen selain URI konten diatur ke
null
. Query + menghasilkan sebuah Kursor yang berisi baris tunggal, dengan kolom tunggal + {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS}. +
+
+ Kelas {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} mendefinisikan + subtabel {@code android.provider.ContactsContract.StreamItemPhotos} yang berisi + baris foto untuk satu item aliran. +
+Interaksi aliran sosial
++ Data aliran sosial yang dikelola oleh Penyedia Kontak, bersama aplikasi kontak + perangkat, menawarkan cara andal untuk menghubungkan sistem jaringan sosial Anda + dengan kontak yang ada. Tersedia fitur-fitur berikut: +
+-
+
- + Dengan menyinkronkan layanan jaringan sosial ke Penyedia Kontak dengan adaptor + sinkronisasi, Anda bisa mengambil aktivitas terbaru untuk kontak pengguna dan menyimpannya dalam tabel-tabel + {@code android.provider.ContactsContract.StreamItems} dan + {@code android.provider.ContactsContract.StreamItemPhotos} untuk digunakan nanti. + +
- + Selain sinkronisasi rutin, Anda bisa memicu adaptor sinkronisasi agar mengambil + data tambahan bila pengguna memilih sebuah kontak untuk ditampilkan. Hal ini memungkinkan adaptor sinkronisasi Anda + mengambil foto resolusi tinggi dan item aliran terbaru untuk kontak. + +
- + Dengan mendaftarkan pemberitahuan pada aplikasi kontak perangkat dan Penyedia Kontak, + Anda bisa menerima intent saat kontak ditampilkan, dan pada saat itu + memperbarui status kontak dari layanan Anda. Pendekatan ini mungkin lebih cepat dan menggunakan + bandwidth lebih sedikit daripada melakukan sinkronisasi penuh dengan adaptor sinkronisasi. + +
- + Pengguna bisa menambahkan kontak ke layanan jaringan sosial Anda sambil melihat kontak + dalam aplikasi kontak perangkat. Anda mengaktifkannya dengan fitur "invite contact", + yang Anda aktifkan dengan kombinasi aktivitas yang menambahkan kontak yang ada ke jaringan + Anda, dan file XML yang menyediakan aplikasi kontak perangkat dan + Penyedia Kontak dengan detail aplikasi Anda. + +
+ Sinkronisasi rutin item aliran dengan Penyedia Kontak sama dengan + sinkronisasi lainnya. Untuk mengetahui selengkapnya tentang sinkronisasi, lihat bagian + Adaptor Sinkronisasi Penyedia Kontak. Mendaftarkan pemberitahuan dan + mengundang kontak dibahas dalam dua bagian berikutnya. +
+Pendaftaran untuk menangani tampilan jaringan sosial
++ Untuk mendaftarkan adaptor sinkronisasi agar menerima pemberitahuan saat pengguna menampilkan kontak + yang dikelola oleh adaptor sinkronisasi Anda: +
+-
+
-
+ Buat file yang bernama
contacts.xml
dalam direktorires/xml/
+ proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. +
+ -
+ Dalam file ini, tambahkan elemen
+
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. + Jika elemen ini sudah ada, langkah ini boleh dilewati. +
+ -
+ Untuk mendaftarkan layanan yang diberitahukan saat pengguna membuka halaman detail kontak dalam
+ aplikasi kontak perangkat, tambahkan atribut
+
viewContactNotifyService="serviceclass"
ke elemen, dengan +serviceclass
sebagai nama kelas mutlak (fully qualified) dari layanan + yang seharusnya menerima intent dari aplikasi kontak perangkat. Untuk layanan + notifier, gunakan kelas yang memperluas {@link android.app.IntentService}, guna memudahkan layanan + untuk menerima intent. Data dalam intent yang masuk berisi URI konten dari kontak + mentah yang diklik pengguna. Untuk layanan notifier, Anda bisa mengikatnya ke kemudian memanggil + adaptor sinkronisasi Anda untuk memperbarui data bagi kontak mentah. +
+
+ Untuk mendaftarkan aktivitas agar dipanggil saat pengguna mengklik item aliran atau foto atau keduanya: +
+-
+
-
+ Buat file yang bernama
contacts.xml
dalam direktorires/xml/
+ proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. +
+ -
+ Dalam file ini, tambahkan elemen
+
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. + Jika elemen ini sudah ada, langkah ini boleh dilewati. +
+ -
+ Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada item aliran dalam
+ aplikasi kontak perangkat, tambahkan atribut
+
viewStreamItemActivity="activityclass"
ke elemen, dengan +activityclass
sebagai nama kelas mutlak (fully-qualified) dari aktivitas + yang harus menerima intent dari aplikasi kontak perangkat. +
+ -
+ Untuk mendaftarkan salah satu aktivitas Anda guna menangani klik oleh pengguna pada foto aliran dalam
+ aplikasi kontak perangkat, tambahkan atribut
+
viewStreamItemPhotoActivity="activityclass"
ke elemen, dengan +activityclass
adalah kelas nama mutlak aktivitas + yang harus menerima intent dari aplikasi kontak perangkat. +
+
+ Elemen <ContactsAccountType>
dijelaskan lebih detail di
+ bagian Elemen <ContactsAccountType>.
+
+ Intent yang masuk berisi URI konten dari materi atau foto yang diklik pengguna. + Untuk mendapatkan aktivitas terpisah bagi item teks dan foto, gunakan kedua atribut dalam file yang sama. +
+Berinteraksi dengan layanan jaringan sosial Anda
++ Pengguna tidak harus meninggalkan aplikasi perangkat kontak untuk mengundang kontak ke situs + jaringan sosial Anda. Sebagai gantinya, Anda bisa meminta aplikasi kontak perangkat mengirimkan intent untuk mengundang + kontak ke salah satu aktivitas Anda. Untuk mempersiapkannya: +
+-
+
-
+ Buat file yang bernama
contacts.xml
dalam direktorires/xml/
+ proyek Anda. Jika sudah memiliki file ini, langkah ini boleh dilewati. +
+ -
+ Dalam file ini, tambahkan elemen
+
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. + Jika elemen ini sudah ada, langkah ini boleh dilewati. +
+ -
+ Tambahkan atribut-atribut berikut:
+
-
+
inviteContactActivity="activityclass"
+ -
+
inviteContactActionLabel="@string/invite_action_label"
+
+
activityclass
adalah nama kelas mutlak + aktivitas yang harus menerima intent ini. Nilaiinvite_action_label
+ adalah string teks yang ditampilkan dalam menu Add Connection dalam + aplikasi kontak perangkat. +
+
+ Catatan: ContactsSource
adalah nama tag yang sudah usang untuk
+ ContactsAccountType
.
+
Acuan contacts.xml
+
+ File contacts.xml
berisi elemen XML yang mengontrol interaksi adaptor sinkronisasi
+ Anda dan aplikasi dengan aplikasi kontak dan Penyedia Kontak. Elemen-elemen ini
+ dijelaskan di bagian-bagian selanjutnya.
+
Elemen <ContactsAccountType>
+
+ Elemen <ContactsAccountType>
mengontrol interaksi aplikasi
+ Anda dengan aplikasi kontak. Sintaksnya adalah sebagai berikut:
+
+<ContactsAccountType + xmlns:android="http://schemas.android.com/apk/res/android" + inviteContactActivity="activity_name" + inviteContactActionLabel="invite_command_text" + viewContactNotifyService="view_notify_service" + viewGroupActivity="group_view_activity" + viewGroupActionLabel="group_action_text" + viewStreamItemActivity="viewstream_activity_name" + viewStreamItemPhotoActivity="viewphotostream_activity_name"> ++
+ dimuat dalam: +
+
+ res/xml/contacts.xml
+
+ bisa berisi: +
+
+ <ContactsDataKind>
+
+ Keterangan: +
++ Mendeklarasikan komponen Android dan label UI yang memungkinkan pengguna mengundang salah satu kontak ke + jaringan sosial, memberi tahu pengguna bila salah satu aliran jaringan sosial diperbarui, dan + seterusnya. +
+
+ Perhatikan bahwa awalan atribut android:
tidak perlu untuk atribut-atribut
+ <ContactsAccountType>
.
+
+ Atribut: +
+-
+
- {@code inviteContactActivity} +
- + Nama kelas mutlak aktivitas dalam aplikasi yang Anda ingin + aktifkan bila pengguna memilih Add connection dari aplikasi kontak + perangkat. + +
- {@code inviteContactActionLabel} +
- + String teks yang ditampilkan untuk aktivitas yang ditetapkan dalam + {@code inviteContactActivity}, dalam menu Add connection. + Misalnya, Anda bisa menggunakan string "Ikuti di jaringan saya". Anda bisa menggunakan identifier sumber daya + string untuk tabel ini. + +
- {@code viewContactNotifyService} +
-
+ Nama kelas mutlak layanan dalam aplikasi Anda yang harus menerima
+ pemberitahuan saat pengguna menampilkan kontak. Pemberitahuan ini dikirimkan oleh aplikasi kontak
+ perangkat; hal ini memungkinkan aplikasi Anda menunda operasi yang banyak memproses data
+ hingga dibutuhkan. Misalnya, aplikasi Anda bisa merespons pemberitahuan ini
+ dengan membaca dalam dan menampilkan foto resolusi tinggi kontak dan item aliran sosial
+ terbaru. Fitur ini dijelaskan lebih detail di bagian
+ Interaksi aliran sosial. Anda bisa melihat
+ contoh layanan pemberitahuan dalam file
NotifierService.java
dalam contoh aplikasi + Sample Sync Adapter. + +
+ - {@code viewGroupActivity} +
- + Nama kelas mutlak aktivitas dalam aplikasi yang bisa menampilkan + informasi grup. Bila pengguna mengklik label grup dalam aplikasi + kontak perangkat, UI aktivitas ini akan ditampilkan. + +
- {@code viewGroupActionLabel} +
-
+ Label yang ditampilkan aplikasi kontak untuk kontrol UI yang memungkinkan
+ pengguna melihat grup dalam aplikasi Anda.
+
+ Misalnya, jika Anda menginstal aplikasi Google+ di perangkat dan menyinkronkan + Google+ dengan aplikasi kontak, Anda akan melihat lingkaran Google+ tercantum sebagai grup + dalam tab Groups aplikasi kontak Anda. Jika Anda mengklik + lingkaran Google+, Anda akan melihat orang-orang di lingkaran itu tercantum sebagai satu "grup". Di atas + tampilan, Anda akan melihat ikon Google+; jika mengklik ikon itu, kontrol akan beralih ke + aplikasi Google+. Aplikasi kontak melakukan ini dengan + {@code viewGroupActivity}, yang menggunakan ikon Google+ sebagai nilai + {@code viewGroupActionLabel}. +
++ Identifier sumber daya string diperbolehkan untuk atribut ini. +
+
+ - {@code viewStreamItemActivity} +
- + Nama kelas mutlak aktivitas dalam aplikasi Anda + yang diluncurkan aplikasi kontak perangkat bila pengguna mengklik item aliran untuk kontak mentah. + +
- {@code viewStreamItemPhotoActivity} +
- + Nama kelas mutlak aktivitas yang diluncurkan + aplikasi kontak perangkat bila pengguna mengklik foto dalam item aliran + untuk kontak mentah. + +
Elemen <ContactsDataKind>
+
+ Elemen <ContactsDataKind>
mengontrol tampilan baris data custom
+ aplikasi Anda dalam UI aplikasi kontak. Sintaksnya adalah sebagai berikut:
+
+<ContactsDataKind + android:mimeType="MIMEtype" + android:icon="icon_resources" + android:summaryColumn="column_name" + android:detailColumn="column_name"> ++
+ dimuat dalam: +
+<ContactsAccountType>
++ Keterangan: +
+
+ Gunakan elemen ini untuk memerintahkan aplikasi kontak agar menampilkan konten baris data custom sebagai
+ bagian dari detail kontak mentah. Setiap elemen anak <ContactsDataKind>
+ <ContactsAccountType>
mewakili tipe baris data custom yang
+ ditambahkan adaptor sinkronisasi Anda ke tabel {@link android.provider.ContactsContract.Data}. Tambahkan satu
+ elemen <ContactsDataKind>
untuk setiap tipe MIME custom yang Anda gunakan. Anda tidak harus
+ menambahkan elemen jika Anda memiliki baris data custom yang datanya tidak ingin ditampilkan.
+
+ Atribut: +
+-
+
- {@code android:mimeType} +
-
+ Tipe MIME custom yang telah Anda definisikan untuk salah satu tipe baris data custom dalam
+ tabel {@link android.provider.ContactsContract.Data}. Misalnya, nilai
+
vnd.android.cursor.item/vnd.example.locationstatus
bisa berupa tipe MIME + custom untuk baris data yang mencatat lokasi kontak yang terakhir diketahui. +
+ - {@code android:icon} +
- + + Sumber daya drawable + Android yang ditampilkan aplikasi kontak di samping data Anda. Gunakan ini untuk menunjukkan kepada + pengguna bahwa data berasal dari layanan Anda. + +
- {@code android:summaryColumn} +
- + Nama kolom untuk yang pertama dari dua nilai yang diambil dari baris data. Nilai + ditampilkan sebagai baris pertama entri untuk baris data ini. Baris pertama + dimaksudkan untuk digunakan sebagai rangkuman data, tetapi itu bersifat opsional. Lihat juga + android:detailColumn. + +
- {@code android:detailColumn} +
- + Nama kolom untuk yang kedua dari dua nilai yang diambil dari baris data. Nilai + ditampilkan sebagai baris kedua entri untuk baris data ini. Lihat juga + {@code android:summaryColumn}. + +
Fitur Tambahan Penyedia Kontak
++ Di samping fitur-fitur utama yang dijelaskan di bagian sebelumnya, Penyedia Kontak menawarkan + fitur-fitur berguna ini untuk digunakan bersama data kontak: +
+-
+
- Grup kontak +
- Fitur foto +
Grup kontak
++ Penyedia Kontak secara opsional bisa melabeli kumpulan kontak terkait dengan data + grup. Jika server yang dikaitkan dengan akun pengguna + ingin mempertahankan grup, adaptor sinkronisasi untuk tipe akun dari akun itu harus mentransfer + data grup antara Penyedia Kontak dan server. Bila pengguna menambahkan kontak baru ke + server, kemudian memasukkan kontak ini dalam grup baru, adaptor sinkronisasi harus menambahkan grup baru + ke tabel {@link android.provider.ContactsContract.Groups}. Grup atau grup-grup yang memiliki kontak + disimpan dalam tabel {@link android.provider.ContactsContract.Data}, dengan menggunakan + tipe MIME {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}. +
++ Jika Anda mendesain adaptor sinkronisasi yang akan menambahkan data kontak mentah dari + server ke Penyedia Kontak, dan Anda tidak menggunakan grup, maka Anda harus memberi tahu + penyedia itu agar membuat data Anda terlihat. Dalam kode yang dijalankan bila pengguna menambahkan akun + ke perangkat, perbarui baris {@link android.provider.ContactsContract.Settings} + yang ditambahkan Penyedia Kontak untuk akunnya. Dalam baris ini, atur nilai kolom + {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE + Settings.UNGROUPED_VISIBLE} ke 1. Bila melakukannya, Penyedia Kontak akan selalu + membuat data kontak Anda terlihat, meskipun Anda tidak menggunakan grup. +
+Foto kontak
++ Tabel {@link android.provider.ContactsContract.Data} menyimpan foto sebagai baris dengan tipe MIME + {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE + Photo.CONTENT_ITEM_TYPE}. Kolom + {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} baris yang ditautkan ke + kolom {@code android.provider.BaseColumns#_ID} kontak mentah yang memiliki kolom itu. + Kelas {@link android.provider.ContactsContract.Contacts.Photo} mendefinisikan subtabel + {@link android.provider.ContactsContract.Contacts} yang berisi informasi foto untuk foto + utama kontak, yang merupakan foto utama dari kontak mentah utama kontak itu. Demikian pula, + kelas {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} mendefinisikan subtabel + {@link android.provider.ContactsContract.RawContacts} yang berisi informasi foto untuk + foto utama kontak mentah. +
++ Dokumentasi acuan untuk {@link android.provider.ContactsContract.Contacts.Photo} dan + {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} berisi contoh-contoh + pengambilan informasi foto. Tidak ada kelas praktis untuk mengambil + thumbnail utama kontak mentah, tetapi Anda bisa mengirim query ke + tabel {@link android.provider.ContactsContract.Data}, dengan memilih + {@code android.provider.BaseColumns#_ID} kontak mentah, + {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE + Photo.CONTENT_ITEM_TYPE}, dan kolom {@link android.provider.ContactsContract.Data#IS_PRIMARY} + untuk menemukan baris foto utama kontak mentah. +
++ Data aliran sosial untuk seseorang bisa juga disertai foto. Data ini disimpan dalam + tabel {@code android.provider.ContactsContract.StreamItemPhotos}, yang dijelaskan lebih detail + di bagian Foto aliran sosial. +
diff --git a/docs/html-intl/intl/in/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/in/guide/topics/providers/content-provider-basics.jd new file mode 100644 index 0000000000000000000000000000000000000000..c4003caba88f3c589462e5a49ff3fab1f00f2524 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/providers/content-provider-basics.jd @@ -0,0 +1,1196 @@ +page.title=Dasar-Dasar Penyedia Konten +@jd:body +Dalam dokumen ini
+-
+
-
+ Ikhtisar
+
-
+
- + Mengakses penyedia + +
- + URI Konten + +
+ -
+ Mengambil Data dari Penyedia
+
-
+
- + Meminta izin akses baca + +
- + Membuat query + +
- + Menampilkan hasil query + +
- + Mendapatkan data dari hasil query + +
+ - + Izin Penyedia Konten + +
-
+ Menyisipkan, Memperbarui, dan Menghapus Data
+
-
+
- + Menyisipkan data + +
- + Memperbarui data + +
- + Menghapus data + +
+ - + Tipe Data Penyedia + +
-
+ Bentuk-Bentuk Alternatif Akses Penyedia
+
-
+
- + Akses batch + +
- + Akses data melalui intent + +
+ - + Kelas-kelas Kontrak + +
- + Acuan Tipe MIME + +
Kelas-kelas utama
+-
+
- + {@link android.content.ContentProvider} + +
- + {@link android.content.ContentResolver} + +
- + {@link android.database.Cursor} + +
- + {@link android.net.Uri} + +
Contoh-Contoh Terkait
+-
+
- + + Kursor (Orang) + +
- + + Kursor (Telepon) + +
Lihat juga
+-
+
- + + Membuat Penyedia Konten + +
- + + Penyedia Kalender + +
+ Penyedia konten mengelola akses ke repository data pusat. Penyedia + adalah bagian dari aplikasi Android, yang sering menyediakan UI-nya sendiri untuk menggunakan + data. Akan tetapi, penyedia konten terutama dimaksudkan untuk digunakan oleh + aplikasi lain, yang mengakses penyedia itu melalui objek klien penyedia. Bersama-sama, penyedia + dan klien penyedia menawarkan antarmuka standar yang konsisten ke data yang juga menangani + komunikasi antar-proses dan akses data aman. +
++ Topik ini menerangkan dasar-dasar dari hal-hal berikut: +
+-
+
- Cara kerja penyedia konten. +
- API yang Anda gunakan untuk mengambil data dari penyedia konten. +
- API yang Anda gunakan untuk menyisipkan, memperbarui, atau menghapus data dalam penyedia konten. +
- Fitur API lainnya yang memudahkan kita menggunakan penyedia. +
Ikhtisar
++ Penyedia konten menyajikan data ke aplikasi eksternal sebagai satu atau beberapa tabel yang + serupa dengan tabel-tabel yang ditemukan dalam database relasional. Sebuah baris mewakili instance beberapa tipe + data yang dikumpulkan penyedia, dan tiap kolom dalam baris mewakili sepotong + data yang dikumpulkan untuk sebuah instance. +
++ Misalnya, salah satu penyedia bawaan di platform Android adalah kamus pengguna, yang + menyimpan ejaan kata-kata tidak-standar yang ingin disimpan pengguna. Tabel 1 mengilustrasikan + wujud data yang mungkin ada dalam tabel penyedia ini: +
+ +word | +app id | +frequency | +locale | +_ID | +
---|---|---|---|---|
mapreduce | +user1 | +100 | +en_US | +1 | +
precompiler | +user14 | +200 | +fr_FR | +2 | +
applet | +user2 | +225 | +fr_CA | +3 | +
const | +user1 | +255 | +pt_BR | +4 | +
int | +user5 | +100 | +en_UK | +5 | +
+ Dalam tabel 1, tiap baris mewakili instance sebuah kata yang mungkin tidak
+ ditemukan dalam kamus standar. Tiap kolom mewakili beberapa data untuk kata itu, misalnya
+ bahasa lokal tempat kata itu ditemukan kali pertama. Header kolom adalah nama kolom yang disimpan dalam
+ penyedia. Untuk mengacu ke bahasa lokal suatu baris, Anda mengacu ke kolom locale
-nya. Untuk
+ penyedia ini, kolom _ID
berfungsi sebagai "kunci utama" kolom yang
+ dipelihara oleh penyedia secara otomatis.
+
+ Catatan: Penyedia tidak diharuskan memiliki kunci utama, dan tidak diharuskan
+ menggunakan _ID
sebagai nama kolom kunci utama jika kunci itu ada. Akan tetapi,
+ jika Anda ingin mengikat data dari penyedia ke {@link android.widget.ListView}, salah satu
+ nama kolom harus _ID
. Ketentuan ini dijelaskan secara lebih detail di bagian
+ Menampilkan hasil query.
+
Mengakses penyedia
++ Aplikasi mengakses data dari penyedia konten dengan + sebuah objek klien {@link android.content.ContentResolver}. Objek ini memiliki metode yang memanggil + metode dengan nama identik dalam objek penyedia, instance salah satu + subkelas konkret dari {@link android.content.ContentProvider}. Metode-metode + {@link android.content.ContentResolver} menyediakan fungsi-fungsi dasar + "CRUD" (create, retrieve, update, dan delete) pada penyimpanan yang persisten. +
++ Objek {@link android.content.ContentResolver} dalam + proses aplikasi klien dan objek {@link android.content.ContentProvider} dalam aplikasi yang memiliki + penyedia itu secara otomatis akan menangani komunikasi antar-proses. + {@link android.content.ContentProvider} juga berfungsi sebagai lapisan abstraksi antara + repository datanya dan penampilan eksternal data sebagai tabel. +
++ Catatan: Untuk mengakses penyedia, aplikasi Anda biasanya harus meminta + izin tertentu dalam file manifesnya. Hal ini dijelaskan lebih detail di bagian + Izin Penyedia Konten +
++ Misalnya, untuk mendapatkan daftar kata dan lokalnya dari Penyedia Kamus Pengguna, + Anda memanggil {@link android.content.ContentResolver#query ContentResolver.query()}. + Metode {@link android.content.ContentResolver#query query()} memanggil + metode {@link android.content.ContentProvider#query ContentProvider.query()} yang didefinisikan oleh + Penyedia Kamus Pengguna. Baris-baris kode berikut menunjukkan sebuah + panggilan {@link android.content.ContentResolver#query ContentResolver.query()}: +
+
+// Queries the user dictionary and returns results +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Selection criteria + mSelectionArgs, // Selection criteria + mSortOrder); // The sort order for the returned rows ++
+ Tabel 2 menampilkan cara argumen untuk + {@link android.content.ContentResolver#query + query(Uri,projection,selection,selectionArgs,sortOrder)} cocok dengan sebuah pernyataan SELECT di SQL: +
+ +Argumen query() | +Kata kunci/parameter SELECT | +Catatan | +
---|---|---|
Uri |
+ FROM table_name |
+ Uri memetakan ke tabel dalam penyedia yang bernama table_name. |
+
projection |
+ col,col,col,... |
+
+ projection adalah satu larik kolom yang harus disertakan untuk tiap baris
+ yang diambil.
+ |
+
selection |
+ WHERE col = value |
+ selection menetapkan kriteria untuk memilih baris. |
+
selectionArgs |
+
+ (Tidak ada padanan persis. Argumen pemilihan mengganti ? placeholder dalam
+ klausa pemilihan.)
+ |
+ |
sortOrder |
+ ORDER BY col,col,... |
+
+ sortOrder menetapkan urutan munculnya baris dalam
+ {@link android.database.Cursor} yang dihasilkan.
+ |
+
URI Konten
++ URI konten adalah URI yang mengidentifikasi data dalam penyedia. URI Konten + menyertakan nama simbolis seluruh penyedia (otoritasnya) dan sebuah + nama yang menunjuk ke tabel (path). Bila Anda memanggil + metode klien untuk mengakses tabel dalam penyedia, URI konten untuk tabel itu adalah salah satu + argumennya. +
++ Dalam baris kode sebelumnya, konstanta + {@link android.provider.UserDictionary.Words#CONTENT_URI} mengandung URI konten dari + tabel "words" kamus pengguna. Objek {@link android.content.ContentResolver} + akan mengurai otoritas URI, dan menggunakannya untuk "mengetahui" penyedia dengan + membandingkan otoritas tersebut dengan sebuah tabel sistem berisi penyedia yang dikenal. +{@link android.content.ContentResolver} kemudian bisa mengirim argumen query ke penyedia + yang benar. +
++ {@link android.content.ContentProvider} menggunakan bagian path dari URI konten untuk memilih + tabel yang akan diakses. Penyedia biasanya memiliki path untuk tiap tabel yang dieksposnya. +
++ Dalam baris kode sebelumnya, URI lengkap untuk tabel "words" adalah: +
++content://user_dictionary/words ++
+ dalam hal ini string user_dictionary
adalah otoritas penyedia, dan string
+ words
adalah path tabel. String
+ content://
(skema) selalu ada,
+ dan mengidentifikasinya sebagai URI konten.
+
+ Banyak penyedia yang memperbolehkan Anda mengakses satu baris dalam tabel dengan menambahkan sebuah ID nilai
+ ke akhir URI. Misalnya, untuk mengambil sebuah baris yang _ID
-nya adalah
+ 4
dari kamus pengguna, Anda bisa menggunakan URI konten ini:
+
+Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); ++
+ Anda akan sering menggunakan nilai-nilai ID bila telah mengambil satu set baris kemudian ingin memperbarui atau menghapus + salah satunya. +
++ Catatan: Kelas-kelas {@link android.net.Uri} dan {@link android.net.Uri.Builder} + berisi metode praktis untuk membangun objek dari string URI yang tersusun dengan baik. +{@link android.content.ContentUris} berisi metode praktis untuk menambahkan nilai ID ke + URI. Cuplikan kode sebelumnya menggunakan {@link android.content.ContentUris#withAppendedId + withAppendedId()} untuk menambahkan id ke URI konten User Dictionary. +
+ + + +Mengambil Data dari Penyedia
++ Bagian ini menerangkan cara mengambil data dari penyedia, dengan menggunakan Penyedia Kamus Pengguna + sebagai contoh. +
++ Demi kejelasan, cuplikan kode di bagian ini memanggil + {@link android.content.ContentResolver#query ContentResolver.query()} pada "UI thread"". Akan tetapi, dalam + kode sesungguhnya, Anda harus melakukan query secara asinkron pada sebuah thread terpisah. Satu cara melakukannya + adalah menggunakan kelas {@link android.content.CursorLoader}, yang dijelaskan + lebih detail dalam panduan + Loader. Juga, baris-baris kode tersebut hanyalah cuplikan; tidak menunjukkan sebuah aplikasi + lengkap. +
++ Untuk mengambil data dari penyedia, ikutilah langkah-langkah dasar ini: +
+-
+
- + Minta izin akses baca untuk penyedia itu. + +
- + Definisikan kode yang mengirim query ke penyedia. + +
Meminta izin akses baca
+
+ Untuk mengambil data dari penyedia, aplikasi Anda memerlukan "izin akses baca" untuk
+ penyedia itu. Anda tidak bisa meminta izin ini saat runtime; sebagai gantinya, Anda harus menetapkan bahwa
+ Anda memerlukan izin ini dalam manifes, dengan menggunakan elemen
+<uses-permission>
+ dan nama persis izin yang didefinisikan oleh
+ penyedia itu. Bila menetapkan elemen ini dalam manifes, Anda secara efektif "meminta"
+ izin ini untuk aplikasi Anda. Bila pengguna menginstal aplikasi Anda, mereka secara implisit akan memberikan
+ permintaan ini.
+
+ Untuk menemukan nama persis dari izin akses baca untuk penyedia yang sedang Anda gunakan, serta + nama-nama izin akses lain yang digunakan oleh penyedia, lihatlah dalam + dokumentasi penyedia. +
++ Peran izin dalam yang mengakses penyedia dijelaskan lebih detail di bagian + Izin Penyedia Konten. +
+
+ Penyedia Kamus Pengguna mendefinisikan izin
+ android.permission.READ_USER_DICTIONARY
dalam file manifesnya, sehingga
+ aplikasi yang ingin membaca dari penyedia itu harus meminta izin ini.
+
Membuat query
++ Langkah berikutnya dalam mengambil data penyedia adalah membuat query. Cuplikan kode pertama ini + mendefinisikan beberapa variabel untuk mengakses Penyedia Kamus Pengguna: +
++ +// A "projection" defines the columns that will be returned for each row +String[] mProjection = +{ + UserDictionary.Words._ID, // Contract class constant for the _ID column name + UserDictionary.Words.WORD, // Contract class constant for the word column name + UserDictionary.Words.LOCALE // Contract class constant for the locale column name +}; + +// Defines a string to contain the selection clause +String mSelectionClause = null; + +// Initializes an array to contain selection arguments +String[] mSelectionArgs = {""}; + ++
+ Cuplikan berikutnya menampilkan cara menggunakan + {@link android.content.ContentResolver#query ContentResolver.query()}, dengan menggunakan Penyedia Kamus Pengguna + sebagai contoh. Query klien penyedia serupa dengan query SQL, dan berisi satu + set kolom yang akan dihasilkan, satu set kriteria pemilihan, dan urutan sortir. +
+
+ Set kolom yang harus dikembalikan query disebut dengan proyeksi
+ (variabel mProjection
).
+
+ Ekspresi yang menetapkan baris yang harus diambil dipecah menjadi klausa pemilihan dan
+ argumen pemilihan. Klausa pemilihan adalah kombinasi ekspresi logis dan boolean,
+ nama kolom, dan nilai (variabel mSelectionClause
). Jika Anda menetapkan
+ parameter ?
yang bisa diganti, sebagai ganti nilai, metode query akan mengambil nilai
+ dari larik argumen pemilihan (variabel mSelectionArgs
).
+
+ Dalam cuplikan berikutnya, jika pengguna tidak memasukkan sebuah kata, klausa pemilihan akan diatur ke
+ null
, dan query menghasilkan semua kata dalam penyedia. Jika pengguna memasukkan
+ sebuah kata, klausa pemilihan akan diatur ke UserDictionary.Words.WORD + " = ?"
dan
+ elemen pertama larik argumen pemilihan diatur ke kata yang dimasukkan pengguna.
+
+/* + * This defines a one-element String array to contain the selection argument. + */ +String[] mSelectionArgs = {""}; + +// Gets a word from the UI +mSearchString = mSearchWord.getText().toString(); + +// Remember to insert code here to check for invalid or malicious input. + +// If the word is the empty string, gets everything +if (TextUtils.isEmpty(mSearchString)) { + // Setting the selection clause to null will return all words + mSelectionClause = null; + mSelectionArgs[0] = ""; + +} else { + // Constructs a selection clause that matches the word that the user entered. + mSelectionClause = UserDictionary.Words.WORD + " = ?"; + + // Moves the user's input string to the selection arguments. + mSelectionArgs[0] = mSearchString; + +} + +// Does a query against the table and returns a Cursor object +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Either null, or the word the user entered + mSelectionArgs, // Either empty, or the string the user entered + mSortOrder); // The sort order for the returned rows + +// Some providers return null if an error occurs, others throw an exception +if (null == mCursor) { + /* + * Insert code here to handle the error. Be sure not to use the cursor! You may want to + * call android.util.Log.e() to log this error. + * + */ +// If the Cursor is empty, the provider found no matches +} else if (mCursor.getCount() < 1) { + + /* + * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily + * an error. You may want to offer the user the option to insert a new row, or re-type the + * search term. + */ + +} else { + // Insert code here to do something with the results + +} ++
+ Query ini analog dengan pernyataan SQL: +
++SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; ++
+ Dalam pernyataan SQL ini, nama kolom yang sesungguhnya digunakan sebagai ganti konstanta kelas kontrak. +
+Melindungi dari input merusak
++ Jika data dikelola oleh penyedia konten berada dalam database SQL, memasukkan data tak dipercaya eksternal + ke dalam pernyataan SQL mentah bisa menyebabkan injeksi SQL. +
++ Perhatikan klausa pemilihan ini: +
++// Constructs a selection clause by concatenating the user's input to the column name +String mSelectionClause = "var = " + mUserInput; ++
+ Jika melakukannya, Anda akan membuat pengguna menyambungkan SQL merusak ke pernyataan SQL Anda.
+ Misalnya, pengguna bisa memasukkan "nothing; DROP TABLE *;" untuk mUserInput
, yang
+ akan menghasilkan klausa pemilihan var = nothing; DROP TABLE *;
. Karena
+ klausa pemilihan diperlakukan sebagai pernyataan SQL, hal ini bisa menyebabkan penyedia itu menghapus semua
+ tabel dalam database SQLite yang mendasarinya (kecuali penyedia disiapkan untuk menangkap upaya
+ injeksi SQL).
+
+ Untuk menghindari masalah ini, gunakan klausa pemilihan yang menggunakan ?
sebagai
+ parameter yang bisa diganti dan larik argumen pemilihan yang terpisah. Bila Anda melakukannya, input pengguna
+ akan dibatasi secara langsung pada query agar tidak ditafsirkan sebagai bagian dari pernyataan SQL.
+ Karena tidak diperlakukan sebagai SQL, input pengguna tidak bisa menyuntikkan SQL merusak. Sebagai ganti menggunakan
+ penyambungan untuk menyertakan input pengguna, gunakan klausa pemilihan ini:
+
+// Constructs a selection clause with a replaceable parameter +String mSelectionClause = "var = ?"; ++
+ Buat larik argumen pemilihan seperti ini: +
++// Defines an array to contain the selection arguments +String[] selectionArgs = {""}; ++
+ Masukkan nilai dalam larik argumen pemilihan seperti ini: +
++// Sets the selection argument to the user's input +selectionArgs[0] = mUserInput; ++
+ Sebuah klausa pemilihan yang menggunakan ?
sebagai parameter yang bisa diganti dan sebuah larik
+ argumen pemilihan adalah cara yang lebih disukai untuk menyebutkan pemilihan, sekalipun penyedia tidak
+ dibuat berdasarkan database SQL.
+
Menampilkan hasil query
++ Metode klien {@link android.content.ContentResolver#query ContentResolver.query()} selalu + menghasilkan {@link android.database.Cursor} berisi kolom-kolom yang ditetapkan oleh + proyeksi query untuk baris yang cocok dengan kriteria pemilihan query. Objek + {@link android.database.Cursor} menyediakan akses baca acak ke baris dan kolom yang + dimuatnya. Dengan metode {@link android.database.Cursor}, Anda bisa mengulang baris-baris dalam + hasil, menentukan tipe data tiap kolom, mengambil data dari kolom, dan memeriksa + properti lain dari hasil. Beberapa implementasi {@link android.database.Cursor} + akan memperbarui objek secara otomatis bila data penyedia berubah, atau memicu metode dalam objek pengamat + bila {@link android.database.Cursor} berubah, atau keduanya. +
++ Catatan: Penyedia bisa membatasi akses ke kolom berdasarkan sifat + objek yang membuat query. Misalnya, Penyedia Kontak membatasi akses untuk beberapa kolom pada + adaptor sinkronisasi, sehingga tidak akan mengembalikannya ke aktivitas atau layanan. +
++ Jika tidak ada baris yang cocok dengan kriteria pemilihan, penyedia + akan mengembalikan objek {@link android.database.Cursor} dengan + {@link android.database.Cursor#getCount Cursor.getCount()} adalah 0 (kursor kosong). +
+
+ Jika terjadi kesalahan internal, hasil query akan bergantung pada penyedia tertentu. Penyedia bisa
+ memilih untuk menghasilkan null
, atau melontarkan {@link java.lang.Exception}.
+
+ Karena {@link android.database.Cursor} adalah "daftar" baris, cara yang cocok untuk menampilkan + konten {@link android.database.Cursor} adalah mengaitkannya dengan {@link android.widget.ListView} + melalui {@link android.widget.SimpleCursorAdapter}. +
++ Cuplikan berikut melanjutkan kode dari cuplikan sebelumnya. Cuplikan ini membuat + objek {@link android.widget.SimpleCursorAdapter} berisi {@link android.database.Cursor} + yang diambil oleh query, dan mengatur objek ini menjadi adaptor bagi + {@link android.widget.ListView}: +
++// Defines a list of columns to retrieve from the Cursor and load into an output row +String[] mWordListColumns = +{ + UserDictionary.Words.WORD, // Contract class constant containing the word column name + UserDictionary.Words.LOCALE // Contract class constant containing the locale column name +}; + +// Defines a list of View IDs that will receive the Cursor columns for each row +int[] mWordListItems = { R.id.dictWord, R.id.locale}; + +// Creates a new SimpleCursorAdapter +mCursorAdapter = new SimpleCursorAdapter( + getApplicationContext(), // The application's Context object + R.layout.wordlistrow, // A layout in XML for one row in the ListView + mCursor, // The result from the query + mWordListColumns, // A string array of column names in the cursor + mWordListItems, // An integer array of view IDs in the row layout + 0); // Flags (usually none are needed) + +// Sets the adapter for the ListView +mWordList.setAdapter(mCursorAdapter); ++
+ Catatan: Untuk mendukung {@link android.widget.ListView} dengan
+ {@link android.database.Cursor}, kursor harus berisi kolom bernama _ID
.
+ Karena itu, query yang ditampilkan sebelumnya mengambil kolom _ID
untuk
+ tabel "words", walaupun {@link android.widget.ListView} tidak menampilkannya.
+ Pembatasan ini juga menjelaskan mengapa sebagian besar penyedia memiliki kolom _ID
untuk masing-masing
+ tabelnya.
+
Mendapatkan data dari hasil query
++ Daripada sekadar menampilkan hasil query, Anda bisa menggunakannya untuk tugas-tugas lain. Misalnya, + Anda bisa mengambil ejaan dari kamus pengguna kemudian mencarinya dalam + penyedia lain. Caranya, ulangi baris-baris dalam {@link android.database.Cursor}: +
++ +// Determine the column index of the column named "word" +int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); + +/* + * Only executes if the cursor is valid. The User Dictionary Provider returns null if + * an internal error occurs. Other providers may throw an Exception instead of returning null. + */ + +if (mCursor != null) { + /* + * Moves to the next row in the cursor. Before the first movement in the cursor, the + * "row pointer" is -1, and if you try to retrieve data at that position you will get an + * exception. + */ + while (mCursor.moveToNext()) { + + // Gets the value from the column. + newWord = mCursor.getString(index); + + // Insert code here to process the retrieved word. + + ... + + // end of while loop + } +} else { + + // Insert code here to report an error if the cursor is null or the provider threw an exception. +} ++
+ Implementasi {@link android.database.Cursor} berisi beberapa metode "get" untuk + mengambil berbagai tipe data dari objek. Misalnya, cuplikan sebelumnya + menggunakan {@link android.database.Cursor#getString getString()}. Implementasi juga memiliki + metode {@link android.database.Cursor#getType getType()} yang menghasilkan nilai yang menunjukkan + tipe data kolom. +
+ + + +Izin Penyedia Konten
++ Aplikasi penyedia bisa menetapkan izin yang harus dimiliki aplikasi lain untuk + mengakses data penyedia. Izin ini akan memastikan bahwa pengguna mengetahui data + yang coba diakses oleh aplikasi. Berdasarkan ketentuan penyedia, aplikasi lain + meminta izin yang diperlukannya untuk mengakses penyedia. Pengguna akhir akan melihat + izin yang diminta saat menginstal aplikasi. +
++ Jika aplikasi penyedia tidak menetapkan izin apa pun, maka aplikasi lain tidak memiliki + akses ke data penyedia. Akan tetapi, komponen-komponen dalam aplikasi penyedia selalu memiliki + akses penuh untuk baca dan tulis, izin apa pun yang ditetapkan. +
+
+ Seperti disebutkan sebelumnya, Penyedia Kamus Pengguna mensyaratkan izin
+ android.permission.READ_USER_DICTIONARY
untuk mengambil data darinya.
+ Penyedia memiliki izin android.permission.WRITE_USER_DICTIONARY
+ yang terpisah untuk menyisipkan, memperbarui, atau menghapus data.
+
+ Untuk mendapatkan izin yang diperlukan untuk mengakses penyedia, aplikasi memintanya dengan elemen
+<uses-permission>
+ dalam file manifesnya. Bila Android Package Manager memasang aplikasi, pengguna
+ harus menyetujui semua izin yang diminta aplikasi. Jika pengguna menyetujui semuanya,
+ Package Manager akan melanjutkan instalasi; jika pengguna tidak menyetujui, Package Manager
+ akan membatalkan instalasi.
+
+ Elemen
+<uses-permission>
+ berikut meminta akses baca ke Penyedia Kamus Pengguna:
+
+ <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> ++
+ Dampak izin pada akses penyedia dijelaskan secara lebih detail dalam panduan + Keamanan dan Izin. +
+ + + +Menyisipkan, Memperbarui, dan Menghapus Data
++ Lewat cara yang sama dengan cara mengambil data dari penyedia, Anda juga menggunakan interaksi antara + klien penyedia dan {@link android.content.ContentProvider} penyedia untuk memodifikasi data. + Anda memanggil metode {@link android.content.ContentResolver} dengan argumen yang diteruskan ke + metode {@link android.content.ContentProvider} yang sesuai. Penyedia dan klien penyedia + menangani secara otomatis keamanan dan komunikasi antar-proses. +
+Menyisipkan data
++ Untuk menyisipkan data ke penyedia, Anda memanggil metode + {@link android.content.ContentResolver#insert ContentResolver.insert()}. + Metode ini menyisipkan sebuah baris baru ke penyedia itu dan menghasilkan URI konten untuk baris itu. + Cuplikan ini menampilkan cara menyisipkan sebuah kata baru ke Penyedia Kamus Pengguna: +
++// Defines a new Uri object that receives the result of the insertion +Uri mNewUri; + +... + +// Defines an object to contain the new values to insert +ContentValues mNewValues = new ContentValues(); + +/* + * Sets the values of each column and inserts the word. The arguments to the "put" + * method are "column name" and "value" + */ +mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); +mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); +mNewValues.put(UserDictionary.Words.WORD, "insert"); +mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); + +mNewUri = getContentResolver().insert( + UserDictionary.Word.CONTENT_URI, // the user dictionary content URI + mNewValues // the values to insert +); ++
+ Data untuk baris baru masuk ke dalam satu objek {@link android.content.ContentValues}, yang
+ serupa bentuknya dengan kursor satu-baris. Kolom dalam objek ini tidak perlu memiliki
+ tipe data yang sama, dan jika Anda tidak ingin menetapkan nilai sama sekali, Anda bisa mengatur kolom
+ ke null
dengan menggunakan {@link android.content.ContentValues#putNull ContentValues.putNull()}.
+
+ Cuplikan ini tidak menambahkan kolom _ID
, karena kolom ini dipelihara
+ secara otomatis. Penyedia menetapkan sebuah nilai unik _ID
ke setiap baris yang
+ ditambahkan. Penyedia biasanya menggunakan nilai ini sebagai kunci utama tabel.
+
+ URI konten yang dihasilkan dalam newUri
akan mengidentifikasi baris yang baru ditambahkan, dengan
+ format berikut:
+
+content://user_dictionary/words/<id_value> ++
+ <id_value>
adalah konten _ID
untuk baris baru.
+ Kebanyakan penyedia bisa mendeteksi bentuk URI konten ini secara otomatis kemudian melakukan
+ operasi yang diminta pada baris tersebut.
+
+ Untuk mendapatkan nilai _ID
dari {@link android.net.Uri} yang dihasilkan, panggil
+ {@link android.content.ContentUris#parseId ContentUris.parseId()}.
+
Memperbarui data
+
+ Untuk memperbarui sebuah baris, gunakan objek {@link android.content.ContentValues} dengan
+ nilai-nilai yang diperbarui, persis seperti yang Anda lakukan pada penyisipan, dan kriteria pemilihan persis seperti yang Anda lakukan pada query.
+ Metode klien yang Anda gunakan adalah
+ {@link android.content.ContentResolver#update ContentResolver.update()}. Anda hanya perlu menambahkan
+ nilai-nilai ke objek {@link android.content.ContentValues} untuk kolom yang sedang Anda perbarui. Jika Anda
+ ingin membersihkan konten kolom, aturlah nilai ke null
.
+
+ Cuplikan berikut mengubah semua baris yang kolom lokalnya memiliki bahasa "en" ke
+ lokal null
. Nilai hasil adalah jumlah baris yang diperbarui:
+
+// Defines an object to contain the updated values +ContentValues mUpdateValues = new ContentValues(); + +// Defines selection criteria for the rows you want to update +String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; +String[] mSelectionArgs = {"en_%"}; + +// Defines a variable to contain the number of updated rows +int mRowsUpdated = 0; + +... + +/* + * Sets the updated value and updates the selected words. + */ +mUpdateValues.putNull(UserDictionary.Words.LOCALE); + +mRowsUpdated = getContentResolver().update( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mUpdateValues // the columns to update + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); ++
+ Anda juga harus membersihkan input pengguna bila memanggil + {@link android.content.ContentResolver#update ContentResolver.update()}. Untuk mengetahui selengkapnya tentang + hal ini, bacalah bagian Melindungi dari input merusak. +
+Menghapus data
++ Menghapus baris serupa dengan mengambil baris data: Anda menetapkan kriteria pemilihan untuk baris + yang ingin Anda hapus dan metode klien akan menghasilkan jumlah baris yang dihapus. + Cuplikan berikut menghapus baris yang appid-nya sama dengan "user". Metode menghasilkan + jumlah baris yang dihapus. +
++ +// Defines selection criteria for the rows you want to delete +String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; +String[] mSelectionArgs = {"user"}; + +// Defines a variable to contain the number of rows deleted +int mRowsDeleted = 0; + +... + +// Deletes the words that match the selection criteria +mRowsDeleted = getContentResolver().delete( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); ++
+ Anda juga harus membersihkan input pengguna bila memanggil + {@link android.content.ContentResolver#delete ContentResolver.delete()}. Untuk mengetahui selengkapnya tentang + hal ini, bacalah bagian Melindungi dari input merusak. +
+ +Tipe Data Penyedia
++ Penyedia konten bisa menawarkan berbagai tipe data. Penyedia Kamus Pengguna hanya menawarkan + teks, namun penyedia juga bisa menawarkan format berikut: +
+-
+
- + integer + +
- + long integer (long) + +
- + floating point + +
- + long floating point (double) + +
+ Tipe data lain yang sering digunakan penyedia adalah Binary Large OBject (BLOB) yang diimplementasikan sebagai + larik byte 64 KB. Anda bisa melihat tipe data yang tersedia dengan memperhatikan metode "get" + kelas {@link android.database.Cursor}. +
++ Tipe data tiap kolom dalam penyedia biasanya tercantum dalam dokumentasinya. + Tipe data untuk Penyedia Kamus Pengguna tercantum dalam dokumentasi acuan + untuk kelas kontraknya {@link android.provider.UserDictionary.Words} (kelas kontrak + dijelaskan di bagian Kelas-kelas Kontrak). + Anda juga bisa menentukan tipe data dengan memanggil {@link android.database.Cursor#getType + Cursor.getType()}. +
++ Penyedia juga memelihara informasi tipe data MIME untuk tiap URI konten yang didefinisikannya. Anda bisa + menggunakan informasi tipe MIME untuk mengetahui apakah aplikasi Anda bisa menangani data yang + disediakan penyedia, atau memilih tipe penanganan berdasarkan tipe MIME. Anda biasanya memerlukan + tipe MIME saat menggunakan penyedia yang berisi + struktur atau file data yang kompleks. Misalnya, tabel {@link android.provider.ContactsContract.Data} + dalam Penyedia Kontak menggunakan tipe MIME untuk memberi label tipe data kontak yang disimpan di tiap + baris. Untuk mendapatkan tipe MIME yang sesuai dengan URI konten, panggil + {@link android.content.ContentResolver#getType ContentResolver.getType()}. +
++ Bagian Acuan Tipe MIME menerangkan + sintaks tipe MIME baik yang standar maupun custom. +
+ + + +Bentuk-Bentuk Alternatif Akses Penyedia
++ Tiga bentuk alternatif akses penyedia adalah penting dalam pengembangan aplikasi: +
+-
+
- + Akses batch: Anda bisa membuat sebuah batch panggilan akses dengan metode-metode dalam + kelas {@link android.content.ContentProviderOperation}, kemudian menerapkannya dengan + {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. + +
- + Query asinkron: Anda harus melakukan query dalam thread terpisah. Satu cara melakukannya adalah + menggunakan objek {@link android.content.CursorLoader}. Contoh-contoh dalam panduan + Loader memperagakan + cara melakukannya. + +
- + Akses data melalui intent: Walaupun tidak bisa mengirim intent + ke penyedia secara langsung, Anda bisa mengirim intent ke aplikasi penyedia, yang + biasanya paling lengkap dibekali untuk memodifikasi data penyedia. + +
+ Akses batch dan modifikasi melalui intent dijelaskan dalam bagian-bagian berikut. +
+Akses batch
++ Akses batch ke penyedia berguna untuk menyisipkan baris dalam jumlah besar, atau menyisipkan + baris ke dalam beberapa tabel dalam panggilan metode yang sama, atau biasanya melakukan satu set + operasi lintas batas proses sebagai transaksi (operasi atomik). +
++ Untuk mengakses penyedia dalam "mode batch", + buat satu larik objek {@link android.content.ContentProviderOperation}, kemudian + kirim larik itu ke penyedia konten dengan + {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. Anda meneruskan + otoritas penyedia konten ke metode ini, daripada URI konten tertentu. + Ini memungkinkan tiap objek {@link android.content.ContentProviderOperation} dalam larik untuk bekerja + terhadap tabel yang berbeda. Panggilan ke {@link android.content.ContentResolver#applyBatch + ContentResolver.applyBatch()} menghasilkan satu larik hasil. +
+
+ Keterangan kelas kontrak {@link android.provider.ContactsContract.RawContacts}
+ menyertakan cuplikan kode yang memperagakan penyisipan batch. Contoh aplikasi
+ Contacts Manager
+ berisi contoh akses batch dalam file sumber ContactAdder.java
-nya
+.
+
Menampilkan data dengan aplikasi pembantu
++ Jika aplikasi Anda memang memiliki izin akses, Anda masih mungkin perlu menggunakan + intent untuk menampilkan data dalam aplikasi lain. Misalnya, aplikasi Kalender menerima + intent {@link android.content.Intent#ACTION_VIEW}, yang menampilkan tanggal atau kejadian tertentu. + Hal ini memungkinkan Anda menampilkan informasi kalender tanpa harus membuat UI sendiri. + Untuk mengetahui selengkapnya tentang fitur ini, lihat panduan + Penyedia Kalender. +
++ Aplikasi yang Anda kirimi intent tidak harus aplikasi + yang terkait dengan penyedia. Misalnya, Anda bisa mengambil satu kontak dari + Penyedia Kontak, kemudian mengirim intent {@link android.content.Intent#ACTION_VIEW} + berisi URI konten untuk gambar kontak itu ke penampil gambar. +
+Akses data melalui intent
++ Intent bisa menyediakan akses tidak langsung ke penyedia konten. Anda memperbolehkan pengguna mengakses + data dalam penyedia sekalipun aplikasi Anda tidak memiliki izin akses, baik dengan + mendapatkan intent yang dihasilkan aplikasi yang memiliki izin, atau dengan mengaktifkan + aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaan di dalamnya. +
+Mendapatkan akses dengan izin sementara
++ Anda bisa mengakses data dalam penyedia konten, sekalipun tidak memiliki + izin akses yang sesuai, dengan mengirimkan intent ke aplikasi yang memang memiliki izin dan + menerima hasil berupa intent berisi izin "URI". + Inilah izin untuk URI konten tertentu yang berlaku hingga aktivitas yang menerima + izin selesai. Aplikasi yang memiliki izin tetap akan memberikan + izin sementara dengan mengatur flag dalam intent yang dihasilkan: +
+-
+
- + Izin baca: + {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} + +
- + Izin tulis: + {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} + +
+ Catatan: Flag ini tidak memberikan akses baca atau tulis umum ke penyedia + yang otoritasnya dimuat dalam URI konten. Aksesnya hanya untuk URI itu sendiri. +
+
+ Penyedia mendefinisikan izin URI untuk URI konten dalam manifesnya, dengan menggunakan atribut
+android:grantUriPermission
+ dari elemen
+<provider>
+, serta elemen anak
+<grant-uri-permission>
+ dari elemen
+<provider>
.
+ Mekanisme izin URI dijelaskan secara lebih detail dalam panduan
+ Keamanan dan Izin,
+ di bagian "Izin URI".
+
+ Misalnya, Anda bisa mengambil data untuk satu kontak di Penyedia Kontak, sekalipun tidak + memiliki izin {@link android.Manifest.permission#READ_CONTACTS}. Anda mungkin ingin melakukan + ini dalam aplikasi yang mengirim kartu ucapan elektronik ke seorang kenalan pada hari ulang tahunnya. Sebagai ganti + meminta {@link android.Manifest.permission#READ_CONTACTS}, yang memberi Anda akses ke semua + kontak pengguna dan semua informasinya, Anda lebih baik membiarkan pengguna mengontrol + kontak-kontak yang akan digunakan oleh aplikasi Anda. Caranya, gunakan proses berikut: +
+-
+
- + Aplikasi Anda akan mengirim intent berisi tindakan + {@link android.content.Intent#ACTION_PICK} dan tipe MIME "contacts" + {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, dengan menggunakan + metode {@link android.app.Activity#startActivityForResult + startActivityForResult()}. + +
- + Karena intent ini cocok dengan filter intent untuk + aktivitas "pemilihan" aplikasi People, aktivitas akan muncul ke latar depan. + +
- + Dalam aktivitas pemilihan, pengguna memilih sebuah + kontak untuk diperbarui. Bila ini terjadi, aktivitas pemilihan akan memanggil + {@link android.app.Activity#setResult setResult(resultcode, intent)} + untuk membuat intent yang akan diberikan kembali ke aplikasi Anda. Intent itu berisi URI konten + kontak yang dipilih pengguna, dan flag "extras" + {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. Semua flag ini memberikan + izin URI ke aplikasi Anda untuk membaca data kontak yang ditunjuk oleh + URI konten. Aktivitas pemilihan kemudian memanggil {@link android.app.Activity#finish()} untuk + mengembalikan kontrol ke aplikasi Anda. + +
- + Aktivitas Anda akan kembali ke latar depan, dan sistem memanggil metode + {@link android.app.Activity#onActivityResult onActivityResult()} + aktivitas Anda. Metode ini menerima intent yang dihasilkan oleh aktivitas pemilihan dalam + aplikasi People. + +
- + Dengan URI konten dari intent yang dihasilkan, Anda bisa membaca data kontak + dari Penyedia Kontak, sekalipun Anda tidak meminta izin akses baca tetap + ke penyedia dalam manifes Anda. Anda kemudian bisa mendapatkan informasi hari ulang tahun si kontak + atau alamat emailnya, kemudian mengirim kartu ucapan elektronik. + +
Menggunakan aplikasi lain
++ Satu cara mudah agar pengguna bisa memodifikasi data yang izin aksesnya tidak Anda miliki adalah + mengaktifkan aplikasi yang memiliki izin dan membiarkan pengguna melakukan pekerjaannya di sana. +
++ Misalnya, aplikasi Kalender menerima + intent {@link android.content.Intent#ACTION_INSERT}, yang memungkinkan Anda mengaktifkan + UI penyisipan aplikasi itu. Anda bisa meneruskan data "extras" dalam intent ini, yang + digunakan aplikasi untuk mengisi dahulu UI-nya. Karena kejadian berulang memiliki sintaks yang rumit, + cara yang lebih disukai untuk menyisipkan kejadian ke dalam Penyedia Kalender adalah mengaktifkan aplikasi Kalender dengan + {@link android.content.Intent#ACTION_INSERT}, kemudian membiarkan pengguna menyisipkan kejadian di sana. +
+ +Kelas-kelas Kontrak
++ Kelas kontrak mendefinisikan konstanta yang membantu aplikasi menggunakan URI konten, nama + kolom, tindakan intent, dan fitur lain pada penyedia konten. Kelas kontrak tidak + disertakan secara otomatis bersama penyedia; pengembang penyedia harus mendefinisikannya kemudian + membuatnya tersedia bagi pengembang lain. Banyak penyedia yang disertakan pada platform Android + memiliki kelas kontrak yang sesuai dalam {@link android.provider} paketnya. +
++ Misalnya, Penyedia Kamus Pengguna memiliki kelas kontrak + {@link android.provider.UserDictionary} yang berisi URI konten dan konstanta nama kolom. URI + konten untuk tabel "words" didefinisikan dalam konstanta + {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}. + Kelas {@link android.provider.UserDictionary.Words} juga berisi konstanta nama kolom, + yang digunakan dalam cuplikan contoh pada panduan ini. Misalnya, sebuah proyeksi query bisa + didefinisikan sebagai: +
++String[] mProjection = +{ + UserDictionary.Words._ID, + UserDictionary.Words.WORD, + UserDictionary.Words.LOCALE +}; ++
+ Kelas kontrak lain adalah {@link android.provider.ContactsContract} untuk Penyedia Kontak. + Dokumentasi acuan untuk kelas ini menyertakan contoh cuplikan kode. Salah satu + subkelasnya, {@link android.provider.ContactsContract.Intents.Insert}, adalah + kelas kontrak yang berisi konstanta untuk intent dan data intent. +
+ + + +Acuan Tipe MIME
++ Penyedia konten bisa menghasilkan tipe media MIME standar, atau string tipe MIME custom, atau keduanya. +
++ Tipe MIME memiliki format +
++type/subtype ++
+ Misalnya, tipe MIME text/html
yang dikenal luas memiliki tipe text
dan
+ subtipe html
. Jika penyedia menghasilkan tipe ini untuk sebuah URI, artinya
+ query dengan URI itu akan menghasilkan teks berisi tag HTML.
+
+ String tipe MIME custom, yang juga disebut dengan tipe MIME "khusus vendor", memiliki nilai-nilai + tipe dan subtipe yang lebih kompleks. Nilai tipe selalu +
++vnd.android.cursor.dir ++
+ untuk beberapa baris, atau +
++vnd.android.cursor.item ++
+ untuk satu baris. +
++ Subtipe adalah khusus penyedia. Penyedia bawaan Android biasanya memiliki subtipe + sederhana. Misalnya, bila aplikasi Contacts membuat satu baris untuk nomor telepon, + aplikasi akan mengatur tipe MIME berikut di baris itu: +
++vnd.android.cursor.item/phone_v2 ++
+ Perhatikan bahwa nilai subtipe adalah sekadar phone_v2
.
+
+ Pengembang penyedia lain bisa membuat pola subtipe sendiri berdasarkan
+ otoritas dan nama-nama tabel penyedia. Misalnya, perhatikan penyedia yang berisi jadwal kereta api.
+ Otoritas penyedia adalah com.example.trains
, dan berisi tabel-tabel
+ Line1, Line2, dan Line3. Untuk merespons URI konten
+
+
+content://com.example.trains/Line1 ++
+ untuk tabel Line1, penyedia menghasilkan tipe MIME +
++vnd.android.cursor.dir/vnd.example.line1 ++
+ Untuk merespons URI konten +
++content://com.example.trains/Line2/5 ++
+ untuk baris 5 di tabel Line2, penyedia menghasilkan tipe MIME +
++vnd.android.cursor.item/vnd.example.line2 ++
+ Kebanyakan penyedia konten mendefinisikan konstanta kelas kontrak untuk tipe MIME yang digunakannya. Kelas kontrak + {@link android.provider.ContactsContract.RawContacts} pada Penyedia Kontak + misalnya, mendefinisikan konstanta + {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} untuk tipe MIME + baris kontak mentah tunggal. +
++ URI konten untuk baris-baris tunggal dijelaskan di bagian + URI Konten. +
diff --git a/docs/html-intl/intl/in/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/in/guide/topics/providers/content-provider-creating.jd new file mode 100644 index 0000000000000000000000000000000000000000..fefce703c2c8c8af1bdaad0dc4a8ded1212a093e --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/providers/content-provider-creating.jd @@ -0,0 +1,1214 @@ +page.title=Membuat Penyedia Konten +@jd:body +Dalam dokumen ini
+-
+
- + Mendesain Penyimpanan Data + +
- + Mendesain URI Konten + +
- + Mengimplementasikan Kelas ContentProvider + + +
-
+ Mengimplementasikan Tipe MIME Penyedia Konten
+
-
+
- + Tipe MIME untuk tabel + +
- + Tipe MIME untuk file + +
+ - + Mengimplementasikan Kelas Kontrak + +
- + Mengimplementasikan Izin Penyedia Konten + +
- + Elemen <provider> + +
- + Intent dan Akses Data + +
Kelas-kelas utama
+-
+
- + {@link android.content.ContentProvider} + +
- + {@link android.database.Cursor} + +
- + {@link android.net.Uri} + +
Contoh-Contoh Terkait
+-
+
- + + Aplikasi contoh Note Pad + + +
Lihat juga
+-
+
- + + Dasar-Dasar Penyedia Konten + +
- + + Penyedia Kalender + +
+ Penyedia konten mengelola akses ke repository data pusat. Anda mengimplementasikan + penyedia sebagai satu atau beberapa kelas dalam aplikasi Android, bersama elemen-elemen dalam + file manifes. Salah satu kelas Anda mengimplementasikan subkelas + {@link android.content.ContentProvider}, yang merupakan antarmuka antara penyedia Anda dan + aplikasi lain. Walaupun penyedia konten dimaksudkan untuk menyediakan data bagi + aplikasi lain, Anda tentu saja bisa memiliki aktivitas dalam aplikasi yang memungkinkan pengguna + melakukan query dan memodifikasi data yang dikelola oleh penyedia Anda. +
++ Bagian selebihnya dalam topik ini adalah daftar langkah-langkah dasar untuk membangun penyedia konten dan daftar + API yang akan digunakan. +
+ + + +Sebelum Anda Mulai Membangun
++ Sebelum Anda mulai membangun penyedia, lakukanlah hal-hal berikut: +
+-
+
-
+ Putuskan apakah Anda memerlukan penyedia konten. Anda perlu membangun sebuah
+ penyedia konten jika ingin menyediakan salah satu atau beberapa dari fitur berikut:
+
-
+
- Anda ingin menawarkan data atau file yang kompleks ke aplikasi lain. +
- Anda ingin memungkinkan pengguna menyalin data yang kompleks dari aplikasi Anda ke dalam aplikasi lain. +
- Anda ingin menyediakan saran pencarian custom dengan menggunakan kerangka kerja pencarian. +
+ Anda tidak mengharuskan penyedia untuk menggunakan database SQLite jika hanya digunakan dalam + aplikasi sendiri. +
+
+ - + Jika Anda belum siap melakukannya, bacalah topik + + Dasar-Dasar Penyedia Konten untuk mengetahui selengkapnya tentang penyedia. + +
+ Berikutnya, ikuti langkah-langkah ini untuk membangun penyedia: +
+-
+
-
+ Desain penyimpanan mentah untuk data Anda. Penyedia konten menawarkan data dengan dua cara:
+
-
+
- + Data file + +
- + Data yang biasanya masuk ke dalam file, misalnya + foto, audio, atau video. Simpan file dalam ruang privat + aplikasi Anda. Untuk merespons permintaan file dari aplikasi lain, + penyedia Anda bisa menawarkan handle ke file tersebut. + +
- + Data "terstruktur" + +
- + Data yang biasanya masuk ke dalam database, larik, atau struktur serupa. + Simpan data dalam bentuk yang kompatibel dengan tabel berisi baris dan kolom. Baris + mewakili entitas, misalnya satu orang atau satu barang inventori. Kolom mewakili + beberapa data untuk entitas itu, misalnya nama orang atau harga barang. Cara umum untuk + menyimpan tipe data ini adalah dalam database SQLite, namun Anda bisa menggunakan tipe + penyimpanan apa saja yang persisten. Untuk mengetahui selengkapnya tentang tipe penyimpanan yang tersedia di + sistem Android, lihat bagian + Mendesain Penyimpanan Data. + +
+ - + Definisikan sebuah implementasi konkret kelas {@link android.content.ContentProvider} dan + metode yang diperlukannya. Kelas ini adalah antarmuka antara data Anda dan bagian selebihnya pada + sistem Android. Untuk informasi selengkapnya tentang kelas ini, lihat bagian + Mengimplementasikan Kelas ContentProvider. + +
- + Definisikan string otoritas, semua URI isinya, dan nama-nama kolom penyedia. Jika Anda ingin + penyedia aplikasi menangani intent, definisikan juga semua tindakan intent, data ekstra, + dan flag. Definisikan juga izin yang akan Anda syaratkan terhadap aplikasi yang ingin + mengakses data Anda. Anda harus mempertimbangkan pendefinisian semua nilai ini sebagai konstanta di + kelas kontrak terpisah; nantinya, Anda bisa mengekspos kelas ini kepada pengembang lain. Untuk + informasi selengkapnya tentang URI konten, lihat + bagian Mendesain URI Konten. + Untuk informasi selengkapnya tentang intent, lihat + bagian Intent dan Akses Data. + +
- + Tambahkan bagian opsional lainnya, seperti data contoh atau implementasi + {@link android.content.AbstractThreadedSyncAdapter} yang bisa menyinkronkan data antara + penyedia dan data berbasis cloud. + +
Mendesain Penyimpanan Data
++ Penyedia konten adalah antarmuka ke data yang disimpan dalam format terstruktur. Sebelum membuat + antarmuka, Anda harus memutuskan cara menyimpan data. Anda bisa menyimpan data dalam bentuk apa saja yang Anda + sukai, kemudian mendesain antarmuka untuk membaca dan menulis data yang diperlukan. +
++ Berikut ini adalah beberapa teknologi penyimpanan data yang tersedia di Android: +
+-
+
-
+ Sistem Android menyertakan API database SQLite yang digunakan penyedia Android sendiri
+ untuk menyimpan data berorientasi tabel. Kelas
+ {@link android.database.sqlite.SQLiteOpenHelper} membantu Anda membuat database, dan kelas
+ {@link android.database.sqlite.SQLiteDatabase} adalah kelas dasar untuk mengakses
+ database.
+
+ Ingatlah bahwa Anda tidak harus menggunakan database untuk mengimplementasikan repository. Penyedia + muncul secara eksternal sebagai satu set tabel, yang serupa dengan sebuah database relasional, namun ini + bukan persyaratan untuk implementasi internal penyedia. +
+
+ - + Untuk menyimpan file data, Android memiliki beragam API berorientasi file. + Untuk mengetahui selengkapnya tentang penyimpanan file, bacalah topik + Penyimpanan Data. Jika Anda sedang + mendesain penyedia yang menawarkan data yang terkait dengan media seperti musik atau video, Anda bisa + memiliki penyedia yang mengombinasikan data tabel dan file. + +
- + Untuk bekerja dengan data berbasis jaringan, gunakan kelas-kelas dalam {@link java.net} dan + {@link android.net}. Anda juga bisa menyinkronkan data berbasis jaringan dengan penyimpanan data lokal + seperti database, kemudian menawarkan data sebagai tabel atau file. + Aplikasi contoh + Sample Sync Adapter memperagakan tipe sinkronisasi ini. + +
+ Pertimbangan desain data +
++ Berikut ini adalah beberapa tip untuk mendesain struktur data penyedia: +
+-
+
-
+ Data tabel harus selalu memiliki kolom "kunci utama" yang dipelihara oleh penyedia
+ sebagai nilai numerik unik untuk setiap baris. Anda bisa menggunakan nilai ini untuk menautkan baris ke
+ baris yang terkait dalam tabel lain (dengan menggunakannya sebagai "kunci asing"). Walaupun Anda bisa menggunakan nama
+ apa saja untuk kolom ini, menggunakan {@link android.provider.BaseColumns#_ID BaseColumns._ID} adalah
+ pilihan terbaik, karena menautkan hasil query penyedia dengan
+ {@link android.widget.ListView} mensyaratkan bahwa salah satu kolom yang diambil memiliki nama
+
_ID
. +
+ - + Jika Anda ingin untuk menyediakan gambar bitmap atau potongan data berorientasi file lainnya yang berukuran sangat besar, simpanlah + data dalam sebuah file kemudian sediakan secara tidak langsung sebagai ganti menyimpannya secara langsung dalam + tabel. Jika melakukannya, Anda perlu memberi tahu pengguna penyedia Anda bahwa mereka perlu menggunakan metode file + {@link android.content.ContentResolver} untuk mengakses data. + +
-
+ Gunakan tipe data Binary Large OBject (BLOB) untuk menyimpan data yang bervariasi ukurannya atau memiliki
+ struktur yang beragam. Misalnya, Anda bisa menggunakan sebuah kolom BLOB untuk menyimpan
+ buffer protokol atau
+ struktur JSON.
+
+ Anda juga bisa menggunakan BLOB untuk mengimplementasikan tabel yang tidak bergantung skema. Dalam + tipe tabel ini, Anda mendefinisikan kolom kunci utama, kolom tipe MIME, dan satu atau beberapa + kolom generik sebagai BLOB. Arti dari data dalam kolom-kolom BLOB ditunjukkan + oleh nilai dalam kolom tipe MIME. Cara ini memungkinkan Anda menyimpan berbagai tipe baris dalam + tabel yang sama. Tabel "data" + {@link android.provider.ContactsContract.Data} Penyedia Kontak adalah contoh tabel yang tidak bergantung skema + tersebut. +
+
+
Mendesain URI Konten
++ URI konten adalah URI yang mengidentifikasi data dalam penyedia. URI Konten + berisi nama simbolis seluruh penyedia (otoritasnya) dan sebuah + nama yang menunjuk ke tabel atau file (path). Bagian id opsional menunjuk ke + satu baris dalam tabel. Setiap metode akses data + {@link android.content.ContentProvider} memiliki sebuah URI konten sebagai argumen; hal ini memungkinkan Anda + menentukan tabel, baris, atau file yang akan diakses. +
++ Dasar-dasar URI konten dijelaskan dalam topik + + Dasar-Dasar Penyedia Konten. +
+Mendesain otoritas
+
+ Penyedia biasanya memiliki otoritas tunggal, yang berfungsi sebagai nama internal Android-nya. Untuk
+ menghindari konflik dengan penyedia lain, Anda harus menggunakan kepemilikan domain internet (secara terbalik)
+ sebagai basis otoritas penyedia Anda. Karena saran ini juga berlaku untuk
+ nama-nama paket Android, Anda bisa mendefinisikan otoritas penyedia sebagai perluasan dari nama
+ paket yang berisi penyedia. Misalnya, jika nama paket Android Anda adalah
+ com.example.<appname>
, Anda harus memberikan penyedia Anda
+ otoritas com.example.<appname>.provider
.
+
Mendesain struktur path
+
+ Pengembang biasanya membuat URI konten dari otoritas dengan menambahkan path yang menunjuk ke
+ masing-masing tabel. Misalnya, jika Anda memiliki dua tabel table1 dan
+ table2, Anda mengombinasikan otoritas dari contoh sebelumnya untuk menghasilkan
+ URI konten
+ com.example.<appname>.provider/table1
dan
+ com.example.<appname>.provider/table2
. Path tidak
+ dibatasi pada segmen tunggal, dan tidak harus berupa tabel untuk masing-masing tingkat path.
+
Menangani ID URI konten
+
+ Berdasarkan standar, penyedia menawarkan akses ke satu baris dalam tabel dengan menerima URI konten
+ dengan sebuah nilai ID untuk baris itu di akhir URI. Juga berdasarkan standar, penyedia mencocokkan
+ nilai ID dengan kolom _ID
tabel, dan melakukan akses yang diminta terhadap baris
+ yang cocok.
+
+ Standar ini memudahkan pola desain umum untuk aplikasi yang mengakses penyedia. Aplikasi
+ melakukan query terhadap penyedia dan menampilkan {@link android.database.Cursor} yang dihasilkan
+ dalam {@link android.widget.ListView} dengan menggunakan {@link android.widget.CursorAdapter}.
+ Definisi {@link android.widget.CursorAdapter} mengharuskan salah satu kolom dalam
+ {@link android.database.Cursor} berupa _ID
+
+ Pengguna kemudian mengambil salah satu baris yang ditampilkan dari UI untuk menemukan atau memodifikasi
+ data. Aplikasi mengambil baris yang sesuai dari {@link android.database.Cursor} yang mendukung
+ {@link android.widget.ListView}, mengambil nilai _ID
untuk baris ini, menambahkannya ke
+ URI konten, dan mengirim permintaan akses ke penyedia. Penyedia nanti bisa melakukan
+ query atau modifikasi terhadap baris yang persis diambil pengguna.
+
Pola URI konten
+
+ Untuk membantu Anda memilih tindakan yang diambil bagi URI konten yang masuk, API penyedia menyertakan
+ kelas praktis {@link android.content.UriMatcher}, yang memetakan "pola-pola" URI konten ke
+ nilai-nilai integer. Anda bisa menggunakan nilai-nilai integer dalam pernyataan switch
yang
+ memilih tindakan yang diinginkan untuk URI konten atau URI yang cocok dengan pola tertentu.
+
+ Pola URI konten mencocokkan dengan URI konten menggunakan karakter wildcard: +
+-
+
-
+
*
: Mencocokkan string yang memiliki karakter yang sah dengan panjang berapa saja. +
+ -
+
#
: Mencocokkan string karakter numerik dengan panjang berapa saja. +
+
+ Sebagai contoh desain dan pemrograman penanganan URI konten, perhatikan penyedia dengan
+ otoritas com.example.app.provider
yang mengenali URI konten berikut
+ yang menunjuk ke tabel-tabel:
+
-
+
-
+
content://com.example.app.provider/table1
: Tabel bernamatable1
. +
+ -
+
content://com.example.app.provider/table2/dataset1
: Tabel bernama +dataset1
. +
+ -
+
content://com.example.app.provider/table2/dataset2
: Tabel bernama +dataset2
. +
+ -
+
content://com.example.app.provider/table3
: Tabel bernamatable3
. +
+
+ Penyedia juga mengenali URI konten ini jika baris ID ditambahkan ke URI,
+ misalnya content://com.example.app.provider/table3/1
untuk baris yang diidentifikasi oleh
+ 1
dalam table3
.
+
+ Pola-pola URI konten berikut akan menjadi mungkin: +
+-
+
-
+
content://com.example.app.provider/*
+
+ - + Mencocokkan URI konten di penyedia. + +
-
+
content://com.example.app.provider/table2/*
: +
+ -
+ Mencocokkan URI konten untuk tabel-tabel
dataset1
+ dandataset2
, namun tidak mencocokkan URI konten untuktable1
atau +table3
. +
+ -
+
content://com.example.app.provider/table3/#
: Mencocokkan URI konten + untuk satu baris ditable3
, misalnya +content://com.example.app.provider/table3/6
untuk baris yang diidentifikasi oleh +6
. +
+
+ Cuplikan kode berikut menunjukkan cara kerja metode di {@link android.content.UriMatcher}.
+ Kode ini menangani URI seluruh tabel secara berbeda dengan URI untuk
+ satu baris, menggunakan pola URI konten
+ content://<authority>/<path>
untuk tabel, dan
+ content://<authority>/<path>/<id>
untuk satu baris.
+
+ Metode {@link android.content.UriMatcher#addURI(String, String, int) addURI()} memetakan
+ otoritas dan path ke nilai integer. Metode {@link android.content.UriMatcher#match(Uri)
+ match()} menghasilkan nilai integer URI. Pernyataan switch
+ memilih antara melakukan query seluruh tabel dan melakukan query satu record:
+
+public class ExampleProvider extends ContentProvider { +... + // Creates a UriMatcher object. + private static final UriMatcher sUriMatcher; +... + /* + * The calls to addURI() go here, for all of the content URI patterns that the provider + * should recognize. For this snippet, only the calls for table 3 are shown. + */ +... + /* + * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used + * in the path + */ + sUriMatcher.addURI("com.example.app.provider", "table3", 1); + + /* + * Sets the code for a single row to 2. In this case, the "#" wildcard is + * used. "content://com.example.app.provider/table3/3" matches, but + * "content://com.example.app.provider/table3 doesn't. + */ + sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); +... + // Implements ContentProvider.query() + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { +... + /* + * Choose the table to query and a sort order based on the code returned for the incoming + * URI. Here, too, only the statements for table 3 are shown. + */ + switch (sUriMatcher.match(uri)) { + + + // If the incoming URI was for all of table3 + case 1: + + if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; + break; + + // If the incoming URI was for a single row + case 2: + + /* + * Because this URI was for a single row, the _ID value part is + * present. Get the last path segment from the URI; this is the _ID value. + * Then, append the value to the WHERE clause for the query + */ + selection = selection + "_ID = " uri.getLastPathSegment(); + break; + + default: + ... + // If the URI is not recognized, you should do some error handling here. + } + // call the code to actually do the query + } ++
+ Kelas lainnya, {@link android.content.ContentUris}, menyediakan metode praktis untuk menggunakan
+ bagian id
URI konten. Kelas-kelas {@link android.net.Uri} dan
+ {@link android.net.Uri.Builder} menyertakan metode praktis untuk mengurai
+ objek {@link android.net.Uri} yang ada dan membuat objek baru.
+
Mengimplementasikan Kelas ContentProvider
++ Instance {@link android.content.ContentProvider} mengelola akses + ke satu set data terstruktur dengan menangani permintaan dari aplikasi lain. Semua bentuk + akses pada akhirnya akan memanggil {@link android.content.ContentResolver}, yang kemudian memanggil + metode konkret {@link android.content.ContentProvider} untuk mendapatkan akses. +
+Metode-metode yang diperlukan
++ Kelas abstrak {@link android.content.ContentProvider} mendefinisikan enam metode abstrak yang + harus Anda implementasikan sebagai bagian dari subkelas konkret Anda sendiri. Semua metode ini kecuali + {@link android.content.ContentProvider#onCreate() onCreate()} dipanggil oleh aplikasi klien + yang berupaya mengakses penyedia konten Anda: +
+-
+
- + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + query()} + +
- + Mengambil data dari penyedia Anda. Menggunakan argumen untuk memilih tabel yang akan + di-query, baris dan kolom yang akan dihasilkan, dan urutan sortir hasilnya. + Menghasilkan data berupa objek {@link android.database.Cursor}. + +
- + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} + +
- + Menyisipkan baris baru ke dalam penyedia Anda. Menggunakan argumen untuk memilih + tabel tujuan dan mendapatkan nilai-nilai kolom yang akan digunakan. Menghasilkan URI konten untuk + baris yang baru disisipkan. + +
- + {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} + +
- + Memperbarui baris yang ada di penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris + yang akan diperbarui dan mendapatkan nilai-nilai kolom yang diperbarui. Menghasilkan jumlah baris yang diperbarui. + +
- + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} + +
- + Menghapus baris dari penyedia Anda. Menggunakan argumen untuk memilih tabel dan baris yang akan + dihapus. Menghasilkan jumlah baris yang dihapus. + +
- + {@link android.content.ContentProvider#getType(Uri) getType()} + +
- + Menghasilkan tipe MIME yang sesuai dengan URI konten. Metode ini dijelaskan lebih detail + di bagian Mengimplementasikan Tipe MIME Penyedia Konten. + +
- + {@link android.content.ContentProvider#onCreate() onCreate()} + +
- + Inisialisasi penyedia Anda. Sistem Android memanggil metode ini segera setelah + membuat penyedia Anda. Perhatikan bahwa penyedia Anda tidak dibuat hingga + objek {@link android.content.ContentResolver} mencoba mengaksesnya. + +
+ Perhatikan bahwa metode-metode ini memiliki signature yang sama dengan + metode-metode {@link android.content.ContentResolver} yang sama namanya. +
++ Implementasi metode-metode ini harus memperhitungkan hal-hal berikut: +
+-
+
- + Semua metode ini kecuali {@link android.content.ContentProvider#onCreate() onCreate()} + bisa dipanggil oleh beberapa thread sekaligus, jadi harus thread-safe (aman untuk thread). Untuk mengetahui + selengkapnya tentang multi-thread, lihat topik + + Proses dan Thread. + +
- + Hindari melakukan operasi yang lama dalam {@link android.content.ContentProvider#onCreate() + onCreate()}. Tunda inisialisasi tugas hingga benar-benar diperlukan. + Bagian Mengimplementasikan metode onCreate() + membahas hal ini secara lebih detail. + +
- + Walaupun harus mengimplementasikan metode-metode ini, kode Anda tidak harus melakukan apa pun selain + tipe data yang diharapkan. Misalnya, Anda mungkin ingin mencegah aplikasi lain + menyisipkan data ke dalam beberapa tabel. Caranya, Anda bisa mengabaikan panggilan ke + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} dan menghasilkan + 0. + +
Mengimplementasikan metode query()
+
+ Metode
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} harus menghasilkan objek {@link android.database.Cursor}, atau jika
+ gagal, melontarkan {@link java.lang.Exception}. Jika menggunakan database SQLite sebagai
+ penyimpanan data, Anda bisa mengembalikan{@link android.database.Cursor} yang dikembalikan oleh salah satu metode
+ query()
dari kelas {@link android.database.sqlite.SQLiteDatabase}.
+ Jika query tidak mencocokkan baris apa pun, Anda harus mengembalikan instance {@link android.database.Cursor}
+ yang metode {@link android.database.Cursor#getCount()}-nya mengembalikan 0.
+ Anda harus mengembalikan null
hanya jika terjadi kesalahan internal selama proses query.
+
+ Jika Anda tidak menggunakan database SQLite sebagai penyimpanan data, gunakan salah satu subkelas konkret + {@link android.database.Cursor}. Misalnya, kelas {@link android.database.MatrixCursor} + mengimplementasikan kursor dengan masing-masing baris berupa larik {@link java.lang.Object}. Dengan kelas ini, + gunakan {@link android.database.MatrixCursor#addRow(Object[]) addRow()} untuk menambahkan baris baru. +
++ Ingatlah bahwa sistem Android harus mampu mengomunikasikan {@link java.lang.Exception} + lintas batas proses. Android bisa melakukannya untuk eksepsi berikut yang mungkin berguna + dalam menangani kesalahan query: +
+-
+
- + {@link java.lang.IllegalArgumentException} (Anda bisa saja melontarkannya jika penyedia Anda + menerima URI konten yang tidak sah) + +
- + {@link java.lang.NullPointerException} + +
Mengimplementasikan metode insert()
++ Metode {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} menambahkan satu + baris baru ke tabel yang sesuai, dengan menggunakan nilai-nilai dalam argumen {@link android.content.ContentValues}. + Jika kolom nama tidak ada dalam argumen {@link android.content.ContentValues}, Anda + mungkin perlu menyediakan nilai default untuknya, baik dalam kode penyedia atau dalam skema database + Anda. +
+
+ Metode ini harus mengembalikan URI konten untuk baris baru. Untuk membuatnya, tambahkan nilai
+ _ID
baris baru (atau kunci utama lainnya) ke tabel URI konten, dengan menggunakan
+ {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
+
Mengimplementasikan metode delete()
++ Metode {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} + tidak harus menghapus baris-baris dari penyimpanan data Anda secara fisik. Jika menggunakan adaptor sinkronisasi + bersama penyedia, Anda harus mempertimbangkan penandaan baris yang dihapus + dengan flag "delete"; bukan menghilangkan baris itu sepenuhnya. Adaptor sinkronisasi bisa + memeriksa baris yang dihapus dan menghilangkannya dari server sebelum menghapusnya dari penyedia. +
+Mengimplementasikan metode update()
+
+ Metode {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+ update()} mengambil argumen {@link android.content.ContentValues} yang sama dengan yang digunakan oleh
+ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, dan
+ argumen-argumen selection
dan selectionArgs
yang sama dengan yang digunakan oleh
+ {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} dan
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()}. Hal ini bisa memungkinkan Anda menggunakan kembali kode di antara metode-metode ini.
+
Mengimplementasikan metode onCreate()
++ Sistem Android memanggil {@link android.content.ContentProvider#onCreate() + onCreate()} saat memulai penyedia. Anda harus melakukan tugas-tugas inisialisasi yang berjalan cepat saja + dalam metode ini, serta menunda pembuatan database dan pemuatan data hingga penyedia benar-benar + menerima permintaan terhadap data. Jika Anda melakukan tugas yang memakan waktu dalam + {@link android.content.ContentProvider#onCreate() onCreate()}, Anda akan memperlambat + startup penyedia. Pada gilirannya, hal ini akan memperlambat respons dari penyedia terhadap + aplikasi lain. +
++ Misalnya, jika menggunakan database SQLite, Anda bisa membuat + sebuah objek {@link android.database.sqlite.SQLiteOpenHelper} baru di + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}, + kemudian membuat tabel-tabel SQL saat pertama kali membuka database itu. Untuk memperlancar hal ini, + saat pertama Anda memanggil {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase + getWritableDatabase()}, metode ini memanggil metode + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} secara otomatis. +
++ Dua cuplikan berikut memperagakan interaksi antara + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} dan + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()}. Cuplikan pertama adalah implementasi + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}: +
++public class ExampleProvider extends ContentProvider + + /* + * Defines a handle to the database helper object. The MainDatabaseHelper class is defined + * in a following snippet. + */ + private MainDatabaseHelper mOpenHelper; + + // Defines the database name + private static final String DBNAME = "mydb"; + + // Holds the database object + private SQLiteDatabase db; + + public boolean onCreate() { + + /* + * Creates a new helper object. This method always returns quickly. + * Notice that the database itself isn't created or opened + * until SQLiteOpenHelper.getWritableDatabase is called + */ + mOpenHelper = new MainDatabaseHelper( + getContext(), // the application context + DBNAME, // the name of the database) + null, // uses the default SQLite cursor + 1 // the version number + ); + + return true; + } + + ... + + // Implements the provider's insert method + public Cursor insert(Uri uri, ContentValues values) { + // Insert code here to determine which table to open, handle error-checking, and so forth + + ... + + /* + * Gets a writeable database. This will trigger its creation if it doesn't already exist. + * + */ + db = mOpenHelper.getWritableDatabase(); + } +} ++
+ Cuplikan berikutnya adalah implementasi + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()}, yang menyertakan kelas helper: +
++... +// A string that defines the SQL statement for creating a table +private static final String SQL_CREATE_MAIN = "CREATE TABLE " + + "main " + // Table's name + "(" + // The columns in the table + " _ID INTEGER PRIMARY KEY, " + + " WORD TEXT" + " FREQUENCY INTEGER " + + " LOCALE TEXT )"; +... +/** + * Helper class that actually creates and manages the provider's underlying data repository. + */ +protected static final class MainDatabaseHelper extends SQLiteOpenHelper { + + /* + * Instantiates an open helper for the provider's SQLite data repository + * Do not do database creation and upgrade here. + */ + MainDatabaseHelper(Context context) { + super(context, DBNAME, null, 1); + } + + /* + * Creates the data repository. This is called when the provider attempts to open the + * repository and SQLite reports that it doesn't exist. + */ + public void onCreate(SQLiteDatabase db) { + + // Creates the main table + db.execSQL(SQL_CREATE_MAIN); + } +} ++ + + +
Mengimplementasikan Tipe MIME Penyedia Konten
++ Kelas {@link android.content.ContentProvider} memiliki dua metode untuk menghasilkan tipe-tipe MIME: +
+-
+
- + {@link android.content.ContentProvider#getType(Uri) getType()} + +
- + Salah satu metode wajib yang harus Anda implementasikan untuk setiap penyedia. + +
- + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} + +
- + Sebuah metode yang diharapkan untuk Anda implementasikan jika penyedia Anda menawarkan file. + +
Tipe MIME untuk tabel
++ Metode {@link android.content.ContentProvider#getType(Uri) getType()} mengembalikan + {@link java.lang.String} dengan format MIME yang menjelaskan tipe data yang dikembalikan oleh + argumen URI konten. Argumen {@link android.net.Uri} bisa berupa pola, bukannya URI tertentu; + dalam hal ini, Anda harus mengembalikan tipe data terkait URI konten yang cocok dengan + polanya. +
++ Untuk tipe data umum misalnya teks, HTML, atau JPEG, + {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan + tipe MIME standar untuk data itu. Daftar lengkap tipe standar ini tersedia di situs web + IANA MIME Media Types. + +
++ Untuk URI konten yang menunjuk ke baris atau baris-baris data tabel, + {@link android.content.ContentProvider#getType(Uri) getType()} harus mengembalikan + tipe MIME dalam format MIME khusus vendor Android: +
+-
+
-
+ Bagian tipe:
vnd
+
+ -
+ Bagian subtipe:
+
-
+
-
+ Jika pola URI adalah untuk satu baris:
android.cursor.item/
+
+ -
+ Jika pola URI adalah untuk lebih dari satu baris:
android.cursor.dir/
+
+
+ -
+ Jika pola URI adalah untuk satu baris:
-
+ Bagian khusus penyedia:
vnd.<name>
.<type>
++ Anda menyediakan
+ +<name>
dan<type>
. + Nilai<name>
harus unik secara global, + dan nilai<type>
harus unik bagi pola URI + yang sesuai. Pilihan tepat untuk<name>
adalah nama perusahaan Anda atau + sebagian dari nama paket Android aplikasi Anda. Pilihan tepat untuk +<type>
adalah string yang mengidentifikasi tabel yang terkait dengan + URI. +
+
+ Misalnya, jika otoritas penyedia adalah
+ com.example.app.provider
, dan penyedia mengekspos tabel bernama
+ table1
, tipe MIME untuk beberapa baris dalam table1
adalah:
+
+vnd.android.cursor.dir/vnd.com.example.provider.table1 ++
+ Untuk satu baris table1
, tipe MIME adalah:
+
+vnd.android.cursor.item/vnd.com.example.provider.table1 ++
Tipe MIME untuk file
++ Jika penyedia Anda menawarkan file, implementasikan + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}. + Metode ini menghasilkan larik {@link java.lang.String} tipe MIME untuk file + yang bisa dikembalikan penyedia Anda untuk URI konten bersangkutan. Anda harus memfilter tipe MIME yang Anda tawarkan dengan argumen filter + tipe MIME, sehingga Anda hanya mengembalikan tipe MIME yang ingin ditangani klien. +
+
+ Misalnya, perhatikan penyedia yang menawarkan gambar foto sebagai file dalam format .jpg
,
+ .png
, dan .gif
.
+ Jika aplikasi memanggil {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} dengan string filter image/*
(sesuatu yang
+ merupakan "gambar"),
+ maka metode {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} harus mengembalikan larik:
+
+{ "image/jpeg", "image/png", "image/gif"} ++
+ Jika aplikasi tertarik pada file .jpg
, maka aplikasi bisa memanggil
+ {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} dengan string filter *\/jpeg
, dan
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} harus mengembalikan:
+
+{"image/jpeg"} ++
+ Jika penyedia Anda tidak menawarkan tipe MIME apa pun yang diminta dalam string filter,
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+ harus mengembalikan null
.
+
Mengimplementasikan Kelas Kontrak
+
+ Kelas kontrak adalah kelas public final
yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan
+metadata lain yang melekat ke penyedia. Kelas
+ membentuk sebuah kontrak antara penyedia dan aplikasi lain dengan memastikan bahwa penyedia
+ bisa diakses dengan benar sekalipun ada perubahan pada nilai URI sesungguhnya, nama kolom,
+ dan seterusnya.
+
+ Kelas kontrak juga membantu pengembang karena kelas ini biasanya memiliki nama-nama simbolik untuk konstantanya, + sehingga memperkecil kemungkinan pengembang menggunakan nilai yang salah untuk nama kolom atau URI. Karena berupa + kelas, kelas ini bisa berisi dokumentasi Javadoc. Lingkungan pengembangan terpadu (IDE) seperti + Eclipse secara otomatis bisa melengkapi nama-nama konstanta dari kelas kontrak dan menampilkan Javadoc untuk + konstanta. +
+
+ Pengembang tidak bisa mengakses file kelas milik kelas kontrak dari aplikasi Anda, namun bisa
+ mengompilasinya secara statis ke dalam aplikasi mereka dari file .jar
yang Anda sediakan.
+
+ Kelas {@link android.provider.ContactsContract} dan kelas-kelas tersarangnya adalah contoh + kelas kontrak. +
+Mengimplementasikan Izin Penyedia Konten
++ Izin dan akses untuk semua aspek sistem Android dijelaskan secara detail dalam + topik Keamanan dan Izin. + Topik Penyimpanan Data juga + menjelaskan keamanan dan izin terkait dengan berbagai tipe penyimpanan. + Singkatnya, poin-poin pentingnya adalah: +
+-
+
- + Secara default, file data yang disimpan pada penyimpanan internal perangkat bersifat privat bagi + aplikasi dan penyedia Anda. + +
- + Database {@link android.database.sqlite.SQLiteDatabase} yang Anda buat bersifat privat bagi + aplikasi dan penyedia Anda. + +
- + Secara default, file data yang Anda simpan ke penyimpanan eksternal bersifat publik dan + bisa dibaca secara global. Anda tidak bisa menggunakan penyedia konten untuk membatasi akses ke file dalam + penyimpanan eksternal, karena aplikasi lain bisa menggunakan panggilan API untuk membaca dan menulis ke file tersebut. + +
- + Panggilan metode untuk membuka atau membuat file atau database SQLite pada + penyimpanan internal perangkat Anda berpotensi memberikan akses baca maupun tulis ke semua aplikasi lain. Jika Anda + menggunakan file atau database internal sebagai repository penyedia, dan Anda memberinya + akses "world-readable" (bisa dibaca secara global) atau "world-writeable" (bisa ditulis secara global), izin yang Anda atur untuk penyedia dalam + manifesnya tidak akan melindungi data Anda. Akses default untuk file dan database dalam + penyimpanan internal adalah "privat", dan untuk repository penyedia, tidak boleh Anda ubah. + +
+ Jika Anda ingin menggunakan izin penyedia konten untuk mengontrol akses ke data Anda, maka Anda harus + menyimpan data Anda dalam file internal, database SQLite, atau "cloud" (misalnya, + di server jauh), dan Anda harus membuat file dan database tetap privat bagi aplikasi Anda. +
+Mengimplementasikan izin
+
+ Semua aplikasi bisa membaca dari atau menulis ke penyedia Anda, sekalipun data yang mendasari adalah
+ privat, karena secara default penyedia Anda tidak mengatur izin. Untuk mengubahnya,
+ atur izin untuk penyedia dalam file manifes, dengan menggunakan atribut atau elemen anak
+ dari elemen
+ <provider>
. Anda bisa mengatur izin yang berlaku pada seluruh penyedia,
+ atau pada tabel tertentu, atau bahkan pada record tertentu, atau ketiganya.
+
+ Anda mendefinisikan izin untuk penyedia dengan satu atau beberapa elemen
+
+ <permission>
dalam file manifes. Untuk membuat
+ izin unik bagi penyedia, gunakan scoping (pengaturan lingkup) bergaya Java untuk
+ atribut
+ android:name
. Misalnya, beri nama izin membaca dengan
+ com.example.app.provider.permission.READ_PROVIDER
.
+
+
+ Daftar berikut menjelaskan lingkup penyedia izin, mulai dengan + izin yang berlaku pada seluruh penyedia kemudian menjadi semakin sempit. + Izin yang lebih sempit akan didahulukan daripada izin yang berlingkup lebih luas: +
+-
+
- + Izin baca-tulis tunggal tingkat penyedia + +
-
+ Suatu izin yang mengontrol akses baca-tulis bagi seluruh penyedia, ditetapkan
+ dengan atribut
+ android:permission
dari + elemen+ <provider>
. +
+ - + Izin baca-tulis terpisah tingkat penyedia + +
-
+ Satu izin baca dan satu izin tulis untuk seluruh penyedia. Anda menetapkan keduanya
+ dengan atribut
+ android:readPermission
dan ++ android:writePermission
dari elemen ++ <provider>
. Kedua izin akan didahulukan daripada izin yang diharuskan oleh ++ android:permission
. +
+ - + Izin tingkat path + +
-
+ Izin baca, tulis, atau baca/tulis untuk URI konten dalam penyedia Anda. Anda menetapkan
+ tiap URI yang ingin dikontrol dengan elemen anak
+
+ <path-permission>
dari + elemen+ <provider>
. Untuk setiap URI konten yang ditetapkan, Anda bisa menetapkan + satu izin baca/tulis, satu izin baca, atau satu izin tulis, atau ketiganya. Izin baca dan + tulis akan didahulukan daripada izin baca/tulis. Juga, + izin tingkat path akan didahulukan daripada izin tingkat penyedia. +
+ - + Izin sementara + +
-
+ Tingkat izin yang memberikan akses sementara ke aplikasi, sekalipun aplikasi itu
+ tidak memiliki izin yang biasanya diminta. Fitur akses
+ sementara mengurangi jumlah izin yang harus diminta aplikasi dalam
+ manifesnya. Bila Anda mengaktifkan izin sementara, satu-satunya aplikasi yang memerlukan
+ izin "permanen" untuk penyedia adalah aplikasi yang mengakses terus-menerus semua
+ data Anda.
+
+ Perhatikan izin yang Anda perlukan untuk mengimplementasikan penyedia dan aplikasi email, bila Anda + ingin memperbolehkan aplikasi penampil gambar dari luar menampilkan lampiran foto dari + penyedia Anda. Untuk memberikan akses yang diperlukan kepada penampil gambar tanpa mengharuskan izin, + siapkan izin sementara untuk URI konten bagi foto. Desainlah aplikasi email Anda agar + bila pengguna ingin menampilkan foto, aplikasi itu akan mengirim intent berisi + URI konten foto dan flag izin ke penampil gambar. Penampil gambar nanti bisa + melakukan query penyedia email untuk mengambil foto, sekalipun penampil itu tidak + memiliki izin baca normal untuk penyedia Anda. +
++ Untuk mengaktifkan izin sementara, atur atribut +
++ android:grantUriPermissions
dari + elemen+ <provider>
, atau tambahkan satu atau beberapa elemen anak ++ <grant-uri-permission>
ke + elemen+ <provider>
Anda. Jika menggunakan izin sementara, Anda harus memanggil + {@link android.content.Context#revokeUriPermission(Uri, int) + Context.revokeUriPermission()} kapan saja Anda menghilangkan dukungan untuk URI konten dari + penyedia, dan URI konten dikaitkan dengan izin sementara. ++ Nilai atribut menentukan seberapa banyak penyedia Anda yang dijadikan bisa diakses. + Jika atribut diatur ke
+true
, maka sistem akan memberikan + izin sementara kepada seluruh penyedia, dengan mengesampingkan izin lain yang diharuskan + oleh izin tingkat penyedia atau tingkat path. ++ Jika flag ini diatur ke
+false
, maka Anda harus menambahkan elemen-elemen anak ++ <grant-uri-permission>
ke + elemen+ <provider>
Anda. Tiap elemen anak menetapkan URI konten atau + URI yang telah diberi akses sementara. ++ Untuk mendelegasikan akses sementara ke sebuah aplikasi, intent harus berisi + {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} atau flag + {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, atau keduanya. Keduanya + diatur dengan metode {@link android.content.Intent#setFlags(int) setFlags()}. +
++ Jika atribut
++ android:grantUriPermissions
tidak ada, atribut ini diasumsikan sebagai +false
. +
+
Elemen <provider>
+
+ Seperti halnya komponen {@link android.app.Activity} dan {@link android.app.Service},
+ subkelas {@link android.content.ContentProvider}
+ harus didefinisikan dalam file manifes untuk aplikasinya, dengan menggunakan elemen
+
+ <provider>
. Sistem Android mendapatkan informasi berikut dari
+ elemen:
+
-
+
- + Otoritas + ({@code + android:authorities}) + +
- + Nama-nama simbolik yang mengidentifikasi seluruh penyedia dalam sistem. Atribut + ini dijelaskan lebih detail di bagian + Mendesain URI Konten. + +
-
+ Nama kelas penyedia
+ (
+android:name +
) +
+ - + Kelas yang mengimplementasikan {@link android.content.ContentProvider}. Kelas ini + dijelaskan lebih detail di bagian + Mengimplementasikan Kelas ContentProvider. + +
- + Izin + +
-
+ Atribut-atribut yang menetapkan izin yang harus dimiliki aplikasi lain untuk mengakses
+ data penyedia:
+
-
+
-
+
+ android:grantUriPermssions
: Flag izin sementara. +
+ -
+
+ android:permission
: Izin baca/tulis tunggal untuk tingkat penyedia. +
+ -
+
+ android:readPermission
: Izin baca untuk tingkat penyedia. +
+ -
+
+ android:writePermission
: Izin tulis untuk tingkat penyedia. +
+
+ Izin dan atribut-atribut yang sesuai dijelaskan lebih detail + di bagian + Mengimplementasikan Izin Penyedia Konten. +
+
+ -
+
- + Atribut-atribut startup dan kontrol + +
-
+ Atribut-atribut ini menentukan cara dan waktu sistem Android memulai penyedia,
+ karakteristik proses penyedia, dan pengaturan runtime lainnya:
+
-
+
-
+
+ android:enabled
: Flag yang memperbolehkan sistem untuk memulai penyedia. +
+ -
+
+ android:exported
: Flag yang memperbolehkan aplikasi lain untuk menggunakan penyedia ini. +
+ -
+
+ android:initOrder
: Urutan yang digunakan untuk memulai penyedia ini, + relatif terhadap penyedia lain dalam proses yang sama. +
+ -
+
+ android:multiProcess
: Flag yang memperbolehkan sistem untuk memulai penyedia + dalam proses yang sama dengan proses klien pemanggil. +
+ -
+
+ android:process
: Nama proses tempat penyedia harus + berjalan. +
+ -
+
+ android:syncable
: Flag yang menunjukkan bahwa data penyedia harus + disinkronkan dengan data di server. +
+
+ Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen +
++ <provider>
. + +
+ -
+
- + Atribut-atribut informatif + +
-
+ Ikon dan label opsional untuk penyedia:
+
-
+
-
+
+ android:icon
: Sumber daya drawable, berisi ikon untuk penyedia. + Ikon ini muncul di sebelah label penyedia dalam daftar aplikasi dalam menu + Settings > Apps > All. +
+ -
+
+ android:label
: Label informatif yang menjelaskan penyedia atau + datanya, atau keduanya. Label ini muncul dalam daftar aplikasi di + Settings > Apps > All. +
+
+ Atribut-atribut ini didokumentasikan dengan lengkap dalam topik panduan pengembang untuk elemen +
++ <provider>
. +
+ -
+
Intent dan Akses Data
++ Aplikasi bisa mengakses penyedia konten secara tidak langsung dengan sebuah {@link android.content.Intent}. + Aplikasi tidak memanggil satu pun dari metode-metode {@link android.content.ContentResolver} atau + {@link android.content.ContentProvider}. Sebagai gantinya, aplikasi mengirim intent yang memulai aktivitas, + yang sering kali merupakan bagian dari aplikasi penyedia sendiri. Aktivitas tujuan bertugas + mengambil dan menampilkan data dalam UI-nya. Bergantung pada tindakan dalam intent, + aktivitas tujuan juga bisa meminta pengguna untuk membuat modifikasi pada data penyedia. + Intent juga bisa berisi data "ekstra" yang menampilkan aktivitas tujuan + dalam UI; pengguna nanti memiliki pilihan untuk mengubah data ini sebelum menggunakannya untuk mengubah + data di penyedia. +
++ +
++ Anda mungkin perlu menggunakan akses intent guna membantu memastikan integritas data. Penyedia Anda mungkin bergantung + pada data yang disisipkan, diperbarui, dan dihapusnya sesuai dengan logika bisnis yang didefinisikan dengan ketat. Jika + demikian halnya, memperbolehkan aplikasi lain mengubah data Anda secara langsung bisa menyebabkan + data yang tidak sah. Jika Anda ingin pengembang menggunakan akses intent, pastikan untuk mendokumentasikannya secara saksama. + Jelaskan kepada mereka alasan akses intent yang menggunakan UI aplikasi Anda sendiri adalah lebih baik daripada mencoba + memodifikasi data dengan kode mereka. +
++ Menangani sebuah intent masuk yang ingin memodifikasi data penyedia Anda tidak berbeda dengan + menangani intent lainnya. Anda bisa mengetahui selengkapnya tentang penggunaan intent dengan membaca topik + Intent dan Filter Intent. +
diff --git a/docs/html-intl/intl/in/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/in/guide/topics/providers/content-providers.jd new file mode 100644 index 0000000000000000000000000000000000000000..fc6f12b6f569cb31c7187a6133d9b7cb6ef5eecc --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/providers/content-providers.jd @@ -0,0 +1,108 @@ +page.title=Penyedia konten +@jd:body +Topik
+-
+
- + + Dasar-Dasar Penyedia Konten + +
- + + Membuat Penyedia Konten + +
- + Penyedia Kalender + +
- + Penyedia Kontak + +
Contoh-Contoh Terkait
+-
+
- + + Aplikasi Contact Manager + +
- + + "Kursor (Orang)" + + +
- + + "Kursor (Telepon)" + +
- + + Contoh Adaptor Sinkronisasi + +
+ Penyedia konten mengelola akses ke set data terstruktur. Penyedia ini membungkus + data, dan menyediakan mekanisme untuk mendefinisikan keamanan data. Penyedia konten adalah antarmuka + standar yang menghubungkan data dalam satu proses dengan kode yang berjalan dalam proses lain. +
++ Bila Anda ingin mengakses data di penyedia konten, Anda menggunakan + {@link android.content.ContentResolver} objek dalam + {@link android.content.Context} aplikasi untuk berkomunikasi dengan penyedia sebagai klien. + Objek {@link android.content.ContentResolver} berkomunikasi dengan objek penyedia, yakni + instance kelas yang mengimplementasikan {@link android.content.ContentProvider}. Objek penyedia + menerima permintaan data dari klien, melakukan tindakan yang diminta, dan + mengembalikan hasilnya. +
++ Anda tidak perlu mengembangkan penyedia sendiri jika tidak bermaksud untuk berbagi data dengan + aplikasi lain. Akan tetapi, Anda memerlukan penyedia buatan sendiri untuk menyediakan saran pencarian custom + dalam aplikasi Anda sendiri. Anda juga memerlukan penyedia sendiri jika ingin menyalin dan +menempelkan data atau file yang kompleks dari aplikasi Anda ke aplikasi lain. +
+
+ Android sendiri berisi penyedia konten yang mengelola data seperti informasi audio, video, gambar, dan
+ kontak pribadi. Anda bisa melihat sebagian informasi ini tercantum dalam dokumentasi
+ acuan untuk paket
+ android.provider
+
. Dengan beberapa batasan, semua penyedia ini bisa diakses oleh aplikasi Android
+ apa saja.
+
+ Topik-topik berikut menjelaskan penyedia konten secara lebih detail: +
+-
+
- + + Dasar-Dasar Penyedia Konten + +
- + Cara mengakses data di penyedia konten bila data disusun dalam tabel. + +
- + + Membuat Penyedia Konten + +
- + Cara membuat penyedia konten sendiri. + +
- + + Penyedia Kalender + +
- + Cara mengakses Penyedia Kalender yang merupakan bagian dari platform Android. + +
- + + Penyedia Kontak + +
- + Cara mengakses Penyedia Kontak yang merupakan bagian dari platform Android. + +
Dalam dokumen ini + + tampilkan maksimal + tampilkan minimal
+-
+
- + Ikhtisar + +
- + Arus Kontrol + +
- + Menulis Aplikasi Klien + + +
- Menulis Penyedia Dokumen Custom
+
-
+
- Manifes +
- Kontrak +
- Subkelas DocumentsProvider +
- Keamanan +
+
+
Kelas-kelas utama
+-
+
- {@link android.provider.DocumentsProvider} +
- {@link android.provider.DocumentsContract} +
Video
+ +-
+
- +DevBytes: Android 4.4 Storage Access Framework: Penyedia +
- +DevBytes: Android 4.4 Storage Access Framework: Klien +
Contoh Kode
+ + + +Lihat Juga
+-
+
- + + Dasar-Dasar Penyedia Konten + + +
Android 4.4 (API level 19) memperkenalkan Storage Access Framework (SAF, Kerangka Kerja Akses Penyimpanan). SAF + memudahkan pengguna menyusuri dan membuka dokumen, gambar, dan file lainnya +di semua penyedia penyimpanan dokumen pilihannya. UI standar yang mudah digunakan +memungkinkan pengguna menyusuri file dan mengakses yang terbaru dengan cara konsisten di antara berbagai aplikasi dan penyedia.
+ +Layanan penyimpanan cloud atau lokal bisa dilibatkan dalam ekosistem ini dengan mengimplementasikan sebuah +{@link android.provider.DocumentsProvider} yang membungkus layanannya. Aplikasi klien +yang memerlukan akses ke dokumen sebuah penyedia bisa berintegrasi dengan SAF cukup dengan beberapa +baris kode.
+ +SAF terdiri dari berikut ini:
+ +-
+
- Penyedia dokumen—Penyedia konten yang memungkinkan +layanan penyimpanan (seperti Google Drive) untuk menampilkan file yang dikelolanya. Penyedia dokumen +diimplementasikan sebagai subkelas dari kelas {@link android.provider.DocumentsProvider}. +Skema penyedia dokumen berdasarkan hierarki file biasa, +walaupun cara penyedia dokumen Anda secara fisik menyimpan data adalah terserah Anda. +Platform Android terdiri dari beberapa penyedia dokumen bawaan, seperti +Downloads, Images, dan Videos. + +
- Aplikasi klien—Aplikasi custom yang memanggil intent +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan/atau +{@link android.content.Intent#ACTION_CREATE_DOCUMENT} dan menerima +file yang dihasilkan penyedia dokumen. + +
- Picker—UI sistem yang memungkinkan pengguna mengakses dokumen dari semua +penyedia dokumen yang memenuhi kriteria pencarian aplikasi klien. +
Beberapa fitur yang disediakan oleh SAF adalah sebagai berikut:
+-
+
- Memungkinkan pengguna menyusuri konten dari semua penyedia dokumen, bukan hanya satu aplikasi. +
- Memungkinkan aplikasi Anda memiliki akses jangka panjang dan tetap ke + dokumen yang dimiliki oleh penyedia dokumen. Melalui akses ini pengguna bisa menambah, mengedit, + menyimpan, dan menghapus file pada penyedia. +
- Mendukung banyak akun pengguna dan akar jangka pendek seperti penyedia penyimpanan +USB, yang hanya muncul jika drive itu dipasang. +
Ikhtisar
+ +SAF berpusat di seputar penyedia konten yang merupakan +subkelas dari kelas {@link android.provider.DocumentsProvider}. Dalam penyedia dokumen, data +distrukturkan sebagai hierarki file biasa:
+ + + +Perhatikan yang berikut ini:
+-
+
+
- Setiap penyedia dokumen melaporkan satu atau beberapa +"akar" yang merupakan titik awal penyusuran pohon dokumen. +Masing-masing akar memiliki sebuah {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} yang unik, +dan menunjuk ke satu dokumen (satu direktori) +yang mewakili konten di bawah akar itu. +Akar sengaja dibuat dinamis untuk mendukung kasus penggunaan seperti multiakun, +perangkat penyimpanan USB jangka pendek, atau masuk/keluar pengguna. + +
- Di bawah tiap akar terdapat satu dokumen. Dokumen itu menunjuk ke dokumen-dokumen 1-ke-N, +yang nanti masing-masing bisa menunjuk ke dokumen 1-ke-N. + +
- Tiap backend penyimpanan memunculkan +masing-masing file dan direktori dengan mengacunya lewat sebuah +{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang unik. +ID dokumen harus unik dan tidak berubah setelah dibuat, karena ID ini digunakan untuk +URI persisten yang diberikan pada saat reboot perangkat. + + +
- Dokumen bisa berupa file yang bisa dibuka (dengan tipe MIME tertentu), atau +direktori yang berisi dokumen tambahan (dengan tipe MIME +{@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR}). + +
- Tiap dokumen bisa mempunyai kemampuan berbeda, sebagaimana yang dijelaskan oleh +{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS}. +Misalnya, {@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE}, +{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}, dan +{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL}. +{@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} yang sama bisa +dimasukkan dalam beberapa direktori. +
Arus Kontrol
+Seperti dinyatakan di atas, model data penyedia dokumen dibuat berdasarkan hierarki file +biasa. Akan tetapi, Anda bisa menyimpan secara fisik data dengan cara apa pun yang disukai, +selama data bisa diakses melalui API {@link android.provider.DocumentsProvider}. Misalnya, Anda +bisa menggunakan penyimpanan cloud berbasis tag untuk data Anda.
+ +Gambar 2 menampilkan contoh cara aplikasi foto bisa menggunakan SAF +untuk mengakses data tersimpan:
+ + + + +Perhatikan yang berikut ini:
+-
+
+
- Di SAF, penyedia dan klien tidak berinteraksi +secara langsung. Klien meminta izin untuk berinteraksi +dengan file (yakni, membaca, mengedit, membuat, atau menghapus file). + +
- Interaksi dimulai bila sebuah aplikasi (dalam contoh ini adalah aplikasi foto) mengeluarkan intent +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} atau {@link android.content.Intent#ACTION_CREATE_DOCUMENT}. Intent bisa berisi filter +untuk mempersempit kriteria—misalnya, "beri saya semua file yang bisa dibuka +yang memiliki tipe MIME 'gambar'". + +
- Setelah intent dibuat, picker sistem akan pergi ke setiap penyedia yang terdaftar +dan menunjukkan kepada pengguna akar konten yang cocok. + +
- Picker memberi pengguna antarmuka standar untuk mengakses dokumen, +walaupun penyedia dokumen dasar bisa sangat berbeda. Misalnya, gambar 2 +menunjukkan penyedia Google Drive, penyedia USB, dan penyedia cloud. +
Gambar 3 menunjukkan picker yang di digunakan pengguna mencari gambar telah memilih +akun Google Drive:
+ + + + + +Bila pengguna memilih Google Drive, gambar-gambar akan ditampilkan, seperti yang ditampilkan dalam +gambar 4. Dari titik itu, pengguna bisa berinteraksi dengan gambar dengan cara apa pun +yang didukung oleh penyedia dan aplikasi klien. + +
+ + + +Menulis Aplikasi Klien
+ +Pada Android 4.3 dan yang lebih rendah, jika Anda ingin aplikasi mengambil file dari +aplikasi lain, aplikasi Anda harus memanggil intent seperti {@link android.content.Intent#ACTION_PICK} +atau {@link android.content.Intent#ACTION_GET_CONTENT}. Pengguna nanti harus memilih +satu aplikasi yang akan digunakan untuk mengambil file dan aplikasi yang dipilih harus menyediakan antarmuka pengguna +bagi untuk menyusuri dan mengambil dari file yang tersedia.
+ +Pada Android 4.4 dan yang lebih tinggi, Anda mempunyai opsi tambahan dalam menggunakan intent +{@link android.content.Intent#ACTION_OPEN_DOCUMENT}, +yang menampilkan UI picker yang dikontrol oleh sistem yang memungkinkan pengguna +menyusuri semua file yang disediakan aplikasi lain. Dari satu UI ini, pengguna +bisa mengambil file dari aplikasi apa saja yang didukung.
+ +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} +tidak dimaksudkan untuk menjadi pengganti {@link android.content.Intent#ACTION_GET_CONTENT}. +Yang harus Anda gunakan bergantung pada kebutuhan aplikasi:
+ +-
+
- Gunakan {@link android.content.Intent#ACTION_GET_CONTENT} jika Anda ingin aplikasi +cuma membaca/mengimpor data. Dengan pendekatan ini, aplikasi akan mengimpor salinan data, +misalnya file gambar. + +
- Gunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT} jika Anda ingin aplikasi +memiliki akses jangka panjang dan jangka pendek ke dokumen yang dimiliki oleh penyedia +dokumen. Contohnya adalah aplikasi pengeditan foto yang memungkinkan pengguna mengedit +gambar yang tersimpan dalam penyedia dokumen. + +
Bagian ini menjelaskan cara menulis aplikasi klien berdasarkan +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan +intent {@link android.content.Intent#ACTION_CREATE_DOCUMENT}.
+ + +Mencari dokumen
+ ++Cuplikan berikut menggunakan {@link android.content.Intent#ACTION_OPEN_DOCUMENT} +untuk mencari penyedia dokumen yang +berisi file gambar:
+ +private static final int READ_REQUEST_CODE = 42; +... +/** + * Fires an intent to spin up the "file chooser" UI and select an image. + */ +public void performFileSearch() { + + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file + // browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones) + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only images, using the image MIME data type. + // If one wanted to search for ogg vorbis files, the type would be "audio/ogg". + // To search for all documents available via installed storage providers, + // it would be "*/*". + intent.setType("image/*"); + + startActivityForResult(intent, READ_REQUEST_CODE); +}+ +
Perhatikan yang berikut ini:
+-
+
- Saat aplikasi mengeluarkan intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT} +, aplikasi akan menjalankan picker yang menampilkan semua penyedia dokumen yang cocok. + +
- Menambahkan kategori {@link android.content.Intent#CATEGORY_OPENABLE} ke +intent akan menyaring hasil agar hanya menampilkan dokumen yang bisa dibuka, seperti file gambar. + +
- Pernyataan {@code intent.setType("image/*")} menyaring lebih jauh agar hanya +menampilkan dokumen yang memiliki tipe data MIME gambar. +
Memproses Hasil
+ +Setelah pengguna memilih dokumen di picker, +{@link android.app.Activity#onActivityResult onActivityResult()} akan dipanggil. +URI yang menunjuk ke dokumen yang dipilih dimasukkan dalam parameter {@code resultData} +. Ekstrak URI dengan {@link android.content.Intent#getData getData()}. +Setelah mendapatkannya, Anda bisa menggunakannya untuk mengambil dokumen yang diinginkan pengguna. Misalnya +:
+ +@Override +public void onActivityResult(int requestCode, int resultCode, + Intent resultData) { + + // The ACTION_OPEN_DOCUMENT intent was sent with the request code + // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the + // response to some other intent, and the code below shouldn't run at all. + + if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + // The document selected by the user won't be returned in the intent. + // Instead, a URI to that document will be contained in the return intent + // provided to this method as a parameter. + // Pull that URI using resultData.getData(). + Uri uri = null; + if (resultData != null) { + uri = resultData.getData(); + Log.i(TAG, "Uri: " + uri.toString()); + showImage(uri); + } + } +} ++ +
Memeriksa metadata dokumen
+ +Setelah Anda memiliki URI untuk dokumen, Anda akan mendapatkan akses ke metadatanya. Cuplikan +ini memegang metadata sebuah dokumen yang disebutkan oleh URI, dan mencatatnya:
+ +public void dumpImageMetaData(Uri uri) { + + // The query, since it only applies to a single document, will only return + // one row. There's no need to filter, sort, or select fields, since we want + // all fields for one document. + Cursor cursor = getActivity().getContentResolver() + .query(uri, null, null, null, null, null); + + try { + // moveToFirst() returns false if the cursor has 0 rows. Very handy for + // "if there's anything to look at, look at it" conditionals. + if (cursor != null && cursor.moveToFirst()) { + + // Note it's called "Display Name". This is + // provider-specific, and might not necessarily be the file name. + String displayName = cursor.getString( + cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + Log.i(TAG, "Display Name: " + displayName); + + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + // If the size is unknown, the value stored is null. But since an + // int can't be null in Java, the behavior is implementation-specific, + // which is just a fancy term for "unpredictable". So as + // a rule, check if it's null before assigning to an int. This will + // happen often: The storage API allows for remote files, whose + // size might not be locally known. + String size = null; + if (!cursor.isNull(sizeIndex)) { + // Technically the column stores an int, but cursor.getString() + // will do the conversion automatically. + size = cursor.getString(sizeIndex); + } else { + size = "Unknown"; + } + Log.i(TAG, "Size: " + size); + } + } finally { + cursor.close(); + } +} ++ +
Membuka dokumen
+ +Setelah mendapatkan URI dokumen, Anda bisa membuka dokumen atau melakukan apa saja +yang diinginkan padanya.
+ +Bitmap
+ +Berikut ini adalah contoh cara membuka {@link android.graphics.Bitmap}:
+ +private Bitmap getBitmapFromUri(Uri uri) throws IOException { + ParcelFileDescriptor parcelFileDescriptor = + getContentResolver().openFileDescriptor(uri, "r"); + FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); + Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); + parcelFileDescriptor.close(); + return image; +} ++ +
Perhatikan bahwa Anda tidak boleh melakukan operasi ini pada thread UI. Lakukan hal ini di latar belakang +, dengan menggunakan {@link android.os.AsyncTask}. Setelah membuka bitmap, Anda +bisa menampilkannya dalam {@link android.widget.ImageView}. +
+ +Mendapatkan InputStream
+ +Berikut ini adalah contoh cara mendapatkan {@link java.io.InputStream} dari URI. Dalam cuplikan ini +, baris-baris file dibaca ke dalam sebuah string:
+ +private String readTextFromUri(Uri uri) throws IOException { + InputStream inputStream = getContentResolver().openInputStream(uri); + BufferedReader reader = new BufferedReader(new InputStreamReader( + inputStream)); + StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + fileInputStream.close(); + parcelFileDescriptor.close(); + return stringBuilder.toString(); +} ++ +
Membuat dokumen baru
+ +Aplikasi Anda bisa membuat dokumen baru dalam penyedia dokumen dengan menggunakan intent +{@link android.content.Intent#ACTION_CREATE_DOCUMENT} +. Untuk membuat file, Anda memberikan satu tipe MIME dan satu nama file pada intent, dan +menjalankannya dengan kode permintaan yang unik. Selebihnya akan diurus untuk Anda:
+ + ++// Here are some examples of how you might call this method. +// The first parameter is the MIME type, and the second parameter is the name +// of the file you are creating: +// +// createFile("text/plain", "foobar.txt"); +// createFile("image/png", "mypicture.png"); + +// Unique request code. +private static final int WRITE_REQUEST_CODE = 43; +... +private void createFile(String mimeType, String fileName) { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + + // Filter to only show results that can be "opened", such as + // a file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Create a file with the requested MIME type. + intent.setType(mimeType); + intent.putExtra(Intent.EXTRA_TITLE, fileName); + startActivityForResult(intent, WRITE_REQUEST_CODE); +} ++ +
Setelah membuat dokumen baru, Anda bisa mendapatkan URI-nya dalam +{@link android.app.Activity#onActivityResult onActivityResult()}, sehingga Anda +bisa terus menulis ke dokumen itu.
+ +Menghapus dokumen
+ +Jika Anda memiliki URI dokumen dan +{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS} + dokumen berisi +{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE}, +Anda bisa menghapus dokumen tersebut. Misalnya:
+ ++DocumentsContract.deleteDocument(getContentResolver(), uri); ++ +
Mengedit dokumen
+ +Anda bisa menggunakan SAF untuk mengedit dokumen teks langsung di tempatnya. +Cuplikan ini memicu +intent {@link android.content.Intent#ACTION_OPEN_DOCUMENT} dan menggunakan +kategori {@link android.content.Intent#CATEGORY_OPENABLE} untuk menampilkan +dokumen yang bisa dibuka saja. Ini akan menyaring lebih jauh untuk menampilkan file teks saja:
+ ++private static final int EDIT_REQUEST_CODE = 44; +/** + * Open a file for writing and append some text to it. + */ + private void editDocument() { + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's + // file browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only text files. + intent.setType("text/plain"); + + startActivityForResult(intent, EDIT_REQUEST_CODE); +} ++ +
Berikutnya, dari {@link android.app.Activity#onActivityResult onActivityResult()} +(lihat Memproses hasil) Anda bisa memanggil kode untuk mengedit. +Cuplikan berikut mendapatkan {@link java.io.FileOutputStream} +dari {@link android.content.ContentResolver}. Secara default, snipet menggunakan mode “tulis”. +Inilah praktik terbaik untuk meminta jumlah akses minimum yang Anda perlukan, jadi jangan meminta +baca/tulis jika yang Anda perlukan hanyalah tulis:
+ +private void alterDocument(Uri uri) { + try { + ParcelFileDescriptor pfd = getActivity().getContentResolver(). + openFileDescriptor(uri, "w"); + FileOutputStream fileOutputStream = + new FileOutputStream(pfd.getFileDescriptor()); + fileOutputStream.write(("Overwritten by MyCloud at " + + System.currentTimeMillis() + "\n").getBytes()); + // Let the document provider know you're done by closing the stream. + fileOutputStream.close(); + pfd.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } +}+ +
Mempertahankan izin
+ +Bila aplikasi Anda membuka file untuk membaca atau menulis, sistem akan memberi +aplikasi Anda izin URI untuk file itu. Pemberian ini berlaku hingga perangkat pengguna di-restart. +Namun anggaplah aplikasi Anda adalah aplikasi pengeditan gambar, dan Anda ingin pengguna bisa +mengakses 5 gambar terakhir yang dieditnya, langsung dari aplikasi Anda. Jika perangkat pengguna telah +di-restart, maka Anda harus mengirim pengguna kembali ke picker sistem untuk menemukan +file, hal ini jelas tidak ideal.
+ +Untuk mencegah terjadinya hal ini, Anda bisa mempertahankan izin yang diberikan +sistem ke aplikasi Anda. Secara efektif, aplikasi Anda akan "mengambil" pemberian izin URI yang bisa dipertahankan +yang ditawarkan oleh sistem. Hal ini memberi pengguna akses kontinu ke file +melalui aplikasi Anda, sekalipun perangkat telah di-restart:
+ + +final int takeFlags = intent.getFlags() + & (Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); +// Check for the freshest data. +getContentResolver().takePersistableUriPermission(uri, takeFlags);+ +
Ada satu langkah akhir. Anda mungkin telah menyimpan +URI terbaru yang diakses aplikasi, namun URI itu mungkin tidak lagi valid,—aplikasi lain +mungkin telah menghapus atau memodifikasi dokumen. Karena itu, Anda harus selalu memanggil +{@code getContentResolver().takePersistableUriPermission()} untuk memeriksa +data terbaru.
+ +Menulis Penyedia Dokumen Custom
+ ++Jika Anda sedang mengembangkan aplikasi yang menyediakan layanan penyimpanan untuk file (misalnya +layanan penyimpanan cloud), Anda bisa menyediakan file melalui +SAF dengan menulis penyedia dokumen custom. Bagian ini menjelaskan +caranya.
+ + +Manifes
+ +Untuk mengimplementasikan penyedia dokumen custom, tambahkan yang berikut ini ke manifes aplikasi +Anda:
+-
+
+
- Target berupa API level 19 atau yang lebih tinggi. + +
- Elemen
<provider>
yang mendeklarasikan penyedia penyimpanan custom +Anda.
+
+ - Nama penyedia Anda, yaitu nama kelasnya, termasuk nama paket.
+Misalnya:
com.example.android.storageprovider.MyCloudProvider
.
+
+ - Nama otoritas Anda, yaitu nama paket Anda (dalam contoh ini,
+
com.example.android.storageprovider
) plus tipe penyedia konten +(documents
). Misalnya, {@code com.example.android.storageprovider.documents}.
+
+ - Atribut
android:exported
yang diatur ke"true"
. +Anda harus mengekspor penyedia sehingga aplikasi lain bisa membacanya.
+
+ - Atribut
android:grantUriPermissions
yang diatur ke +"true"
. Pengaturan ini memungkinkan sistem memberi aplikasi lain akses +ke konten dalam penyedia Anda. Untuk pembahasan cara mempertahankan pemberian bagi +dokumen tertentu, lihat Mempertahankan izin.
+
+ - Izin {@code MANAGE_DOCUMENTS}. Secara default, penyedia tersedia +bagi siapa saja. Menambahkan izin ini akan membatasi penyedia Anda pada sistem. +Pembatasan ini penting untuk keamanan. + +
- Atribut {@code android:enabled} yang diatur ke nilai boolean didefinisikan dalam file
+sumber daya. Tujuan atribut ini adalah menonaktifkan penyedia pada perangkat yang menjalankan Android 4.3 atau yang lebih rendah.
+Misalnya, {@code android:enabled="@bool/atLeastKitKat"}. Selain
+memasukkan atribut ini dalam manifes, Anda perlu melakukan hal-hal berikut:
+
-
+
- Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
+baris ini:
<bool name="atLeastKitKat">false</bool>
+
+ - Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
+baris ini:
<bool name="atLeastKitKat">true</bool>
+
+
+ - Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
+baris ini:
- Sebuah filter intent berisi tindakan +{@code android.content.action.DOCUMENTS_PROVIDER}, agar penyedia Anda +muncul dalam picker saat sistem mencari penyedia. + +
Berikut ini adalah kutipan contoh manifes berisi penyedia yang:
+ +<manifest... > + ... + <uses-sdk + android:minSdkVersion="19" + android:targetSdkVersion="19" /> + .... + <provider + android:name="com.example.android.storageprovider.MyCloudProvider" + android:authorities="com.example.android.storageprovider.documents" + android:grantUriPermissions="true" + android:exported="true" + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="@bool/atLeastKitKat"> + <intent-filter> + <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> + </intent-filter> + </provider> + </application> + +</manifest>+ +
Mendukung perangkat yang menjalankan Android 4.3 dan yang lebih rendah
+ +Intent +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} hanya tersedia +pada perangkat yang menjalankan Android 4.4 dan yang lebih tinggi. +Jika ingin aplikasi Anda mendukung {@link android.content.Intent#ACTION_GET_CONTENT} +untuk mengakomodasi perangkat yang menjalankan Android 4.3 dan yang lebih rendah, Anda harus +menonaktifkan filter inten {@link android.content.Intent#ACTION_GET_CONTENT} dalam +manifes untuk perangkat yang menjalankan Android 4.4 atau yang lebih tinggi. Penyedia +dokumen dan {@link android.content.Intent#ACTION_GET_CONTENT} harus dianggap +saling eksklusif. Jika Anda mendukung keduanya sekaligus, aplikasi Anda akan +muncul dua kali dalam UI picker sistem, yang menawarkan dua cara mengakses +data tersimpan Anda. Hal ini akan membingungkan pengguna.
+ +Berikut ini adalah cara yang disarankan untuk menonaktifkan +filter intent {@link android.content.Intent#ACTION_GET_CONTENT} untuk perangkat +yang menjalankan Android versi 4.4 atau yang lebih tinggi:
+ +-
+
- Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values/}, tambahkan
+baris ini:
<bool name="atMostJellyBeanMR2">true</bool>
+
+ - Dalam file sumber daya {@code bool.xml} Anda di bawah {@code res/values-v19/}, tambahkan
+baris ini:
<bool name="atMostJellyBeanMR2">false</bool>
+
+ - Tambahkan
+alias
+aktivitas untuk menonaktifkan filter intent {@link android.content.Intent#ACTION_GET_CONTENT}
+bagi versi 4.4 (API level 19) dan yang lebih tinggi. Misalnya:
+
+
+<!-- This activity alias is added so that GET_CONTENT intent-filter + can be disabled for builds on API level 19 and higher. --> +<activity-alias android:name="com.android.example.app.MyPicker" + android:targetActivity="com.android.example.app.MyActivity" + ... + android:enabled="@bool/atMostJellyBeanMR2"> + <intent-filter> + <action android:name="android.intent.action.GET_CONTENT" /> + <category android:name="android.intent.category.OPENABLE" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="image/*" /> + <data android:mimeType="video/*" /> + </intent-filter> +</activity-alias> +
+
+
Kontrak
+ +Biasanya bila Anda menulis penyedia konten custom, salah satu tugas adalah +mengimplementasikan kelas kontrak, seperti dijelaskan dalam panduan pengembang + +Penyedia Konten. Kelas kontrak adalah kelas {@code public final} +yang berisi definisi konstanta untuk URI, nama kolom, tipe MIME, dan +metadata lain yang berkenaan dengan penyedia. SAF +menyediakan kelas-kelas kontrak ini untuk Anda, jadi Anda tidak perlu menulisnya +sendiri:
+ +-
+
- {@link android.provider.DocumentsContract.Document} +
- {@link android.provider.DocumentsContract.Root} +
Misalnya, berikut ini adalah kolom-kolom yang bisa Anda hasilkan di kursor bila +penyedia dokumen Anda membuat query dokumen atau akar:
+ +private static final String[] DEFAULT_ROOT_PROJECTION = + new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES, + Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE, + Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID, + Root.COLUMN_AVAILABLE_BYTES,}; +private static final String[] DEFAULT_DOCUMENT_PROJECTION = new + String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_FLAGS, Document.COLUMN_SIZE,}; ++ +
Subkelas DocumentsProvider
+ +Langkah berikutnya dalam menulis penyedia dokumen custom adalah menjadikan +kelas abstrak sebagai subkelas {@link android.provider.DocumentsProvider}. Setidaknya, Anda perlu + mengimplementasikan metode berikut:
+ +-
+
- {@link android.provider.DocumentsProvider#queryRoots queryRoots()} + +
- {@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} + +
- {@link android.provider.DocumentsProvider#queryDocument queryDocument()} + +
- {@link android.provider.DocumentsProvider#openDocument openDocument()} +
Hanya inilah metode yang diwajibkan kepada Anda secara ketat untuk diimplementasikan, namun ada +banyak lagi yang mungkin Anda inginkan. Lihat {@link android.provider.DocumentsProvider} +untuk detailnya.
+ +Mengimplementasikan queryRoots
+ +Implementasi {@link android.provider.DocumentsProvider#queryRoots +queryRoots()} oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua +direktori akar penyedia dokumen, dengan menggunakan kolom-kolom yang didefinisikan dalam +{@link android.provider.DocumentsContract.Root}.
+ +Dalam cuplikan berikut, parameter {@code projection} mewakili bidang-bidang +tertentu yang ingin didapatkan kembali oleh pemanggil. Cuplikan ini membuat kursor baru +dan menambahkan satu baris ke satu akar— kursor, satu direktori level atas, seperti +Downloads atau Images. Kebanyakan penyedia hanya mempunyai satu akar. Anda bisa mempunyai lebih dari satu, +misalnya, jika ada banyak akun pengguna. Dalam hal itu, cukup tambahkan sebuah +baris kedua ke kursor.
+ ++@Override +public Cursor queryRoots(String[] projection) throws FileNotFoundException { + + // Create a cursor with either the requested fields, or the default + // projection if "projection" is null. + final MatrixCursor result = + new MatrixCursor(resolveRootProjection(projection)); + + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; + } + + // It's possible to have multiple roots (e.g. for multiple accounts in the + // same app) -- just add multiple cursor rows. + // Construct one row for a root called "MyCloud". + final MatrixCursor.RowBuilder row = result.newRow(); + row.add(Root.COLUMN_ROOT_ID, ROOT); + row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary)); + + // FLAG_SUPPORTS_CREATE means at least one directory under the root supports + // creating documents. FLAG_SUPPORTS_RECENTS means your application's most + // recently used documents will show up in the "Recents" category. + // FLAG_SUPPORTS_SEARCH allows users to search all documents the application + // shares. + row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | + Root.FLAG_SUPPORTS_RECENTS | + Root.FLAG_SUPPORTS_SEARCH); + + // COLUMN_TITLE is the root title (e.g. Gallery, Drive). + row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title)); + + // This document id cannot change once it's shared. + row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir)); + + // The child MIME types are used to filter the roots and only present to the + // user roots that contain the desired type somewhere in their file hierarchy. + row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir)); + row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace()); + row.add(Root.COLUMN_ICON, R.drawable.ic_launcher); + + return result; +}+ +
Mengimplementasikan queryChildDocuments
+ +Implementasi +{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} +oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke semua file dalam +direktori yang ditentukan, dengan menggunakan kolom-kolom yang didefinisikan dalam +{@link android.provider.DocumentsContract.Document}.
+ +Metode ini akan dipanggil bila Anda memilih akar aplikasi dalam picker UI. +Metode mengambil dokumen anak dari direktori di bawah akar. Metode ini bisa dipanggil pada level apa saja dalam +hierarki file, bukan hanya akar. Cuplikan ini +membuat kursor baru dengan kolom-kolom yang diminta, lalu menambahkan informasi tentang +setiap anak langsung dalam direktori induk ke kursor. +Satu anak bisa berupa gambar, direktori lain—file apa saja:
+ +@Override +public Cursor queryChildDocuments(String parentDocumentId, String[] projection, + String sortOrder) throws FileNotFoundException { + + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + final File parent = getFileForDocId(parentDocumentId); + for (File file : parent.listFiles()) { + // Adds the file's display name, MIME type, size, and so on. + includeFile(result, null, file); + } + return result; +} ++ +
Mengimplementasikan queryDocument
+ +Implementasi +{@link android.provider.DocumentsProvider#queryDocument queryDocument()} +oleh Anda harus menghasilkan {@link android.database.Cursor} yang menunjuk ke file yang disebutkan, +dengan menggunakan kolom-kolom yang didefinisikan dalam {@link android.provider.DocumentsContract.Document}. +
+ +Metode {@link android.provider.DocumentsProvider#queryDocument queryDocument()} +menghasilkan informasi yang sama yang diteruskan dalam +{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()}, +namun untuk file tertentu:
+ + +@Override +public Cursor queryDocument(String documentId, String[] projection) throws + FileNotFoundException { + + // Create a cursor with the requested projection, or the default projection. + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + includeFile(result, documentId, null); + return result; +} ++ +
Mengimplementasikan openDocument
+ +Anda harus mengimplementasikan {@link android.provider.DocumentsProvider#openDocument +openDocument()} untuk menghasilkan {@link android.os.ParcelFileDescriptor} yang mewakili +file yang disebutkan. Aplikasi lain bisa menggunakan {@link android.os.ParcelFileDescriptor} +yang dihasilkan untuk mengalirkan data. Sistem memanggil metode ini setelah pengguna memilih file +dan aplikasi klien meminta akses ke file itu dengan memanggil +{@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}. +Misalnya:
+ +@Override +public ParcelFileDescriptor openDocument(final String documentId, + final String mode, + CancellationSignal signal) throws + FileNotFoundException { + Log.v(TAG, "openDocument, mode: " + mode); + // It's OK to do network operations in this method to download the document, + // as long as you periodically check the CancellationSignal. If you have an + // extremely large file to transfer from the network, a better solution may + // be pipes or sockets (see ParcelFileDescriptor for helper methods). + + final File file = getFileForDocId(documentId); + + final boolean isWrite = (mode.indexOf('w') != -1); + if(isWrite) { + // Attach a close listener if the document is opened in write mode. + try { + Handler handler = new Handler(getContext().getMainLooper()); + return ParcelFileDescriptor.open(file, accessMode, handler, + new ParcelFileDescriptor.OnCloseListener() { + @Override + public void onClose(IOException e) { + + // Update the file with the cloud server. The client is done + // writing. + Log.i(TAG, "A file with id " + + documentId + " has been closed! + Time to " + + "update the server."); + } + + }); + } catch (IOException e) { + throw new FileNotFoundException("Failed to open document with id " + + documentId + " and mode " + mode); + } + } else { + return ParcelFileDescriptor.open(file, accessMode); + } +} ++ +
Keamanan
+ +Anggaplah penyedia dokumen Anda sebuah layanan penyimpanan cloud yang dilindungi kata sandi +dan Anda ingin memastikan bahwa pengguna sudah login sebelum Anda mulai berbagi file mereka. +Apakah yang harus dilakukan aplikasi Anda jika pengguna tidak login? Solusinya adalah menghasilkan +akar nol dalam implementasi {@link android.provider.DocumentsProvider#queryRoots +queryRoots()} Anda. Yakni, sebuah kursor akar kosong:
+ ++public Cursor queryRoots(String[] projection) throws FileNotFoundException { +... + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; +} ++ +
Langkah lainnya adalah memanggil {@code getContentResolver().notifyChange()}. +Ingat {@link android.provider.DocumentsContract}? Kita menggunakannya untuk membuat +URI ini. Cuplikan berikut memberi tahu sistem untuk membuat query akar penyedia dokumen Anda +kapan saja status login pengguna berubah. Jika pengguna tidak +login, panggilan ke {@link android.provider.DocumentsProvider#queryRoots queryRoots()} akan menghasilkan +kursor kosong, seperti yang ditampilkan di atas. Cara ini akan memastikan bahwa dokumen penyedia hanya +tersedia jika pengguna login ke penyedia itu.
+ +private void onLoginButtonClick() { + loginOrLogout(); + getContentResolver().notifyChange(DocumentsContract + .buildRootsUri(AUTHORITY), null); +} +\ No newline at end of file diff --git a/docs/html-intl/intl/in/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/in/guide/topics/resources/accessing-resources.jd new file mode 100644 index 0000000000000000000000000000000000000000..e4a0bea1e36ab36ad6cd83d4fe8c66786da897b3 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/resources/accessing-resources.jd @@ -0,0 +1,337 @@ +page.title=Mengakses Sumber Daya +parent.title=Sumber Daya Aplikasi +parent.link=index.html +@jd:body + +
Tampilan Cepat
+-
+
- Sumber daya bisa diacu dari kode dengan menggunakan integer dari {@code R.java}, seperti +{@code R.drawable.myimage} +
- Sumber daya bisa diacu dari sumber daya dengan menggunakan sintaks XML khusus, seperti {@code +@drawable/myimage} +
- Anda juga bisa mengakses sumber daya aplikasi Anda dengan berbagai metode di +{@link android.content.res.Resources} +
Kelas-Kelas Utama
+-
+
- {@link android.content.res.Resources} +
Dalam dokumen ini
+-
+
- Mengakses Sumber Daya dari Kode +
- Mengakses Sumber Daya dari XML + + +
- Mengakses Sumber Daya Platform +
Lihat juga
+ +Setelah Anda menyediakan sumber daya dalam aplikasi Anda (yang dibicarakan di Menyediakan Sumber Daya), Anda bisa menerapkannya dengan +mengacu ID sumber dayanya. Semua ID sumber daya didefinisikan di kelas {@code R} proyek Anda, yang +dihasilkan oleh alat {@code aapt} secara otomatis.
+ +Bila aplikasi Anda dikompilasi, {@code aapt} akan membuat kelas {@code R}, yang berisi +ID sumber daya untuk semua sumber daya dalam direktori {@code +res/} Anda. Untuk masing-masing tipe sumber daya, ada subkelas {@code R} (misalnya, +{@code R.drawable} untuk semua sumber daya yang bisa ditarik), dan untuk masing-masing sumber daya dari tipe itu, ada satu integer statis + (misalnya, {@code R.drawable.icon}). Integer ini adalah ID sumber daya yang bisa Anda gunakan +untuk mengambil sumber daya Anda.
+ +Walaupun kelas {@code R} adalah tempat menyebutkan ID sumber daya, Anda tidak perlu +melihat ke sana untuk menemukan ID sumber daya. ID sumber daya selalu terdiri dari:
+-
+
- Tipe sumber daya: Masing-masing sumber daya dikelompokkan menjadi "tipe", misalnya {@code +string}, {@code drawable}, dan {@code layout}. Untuk mengetahui selengkapnya tentang berbagai tipe, lihat Tipe Sumber Daya. + +
- Nama sumber daya, bisa berupa: nama file, +tidak termasuk ekstensi; atau nilai dalam atribut {@code android:name} XML, jika +sumber daya itu sebuah nilai sederhana (misalnya sebuah string). +
Ada dua cara untuk mengakses sumber daya:
+-
+
- Dalam kode: Menggunakan integer statis dari subkelas dari kelas {@code R}
+, misalnya:
+
R.string.hello
+{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Ada banyak +API Android yang bisa mengakses sumber daya Anda bila Anda menyediakan ID sumber daya dengan format ini. Lihat +Mengakses Sumber Daya dalam Kode.
+
+ - Dalam XML: Menggunakan sebuah sintaks XML khusus yang juga berkaitan dengan
+ID sumber daya yang didefinisikan dalam kelas {@code R}, misalnya:
+
@string/hello
+{@code string} adalah tipe sumber daya dan {@code hello} adalah nama sumber daya. Anda bisa menggunakan +sintaks ini dalam sumber daya XML di mana saja Anda ingin menyediakan sebuah nilai dalam sebuah sumber daya. Lihat Mengakses Sumber Daya dari XML.
+
+
Mengakses Sumber Daya dalam Kode
+ +Anda bisa menggunakan sumber daya dalam kode dengan menyalurkan ID sumber daya sebagai sebuah parameter metode. Misalnya, + Anda bisa mengatur sebuah {@link android.widget.ImageView} agar menggunakan sumber daya{@code res/drawable/myimage.png} +dengan menggunakan {@link android.widget.ImageView#setImageResource(int) setImageResource()}:
++ImageView imageView = (ImageView) findViewById(R.id.myimageview); +imageView.setImageResource(R.drawable.myimage); ++ +
Anda juga bisa mengambil tiap sumber daya dengan menggunakan berbagai metode di {@link +android.content.res.Resources}, di mana Anda bisa mendapatkan instance + {@link android.content.Context#getResources()}.
+ +Akses ke File Asli
+ +Walaupun tidak lazim, Anda mungkin perlu mengakses file dan direktori asli Anda. Jika demikian, maka +menyimpan file Anda di {@code res/} tidak akan berhasil, karena satu-satunya cara untuk membaca sebuah sumber daya dari +{@code res/} adalah dengan ID sumber daya. Sebagai gantinya, Anda bisa menyimpan sumber daya dalam direktori +{@code assets/}.
+File yang tersimpan di direktori {@code assets/} tidak diberi ID +sumber daya, sehingga Anda tidak bisa mengacunya melalui kelas {@code R} atau dari sumber daya XML. Sebagai gantinya, Anda bisa melakukan +query file di direktori {@code assets/} seperti sebuah sistem file biasa dan membaca data mentah dengan menggunakan +{@link android.content.res.AssetManager}.
+Akan tetapi, jika yang Anda butuhkan hanya kemampuan membaca data mentah (misalnya sebuah file video atau audio), +maka simpanlah file itu di direktori {@code res/raw/} dan baca aliran byte dengan menggunakan {@link +android.content.res.Resources#openRawResource(int) openRawResource()}.
+ +Sintaks
+ +Inilah sintaks untuk mengacu sumber daya dalam kode:
+ ++[<package_name>.]R.<resource_type>.<resource_name> ++ +
-
+
- {@code <package_name>}adalah nama paket yang di dalamnya terdapat sumber daya (tidak +dibutuhkan bila mengacu sumber daya dari paket Anda sendiri). +
- {@code <resource_type>} adalah subkelas {@code R} untuk tipe sumber daya. +
- {@code <resource_name>} bisa berupa nama file sumber daya +tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai +sederhana). +
Lihat Tipe Sumber Daya untuk +informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.
+ + +Kasus penggunaan
+ +Ada banyak metode yang menerima parameter ID sumber daya dan Anda bisa mengambil sumber daya dengan menggunakan +metode di {@link android.content.res.Resources}. Anda bisa mengambil instance {@link +android.content.res.Resources} dengan {@link android.content.Context#getResources +Context.getResources()}.
+ + +Berikut adalah beberapa contoh cara mengakses sumber daya dalam kode:
+ ++// Load a background for the current screen from a drawable resource +{@link android.app.Activity#getWindow()}.{@link +android.view.Window#setBackgroundDrawableResource(int) +setBackgroundDrawableResource}(R.drawable.my_background_image) ; + +// Set the Activity title by getting a string from the Resources object, because +// this method requires a CharSequence rather than a resource ID +{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence) +setTitle}(getResources().{@link android.content.res.Resources#getText(int) +getText}(R.string.main_title)); + +// Load a custom layout for the current screen +{@link android.app.Activity#setContentView(int) +setContentView}(R.layout.main_screen); + +// Set a slide in animation by getting an Animation from the Resources object +mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation) +setInAnimation}(AnimationUtils.loadAnimation(this, + R.anim.hyperspace_in)); + +// Set the text on a TextView object using a resource ID +TextView msgTextView = (TextView) findViewById(R.id.msg); +msgTextView.{@link android.widget.TextView#setText(int) +setText}(R.string.hello_message); ++ + +
Perhatian: Anda tidak boleh memodifikasi file {@code +R.java} secara manual—, ini dihasilkan oleh alat {@code aapt} bila proyek Anda telah +dikompilasi. Perubahan apa pun akan ditimpa bila nanti Anda mengompilasi.
+ + + +Mengakses Sumber Daya dari XML
+ +Anda bisa mendefinisikan nilai untuk beberapa atribut dan elemen XML dengan menggunakan +acuan ke sumber daya yang ada. Anda akan sering melakukannya saat membuat file layout, untuk +memasok string dan gambar bagi widget Anda.
+ +Misalnya, jika Anda menambahkan sebuah {@link android.widget.Button} ke layout, Anda harus menggunakan +sebuah sumber daya string bagi teks tombolnya:
+ ++<Button + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/submit" /> ++ + +
Sintaks
+ +Berikut adalah sintaks untuk mengacu sumber daya di sumber daya XML:
+ ++@[<package_name>:]<resource_type>/<resource_name> ++ +
-
+
- {@code <package_name>} adalah nama paket yang di dalamnya terdapat sumber daya (tidak +dibutuhkan bila mengacu sumber daya dari paket yang sama) +
- {@code <resource_type>} adalah subkelas +{@code R} untuk tipe sumber daya +
- {@code <resource_name>} bisa berupa nama file sumber daya +tanpa ekstensi atau nilai atribut {@code android:name} dalam elemen XML (untuk nilai +sederhana). +
Lihat Tipe Sumber Daya untuk +informasi selengkapnya tentang masing-masing tipe sumber daya dan cara mengacunya.
+ + +Kasus penggunaan
+ +Dalam beberapa kasus, Anda harus menggunakan sumber daya untuk suatu nilai dalam XML (misalnya, untuk menerapkan gambar yang bisa ditarik +pada widget), namun Anda juga bisa menggunakan sumber daya di XML mana saja yang menerima nilai sederhana. Misalnya, jika +Anda mempunyai file sumber daya berikut yang berisi sumber daya warna dan sumber daya string:
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="opaque_red">#f00</color> + <string name="hello">Hello!</string> +</resources> ++ +
Anda bisa menggunakan sumber daya ini dalam file layout berikut untuk mengatur warna teks dan +string teks:
+ ++<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="@color/opaque_red" + android:text="@string/hello" /> ++ +
Dalam hal ini, Anda tidak perlu menyebutkan nama paket dalam sumber daya acuan karena +sumber daya berasal dari paket Anda sendiri. Untuk +mengacu sumber daya sistem, Anda perlu memasukkan nama paketnya. Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="@android:color/secondary_text_dark" + android:text="@string/hello" /> ++ +
Catatan: Anda harus menggunakan sumber daya string sepanjang +waktu, sehingga aplikasi Anda bisa dilokalkan untuk bahasa lain. +Untuk informasi tentang cara menciptakan +sumber daya alternatif (seperti string lokal), lihat Menyediakan Sumber Daya Alternatif +. Untuk panduan lengkap melokalkan aplikasi Anda ke bahasa lain, +lihat Pelokalan.
+ +Anda bahkan bisa menggunakan sumber daya dalam XML untuk membuat alias. Misalnya, Anda bisa membuat +sumber daya yang bisa ditarik yang merupakan alias bagi sumber daya yang bisa ditarik lainnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/other_drawable" /> ++ +
Hal ini terdengar berlebihan, namun bisa sangat berguna saat menggunakan sumber daya alternatif. Baca selengkapnya tentang +Membuat sumber daya alias.
+ + + +Mengacu atribut gaya
+ +Sumber daya atribut gaya memungkinkan Anda mengacu nilai +suatu atribut dalam tema yang diterapkan saat ini. Dengan mengacu sebuah atribut gaya memungkinkan Anda +menyesuaikan tampilan elemen UI dengan mengatur gayanya agar cocok dengan beragam variasi standar yang dipasok oleh +tema saat ini, sebagai ganti memasok nilai yang ditanamkan (hard-coded). Mengacu sebuah atribut gaya +pada dasarnya adalah "gunakan gaya yang didefinisikan oleh atribut ini, dalam tema saat ini".
+ +Untuk mengacu sebuah atribut gaya, sintaks namanya hampir sama dengan format sumber daya normal +, namun sebagai ganti simbol @ ({@code @}), gunakan sebuah tanda tanya ({@code ?}), dan +porsi tipe sumber daya bersifat opsional. Sebagai contoh:
+ ++?[<package_name>:][<resource_type>/]<resource_name> ++ +
Misalnya, begini cara Anda mengacu suatu atribut untuk mengatur warna teks agar cocok dengan +warna teks "utama" tema sistem:
+ ++<EditText id="text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textColor="?android:textColorSecondary" + android:text="@string/hello_world" /> ++ +
Di sini, atribut {@code android:textColor} menyebutkan nama atribut gaya
+dalam tema saat ini. Android kini menggunakan nilai yang diterapkan pada atribut gaya {@code android:textColorSecondary}
+sebagai nilai untuk {@code android:textColor} dalam widget ini. Karena alat sumber daya
+mengetahui bahwa atribut sumber daya diharapkan dalam konteks ini,
+maka Anda tidak perlu menyatakan tipenyanya secara eksplisit (yang akan berupa
+?android:attr/textColorSecondary
)—Anda bisa mengecualikan tipe {@code attr}.
Mengakses Sumber Daya Platform
+ +Android berisi sejumlah sumber daya standar, seperti gaya, tema, dan layout. Untuk
+mengakses semua sumber daya ini, tetapkan acuan sumber daya Anda dengan nama paket
+android
. Misalnya, Android menyediakan sumber daya layout yang bisa Anda gunakan untuk
+item daftar dalam{@link android.widget.ListAdapter}:
+{@link android.app.ListActivity#setListAdapter(ListAdapter) +setListAdapter}(new {@link +android.widget.ArrayAdapter}<String>(this, android.R.layout.simple_list_item_1, myarray)); ++ +
Dalam contoh ini, {@link android.R.layout#simple_list_item_1} adalah sumber daya layout yang didefinisikan oleh +platform untuk item di {@link android.widget.ListView}. Anda bisa menggunakannya sebagai ganti menciptakan +layout sendiri untuk item daftar. Untuk informasi selengkapnya, lihat panduan pengembang +List View.
+ diff --git a/docs/html-intl/intl/in/guide/topics/resources/overview.jd b/docs/html-intl/intl/in/guide/topics/resources/overview.jd new file mode 100644 index 0000000000000000000000000000000000000000..966800cf7daa52b0a9478683f8b06cafeaae1764 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/resources/overview.jd @@ -0,0 +1,103 @@ +page.title=Ikhtisar Sumber Daya +@jd:body + +Anda harus selalu mengeksternalkan sumber daya seperti gambar dan string dari kode +aplikasi, agar Anda bisa memeliharanya secara independen. Mengeksternalkan +sumber daya juga membuat Anda dapat menyediakan sumber daya alternatif yang mendukung konfigurasi +perangkat tertentu seperti bahasa atau ukuran layar yang berbeda, yang semakin penting +seiring semakin banyak tersedianya perangkat berbasis Android dengan konfigurasi berbeda. Untuk +memberikan kompatibilitas dengan konfigurasi berbeda, Anda harus menata sumber daya dalam +direktori {@code res/} proyek Anda, menggunakan berbagai subdirektori yang mengelompokkan sumber daya menurut tipe +dan konfigurasinya.
+ +Bagi setiap tipe sumber daya, Anda bisa menetapkan sumber daya default dan sumber daya +alternatif untuk aplikasi Anda:
+-
+
- Sumber daya default adalah sumber daya yang harus digunakan apa pun +konfigurasi perangkatnya atau jika tidak ada sumber daya alternatif yang sesuai +dengan konfigurasi saat ini. +
- Sumber daya alternatif adalah sumber daya yang Anda desain untuk digunakan dengan +konfigurasi tertentu. Untuk menetapkan bahwa satu kelompok sumber daya ditujukan bagi konfigurasi tertentu, +tambahkan qualifier konfigurasi yang sesuai ke nama direktori. +
Misalnya, walaupun layout +UI default Anda disimpan dalam direktori {@code res/layout/}, Anda dapat menetapkan layout berbeda +untuk digunakan saat layar dalam orientasi lanskap, dengan menyimpannya dalam direktori {@code res/layout-land/} +. Android secara otomatis memberlakukan sumber daya yang sesuai dengan mencocokkan konfigurasi perangkat +saat ini dengan nama direktori sumber daya.
+ +Gambar 1 mengilustrasikan cara sistem memberlakukan layout yang sama untuk +dua perangkat berbeda saat sumber daya alternatif tidak tersedia. Gambar 2 menunjukkan +aplikasi yang sama saat menambahkan sumber daya layout alternatif untuk layar yang lebih besar.
+ +Dokumen-dokumen berikut berisi panduan lengkap mengenai cara menata sumber daya aplikasi, +menetapkan sumber daya alternatif, mengaksesnya dalam aplikasi, dan banyak lagi:
+ +-
+
- Menyediakan Sumber Daya +
- Jenis sumber daya yang dapat Anda sediakan dalam aplikasi, tempat menyimpannya, dan cara membuat sumber daya +alternatif untuk konfigurasi perangkat tertentu. +
- Mengakses Sumber Daya +
- Cara menggunakan sumber daya yang telah Anda sediakan, baik dengan mengacunya dari kode +aplikasi Anda atau dari sumber daya XML lainnya. +
- Menangani Perubahan Runtime +
- Cara mengelola perubahan konfigurasi yang terjadi saat Aktivitas Anda berjalan. +
- Pelokalan +
- Panduan dari pengalaman untuk melokalkan aplikasi menggunakan sumber daya alternatif. Walaupun ini +hanya satu penggunaan tertentu dari sumber daya alternatif, hal ini sangat penting dalam meraih pengguna lebih +banyak. +
- Tipe Sumber Daya +
- Acuan dari berbagai tipe sumber daya yang dapat Anda sediakan, menjelaskan elemen-elemen XML, +atribut, dan sintaksnya. Misalnya, acuan ini menunjukkan kepada Anda cara membuat sumber daya untuk +menu aplikasi, drawable, animasi, dan lainnya. +
Tampilan Cepat
+-
+
- Berbagai tipe sumber daya termasuk dalam subdirektori {@code res/} +
- Sumber daya alternatif menyediakan file sumber daya dengan konfigurasi tertentu +
- Sertakan selalu sumber daya default agar aplikasi Anda tidak bergantung pada +konfigurasi perangkat tertentu +
Dalam dokumen ini
+-
+
- Mengelompokkan Tipe Sumber Daya +
- Menyediakan Sumber Daya Alternatif + + +
- Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya +
- Cara Android Menemukan Sumber Daya yang Paling Cocok +
Lihat juga
+ +Anda harus selalu mengeksternalkan sumber daya aplikasi seperti gambar dan string dari kode +, agar Anda bisa memeliharanya secara independen. Anda juga harus menyediakan sumber daya alternatif untuk +konfigurasi perangkat tertentu, dengan mengelompokkannya dalam direktori sumber daya bernama khusus. Saat +runtime, Android menggunakan sumber daya yang sesuai berdasarkan konfigurasi saat ini. Misalnya, Anda mungkin +ingin menyediakan layout UI berbeda bergantung pada ukuran layar atau string berbeda bergantung pada +pengaturan bahasa.
+ +Setelah mengeksternalkan sumber daya aplikasi, Anda dapat mengaksesnya menggunakan +ID sumber daya yang dibuat dalam kelas {@code R} proyek Anda. Cara menggunakan +sumber daya dalam aplikasi dibahas dalam Mengakses +Sumber Daya. Dokumen ini menampilkan cara mengelompokkan sumber daya +dalam proyek Android Anda dan menyediakan sumber daya alternatif untuk konfigurasi perangkat tertentu.
+ + +Mengelompokkan Tipe Sumber Daya
+ +Anda harus menempatkan setiap tipe sumber daya dalam subdirektori spesifik pada direktori +{@code res/} proyek. Misalnya, inilah hierarki file untuk proyek sederhana:
+ ++MyProject/ + src/ + MyActivity.java + res/ + drawable/ + graphic.png + layout/ + main.xml + info.xml + mipmap/ + icon.png + values/ + strings.xml ++ +
Seperti yang Anda lihat dalam contoh ini, direktori {@code res/} berisi semua sumber daya (dalam +subdirektori): sumber daya gambar, dua sumber daya layout, direktori {@code mipmap/} untuk ikon +launcher, dan satu file sumber daya string. Nama direktori +sumber daya penting dan dijelaskan dalam tabel 1.
+ +Catatan: Untuk informasi selengkapnya tentang menggunakan folder mipmap, lihat +Mengelola Ikhtisar Proyek.
+ + + +Direktori | +Tipe Sumber Daya | +
---|---|
animator/ |
+ File XML yang mendefinisikan animasi +properti. | +
anim/ |
+ File XML yang mendefinisikan animasi +tween. (Animasi properti juga dapat disimpan dalam direktori ini, namun +direktori {@code animator/} lebih disukai bagi animasi properti agar kedua tipe +ini dapat dibedakan.) | +
color/ |
+ File XML yang mendefinisikan daftar status warna. Lihat Sumber Daya +Daftar Status Warna | +
drawable/ |
+
+ File bitmap ({@code .png}, {@code .9.png}, {@code .jpg}, {@code .gif}) atau file XML yang +dikompilasi menjadi subtipe sumber daya drawable berikut: +
Lihat Sumber Daya Drawable. + |
+
mipmap/ |
+ File drawable untuk densitas ikon launcher yang berbeda. Untuk informasi selengkapnya tentang + mengelola ikon launcher dengan folder {@code mipmap/}, lihat +Mengelola Ikhtisar Proyek. | +
layout/ |
+ File XML yang mendefinisikan layout antarmuka pengguna. + Lihat Sumber Daya Layout. | +
menu/ |
+ File XML yang mendefinisikan menu aplikasi, seperti Menu Opsi, Menu Konteks, atau Sub +Menu. Lihat Sumber Daya Menu. | +
raw/ |
+ File tak didukung yang akan disimpan dalam bentuk mentah. Untuk membuka sumber daya ini dengan +{@link java.io.InputStream} mentah, panggil {@link android.content.res.Resources#openRawResource(int) +Resources.openRawResource()} dengan ID sumber daya, yaitu {@code R.raw.filename}. +Akan tetapi, jika Anda butuh akses ke nama file asli dan hierarki file, Anda bisa mempertimbangkan +untuk menyimpan beberapa sumber daya dalam direktori {@code +assets/} (sebagai ganti {@code res/raw/}). File dalam {@code assets/} tidak diberi +ID sumber daya, jadi Anda bisa membacanya hanya dengan menggunakan {@link android.content.res.AssetManager}. |
+
values/ |
+ File XML yang berisi nilai-nilai sederhana, seperti string, integer, dan warna. +Walaupun file sumber daya XML dalam subdirektori {@code res/} lainnya mendefinisikan satu sumber daya +berdasarkan nama file XML, file dalam direktori {@code values/} menggambarkan beberapa sumber daya. +Untuk file dalam direktori ini, setiap anak elemen {@code <resources>} mendefinisikan satu sumber +daya. Misalnya, elemen {@code <string>} membuat sumber daya +{@code R.string} dan elemen {@code <color>} membuat sumber daya {@code R.color} +. +Karena setiap sumber daya didefinisikan dengan elemen XML-nya sendiri, Anda bisa bebas menamai file +ini dan menempatkan tipe sumber daya berbeda dalam satu file. Akan tetapi, agar jelas, Anda mungkin +perlu menempatkan tipe sumber daya unik dalam file berbeda. Misalnya, berikut ini adalah beberapa ketentuan +penamaan file untuk sumber daya yang dapat Anda buat dalam direktori ini: +
Lihat Sumber Daya String, + Sumber Daya Gaya, dan + Tipe Sumber Daya Lainnya. + |
+
xml/ |
+ File XML tak didukung yang bisa dibaca saat runtime dengan memanggil {@link +android.content.res.Resources#getXml(int) Resources.getXML()}. Berbagai file konfigurasi XML +harus disimpan di sini, seperti konfigurasi yang dapat dicari. + | +
Perhatian: Jangan menyimpan file sumber daya secara langsung dalam +direktori {@code res/}— karena akan menyebabkan kesalahan compiler.
+ +Untuk informasi selengkapnya tentang tipe sumber daya tertentu, lihat dokumentasi Tipe Sumber Daya.
+ +Sumber daya yang disimpan dalam subdirektori yang didefinisikan dalam tabel 1 adalah sumber daya +"default" Anda. Berarti sumber daya ini mendefinisikan desain default dan konten untuk aplikasi Anda. +Akan tetapi, beberapa tipe perangkat berbasis Android mungkin memanggil tipe sumber daya yang berbeda. +Misalnya, jika perangkat memiliki layar yang lebih besar daripada layar normal, maka Anda harus +menyediakan sumber daya layout berbeda yang memanfaatkan ruang layar yang lebih besar. Atau, jika perangkat +memiliki pengaturan bahasa berbeda, maka Anda harus menyediakan sumber daya string berbeda yang menerjemahkan teks dalam +antarmuka pengguna Anda. Untuk menyediakan sumber daya berbeda ini bagi +konfigurasi perangkat yang berbeda, Anda harus menyediakan sumber daya alternatif, selain sumber +daya default.
+ + +Menyediakan Sumber Daya Alternatif
+ + +Hampir setiap aplikasi harus menyediakan sumber daya alternatif untuk mendukung konfigurasi +perangkat tertentu. Misalnya, Anda harus menyertakan sumber daya drawable alternatif untuk densitas layar +berbeda dan sumber daya string alternatif untuk bahasa yang berbeda. Saat runtime, Android +akan mendeteksi konfigurasi perangkat aktif dan memuat +sumber daya yang sesuai untuk aplikasi Anda.
+ +Untuk menyebutkan alternatif konfigurasi tertentu untuk satu set sumber daya:
+-
+
- Buat direktori baru dalam {@code res/} yang dinamai dalam bentuk {@code
+<resources_name>-<config_qualifier>}.
+
-
+
- {@code <resources_name>} adalah nama direktori dari sumber daya default +terkait (didefinisikan dalam tabel 1). +
- {@code <qualifier>} adalah nama yang menetapkan konfigurasi individu +yang akan digunakan sumber daya ini (didefinisikan dalam tabel 2). +
Anda bisa menambahkan lebih dari satu {@code <qualifier>}. Pisahkan masing-masing +dengan tanda hubung.
+Perhatian: Saat menambahkan beberapa qualifier, Anda +harus menempatkannya dalam urutan yang sama dengan yang tercantum dalam tabel 2. Jika urutan qualifier +salah, sumber daya akan diabaikan.
+
+ - Simpan masing-masing sumber daya alternatif dalam direktori baru ini. File sumber daya harus dinamai +sama persis dengan file sumber daya default. +
Misalnya, berikut ini beberapa sumber daya default dan sumber daya alternatif:
+ ++res/ + drawable/ + icon.png + background.png + drawable-hdpi/ + icon.png + background.png ++ +
Qualifier {@code hdpi} menunjukkan bahwa sumber daya dalam direktori itu diperuntukkan bagi perangkat dengan +layar densitas tinggi. Gambar di masing-masing direktori drawable memiliki ukuran untuk densitas layar +tertentu, namun nama filenya persis +sama. Dengan demikian, ID sumber daya yang Anda gunakan untuk mengacu gambar {@code icon.png} atau @code +background.png} selalu sama, namun Android memilih +versi masing-masing sumber daya yang paling cocok dengan perangkat saat ini, dengan membandingkan informasi konfigurasi +perangkat dengan qualifier dalam nama direktori sumber daya.
+ +Android mendukung beberapa qualifier konfigurasi dan Anda dapat +menambahkan beberapa qualifier ke satu nama direktori, dengan memisahkan setiap qualifier dengan tanda hubung. Tabel 2 +berisi daftar qualifier konfigurasi yang valid, dalam urutan prioritas—jika Anda menggunakan beberapa +qualifier sebagai direktori sumber daya, Anda harus menambahkannya ke nama direktori sesuai urutan +yang tercantum dalam tabel.
+ + + +Konfigurasi | +Nilai-nilai Qualifier | +Keterangan | +
---|---|---|
MCC dan MNC | +Contoh: + mcc310 +
+ mcc208-mnc00 + dll. + |
+
+ Kode negara seluler (MCC), bisa diikuti dengan kode jaringan seluler (MNC)
+ dari kartu SIM dalam perangkat. Misalnya, Jika perangkat menggunakan koneksi radio (ponsel GSM), nilai-nilai MCC dan MNC berasal +dari kartu SIM. +Anda juga dapat menggunakan MNC saja (misalnya, untuk menyertakan sumber daya legal +spesifik untuk negara itu di aplikasi Anda). Jika Anda perlu menetapkan hanya berdasarkan bahasa, maka gunakan qualifier +bahasa dan wilayah sebagai gantinya (akan dibahas nanti). Jika Anda memutuskan untuk menggunakan qualifier MCC dan +MNC, Anda harus melakukannya dengan hati-hati dan menguji apakah qualifier itu berjalan sesuai harapan. +Lihat juga bidang konfigurasi {@link +android.content.res.Configuration#mcc}, dan {@link +android.content.res.Configuration#mnc}, yang masing-masing menunjukkan kode negara seluler saat ini +dan kode jaringan seluler. + |
+
Bahasa dan wilayah | +Contoh: + en + fr + en-rUS + fr-rFR + fr-rCA + dll. + |
+ Bahasa didefinisikan oleh kode bahasa dua huruf ISO +639-1, bisa juga diikuti dengan kode wilayah +dua huruf ISO +3166-1-alpha-2 (diawali dengan huruf kecil "{@code r}"). + + Kode tidak membedakan huruf besar atau kecil; awalan {@code r} akan digunakan untuk +membedakan bagian wilayah. + Anda tidak bisa menetapkan wilayah saja. +Ini bisa berubah selama masa pakai +aplikasi Anda jika pengguna mengubah bahasanya dalam pengaturan sistem. Lihat Menangani Perubahan Runtime untuk informasi tentang +bagaimana hal ini dapat memengaruhi aplikasi Anda selama runtime. +Lihat Pelokalan untuk panduan lengkap melokalkan +aplikasi Anda ke bahasa lain. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#locale} yang menunjukkan +bahasa setempat yang digunakan saat ini. + |
+
Arah Layout | +ldrtl + ldltr + |
+ Arah layout aplikasi Anda. {@code ldrtl} berarti "arah layout dari kanan ke kiri". + {@code ldltr} berarti "arah layout dari kiri ke kanan" dan merupakan nilai implisit default. + +Ini bisa berlaku untuk sumber daya mana pun seperti layout, drawable, atau nilai-nilai. + +Misalnya, jika Anda ingin memberikan beberapa layout khusus untuk bahasa Arab dan beberapa +layout umum untuk setiap bahasa lainnya yang menggunakan "kanan-ke-kiri" lainnya (seperti bahasa Persia atau Ibrani) maka Anda akan memiliki: + ++res/ + layout/ + main.xml (Default layout) + layout-ar/ + main.xml (Specific layout for Arabic) + layout-ldrtl/ + main.xml (Any "right-to-left" language, except + for Arabic, because the "ar" language qualifier + has a higher precedence.) ++ Catatan: Untuk mengaktifkan fitur +layout kanan-ke-kiri untuk aplikasi, Anda harus mengatur {@code + supportsRtl} ke {@code "true"} dan mengatur {@code targetSdkVersion} ke 17 atau yang lebih tinggi. +Ditambahkan dalam API level 17. + |
+
smallestWidth | +sw<N>dp + Contoh: + sw320dp + sw600dp + sw720dp + dll. + |
+
+ Ukuran dasar layar, sebagaimana yang ditunjukkan oleh dimensi terpendek dari area layar +yang tersedia. Secara spesifik, smallestWidth perangkat adalah yang terpendek dari +tinggi dan lebar layar yang tersedia (Anda dapat menganggapnya sebagai "lebar terkecil yang memungkinkan" untuk layar). Anda bisa +menggunakan qualifier ini untuk memastikan bahwa, apa pun orientasi layar saat ini, aplikasi +Anda memiliki paling tidak {@code <N>} dps dari lebar yang tersedia untuk UI-nya. +Misalnya, jika layout mengharuskan dimensi layar terkecilnya setiap saat paling tidak +600 dp, maka Anda dapat menggunakan qualifer ini untuk membuat sumber daya layout, {@code +res/layout-sw600dp/}. Sistem akan menggunakan sumber daya ini hanya bila dimensi layar terkecil yang +tersedia paling tidak 600 dp, tanpa mempertimbangkan apakah sisi 600 dp adalah tinggi atau +lebar yang dipersepsikan pengguna. SmallestWidth adalah karakteristik ukuran layar tetap dari perangkat; smallestWidth +perangkat tidak berubah saat orientasi layar berubah. +SmallestWidth perangkat memperhitungkan dekorasi layar dan UI sistem. Misalnya +, jika perangkat memiliki beberapa elemen UI persisten pada layar yang menghitung ruang di sepanjang +sumbu smallestWidth, sistem akan mendeklarasikan smallestWidth lebih kecil daripada ukuran layar sebenarnya, +karena itu adalah piksel layar yang tidak tersedia untuk UI Anda. Sehingga nilai yang Anda +gunakan haruslah merupakan dimensi terkecil sebenarnya yang dibutuhkan oleh layout Anda (biasanya, nilai ini adalah +"lebar terkecil" yang didukung layout Anda, apa pun orientasi layar saat ini). +Sebagian nilai yang mungkin Anda gunakan untuk ukuran layar umum: +
Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda untuk +qualifier smallestWidth terkecil, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi) +smallestWidth perangkat. +Ditambahkan dalam API level 13. +Lihat juga atribut {@code +android:requiresSmallestWidthDp}, yang mendeklarasikan smallestWidth minimum yang +kompatibel dengan aplikasi Anda, dan bidang konfigurasi {@link +android.content.res.Configuration#smallestScreenWidthDp}, yang menyimpan nilai +smallestWidth perangkat. +Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan +qualifier ini, lihat panduan pengembang Mendukung +Multi Layar. + |
+
Lebar yang tersedia | +w<N>dp + Contoh: + w720dp + w1024dp + dll. + |
+
+ Menetapkan lebar layar minimum yang tersedia, di unit {@code dp} yang
+menggunakan sumber daya—yang didefinisikan oleh nilai Bila aplikasi Anda menyediakan beberapa direktori sumber daya dengan nilai yang berbeda + untuk konfigurasi ini, sistem akan menggunakan nilai terdekat dengan (tanpa melebihi) + lebar layar perangkat saat ini. Nilai +di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa +elemen UI persisten di tepi kiri atau kanan, layar +menggunakan nilai lebar yang lebih kecil daripada ukuran layar sebenarnya, yang memperhitungkan +elemen UI ini dan mengurangi ruang aplikasi yang tersedia. +Ditambahkan dalam API level 13. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenWidthDp} + yang menyimpan lebar layar saat ini. +Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan +qualifier ini, lihat panduan pengembang Mendukung +Multi Layar. + |
+
Tinggi yang tersedia | +h<N>dp + Contoh: + h720dp + h1024dp + dll. + |
+
+ Menetapkan tinggi layar minimum yang tersedia, dalam satuan "dp" yang harus digunakan
+sumber daya —bersama nilai yang didefinisikan oleh Bila aplikasi menyediakan beberapa direktori sumber daya dengan nilai yang berbeda + untuk konfigurasi ini, sistem akan menggunakan nilai yang terdekat dengan (tanpa melebihi) + tinggi layar perangkat saat ini. Nilai +di sini memperhitungkan dekorasi layar akun, jadi jika perangkat memiliki beberapa +elemen UI persisten di tepi atas atau bawah, layar akan +menggunakan nilai tinggi yang lebih kecil daripada ukuran layar sebenarnya, memperhitungkan +elemen UI ini dan mengurangi ruang aplikasi yang tersedia. Dekorasi +layar yang tidak tetap (misalnya baris status (status-bar) telepon yang bisa +disembunyikan saat layar penuh) di sini tidak diperhitungkan, demikian pula +dekorasi jendela seperti baris judul (title-bar)atau baris tindakan (action-bar), jadi aplikasi harus disiapkan +untuk menangani ruang yang agak lebih kecil daripada yang ditetapkan. + Ditambahkan dalam API level 13. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenHeightDp} + yang menyimpan lebar layar saat ini. +Untuk informasi selengkapnya tentang mendesain untuk layar berbeda dan menggunakan +qualifier ini, lihat panduan pengembang Mendukung +Multi Layar. + |
+
Ukuran layar | +
+ small + normal + large + xlarge
+ |
+
+
Catatan: Menggunakan qualifier ukuran tidak berarti bahwa +sumber daya hanya untuk layar ukuran itu saja. Jika Anda tidak menyediakan sumber +daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya +mana saja yang paling cocok. +Perhatian: Jika semua sumber daya Anda menggunakan +qualifier yang berukuran lebih besar daripada layar saat ini, sistem tidak akan menggunakannya dan aplikasi +Anda akan crash saat runtime (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code +xlarge}, namun perangkat memiliki ukuran layar normal). +Ditambahkan dalam API level 4. + +Lihat Mendukung Beberapa +Layar untuk informasi selengkapnya. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout}, + yang menunjukkan apakah layar berukuran kecil, normal, atau +besar. + |
+
Aspek layar | +
+ long + notlong
+ |
+
+
Ditambahkan dalam API level 4. +Ini berdasarkan sepenuhnya pada rasio aspek layar (layar "panjang" lebih lebar). Ini +tidak ada kaitannya dengan orientasi layar. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#screenLayout}, + yang menunjukkan apakah layar panjang. + |
+
Orientasi layar | +
+ port + land
+ |
+
+
Ini bisa berubah selama masa pakai aplikasi Anda jika pengguna memutar +layar. Lihat Menangani Perubahan Runtime untuk + informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#orientation}, +yang menunjukkan orientasi perangkat saat ini. + |
+
Mode UI | +
+ car + desk + television + appliance
+ watch
+ |
+
+
Ditambahkan dalam API level 8, televisi ditambahkan dalam API 13, jam ditambahkan dalam API 20. +Untuk informasi tentang cara aplikasi merespons saat perangkat dimasukkan +ke dalam atau dilepaskan dari dudukannya, bacalah Menentukan +dan Memantau Kondisi dan Tipe Dudukan. +Ini bisa berubah selama masa pakai aplikasi jika pengguna menempatkan perangkat di +dudukannya. Anda dapat mengaktifkan atau menonaktifkan sebagian mode ini menggunakan {@link +android.app.UiModeManager}. Lihat Menangani Perubahan Runtime untuk +informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime. + |
+
Mode malam | +
+ night + notnight
+ |
+
+
Ditambahkan dalam API level 8. +Ini bisa berubah selama masa pakai aplikasi jika mode malam dibiarkan dalam +mode otomatis (default), dalam hal ini perubahan mode berdasarkan pada waktu hari. Anda dapat mengaktifkan +atau menonaktifkan mode ini menggunakan {@link android.app.UiModeManager}. Lihat Menangani Perubahan Runtime untuk informasi tentang bagaimana hal ini memengaruhi +aplikasi Anda selama runtime. + |
+
Densitas piksel layar (dpi) | +
+ ldpi + mdpi + hdpi + xhdpi + xxhdpi + xxxhdpi + nodpi + tvdpi
+ |
+
+
Terdapat rasio skala 3:4:6:8:12:16 antara enam densitas utama (dengan mengabaikan densitas +tvdpi). Jadi bitmap 9x9 di ldpi adalah 12x12 di mdpi, 18x18 di hdpi, 24x24 di xhdpi dan seterusnya. + +Jika Anda memutuskan bahwa sumber daya gambar tidak terlihat cukup baik di televisi +atau perangkat tertentu lainnya dan ingin mencoba sumber daya tvdpi, faktor skalanya adalah 1,33*mdpi. Misalnya, +gambar 100px x 100px untuk layar mdpi harus 133px x 133px untuk tvdpi. +Catatan: Menggunakan qualifier densitas tidak berarti bahwa +sumber daya hanya untuk layar dengan ukuran itu saja. Jika Anda tidak menyediakan sumber +daya alternatif dengan qualifier yang lebih cocok dengan konfigurasi perangkat saat ini, sistem dapat menggunakan sumber daya +mana saja yang paling cocok. +Lihat Mendukung Beberapa +Layar untuk informasi selengkapnya tentang cara menangani densitas layar yang berbeda dan cara Android +menurunkan skala bitmap Anda agar sesuai dengan densitas saat ini. + |
+
Tipe layar sentuh | +
+ notouch + finger
+ |
+
+
Lihat juga bidang konfigurasi {@link android.content.res.Configuration#touchscreen}, yang +menunjukkan tipe layar sentuh pada perangkat. + |
+
Ketersediaan keyboard | +
+ keysexposed + keyshidden + keyssoft
+ |
+
+
Jika Anda menyediakan sumber daya Ini bisa berubah selama masa pakai aplikasi jika pengguna membuka keyboard +fisik. Lihat Menangani Perubahan Runtime untuk informasi tentang bagaimana +hal ini memengaruhi aplikasi Anda selama runtime. +Lihat juga bidang konfigurasi {@link +android.content.res.Configuration#hardKeyboardHidden} dan {@link +android.content.res.Configuration#keyboardHidden}, yang menunjukkan visibilitas +keyboard fisik dan visibilitas segala jenis keyboard (termasuk keyboard perangkat lunak), masing-masing. + |
+
Metode input teks utama | +
+ nokeys + qwerty + 12key
+ |
+
+
Lihat juga bidang konfigurasi {@link android.content.res.Configuration#keyboard}, +yang menunjukkan metode utama input teks yang tersedia. + |
+
Ketersediaan tombol navigasi | +
+ navexposed + navhidden
+ |
+
+
Ini bisa berubah selama masa pakai aplikasi jika pengguna menyingkap tombol +navigasi. Lihat Menangani Perubahan Runtime untuk +informasi tentang bagaimana hal ini memengaruhi aplikasi Anda selama runtime. +Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigationHidden}, yang menunjukkan +apakah tombol navigasi disembunyikan. + |
+
Metode navigasi non-sentuh utama | +
+ nonav + dpad + trackball + wheel
+ |
+
+
Lihat juga bidang konfigurasi {@link android.content.res.Configuration#navigation}, +yang menunjukkan tipe metode navigasi yang tersedia. + |
+
Versi Platform (level API) | +Contoh: + v3 + v4 + v7 + dll. |
+
+ Level API yang didukung perangkat. Misalnya, |
+
Catatan: Sebagian qualifier konfigurasi telah ditambahkan sejak Android
+1.0, jadi tidak semua versi Android mendukung semua qualifier. Menggunakan qualifier baru secara implisit
+akan menambahkan qualifier versi platform sehingga perangkat yang lebih lama pasti mengabaikannya. Misalnya, menggunakan qualifier
+w600dp
secara otomatis akan menyertakan qualifier v13
, karena
+qualifier lebar yang tersedia baru di API level 13. Untuk menghindari masalah, selalu sertakan satu set
+sumber daya default (satu set sumber daya tanpa qualifier). Untuk informasi selengkapnya, lihat
+bagian tentang Menyediakan Kompatibilitas Perangkat Terbaik dengan
+Sumber Daya.
Aturan penamaan qualifier
+ +Inilah beberapa aturan tentang penggunaan nama qualifier konfigurasi:
+ +-
+
- Anda bisa menetapkan beberapa qualifier untuk satu set sumber daya, yang dipisahkan dengan tanda hubung. Misalnya,
+
drawable-en-rUS-land
berlaku untuk perangkat bahasa Inggris-AS dalam orientasi +lanskap.
+ - Qualifier harus dalam urutan seperti yang tercantum dalam tabel 2.
+Misalnya:
+
-
+
- Salah:
drawable-hdpi-port/
+ - Benar:
drawable-port-hdpi/
+
+ - Salah:
- Direktori sumber daya alternatif tidak bisa digunakan. Misalnya, Anda tidak bisa memiliki
+
res/drawable/drawable-en/
.
+ - Nilai tidak membedakan huruf besar maupun kecil. Compiler sumber daya mengubah nama direktori +menjadi huruf kecil sebelum pemrosesan untuk menghindari masalah pada sistem file yang membedakan +huruf kecil dan besar. Setiap penggunaan huruf besar dalam nama hanyalah demi keterbacaan. +
- Hanya didukung satu nilai untuk setiap tipe qualifier. Misalnya, jika Anda ingin menggunakan
+file drawable yang sama untuk Spanyol dan Prancis, Anda tidak bisa memiliki direktori bernama
+
drawable-rES-rFR/
. Sebagai gantinya, Anda perlu dua direktori sumber daya, seperti +drawable-rES/
dandrawable-rFR/
, berisi file yang sesuai. +Akan tetapi, Anda tidak harus benar-benar menggandakan file yang sama di kedua lokasi. Sebagai gantinya, Anda +bisa membuat alias ke satu sumber daya. Lihat Membuat +sumber daya alias di bawah ini.
+
Setelah Anda menyimpan sumber daya alternatif ke dalam direktori yang diberi nama dengan +qualifier ini, Android secara otomatis menerapkan sumber daya dalam +aplikasi Anda berdasarkan pada konfigurasi perangkat saat ini. Setiap kali sumber daya diminta, Android akan memeriksa direktori sumber daya +alternatif berisi file sumber daya yang diminta, lalu mencari sumber daya yang +paling cocok(dibahas di bawah). Jika tidak ada sumber daya alternatif yang cocok +dengan konfigurasi perangkat tertentu, Android akan menggunakan sumber daya default terkait (set +sumber daya untuk tipe sumber daya tertentu yang tidak termasuk qualifier +konfigurasi).
+ + + +Membuat sumber daya alias
+ +Bila memiliki sumber daya yang ingin Anda gunakan untuk lebih dari satu konfigurasi +perangkat (namun tidak ingin menyediakannya sebagai sumber daya default), Anda tidak perlu menempatkan sumber daya +yang sama di lebih dari satu direktori sumber daya alternatif. Sebagai gantinya, (dalam beberapa kasus) Anda bisa membuat +sumber daya alternatif +yang berfungsi sebagai alias untuk sumber daya yang disimpan dalam direktori sumber daya default.
+ +Catatan: Tidak semua sumber daya menawarkan mekanisme yang memungkinkan Anda +membuat alias ke sumber daya lain. Khususnya, animasi, menu, raw, dan +sumber daya lain yang tidak ditetapkan dalam direktori {@code xml/} tidak menawarkan fitur ini.
+ +Misalnya, bayangkan Anda memiliki ikon aplikasi {@code icon.png}, dan membutuhkan versi uniknya +untuk lokal berbeda. Akan tetapi, dua lokal, bahasa Inggris-Kanada dan bahasa Prancis-Kanada, harus menggunakan +versi yang sama. Anda mungkin berasumsi bahwa Anda perlu menyalin gambar +yang sama ke dalam direktori sumber daya baik untuk bahasa Inggris-Kanada maupun bahasa Prancis-Kanada, namun +bukan demikian. Sebagai gantinya, Anda bisa menyimpan gambar yang sama-sama digunakan sebagai {@code icon_ca.png} (nama +apa saja selain {@code icon.png}) dan memasukkannya +dalam direktori default {@code res/drawable/}. Lalu buat file {@code icon.xml} dalam {@code +res/drawable-en-rCA/} dan {@code res/drawable-fr-rCA/} yang mengacu ke sumber daya {@code icon_ca.png} +yang menggunakan elemen {@code <bitmap>}. Hal ini memungkinkan Anda menyimpan satu versi saja dari +file PNG dan dua file XML kecil yang menunjuk ke sana. (Contoh file XML ditampilkan di bawah.)
+ + +Drawable
+ +Untuk membuat alias ke drawable yang ada, gunakan elemen {@code <bitmap>}. +Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/icon_ca" /> ++ +
Jika Anda menyimpan file ini sebagai {@code icon.xml} (dalam direktori sumber daya alternatif, seperti +{@code res/drawable-en-rCA/}), maka file akan dikompilasi menjadi sumber daya yang dapat Anda acu +sebagai {@code R.drawable.icon}, namun sebenarnya merupakan alias untuk sumber daya {@code +R.drawable.icon_ca} (yang disimpan dalam {@code res/drawable/}).
+ + +Layout
+ +Untuk membuat alias ke layout yang ada, gunakan elemen {@code <include>}, +yang dibungkus dalam {@code <merge>}. Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<merge> + <include layout="@layout/main_ltr"/> +</merge> ++ +
Jika Anda menyimpan file ini sebagai {@code main.xml}, file akan dikompilasi menjadi sumber daya yang dapat Anda acu +sebagai {@code R.layout.main}, namun sebenarnya merupakan alias untuk sumber daya {@code R.layout.main_ltr} +.
+ + +String dan nilai-nilai sederhana lainnya
+ +Untuk membuat alias ke string yang ada, cukup gunakan ID sumber daya +dari string yang diinginkan sebagai nilai untuk string baru. Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="hello">Hello</string> + <string name="hi">@string/hello</string> +</resources> ++ +
Sumber daya {@code R.string.hi} sekarang merupakan alias untuk {@code R.string.hello}.
+ +Nilai sederhana lainnya sama +cara kerjanya. Misalnya, sebuah warna:
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="yellow">#f00</color> + <color name="highlight">@color/red</color> +</resources> ++ + + + +
Menyediakan Kompatibilitas Perangkat Terbaik dengan Sumber Daya
+ +Agar aplikasi Anda mendukung beberapa konfigurasi perangkat, +Anda harus selalu menyediakan sumber daya default untuk setiap tipe sumber daya yang menggunakan aplikasi Anda.
+ +Misalnya, jika aplikasi Anda mendukung beberapa bahasa, sertakan selalu direktori {@code +values/} (tempat string Anda disimpan) tanpa qualifier bahasa dan wilayah. Jika sebaliknya Anda menempatkan semua file +string dalam direktori yang memiliki qualifier bahasa dan wilayah, maka aplikasi Anda akan crash saat berjalan +pada perangkat yang telah diatur ke bahasa yang tidak didukung string Anda. Namun asalkan Anda menyediakan sumber daya default +{@code values/}, aplikasi akan berjalan lancar (meskipun pengguna +tidak memahami bahasa itu—, ini lebih baik daripada crash).
+ +Demikian pula, jika Anda menyediakan sumber daya layout berbeda berdasarkan orientasi layar, Anda harus +memilih satu orientasi sebagai default. Misalnya, sebagai ganti menyediakan sumber daya dalam {@code +layout-land/} untuk lanskap dan {@code layout-port/} untuk potret, biarkan salah satu sebagai default, seperti +{@code layout/} untuk lanskap dan {@code layout-port/} untuk potret.
+ +Sumber daya default perlu disediakan bukan hanya karena aplikasi mungkin berjalan pada +konfigurasi yang belum Anda antisipasi, namun juga karena versi baru Android terkadang menambahkan +qualifier konfigurasi yang tidak didukung oleh versi lama. Jika Anda menggunakan qualifier sumber daya baru, +namun mempertahankan kompatibilitas kode dengan versi Android yang lebih lama, maka saat versi lama +Android menjalankan aplikasi, aplikasi itu akan crash jika Anda tidak menyediakan sumber daya default, aplikasi +tidak bisa menggunakan sumber daya yang dinamai dengan qualifier baru. Misalnya, jika {@code +minSdkVersion} Anda diatur ke 4, dan Anda memenuhi syarat semua sumber daya drawable dengan menggunakan mode malam ({@code night} atau {@code notnight}, yang ditambahkan di API +Level 8), maka perangkat API level 4 tidak bisa mengakses sumber daya drawable dan akan crash. Dalam hal +ini, Anda mungkin ingin {@code notnight} menjadi sumber daya default, jadi Anda harus mengecualikan +qualifier itu agar sumber daya drawable Anda ada dalam {@code drawable/} atau {@code drawable-night/}.
+ +Jadi, agar bisa menyediakan kompatibilitas perangkat terbaik, sediakan selalu sumber daya +default untuk sumber daya yang diperlukan aplikasi Anda untuk berjalan dengan benar. Selanjutnya buatlah sumber daya +alternatif untuk konfigurasi perangkat tertentu dengan menggunakan qualifier konfigurasi.
+ +Ada satu eksepsi untuk aturan ini: Jika {@code minSdkVersion} aplikasi Anda adalah 4 atau +lebih, Anda tidak memerlukan sumber daya drawable default saat menyediakan sumber daya +drawable alternatif dengan qualifier densitas layar. Tanpa sumber daya +drawable default sekali pun, Android bisa menemukan yang paling cocok di antara densitas layar alternatif dan menskalakan +bitmap sesuai kebutuhan. Akan tetapi, demi pengalaman terbaik pada semua jenis perangkat, Anda harus +menyediakan drawable alternatif untuk ketiga tipe densitas.
+ + + +Cara Android Menemukan Sumber Daya yang Paling Cocok
+ +Saat Anda meminta sumber daya yang Anda berikan alternatifnya, Android akan memilih +sumber daya alternatif yang akan digunakan saat runtime, bergantung pada konfigurasi perangkat saat ini. Untuk +mendemonstrasikan cara Android memilih sumber daya alternatif, anggaplah direktori drawable berikut +masing-masing berisi versi berbeda dari gambar yang sama:
+ ++drawable/ +drawable-en/ +drawable-fr-rCA/ +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ ++ +
Dan anggaplah yang berikut ini merupakan konfigurasi perangkatnya:
+ +
+Lokal = en-GB
+Orientasi layar = port
+Densitas piksel layar = hdpi
+Tipe layar sentuh = notouch
+Metode input teks utama = 12key
+
Dengan membandingkan konfigurasi perangkat dengan sumber daya alternatif yang tersedia, Android akan memilih +drawable dari {@code drawable-en-port}.
+ +Sistem akan menentukan keputusannya mengenai sumber daya yang akan digunakan dengan logika +berikut:
+ + +-
+
- Menghapus file sumber daya yang bertentangan dengan konfigurasi perangkat.
+
Direktori
+drawable-fr-rCA/
dihapus karena bertentangan +dengan lokalen-GB
.+drawable/ +drawable-en/ +
+drawable-fr-rCA/+drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ +Eksepsi: Densitas piksel layar adalah satu qualifier yang +tidak dihapus karena bertentangan. Meskipun densitas layar perangkat adalah hdpi, +
drawable-port-ldpi/
tidak dihapus karena setiap densitas layar +dianggap cocok untuk saat ini. Informasi selengkapnya tersedia dalam dokumen Mendukung Beberapa +Layar.
+
+ - Pilih qualifier berkedudukan tertinggi (berikutnya) dalam daftar (tabel 2). +(Mulai dengan MCC, lalu pindah ke bawah.) +
- Apakah salah satu direktori sumber daya menyertakan qualifier ini? +
- Jika Tidak, kembali ke langkah 2 dan lihat qualifier berikutnya. (Dalam contoh, +jawabannya adalah "tidak" hingga qualifier bahasa tercapai.) +
- Jika Ya, lanjutkan ke langkah 4. +
- Hapus direktori sumber daya yang tidak menyertakan qualifier ini. Dalam contoh, sistem +menghapus semua direktori yang tidak menyertakan qualifier bahasa: +
- Kembali dan ulangi langkah 2, 3, dan 4 hingga tersisa satu direktori. Dalam contoh ini, orientasi
+layar adalah qualifier berikutnya yang memiliki kecocokan.
+Jadi, sumber daya yang tidak menetapkan orientasi layar akan dihapus:
+
+
+drawable-en/+drawable-en-port/ +drawable-en-notouch-12key/+Direktori yang tersisa adalah {@code drawable-en-port}.
+
+
-
+
++drawable/+drawable-en/ +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/+drawable-port-notouch-12key/+
Eksepsi: Jika qualifier yang dimaksud adalah densitas piksel layar, +Android akan memilih opsi yang paling cocok dengan densitas layar perangkat. +Secara umum, Android lebih suka menurunkan skala gambar asli yang lebih besar daripada menaikkan skala +atas gambar asli yang lebih kecil. Lihat Mendukung Beberapa +Layar.
+ + +Meskipun prosedur dijalankan untuk setiap sumber daya yang diminta, sistem akan mengoptimalkan beberapa aspek +lebih lanjut. Satu optimalisasi tersebut adalah bahwa setelah konfigurasi perangkat diketahui, sistem mungkin +akan menghapus sumber daya alternatif yang sama sekali tidak cocok. Misalnya, jika bahasa konfigurasi +adalah bahasa Inggris ("en"), maka setiap direktori sumber daya yang memiliki qualifier bahasa akan diatur ke +selain bahasa Inggris tidak akan pernah disertakan dalam pool sumber daya yang diperiksa (meskipun +direktori sumber daya tanpa qualifier bahasa masih disertakan).
+ +Saat memilih sumber daya berdasarkan qualifier ukuran layar, sistem akan menggunakan +sumber daya yang didesain untuk layar yang lebih kecil daripada layar saat ini jika tidak ada sumber daya yang lebih cocok +(misalnya, layar ukuran besar akan menggunakan sumber daya layar ukuran normal jika diperlukan). Akan tetapi, +jika satu-satunya sumber daya yang tersedia lebih besar daripada layar saat ini, sistem +tidak akan menggunakannya dan aplikasi Anda akan crash jika tidak ada sumber daya lain yang cocok dengan konfigurasi +perangkat (misalnya, jika semua sumber daya layout ditandai dengan qualifier {@code xlarge}, +namun perangkat memiliki ukuran layar normal).
+ +Catatan: Kedudukan qualifier (dalam tabel 2) lebih penting
+daripada jumlah qualifier yang benar-benar pas dengan perangkat. Misalnya, dalam langkah 4 di atas, pilihan
+terakhir pada daftar berisi tiga qualifier yang bebar-benar cocok dengan perangkat (orientasi, tipe
+layar sentuh, dan metode input), sementara drawable-en
hanya memiliki satu parameter yang cocok
+(bahasa). Akan tetapi, bahasa memiliki kedudukan lebih tinggi dari pada qualifier lainnya, sehingga
+drawable-port-notouch-12key
tidak masuk.
Untuk mengetahui selengkapnya tentang cara menggunakan sumber daya dalam aplikasi, lanjutkan ke Mengakses Sumber Daya.
diff --git a/docs/html-intl/intl/in/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/in/guide/topics/resources/runtime-changes.jd new file mode 100644 index 0000000000000000000000000000000000000000..c9a5ead63c77d4b1e36e5f2429bffd361746fbe0 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/resources/runtime-changes.jd @@ -0,0 +1,281 @@ +page.title=Menangani Perubahan Runtime +page.tags=aktivitas,daur hidup +@jd:body + +Dalam dokumen ini
+ + +Lihat juga
+ +Sebagian konfigurasi perangkat bisa berubah selama runtime +(seperti orientasi layar, ketersediaan keyboard, dan bahasa). Saat perubahan demikian terjadi, +Android akan me-restart +{@link android.app.Activity} yang berjalan ({@link android.app.Activity#onDestroy()} dipanggil, diikuti oleh {@link +android.app.Activity#onCreate(Bundle) onCreate()}). Perilaku restart didesain untuk membantu +aplikasi Anda beradaptasi dengan konfigurasi baru melalui pemuatan kembali aplikasi Anda secara otomatis dengan +sumber daya alternatif sumber yang sesuai dengan konfigurasi perangkat baru.
+ +Untuk menangani restart dengan benar, aktivitas Anda harus mengembalikan +statusnya seperti semula melalui Daur hidup +aktivitas normal, dalam hal ini Android akan memanggil +{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} sebelum menghentikan +aktivitas Anda sehingga Anda dapat menyimpan data mengenai status aplikasi. Selanjutnya Anda bisa mengembalikan status +selama {@link android.app.Activity#onCreate(Bundle) onCreate()} atau {@link +android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.
+ +Untuk menguji bahwa aplikasi me-restart sendiri dengan status tak berubah, Anda harus +memanggil perubahan konfigurasi (seperti mengubah orientasi layar) saat melakukan berbagai +tugas dalam aplikasi. Aplikasi Anda harus dapat me-restart setiap saat tanpa kehilangan +data pengguna atau status untuk menangani kejadian seperti perubahan konfigurasi atau bila pengguna menerima panggilan telepon +masuk lalu kembali ke aplikasi setelah proses +aplikasi Anda dimusnahkan. Untuk mengetahui cara mengembalikan status aktivitas, bacalah tentang Daur hidup aktivitas.
+ +Akan tetapi, Anda mungkin menemui situasi ketika me-restart aplikasi dan +mengembalikan data dalam jumlah besar malah menjadi mahal dan menghasilkan pengalaman pengguna yang buruk. Dalam situasi +demikian, Anda memiliki dua opsi lain:
+ +-
+
- Mempertahankan objek selama perubahan konfigurasi
+
Izinkan aktivitas Anda me-restart saat konfigurasi berubah, namun bawa objek +berstatus (stateful) ke instance baru aktivitas Anda.
+ +
+ - Menangani sendiri perubahan konfigurasi
+
Cegah sistem me-restart aktivitas selama perubahan konfigurasi +tertentu, namun terima callback saat konfigurasi benar-benar berubah, agar Anda bisa memperbarui +aktivitas secara manual bila diperlukan.
+
+
Mempertahankan Objek Selama Perubahan Konfigurasi
+ +Jika me-restart aktivitas mengharuskan pemulihan seperangkat data dalam jumlah besar, menghubungkan kembali koneksi +jaringan, atau melakukan operasi intensif lainnya, maka restart penuh karena perubahan konfigurasi mungkin +menjadi pengalaman pengguna yang lambat. Selain itu, Anda mungkin tidak bisa sepenuhnya mengembalikan status +aktivitas dengan {@link android.os.Bundle} yang disimpan sistem untuk Anda dengan callback {@link +android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()}—itu tidaklah +didesain untuk membawa objek besar (seperti bitmap) dan data di dalamnya harus diserialkan kemudian +dinon-serialkan, yang bisa menghabiskan banyak memori dan membuat perubahan konfigurasi menjadi lambat. Dalam situasi +demikian, Anda bisa meringankan beban memulai kembali aktivitas Anda dengan mempertahankan {@link +android.app.Fragment} saat aktivitas Anda di-restart karena perubahan konfigurasi. Fragmen ini +bisa berisi acuan ke objek stateful yang ingin Anda pertahankan.
+ +Bila sistem Android menghentikan aktivitas Anda karena perubahan konfigurasi, fragmen +aktivitas yang telah ditandai untuk dipertahankan tidak akan dimusnahkan. Anda dapat menambahkan fragmen tersebut ke +aktivitas untuk mempertahankan objek stateful.
+ +Untuk mempertahankan objek stateful dalam fragmen selama perubahan konfigurasi runtime:
+ +-
+
- Perluas kelas {@link android.app.Fragment} dan deklarasikan referensi ke objek stateful +Anda. +
- Panggil {@link android.app.Fragment#setRetainInstance(boolean)} saat fragmen dibuat. + +
- Tambahkan fragmen ke aktivitas. +
- Gunakan {@link android.app.FragmentManager} untuk mengambil fragmen saat aktivitas +di-restart. +
Misalnya, definisikan fragmen sebagai berikut:
+ ++public class RetainedFragment extends Fragment { + + // data object we want to retain + private MyDataObject data; + + // this method is only called once for this fragment + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // retain this fragment + setRetainInstance(true); + } + + public void setData(MyDataObject data) { + this.data = data; + } + + public MyDataObject getData() { + return data; + } +} ++ +
Perhatian: Meskipun bisa menyimpan objek apa saja, Anda +sama sekali tidak boleh meneruskan objek yang terkait dengan {@link android.app.Activity}, seperti {@link +android.graphics.drawable.Drawable}, {@link android.widget.Adapter}, {@link android.view.View} +atau objek lainnya mana pun yang terkait dengan {@link android.content.Context}. Jika Anda melakukannya, hal tersebut akan +membocorkan semua tampilan dan sumber daya instance aktivitas semula. (Sumber daya yang bocor +berarti bahwa aplikasi Anda tetap menyimpannya dan tidak bisa dijadikan kumpulan sampah, sehingga bisa banyak +memori yang hilang.)
+ +Selanjutnya gunakan {@link android.app.FragmentManager} untuk menambahkan fragmen ke aktivitas. +Anda bisa memperoleh objek data dari fragmen saat aktivitas memulai kembali selama perubahan +konfigurasi runtime. Misalnya, definisikan aktivitas Anda sebagai berikut:
+ ++public class MyActivity extends Activity { + + private RetainedFragment dataFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // find the retained fragment on activity restarts + FragmentManager fm = getFragmentManager(); + dataFragment = (DataFragment) fm.findFragmentByTag(“data”); + + // create the fragment and data the first time + if (dataFragment == null) { + // add the fragment + dataFragment = new DataFragment(); + fm.beginTransaction().add(dataFragment, “data”).commit(); + // load the data from the web + dataFragment.setData(loadMyData()); + } + + // the data is available in dataFragment.getData() + ... + } + + @Override + public void onDestroy() { + super.onDestroy(); + // store the data in the fragment + dataFragment.setData(collectMyLoadedData()); + } +} ++ +
Dalam contoh ini, {@link android.app.Activity#onCreate(Bundle) onCreate()} menambahkan fragmen +atau mengembalikan referensinya. {@link android.app.Activity#onCreate(Bundle) onCreate()} juga +menyimpan objek stateful dalam instance fragmen. +{@link android.app.Activity#onDestroy() onDestroy()} akan memperbarui objek stateful dalam +instance fragmen yang dipertahankan.
+ + + + + +Menangani Sendiri Perubahan Konfigurasi
+ +Jika aplikasi Anda tidak memerlukan pembaruan sumber daya selama perubahan konfigurasi +tertentu dan Anda memiliki keterbatasan kinerja yang mengharuskan Anda untuk +menghindari restart aktivitas, maka Anda bisa mendeklarasikan agar aktivitas Anda menangani sendiri perubahan +konfigurasinya, sehingga mencegah sistem me-restart aktivitas.
+ +Catatan: Menangani sendiri perubahan konfigurasi bisa jauh lebih +mempersulit penggunaan sumber daya alternatif, karena sistem tidak menerapkannya secara otomatis +untuk Anda. Teknik ini harus dianggap sebagai usaha terakhir bila Anda harus menghindari restart +karena perubahan konfigurasi dan tidak disarankan untuk sebagian besar aplikasi.
+ +Untuk mendeklarasikan agar aktivitas Anda menangani perubahan konfigurasi, edit elemen {@code <activity>} yang sesuai +dalam file manifes Anda agar menyertakan atribut {@code +android:configChanges} dengan nilai yang mewakili konfigurasi yang ingin +ditangani. Nilai yang memungkinkan tercantum dalam dokumentasi untuk atribut {@code +android:configChanges} (nilai paling sering digunakan adalah {@code "orientation"} untuk +mencegah restart saat orientasi layar berubah dan {@code "keyboardHidden"} untuk mencegah +restart saat ketersediaan keyboard berubah). Anda dapat mendeklarasikan beberapa nilai konfigurasi +dalam atribut dengan memisahkannya menggunakan karakter pipa {@code |}.
+ +Misalnya, kode manifes berikut menyatakan aktivitas yang menangani +perubahan orientasi layar maupun perubahan ketersediaan keyboard:
+ ++<activity android:name=".MyActivity" + android:configChanges="orientation|keyboardHidden" + android:label="@string/app_name"> ++ +
Sekarang, bila salah satu konfigurasi ini berubah, {@code MyActivity} tidak akan me-restart. +Sebagai gantinya, {@code MyActivity} akan menerima panggilan ke {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Metode ini +meneruskan objek {@link android.content.res.Configuration} yang menetapkan +konfigurasi perangkat baru. Dengan membaca bidang-bidang dalam {@link android.content.res.Configuration}, +Anda dapat menentukan konfigurasi baru dan membuat perubahan yang sesuai dengan memperbarui +sumber daya yang digunakan dalam antarmuka. Pada saat +metode ini dipanggil, objek {@link android.content.res.Resources} aktivitas Anda akan diperbarui untuk +mengembalikan sumber daya berdasarkan konfigurasi baru, jadi Anda bisa dengan mudah +me-reset elemen UI tanpa membuat sistem me-restart aktivitas Anda.
+ +Perhatian: Mulai Android 3.2 (API level 13), +"ukuran layar" juga berubah bila perangkat beralih orientasi antara potret +dan lanskap. Jadi jika Anda tidak ingin runtime di-restart karena perubahan orientasi saat mengembangkan +API level 13 atau yang lebih tinggi (sebagaimana dideklarasikan oleh atribut {@code minSdkVersion} dan {@code targetSdkVersion} +), Anda harus menyertakan nilai {@code "screenSize"} selain nilai {@code +"orientation"}. Yaitu Anda harus mendeklarasikan {@code +android:configChanges="orientation|screenSize"}. Akan tetapi, jika aplikasi Anda menargetkan API level +12 atau yang lebih rendah, maka aktivitas Anda akan selalu menangani sendiri perubahan konfigurasi ini (perubahan +konfigurasi ini tidak me-restart aktivitas Anda, bahkan saat berjalan pada perangkat Android 3.2 atau yang lebih tinggi).
+ +Misalnya, implementasi {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} berikut akan +memeriksa orientasi perangkat saat ini:
+ ++@Override +public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + // Checks the orientation of the screen + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ + Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); + } +} ++ +
Objek {@link android.content.res.Configuration} mewakili semua konfigurasi +saat ini, tidak hanya konfigurasi yang telah berubah. Seringkali Anda tidak perlu memperhatikan dengan persis bagaimana +konfigurasi berubah dan cukup menetapkan kembali semua sumber daya yang memberikan alternatif untuk +konfigurasi sedang ditangani. Misalnya, karena objek {@link +android.content.res.Resources} sekarang diperbarui, Anda dapat me-reset +setiap {@link android.widget.ImageView} dengan {@link android.widget.ImageView#setImageResource(int) +setImageResource()} +dan sumber daya yang sesuai untuk konfigurasi baru yang digunakan (seperti dijelaskan dalam Menyediakan Sumber Daya).
+ +Perhatikan bahwa nilai-nilai dari bidang {@link +android.content.res.Configuration} adalah integer yang sesuai dengan konstanta spesifik +dari kelas {@link android.content.res.Configuration}. Untuk dokumentasi tentang konstanta +yang harus digunakan di setiap bidang, lihat bidang yang sesuai dalam referensi {@link +android.content.res.Configuration}.
+ +Ingatlah: Saat mendeklarasikan aktivitas untuk menangani perubahan +konfigurasi, Anda bertanggung jawab untuk me-reset setiap elemen yang alternatifnya Anda berikan. Jika Anda +mendeklarasikan aktivitas untuk menangani perubahan orientasi dan memiliki gambar yang harus berubah +antara lanskap dan potret, Anda harus menetapkan kembali setiap sumber daya elemen selama {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.
+ +Jika Anda tidak perlu memperbarui aplikasi berdasarkan perubahan +konfigurasi ini, sebagai gantinya Anda bisa saja tidak mengimplementasikan {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Dalam +hal ini, semua sumber daya yang digunakan sebelum perubahan konfigurasi akan tetap digunakan +dan Anda hanya menghindari restart aktivitas. Akan tetapi, aplikasi Anda harus selalu +bisa dimatikan dan di-restart dengan status sebelumnya tetap utuh, sehingga Anda jangan menganggap teknik +ini sebagai jalan keluar untuk mempertahankan status selama daur hidup aktivitas normal. Tidak hanya +karena ada perubahan konfigurasi lainnya yang tidak bisa Anda cegah untuk me-restart aplikasi, namun +juga karena Anda harus menangani kejadian seperti saat pengguna meninggalkan aplikasi dan +dimusnahkan sebelum pengguna kembali ke aplikasi.
+ +Untuk informasi selengkapnya tentang perubahan konfigurasi yang bisa Anda tangani dalam aktivitas, lihat dokumentasi {@code +android:configChanges} dan kelas {@link android.content.res.Configuration} +.
diff --git a/docs/html-intl/intl/in/guide/topics/ui/controls.jd b/docs/html-intl/intl/in/guide/topics/ui/controls.jd new file mode 100644 index 0000000000000000000000000000000000000000..7ee2957980a898008c8d5df15d821184e356a249 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/controls.jd @@ -0,0 +1,90 @@ +page.title=Kontrol Input +parent.title=Antarmuka Pengguna +parent.link=index.html +@jd:body + +Kontrol input adalah komponen interaktif dalam antarmuka pengguna aplikasi Anda. Android menyediakan +aneka ragam kontrol yang bisa Anda gunakan dalam UI, seperti tombol, bidang teks, bilah pencarian, +kotak cek, tombol zoom, tombol toggle, dan masih banyak lagi.
+ +Menambahkan sebuah kontrol input ke UI adalah semudah menambahkan satu elemen XML ke layout XML. Misalnya, inilah sebuah +layout dengan satu bidang teks dan satu tombol:
+ ++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="horizontal"> + <EditText android:id="@+id/edit_message" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:hint="@string/edit_message" /> + <Button android:id="@+id/button_send" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_send" + android:onClick="sendMessage" /> +</LinearLayout> ++ +
Tiap kontrol input mendukung satu set kejadian input sehingga Anda bisa menangani berbagai kejadian seperti saat +pengguna memasukkan teks atau menyentuh tombol.
+ + +Kontrol Umum
+Berikut adalah daftar beberapa kontrol umum yang bisa Anda gunakan dalam aplikasi. Ikuti tautan ini untuk mengetahui +selengkapnya tentang penggunaannya masing-masing.
+ +Catatan: Android menyediakan beberapa kontrol lain yang tidak tercantum +di sini. Telusuri paket {@link android.widget} untuk mengetahui selengkapnya. Jika aplikasi Anda memerlukan +semacam kontrol input tertentu, Anda bisa membangun komponen custom sendiri.
+ +Tipe Kontrol | +Keterangan | +Kelas Terkait | +
---|---|---|
Tombol | +Tombol tekan yang bisa ditekan, atau diklik, oleh pengguna untuk melakukan suatu tindakan. | +{@link android.widget.Button Button} | +
Bidang teks | +Bidang teks yang bisa diedit. Anda bisa menggunakan widget AutoCompleteTextView untuk membuat widget entri teks yang menyediakan saran pelengkapan otomatis |
+ {@link android.widget.EditText EditText}, {@link android.widget.AutoCompleteTextView} | +
Kotak cek | +Switch aktif/nonaktif yang bisa diubah oleh pengguna. Anda harus menggunakan kotak cek saat menampilkan sekumpulan opsi yang bisa dipilih pengguna dan bila keduanya mungkin terjadi bersamaan. | +{@link android.widget.CheckBox CheckBox} | +
Tombol radio | +Mirip dengan kotak cek, hanya saja cuma satu opsi yang bisa dipilih dalam kumpulan tersebut. | +{@link android.widget.RadioGroup RadioGroup}
+ {@link android.widget.RadioButton RadioButton} |
+
Tombol toggle | +Tombol aktif/nonaktif dengan indikator cahaya. | +{@link android.widget.ToggleButton ToggleButton} | +
Spinner | +Daftar tarik-turun yang memungkinkan pengguna memilih salah satu dari serangkaian nilai. | +{@link android.widget.Spinner Spinner} | +
Picker | +Dialog bagi pengguna untuk memilih satu nilai dari satu kumpulan dengan menggunakan tombol naik/turun atau dengan gerakan mengusap. Gunakan widget DatePicker code> untuk memasukkan nilai tanggal (bulan, hari, tahun) atau widget TimePicker untuk memasukkan nilai waktu (jam, menit, AM/PM), yang akan diformat secara otomatis untuk lokasi pengguna tersebut. |
+ {@link android.widget.DatePicker}, {@link android.widget.TimePicker} | +
Dalam dokumen ini
+-
+
- Tulis XML +
- Muat Sumber Daya XML +
- Atribut
+
-
+
- ID +
- Parameter Layout +
+ - Posisi Layout +
- Ukuran, Pengisi, dan Margin +
- Layout Umum +
- Membangun Layout dengan Adaptor + + +
Kelas-kelas utama
+-
+
- {@link android.view.View} +
- {@link android.view.ViewGroup} +
- {@link android.view.ViewGroup.LayoutParams} +
Lihat juga
+Layout mendefinisikan struktur visual untuk antarmuka pengguna, seperti UI sebuah aktivitas atau widget aplikasi. +Anda dapat mendeklarasikan layout dengan dua cara:
+-
+
- Deklarasikan elemen UI dalam XML. Android menyediakan sebuah kosakata XML +sederhana yang sesuai dengan kelas dan subkelas View, seperti halnya untuk widget dan layout. +
- Buat instance elemen layout saat runtime. Aplikasi Anda +bisa membuat objek View dan ViewGroup (dan memanipulasi propertinya) lewat program. +
Kerangka kerja Android memberi Anda fleksibilitas untuk menggunakan salah satu atau kedua metode ini guna mendeklarasikan dan mengelola UI aplikasi Anda. Misalnya, Anda bisa mendeklarasikan layout default aplikasi Anda dalam XML, termasuk elemen-elemen layar yang akan muncul di dalamnya dan di propertinya. Anda nanti bisa menambahkan kode dalam aplikasi yang akan memodifikasi status objek layar, termasuk yang dideklarasikan dalam XML, saat runtime.
+ +-
+
- ADT + Plugin for Eclipse menawarkan preview layout XML — + Anda dengan file XML yang dibuka, pilih tab Layout. +
- Anda juga harus mencoba alat + Hierarchy Viewer, + untuk merunut layout — alat ini akan menampilkan nilai-nilai properti layout, + menggambar bentuk kerangka dengan indikator pengisi/margin, dan tampilan yang dirender penuh selagi + Anda merunut pada emulator atau perangkat. +
- Alat layoutopt memungkinkan + Anda menganalisis layout dan hierarki dengan untuk mengetahui ketidakefisienan atau masalah lainnya. +
Keuntungan mendeklarasikan UI dalam XML adalah karena hal ini memungkinkan Anda memisahkan penampilan aplikasi dari kode yang mengontrol perilakunya dengan lebih baik. Keterangan UI Anda bersifat eksternal bagi kode aplikasi Anda, yang berarti bahwa Anda bisa memodifikasi atau menyesuaikannya tanpa harus memodifikasi dan mengompilasi ulang kode sumber. Misalnya, Anda bisa membuat layout XML untuk berbagai orientasi layar, berbagai ukuran layar perangkat, dan berbagai bahasa. Selain itu, mendeklarasikan layout dalam XML akan mempermudah Anda memvisualisasikan struktur UI, sehingga lebih mudah merunut masalahnya. Karena itu, dokumen ini berfokus pada upaya mengajari Anda cara mendeklarasikan layout dalam XML. Jika Anda +tertarik dalam membuat instance objek View saat runtime, lihat referensi kelas {@link android.view.ViewGroup} dan +{@link android.view.View}.
+ +Secara umum, kosakata XML untuk mendeklarasikan elemen UI mengikuti dengan sangat mirip struktur serta penamaan kelas dan metode, dengan nama elemen dipadankan dengan nama kelas dan nama atribut dipadankan dengan metode. Sebenarnya, pemadanan ini kerap kali begitu jelas sehingga Anda bisa menebak atribut XML yang berpadanan dengan sebuah metode kelas, atau menebak kelas yang berpadanan dengan sebuah elemen XML. Akan tetapi, perhatikan bahwa tidak semua kosakata identik. Dalam beberapa kasus, ada sedikit perbedaan penamaan. Misalnya
+, elemen EditText memiliki atribut text
yang berpadanan dengan
+EditText.setText()
.
Tip: Ketahui selengkapnya berbagai tipe layout dalam Objek +Layout Umum. Ada juga sekumpulan tutorial tentang cara membangun berbagai layout dalam panduan tutorial +Hello Views.
+ +Tulis XML
+ +Dengan menggunakan kosakata XML Android, Anda bisa mendesain secara cepat layout UI dan elemen layar yang dimuatnya, sama dengan cara membuat halaman web dalam HTML — dengan serangkaian elemen tersarang.
+ +Tiap file layout harus berisi persis satu elemen akar, yang harus berupa sebuah objek View atau ViewGroup. Setelah mendefinisikan elemen akar, Anda bisa menambahkan objek atau widget layout tambahan sebagai elemen anak untuk membangun hierarki View yang mendefinisikan layout Anda secara bertahap. Misalnya, inilah layout XML yang menggunakan {@link android.widget.LinearLayout} +vertikal untuk menyimpan {@link android.widget.TextView} dan {@link android.widget.Button}:
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a Button" /> +</LinearLayout> ++ +
Setelah Anda mendeklarasikan layout dalam XML, simpanlah file dengan ekstensi .xml
,
+dalam direktori res/layout/
proyek Android, sehingga nanti bisa dikompilasi dengan benar.
Informasi selengkapnya tentang sintaks untuk file XML layout tersedia dalam dokumen Sumber Daya Layout.
+ +Muat Sumber Daya XML
+ +Saat mengompilasi aplikasi, masing-masing file layout XML akan dikompilasi dalam sebuah sumber daya
+{@link android.view.View}. Anda harus memuat sumber daya layout dari kode aplikasi, dalam implementasi
+callback {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}.
+Lakukan dengan memanggil {@link android.app.Activity#setContentView(int) setContentView()}
,
+dengan meneruskan acuan ke sumber daya layout berupa:
+R.layout.layout_file_name
.
+Misalnya, jika XML layout Anda disimpan sebagai main_layout.xml
, Anda akan memuatnya
+untuk Activity seperti ini:
+public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); +} ++ +
Metode callback onCreate()
dalam Activity dipanggil oleh kerangka kerja Android saat
+Activity Anda dijalankan (lihat diskusi tentang daur hidup, dalam dokumen
+Aktivitas
+).
Atribut
+ +Setiap objek View dan ViewGroup mendukung variasi atribut XML-nya sendiri.
+Sebagian atribut bersifat spesifik untuk objek View (misalnya, TextView mendukung atribut textSize
+), namun atribut ini juga diwarisi oleh sembarang objek View yang dapat memperluas kelas ini.
+Sebagian atribut bersifat umum untuk semua objek View, karena diwarisi dari kelas View akar (seperti
+atribut id
). Dan, atribut lain dianggap sebagai "parameter layout" yaitu
+atribut yang menjelaskan orientasi layout tertentu dari objek View, seperti yang didefinisikan oleh objek ViewGroup induk
+dari objek itu.
ID
+ +Objek View apa saja dapat memiliki ID integer yang dikaitkan dengannya, untuk mengidentifikasi secara unik View dalam pohon.
+Bila aplikasi dikompilasi, ID ini akan diacu sebagai integer, namun ID biasanya
+ditetapkan dalam file XML layout sebagai string, dalam atribut id
.
+Ini atribut XML yang umum untuk semua objek View
+(yang didefinisikan oleh kelas {@link android.view.View}) dan Anda akan sering sekali menggunakannya.
+Sintaks untuk ID dalam tag XML adalah:
android:id="@+id/my_button"+ +
Simbol "at" (@) pada awal string menunjukkan parser XML harus mengurai dan memperluas
+ID string selebihnya dan mengenalinya sebagai ID sumber daya. Simbol tanda tambah (+) berarti ini nama sumber daya baru yang harus
+dibuat dan ditambahkan ke sumber daya kita (dalam file R.java
). Ada sejumlah sumber daya ID lain yang
+ditawarkan oleh kerangka kerja Android. Saat mengacu sebuah ID sumber daya Android, Anda tidak memerlukan simbol tanda tambah,
+namun harus menambahkan namespace paket android
, sehingga:
android:id="@android:id/empty"+
Dengan namespace paket android
yang tersedia, kita sekarang mengacu ID dari kelas sumber daya android.R
+, daripada kelas sumber daya lokal.
Untuk membuat tampilan dan mengacunya dari aplikasi, pola yang umum adalah:
+-
+
- Mendefinisikan tampilan/widget dalam file layout dan memberinya ID unik:
+
+<Button android:id="@+id/my_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/my_button_text"/> +
+
+ - Kemudian buat instance objek tampilan dan tangkap instance itu dari layout
+(biasanya dalam metode
{@link android.app.Activity#onCreate(Bundle) onCreate()}
): ++Button myButton = (Button) findViewById(R.id.my_button); +
+
+
Mendefinisikan ID untuk objek tampilan adalah penting saat membuat {@link android.widget.RelativeLayout}. +Dalam layout relatif, tampilan saudara bisa mendefinisikan layout secara relatif terhadap tampilan saudara lainnya, +yang diacu melalui ID unik.
+ID tidak perlu unik di seluruh pohon, namun harus +unik di bagian pohon yang Anda cari (yang mungkin sering kali seluruh pohon, jadi lebih baik +benar-benar unik bila memungkinkan).
+ + +Parameter Layout
+ +Atribut layout XML bernama layout_something
mendefinisikan
+parameter layout View yang cocok untuk ViewGroup tempatnya berada.
Setiap kelas ViewGroup mengimplementasikan kelas tersarang yang memperluas {@link +android.view.ViewGroup.LayoutParams}. Subkelas ini +berisi tipe properti yang mendefinisikan ukuran dan posisi masing-masing tampilan anak, sebagaimana +mestinya untuk grup tampilan. Seperti yang bisa Anda lihat dalam gambar 1, +grup tampilan induk mendefinisikan parameter layout untuk masing-masing tampilan anak (termasuk grup tampilan anak).
+ + + + +Perhatikan bahwa setiap subkelas LayoutParams memiliki sintaksnya sendiri untuk menetapkan +nilai-nilai. Tiap elemen anak harus mendefinisikan LayoutParams yang semestinya bagi induknya, +meskipun elemen itu bisa juga mendefinisikan LayoutParams untuk anak-anaknya sendiri.
+ +Semua grup tampilan berisi lebar dan tinggi (layout_width
dan
+layout_height
), dan masing-masing tampilan harus mendefinisikannya. Banyak
+LayoutParams yang juga menyertakan margin dan border opsional.
+ +
Anda bisa menetapkan lebar dan tinggi dengan ukuran persis, meskipun Anda mungkin +tidak ingin sering-sering melakukannya. Lebih sering, Anda akan menggunakan salah satu konstanta ini untuk +mengatur lebar atau tinggi:
+ +-
+
- wrap_content memberi tahu tampilan Anda agar menyesuaikan sendiri ukurannya dengan dimensi +yang dibutuhkan oleh isinya. +
- match_parent (bernama fill_parent sebelum API Level 8) +memberi tahu tampilan Anda agar menjadi sebesar yang diperbolehkan oleh grup tampilan induknya. +
Secara umum, menetapkan lebar dan tinggi layout dengan satuan mutlak seperti +piksel tidaklah disarankan. Melainkan dengan menggunakan ukuran relatif seperti +satuan piksel yang tidak bergantung pada kerapatan (dp), wrap_content, atau +match_parent, adalah sebuah pendekatan yang lebih baik, karena membantu memastikan bahwa +aplikasi Anda akan ditampilkan dengan benar pada berbagai ukuran layar perangkat. +Tipe ukuran yang diterima didefinisikan dalam dokumen + +Sumber Daya yang Tersedia.
+ + +Posisi Layout
++ Geometri tampilan adalah persegi panjang. Sebuah tampilan memiliki lokasi, + yang dinyatakan berupa sepasang koordinat kiri dan atas, dan + dua dimensi, yang dinyatakan berupa lebar dan tinggi. Satuan untuk lokasi + dan dimensi adalah piksel. +
+ +
+ Lokasi tampilan dapat diambil dengan memanggil metode
+ {@link android.view.View#getLeft()} dan {@link android.view.View#getTop()}. Metode terdahulu menghasilkan koordinat kiri, atau X,
+ persegi panjang yang mewakili tampilan. Metode selanjutnya menghasilkan koordinat
+ atas, atau Y, persegi panjang yang mewakili tampilan. Kedua metode ini
+ menghasilkan lokasi tampilan relatif terhadap induknya. Misalnya,
+ bila getLeft()
menghasilkan 20, berarti tampilan berlokasi 20 piksel ke
+ kanan dari tepi kiri induk langsungnya.
+
+ Selain itu, beberapa metode praktis ditawarkan untuk menghindari komputasi yang tidak perlu,
+ yakni {@link android.view.View#getRight()} dan {@link android.view.View#getBottom()}.
+ Kedua metode ini menghasilkan koordinat tepi kanan dan bawah
+ persegi panjang yang mewakili tampilan. Misalnya, memanggil {@link android.view.View#getRight()}
+ serupa dengan komputasi berikut: getLeft() + getWidth()
.
+
Ukuran, Pengisi, dan Margin
++ Ukuran tampilan dinyatakan dengan lebar dan tinggi. Tampilan sebenarnya + memiliki dua pasang nilai lebar dan tinggi. +
+ ++ Sepasang pertama disebut lebar terukur dan + tinggi terukur. Dimensi ini mendefinisikan seberapa besar tampilan yang diinginkan + dalam induknya. Dimensi + terukur bisa diperoleh dengan memanggil {@link android.view.View#getMeasuredWidth()} + dan {@link android.view.View#getMeasuredHeight()}. +
+ ++ Sepasang kedua cukup disebut dengan lebar dan tinggi, atau + kadang-kadang lebar penggambaran dan tinggi penggambaran. Dimensi-dimensi ini + mendefinisikan ukuran tampilan sebenarnya pada layar, saat digambar dan + setelah layout. Nilai-nilai ini mungkin, namun tidak harus, berbeda dengan + lebar dan tinggi terukur. Lebar dan tinggi bisa diperoleh dengan memanggil + {@link android.view.View#getWidth()} dan {@link android.view.View#getHeight()}. +
+ ++ Untuk mengukur dimensinya, tampilan akan memperhitungkan pengisinya (padding). Pengisi + dinyatakan dalam piksel untuk bagian kiri, atas, kanan, dan bawah tampilan. + Pengisi bisa digunakan untuk meng-offset isi tampilan dengan + piksel dalam jumlah tertentu. Misalnya, pengisi kiri sebesar 2 akan mendorong isi tampilan sebanyak + 2 piksel ke kanan dari tepi kiri. Pengisi bisa diatur menggunakan + metode {@link android.view.View#setPadding(int, int, int, int)} dan diketahui dengan memanggil + {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()}, + {@link android.view.View#getPaddingRight()}, dan {@link android.view.View#getPaddingBottom()}. +
+ ++ Meskipun bisa mendefinisikan pengisi, tampilan tidak menyediakan dukungan untuk + margin. Akan tetapi, grup tampilan menyediakan dukungan tersebut. Lihat + {@link android.view.ViewGroup} dan + {@link android.view.ViewGroup.MarginLayoutParams} untuk informasi lebih jauh. +
+ +Untuk informasi selengkapnya tentang dimensi, lihat + Nilai-Nilai Dimensi. +
+ + + + + + + + + + + +Layout Umum
+ +Tiap subkelas dari kelas {@link android.view.ViewGroup} menyediakan cara unik untuk menampilkan +tampilan yang Anda sarangkan di dalamnya. Di bawah ini adalah beberapa tipe layout lebih umum yang dibuat +ke dalam platform Android.
+ +Catatan: Walaupun Anda bisa menyarangkan satu atau beberapa layout dalam +layout lain untuk mendapatkan desain UI, Anda harus berusaha menjaga hierarki layout sedangkal +mungkin. Layout Anda akan digambar lebih cepat jika memiliki layout tersarang yang lebih sedikit (hierarki tampilan yang melebar +lebih baik daripada hierarki tampilan yang dalam).
+ + + + +Layout Linier
+ +Layout yang mengatur anak-anaknya menjadi satu baris horizontal atau vertikal. Layout ini + akan membuat scrollbar jika panjang jendela melebihi panjang layar.
+Layout Relatif
+ +Memungkinkan Anda menentukan lokasi objek anak relatif terhadap satu sama lain (anak A di +kiri anak B) atau terhadap induk (disejajarkan dengan atas induknya).
+Membangun Layout dengan Adaptor
+ +Bila isi layout bersifat dinamis atau tidak dipastikan sebelumnya, Anda bisa menggunakan layout yang menjadi +subkelas {@link android.widget.AdapterView} untuk mengisi layout dengan tampilan saat runtime. +Subkelas dari kelas {@link android.widget.AdapterView} menggunakan {@link android.widget.Adapter} untuk +mengikat data ke layoutnya. {@link android.widget.Adapter} berfungsi sebagai penghubung antara sumber data +dan layout{@link android.widget.AdapterView}—{@link android.widget.Adapter} +menarik data (dari suatu sumber seperti larik (array) atau query database) dan mengubah setiap entri +menjadi tampilan yang bisa ditambahkan ke dalam layout {@link android.widget.AdapterView}.
+ +Layout umum yang didukung oleh adaptor meliputi:
+ + + + + + + +Mengisi tampilan adaptor dengan data
+ +Anda bisa mengisi {@link android.widget.AdapterView} seperti {@link android.widget.ListView} atau +{@link android.widget.GridView} dengan mengikat instance {@link android.widget.AdapterView} ke +{@link android.widget.Adapter}, yang akan mengambil data dari sumber eksternal dan membuat {@link +android.view.View} yang mewakili tiap entri data.
+ +Android menyediakan beberapa subkelas {@link android.widget.Adapter} yang berguna untuk +menarik berbagai jenis data dan membangun tampilan untuk {@link android.widget.AdapterView}. Dua + adaptor yang paling umum adalah:
+ +-
+
- {@link android.widget.ArrayAdapter} +
- Gunakan adaptor ini bila sumber data Anda berupa larik. Secara default, {@link
+android.widget.ArrayAdapter} akan membuat tampilan untuk tiap elemen larik dengan memanggil {@link
+java.lang.Object#toString()} pada tiap elemen dan menempatkan isinya dalam {@link
+android.widget.TextView}.
+
Misalnya, jika Anda memiliki satu larik string yang ingin ditampilkan dalam {@link +android.widget.ListView}, buatlah {@link android.widget.ArrayAdapter} baru dengan konstruktor +untuk menentukan layout setiap string dan larik string:
++ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_list_item_1, myStringArray); +
+Argumen-argumen untuk konstruktor ini adalah:
+-
+
- {@link android.content.Context} aplikasi Anda +
- Layout yang berisi {@link android.widget.TextView} untuk tiap string dalam larik +
- Larik string +
Kemudian tinggal panggil +{@link android.widget.ListView#setAdapter setAdapter()} pada {@link android.widget.ListView} Anda:
++ListView listView = (ListView) findViewById(R.id.listview); +listView.setAdapter(adapter); +
+ +Untuk menyesuaikan penampilan setiap item, Anda bisa mengesampingkan metode {@link +java.lang.Object#toString()} bagi objek dalam larik Anda. Atau, untuk membuat tampilan tiap +elemen selain {@link android.widget.TextView} (misalnya, jika Anda menginginkan +{@link android.widget.ImageView} bagi setiap item larik), perluas kelas {@link +android.widget.ArrayAdapter} dan kesampingkan {@link android.widget.ArrayAdapter#getView +getView()} agar memberikan tipe tampilan yang Anda inginkan bagi tiap item.
+ +
+
+ - {@link android.widget.SimpleCursorAdapter} +
- Gunakan adaptor ini bila data Anda berasal dari {@link android.database.Cursor}. Saat
+menggunakan {@link android.widget.SimpleCursorAdapter}, Anda harus menentukan layout yang akan digunakan untuk tiap
+baris dalam {@link android.database.Cursor} dan di kolom mana di {@link android.database.Cursor}
+harus memasukkan tampilan layout. Misalnya, jika Anda ingin untuk membuat daftar
+nama orang dan nomor telepon, Anda bisa melakukan query yang menghasilkan {@link
+android.database.Cursor} yang berisi satu baris untuk tiap orang dan kolom-kolom untuk nama dan
+nomor. Selanjutnya Anda membuat larik string yang menentukan kolom dari {@link
+android.database.Cursor} yang Anda inginkan dalam layout untuk setiap hasil dan larik integer yang menentukan
+tampilan yang sesuai untuk menempatkan masing-masing kolom:
+
+String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER}; +int[] toViews = {R.id.display_name, R.id.phone_number}; +
+Bila Anda membuat instance {@link android.widget.SimpleCursorAdapter}, teruskan layout yang akan digunakan untuk +setiap hasil, {@link android.database.Cursor} yang berisi hasil tersebut, dan dua larik ini:
++SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); +ListView listView = getListView(); +listView.setAdapter(adapter); +
+{@link android.widget.SimpleCursorAdapter} kemudian membuat tampilan untuk tiap baris dalam +{@link android.database.Cursor} dengan layout yang disediakan dengan memasukkan setiap item {@code +fromColumns} ke dalam tampilan {@code toViews} yang sesuai.
+
Jika, selama aplikasi berjalan, Anda mengubah data sumber yang dibaca oleh +adaptor, maka Anda harus memanggil {@link android.widget.ArrayAdapter#notifyDataSetChanged()}. Hal ini akan +memberi tahu tampilan yang bersangkutan bahwa data telah berubah dan tampilan harus memperbarui dirinya sendiri.
+ + + +Menangani kejadian klik
+ +Anda bisa merespons kejadian klik pada setiap item dalam {@link android.widget.AdapterView} dengan +menerapkan antarmuka {@link android.widget.AdapterView.OnItemClickListener}. Misalnya:
+ ++// Create a message handling object as an anonymous class. +private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, int position, long id) { + // Do something in response to the click + } +}; + +listView.setOnItemClickListener(mMessageClickedHandler); ++ + + diff --git a/docs/html-intl/intl/in/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/in/guide/topics/ui/dialogs.jd new file mode 100644 index 0000000000000000000000000000000000000000..65714a9e4c4dfd1387b2be5f93d25362ed1fdffe --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/dialogs.jd @@ -0,0 +1,798 @@ +page.title=Dialog +page.tags=alertdialog,dialogfragment + +@jd:body + + + +
Dalam dokumen ini
+-
+
- Membuat Fragmen Dialog +
- Membuat Dialog Peringatan + + +
- Meneruskan Kejadian Kembali ke Host Dialog +
- Menampilkan Dialog +
- Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam + + +
- Menutup Dialog +
Kelas-kelas utama
+-
+
- {@link android.app.DialogFragment} +
- {@link android.app.AlertDialog} +
Lihat juga
+-
+
- Panduan desain dialog +
- Picker (dialog Tanggal/Waktu) +
Dialog adalah jendela kecil yang meminta pengguna untuk +membuat keputusan atau memasukkan informasi tambahan. Dialog tidak mengisi layar dan +biasanya digunakan untuk kejadian modal yang mengharuskan pengguna untuk melakukan tindakan sebelum bisa melanjutkan.
+ +Desain Dialog
+Untuk informasi tentang cara mendesain dialog, termasuk saran + untuk bahasa, bacalah panduan Desain dialog.
+Kelas {@link android.app.Dialog} adalah kelas basis untuk dialog, namun Anda +harus menghindari pembuatan instance {@link android.app.Dialog} secara langsung. +Sebagai gantinya, gunakan salah satu subkelas berikut:
+-
+
- {@link android.app.AlertDialog} +
- Dialog yang bisa menampilkan judul, hingga tiga tombol, daftar + item yang dapat dipilih, atau layout custom. +
- {@link android.app.DatePickerDialog} atau {@link android.app.TimePickerDialog} +
- Dialog berisi UI yang sudah didefinisikan dan memungkinkan pengguna memilih tanggal atau waktu. +
Hindari ProgressDialog
+Android menyertakan kelas dialog lain yang disebut +{@link android.app.ProgressDialog} yang menampilkan dialog berisi progress-bar. Akan tetapi, jika Anda +perlu menunjukkan kemajuan pemuatan ataupun kemajuan yang tidak pasti, maka Anda harus mengikuti +panduan desain untuk Kemajuan & +Aktivitas dan menggunakan {@link android.widget.ProgressBar} dalam layout Anda.
+Kelas-kelas ini mendefinisikan gaya dan struktur dialog Anda, namun Anda harus +menggunakan {@link android.support.v4.app.DialogFragment} sebagai kontainer dialog Anda. +Kelas {@link android.support.v4.app.DialogFragment} menyediakan semua kontrol yang Anda +perlukan untuk membuat dialog dan mengelola penampilannya, sebagai ganti memanggil metode +pada objek {@link android.app.Dialog}.
+ +Menggunakan {@link android.support.v4.app.DialogFragment} untuk mengelola dialog +akan memastikan bahwa kelas itu menangani kejadian daur hidup +dengan benar seperti ketika pengguna menekan tombol Back atau memutar layar. Kelas {@link +android.support.v4.app.DialogFragment} juga memungkinkan Anda menggunakan ulang dialog UI sebagai +komponen yang bisa ditanamkan dalam UI yang lebih besar, persis seperti {@link +android.support.v4.app.Fragment} tradisional (seperti saat Anda ingin dialog UI muncul berbeda +pada layar besar dan kecil).
+ +Bagian-bagian berikutnya dalam panduan ini akan menjelaskan cara menggunakan {@link +android.support.v4.app.DialogFragment} yang dikombinasikan dengan objek {@link android.app.AlertDialog} +. Jika Anda ingin membuat picker tanggal atau waktu, Anda harus membaca panduan +Picker.
+ +Catatan:
+Karena kelas {@link android.app.DialogFragment} mulanya ditambahkan pada
+Android 3.0 (API level 11), dokumen ini menjelaskan cara menggunakan kelas {@link
+android.support.v4.app.DialogFragment} yang disediakan bersama Pustaka Dukungan. Dengan menambahkan pustaka ini
+ke aplikasi, Anda bisa menggunakan {@link android.support.v4.app.DialogFragment} dan berbagai
+API lain pada perangkat yang menjalankan Android 1.6 atau yang lebih tinggi. Jika versi minimum yang didukung aplikasi Anda
+adalah API level 11 atau yang lebih tinggi, maka Anda bisa menggunakan versi kerangka kerja {@link
+android.app.DialogFragment}, namun ketahuilah bahwa tautan dalam dokumen ini adalah untuk API
+pustaka dukungan. Saat menggunakan pustaka dukungan,
+pastikan Anda mengimpor kelas android.support.v4.app.DialogFragment
+dan bukan android.app.DialogFragment
.
Membuat Fragmen Dialog
+ +Anda bisa menghasilkan beragam rancangan dialog—termasuk +layout custom dan desain yang dijelaskan dalam panduan desain Dialog +—dengan memperluas +{@link android.support.v4.app.DialogFragment} dan membuat {@link android.app.AlertDialog} +dalam metode callback {@link android.support.v4.app.DialogFragment#onCreateDialog +onCreateDialog()}.
+ +Misalnya, berikut ini sebuah {@link android.app.AlertDialog} dasar yang dikelola dalam +{@link android.support.v4.app.DialogFragment}:
+ ++public class FireMissilesDialogFragment extends DialogFragment { + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Use the Builder class for convenient dialog construction + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // FIRE ZE MISSILES! + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); + // Create the AlertDialog object and return it + return builder.create(); + } +} ++ +
Sekarang, bila Anda membuat instance kelas ini dan memanggil {@link +android.support.v4.app.DialogFragment#show show()} pada objek itu, dialog akan muncul seperti +yang ditampilkan dalam gambar 1.
+ +Bagian berikutnya menjelaskan lebih jauh tentang penggunaan API {@link android.app.AlertDialog.Builder} +untuk membuat dialog.
+ +Bergantung pada seberapa rumit dialog tersebut, Anda bisa menerapkan berbagai metode callback lain +dalam {@link android.support.v4.app.DialogFragment}, termasuk semua +metode daur hidup fragmen dasar. + + + + + +
Membuat Dialog Peringatan
+ + +Kelas {@link android.app.AlertDialog} memungkinkan Anda membuat berbagai desain dialog dan +seringkali satu-satunya kelas dialog yang akan Anda perlukan. +Seperti yang ditampilkan dalam gambar 2, ada tiga area pada dialog peringatan:
+ +-
+
- Judul
+
Area ini opsional dan hanya boleh digunakan bila area konten + ditempati oleh pesan terperinci, daftar, atau layout custom. Jika Anda perlu menyatakan + pesan atau pertanyaan sederhana (seperti dialog dalam gambar 1), Anda tidak memerlukan judul.
+ - Area konten
+
Area ini bisa menampilkan pesan, daftar, atau layout custom lainnya.
+ - Tombol tindakan
+
Tidak boleh ada lebih dari tiga tombol tindakan dalam sebuah dialog.
+
Kelas {@link android.app.AlertDialog.Builder} + menyediakan API yang memungkinkan Anda membuat {@link android.app.AlertDialog} +dengan jenis konten ini, termasuk layout custom.
+ +Untuk membuat {@link android.app.AlertDialog}:
+ ++// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor +AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + +// 2. Chain together various setter methods to set the dialog characteristics +builder.setMessage(R.string.dialog_message) + .setTitle(R.string.dialog_title); + +// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()} +AlertDialog dialog = builder.create(); ++ +
Topik-topik selanjutnya menampilkan cara mendefinisikan berbagai atribut dialog dengan menggunakan +kelas {@link android.app.AlertDialog.Builder}.
+ + + + +Menambahkan tombol
+ +Untuk menambahkan tombol tindakan seperti dalam gambar 2, +panggil metode {@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} dan +{@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()}:
+ ++AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); +// Add the buttons +builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User clicked OK button + } + }); +builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); +// Set other dialog properties +... + +// Create the AlertDialog +AlertDialog dialog = builder.create(); ++ +
Metode set...Button()
mengharuskan adanya judul bagi tombol (disediakan
+oleh suatu sumber daya string) dan
+{@link android.content.DialogInterface.OnClickListener} yang mendefinisikan tindakan yang diambil
+bila pengguna menekan tombol.
Ada tiga macam tombol tindakan yang Anda bisa tambahkan:
+-
+
- Positif +
- Anda harus menggunakan tipe ini untuk menerima dan melanjutkan tindakan (tindakan "OK"). +
- Negatif +
- Anda harus menggunakan tipe ini untuk membatalkan tindakan. +
- Netral +
- Anda harus menggunakan tipe ini bila pengguna mungkin tidak ingin melanjutkan tindakan, + namun tidak ingin membatalkan. Tipe ini muncul antara tombol positif dan +tombol negatif. Misalnya, tindakan bisa berupa "Ingatkan saya nanti". +
Anda hanya bisa menambahkan salah satu tipe tombol ke {@link +android.app.AlertDialog}. Artinya, Anda tidak bisa memiliki lebih dari satu tombol "positif".
+ + + +Menambahkan daftar
+ +Ada tiga macam daftar yang tersedia pada API {@link android.app.AlertDialog}:
+-
+
- Daftar pilihan tunggal biasa +
- Daftar pilihan tunggal persisten (tombol radio) +
- Daftar pilihan ganda persisten (kotak cek) +
Untuk membuat daftar pilihan tunggal seperti dalam gambar 3, +gunakan metode {@link android.app.AlertDialog.Builder#setItems setItems()}:
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.pick_color) + .setItems(R.array.colors_array, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // The 'which' argument contains the index position + // of the selected item + } + }); + return builder.create(); +} ++ +
Karena daftar muncul dalam area konten dialog, +dialog tidak bisa menampilkan pesan dan daftar sekaligus dan Anda harus menetapkan judul untuk +dialog dengan {@link android.app.AlertDialog.Builder#setTitle setTitle()}. +Untuk menentukan item daftar, panggil {@link +android.app.AlertDialog.Builder#setItems setItems()}, dengan meneruskan larik. +Atau, Anda bisa menetapkan daftar menggunakan {@link +android.app.AlertDialog.Builder#setAdapter setAdapter()}. Hal ini memungkinkan Anda mendukung daftar +dengan data dinamis (seperti dari database) dengan menggunakan {@link android.widget.ListAdapter}.
+ +Jika Anda memilih untuk mendukung daftar dengan {@link android.widget.ListAdapter}, +selalu gunakan sebuah {@link android.support.v4.content.Loader} agar konten dimuat +secara asinkron. Hal ini dijelaskan lebih jauh dalam panduan +Membuat Layout +dengan Adaptor dan Loader +.
+ +Catatan: Secara default, menyentuh sebuah item daftar akan menutup dialog, +kecuali Anda menggunakan salah satu daftar pilihan persisten berikut ini.
+ +Menambahkan daftar pilihan ganda atau pilihan tunggal persisten
+ +Untuk menambahkan daftar item pilihan ganda (kotak cek) atau +item pilihan tunggal (tombol radio), gunakan masing-masing metode +{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()}, atau +{@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()}.
+ +Misalnya, berikut ini cara membuat daftar pilihan ganda seperti +yang ditampilkan dalam gambar 4 yang menyimpan item +yang dipilih dalam {@link java.util.ArrayList}:
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + mSelectedItems = new ArrayList(); // Where we track the selected items + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Set the dialog title + builder.setTitle(R.string.pick_toppings) + // Specify the list array, the items to be selected by default (null for none), + // and the listener through which to receive callbacks when items are selected + .setMultiChoiceItems(R.array.toppings, null, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, + boolean isChecked) { + if (isChecked) { + // If the user checked the item, add it to the selected items + mSelectedItems.add(which); + } else if (mSelectedItems.contains(which)) { + // Else, if the item is already in the array, remove it + mSelectedItems.remove(Integer.valueOf(which)); + } + } + }) + // Set the action buttons + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // User clicked OK, so save the mSelectedItems results somewhere + // or return them to the component that opened the dialog + ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + ... + } + }); + + return builder.create(); +} ++ +
Walaupun daftar tradisional maupun daftar dengan tombol radio +menyediakan tindakan "pilihan tunggal", Anda harus menggunakan {@link +android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} jika ingin mempertahankan pilihan pengguna. +Yakni, jika nanti membuka dialog lagi untuk menunjukkan pilihan pengguna, +maka Anda perlu membuat daftar dengan tombol radio.
+ + + + + +Membuat Layout Custom
+ +Jika Anda menginginkan layout custom dalam dialog, buatlah layout dan tambahkan ke +{@link android.app.AlertDialog} dengan memanggil {@link +android.app.AlertDialog.Builder#setView setView()} pada objek {@link +android.app.AlertDialog.Builder} Anda.
+ +Secara default, layout custom akan mengisi jendela dialog, namun Anda masih bisa +menggunakan metode {@link android.app.AlertDialog.Builder} untuk menambahkan tombol dan judul.
+ +Misalnya, berikut ini adalah file layout untuk dialog dalam Gambar 5:
+ + ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ImageView + android:src="@drawable/header_logo" + android:layout_width="match_parent" + android:layout_height="64dp" + android:scaleType="center" + android:background="#FFFFBB33" + android:contentDescription="@string/app_name" /> + <EditText + android:id="@+id/username" + android:inputType="textEmailAddress" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="4dp" + android:hint="@string/username" /> + <EditText + android:id="@+id/password" + android:inputType="textPassword" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="16dp" + android:fontFamily="sans-serif" + android:hint="@string/password"/> +</LinearLayout> ++ +
Tip: Secara default, bila Anda telah mengatur sebuah elemen {@link android.widget.EditText} +agar menggunakan tipe input {@code "textPassword"}, keluarga font akan diatur ke spasi tunggal, sehingga +Anda harus mengubah keluarga font ke {@code "sans-serif"} sehingga kedua bidang teks menggunakan +gaya font yang cocok.
+ +Untuk memekarkan layout dalam {@link android.support.v4.app.DialogFragment} Anda, +ambillah {@link android.view.LayoutInflater} dengan +{@link android.app.Activity#getLayoutInflater()} dan panggil +{@link android.view.LayoutInflater#inflate inflate()}, dengan parameter pertama +adalah ID sumber daya layout dan parameter kedua adalah tampilan induk untuk layout. +Selanjutnya Anda bisa memanggil {@link android.app.AlertDialog#setView setView()} +untuk menempatkan layout dalam dialog.
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + LayoutInflater inflater = getActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + builder.setView(inflater.inflate(R.layout.dialog_signin, null)) + // Add action buttons + .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // sign in the user ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + LoginDialogFragment.this.getDialog().cancel(); + } + }); + return builder.create(); +} ++ +
Tip: Jika Anda menginginkan dialog custom, +Anda bisa menampilkan {@link android.app.Activity} sebagai dialog +daripada menggunakan API {@link android.app.Dialog}. Cukup buat satu aktivitas dan mengatur temanya ke +{@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog} +di elemen manifes {@code +<activity>}:
+ ++<activity android:theme="@android:style/Theme.Holo.Dialog" > ++
Demikian saja. Aktivitas sekarang ditampilkan dalam jendela dialog, sebagai ganti layar penuh.
+Meneruskan Kejadian Kembali ke Host Dialog
+ +Bila pengguna menyentuh salah satu tombol tindakan dialog atau memilih satu item dari daftarnya, +{@link android.support.v4.app.DialogFragment} Anda bisa melakukan sendiri tindakan yang diperlukan +, namun sering kali Anda perlu mengirim kejadian itu ke aktivitas atau fragmen yang +membuka dialog. Caranya, definisikan antarmuka dengan sebuah metode untuk masing-masing tipe kejadian klik. +Lalu implementasikan antarmuka itu dalam komponen host yang akan +menerima kejadian tindakan dari dialog.
+ +Misalnya, berikut ini adalah {@link android.support.v4.app.DialogFragment} yang mendefinisikan +antarmuka yang akan digunakan untuk mengirim kembali suatu kejadian ke aktivitas host:
+ ++public class NoticeDialogFragment extends DialogFragment { + + /* The activity that creates an instance of this dialog fragment must + * implement this interface in order to receive event callbacks. + * Each method passes the DialogFragment in case the host needs to query it. */ + public interface NoticeDialogListener { + public void onDialogPositiveClick(DialogFragment dialog); + public void onDialogNegativeClick(DialogFragment dialog); + } + + // Use this instance of the interface to deliver action events + NoticeDialogListener mListener; + + // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + mListener = (NoticeDialogListener) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + ... +} ++ +
Aktivitas yang menjadi host dialog tersebut akan membuat instance dialog +dengan konstruktor fragmen dialog dan menerima kejadian dialog +melalui implementasi antarmuka {@code NoticeDialogListener}:
+ ++public class MainActivity extends FragmentActivity + implements NoticeDialogFragment.NoticeDialogListener{ + ... + + public void showNoticeDialog() { + // Create an instance of the dialog fragment and show it + DialogFragment dialog = new NoticeDialogFragment(); + dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); + } + + // The dialog fragment receives a reference to this Activity through the + // Fragment.onAttach() callback, which it uses to call the following methods + // defined by the NoticeDialogFragment.NoticeDialogListener interface + @Override + public void onDialogPositiveClick(DialogFragment dialog) { + // User touched the dialog's positive button + ... + } + + @Override + public void onDialogNegativeClick(DialogFragment dialog) { + // User touched the dialog's negative button + ... + } +} ++ +
Karena aktivitas host mengimplementasikan {@code NoticeDialogListener}—yang +diberlakukan oleh metode callback {@link android.support.v4.app.Fragment#onAttach onAttach()} +di atas,—fragmen dialog bisa menggunakan +metode callback antarmuka untuk mengirimkan kejadian klik ke aktivitas:
+ ++public class NoticeDialogFragment extends DialogFragment { + ... + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Build the dialog and set up the button click handlers + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the positive button event back to the host activity + mListener.onDialogPositiveClick(NoticeDialogFragment.this); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the negative button event back to the host activity + mListener.onDialogNegativeClick(NoticeDialogFragment.this); + } + }); + return builder.create(); + } +} ++ + + +
Menampilkan Dialog
+ +Bila Anda ingin menampilkan dialog, buatlah instance {@link +android.support.v4.app.DialogFragment} dan panggil {@link android.support.v4.app.DialogFragment#show +show()}, dengan meneruskan {@link android.support.v4.app.FragmentManager} dan nama tag +untuk fragmen dialognya.
+ +Anda bisa mendapatkan {@link android.support.v4.app.FragmentManager} dengan memanggil +{@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} dari + {@link android.support.v4.app.FragmentActivity} atau {@link +android.support.v4.app.Fragment#getFragmentManager()} dari {@link +android.support.v4.app.Fragment}. Misalnya:
+ ++public void confirmFireMissiles() { + DialogFragment newFragment = new FireMissilesDialogFragment(); + newFragment.show(getSupportFragmentManager(), "missiles"); +} ++ +
Argumen kedua, {@code "missiles"}, adalah nama tag unik yang digunakan sistem untuk menyimpan +dan memulihkan status fragmen bila diperlukan. Tag ini juga memungkinkan Anda mendapatkan handle ke +fragmen dengan memanggil {@link android.support.v4.app.FragmentManager#findFragmentByTag +findFragmentByTag()}.
+ + + + +Menampilkan Dialog sebagai Layar Penuh atau Fragmen Tertanam
+ +Anda mungkin memiliki desain UI yang di dalamnya Anda ingin UI muncul sebagai dialog dalam beberapa +situasi, namun sebagai layar penuh atau fragmen tertanam dalam situasi lain (mungkin bergantung pada apakah +perangkat memiliki layar besar atau layar kecil). Kelas {@link android.support.v4.app.DialogFragment} +menawarkan fleksibilitas ini karena masih bisa berperilaku sebagai {@link +android.support.v4.app.Fragment} yang bisa ditanamkan.
+ +Akan tetapi, dalam hal ini Anda tidak bisa menggunakan {@link android.app.AlertDialog.Builder AlertDialog.Builder} +atau objek {@link android.app.Dialog} lain untuk membangun dialog. Jika +Anda ingin {@link android.support.v4.app.DialogFragment} +bisa ditanamkan, Anda harus mendefinisikan dialog UI dalam layout, lalu memuat layout itu dalam metode callback +{@link android.support.v4.app.DialogFragment#onCreateView +onCreateView()}.
+ +Berikut ini adalah contoh {@link android.support.v4.app.DialogFragment} yang bisa muncul sebagai
+dialog maupun fragmen yang bisa ditanamkan (menggunakan layout bernama purchase_items.xml
):
+public class CustomDialogFragment extends DialogFragment { + /** The system calls this to get the DialogFragment's layout, regardless + of whether it's being displayed as a dialog or an embedded fragment. */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout to use as dialog or embedded fragment + return inflater.inflate(R.layout.purchase_items, container, false); + } + + /** The system calls this only when creating the layout in a dialog. */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // The only reason you might override this method when using onCreateView() is + // to modify any dialog characteristics. For example, the dialog includes a + // title by default, but your custom layout might not need it. So here you can + // remove the dialog title, but you must call the superclass to get the Dialog. + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } +} ++ +
Dan berikut ini adalah beberapa kode yang memutuskan apakah akan menampilkan fragmen sebagai dialog +atau UI layar penuh, berdasarkan ukuran layar:
+ ++public void showDialog() { + FragmentManager fragmentManager = getSupportFragmentManager(); + CustomDialogFragment newFragment = new CustomDialogFragment(); + + if (mIsLargeLayout) { + // The device is using a large layout, so show the fragment as a dialog + newFragment.show(fragmentManager, "dialog"); + } else { + // The device is smaller, so show the fragment fullscreen + FragmentTransaction transaction = fragmentManager.beginTransaction(); + // For a little polish, specify a transition animation + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + // To make it fullscreen, use the 'content' root view as the container + // for the fragment, which is always the root view for the activity + transaction.add(android.R.id.content, newFragment) + .addToBackStack(null).commit(); + } +} ++ +
Untuk informasi selengkapnya tentang melakukan transaksi fragmen, lihat panduan +Fragmen.
+ +Dalam contoh ini, nilai boolean mIsLargeLayout
menentukan apakah perangkat saat ini
+harus menggunakan desain layout besar aplikasi (dan dengan demikian menampilkan fragmen ini sebagai dialog, bukan
+layar penuh). Cara terbaik untuk mengatur jenis boolean ini adalah mendeklarasikan
+nilai sumber daya boolean
+dengan nilai sumber daya alternatif untuk berbagai ukuran layar. Misalnya, berikut ini adalah dua
+versi sumber daya boolean untuk berbagai ukuran layar:
+<!-- Default boolean values --> +<resources> + <bool name="large_layout">false</bool> +</resources> ++ + +
+<!-- Large screen boolean values --> +<resources> + <bool name="large_layout">true</bool> +</resources> ++ +
Selanjutnya Anda bisa menetapkan nilai {@code mIsLargeLayout} selama +metode {@link android.app.Activity#onCreate onCreate()} aktivitas:
+ ++boolean mIsLargeLayout; + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mIsLargeLayout = getResources().getBoolean(R.bool.large_layout); +} ++ + + +
Menampilkan aktivitas sebagai dialog pada layar besar
+ +Sebagai ganti menampilkan dialog berupa UI layar penuh saat di layar kecil, Anda bisa memperoleh +hasil yang sama dengan menampilkan {@link android.app.Activity} sebagai dialog saat di +layar besar. Pendekatan yang Anda pilih bergantung pada desain aplikasi, namun +menampilkan aktivitas sebagai dialog sering kali berguna bila aplikasi Anda sudah didesain untuk +layar kecil dan Anda ingin meningkatkan pengalaman pada tablet dengan menampilkan aktivitas berjangka pendek +sebagai dialog.
+ +Untuk menampilkan aktivitas sebagai dialog hanya saat di layar besar, +terapkan tema {@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge} + pada elemen manifes {@code +<activity>}:
+ ++<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" > ++ +
Untuk informasi selengkapnya tentang mengatur gaya aktivitas Anda dengan tema, lihat panduan Gaya dan Tema.
+ + + +Menutup Dialog
+ +Bila pengguna menyentuh salah satu tombol tindakan yang dibuat dengan +{@link android.app.AlertDialog.Builder}, sistem akan menutup dialog untuk Anda.
+ +Sistem juga menutup dialog bila pengguna menyentuh sebuah item dalam daftar dialog, kecuali +bila daftar itu menggunakan tombol radio atau kotak cek. Jika tidak, Anda bisa menutup dialog secara manual +dengan memanggil {@link android.support.v4.app.DialogFragment#dismiss()} pada {@link +android.support.v4.app.DialogFragment} Anda.
+ +Jika Anda perlu melakukan +tindakan tertentu saat dialog menghilang, Anda bisa menerapkan metode {@link +android.support.v4.app.DialogFragment#onDismiss onDismiss()} dalam {@link +android.support.v4.app.DialogFragment} Anda.
+ +Anda juga bisa membatalkan dialog. Ini merupakan kejadian khusus yang menunjukkan bahwa pengguna +secara eksplisit meninggalkan dialog tanpa menyelesaikan tugas. Hal ini terjadi jika pengguna menekan tombol +Back, menyentuh layar di luar area dialog, +atau jika Anda secara eksplisit memanggil {@link android.app.Dialog#cancel()} pada {@link +android.app.Dialog} (seperti saat merespons tombol "Cancel" dalam dialog).
+ +Seperti yang ditampilkan dalam contoh di atas, Anda bisa merespons kejadian batal dengan menerapkan +{@link android.support.v4.app.DialogFragment#onCancel onCancel()} dalam kelas {@link +android.support.v4.app.DialogFragment} Anda.
+ +Catatan: Sistem akan memanggil +{@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} pada tiap kejadian yang +memanggil callback {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Akan tetapi, +jika Anda memanggil {@link android.app.Dialog#dismiss Dialog.dismiss()} atau {@link +android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()}, +sistem akan memanggil {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} namun +bukan {@link android.support.v4.app.DialogFragment#onCancel onCancel()}. Jadi biasanya Anda harus +memanggil {@link android.support.v4.app.DialogFragment#dismiss dismiss()} bila pengguna menekan tombol +positif dalam dialog untuk menghilangkan tampilan dialog.
+ + diff --git a/docs/html-intl/intl/in/guide/topics/ui/menus.jd b/docs/html-intl/intl/in/guide/topics/ui/menus.jd new file mode 100644 index 0000000000000000000000000000000000000000..2cd3e6a33aa5ed330072ce116e9a0b91b4df6eb7 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/menus.jd @@ -0,0 +1,1031 @@ +page.title=Menu +parent.title=Antarmuka Pengguna +parent.link=index.html +@jd:body + +Dalam dokumen ini
+-
+
- Mendefinisikan Menu dalam XML +
- Membuat Menu Opsi + + +
- Membuat Menu Kontekstual + + +
- Membuat Menu Popup + + +
- Membuat Grup Menu + + +
- Menambahkan Item Menu Berdasarkan Intent + + +
Kelas-kelas utama
+-
+
- {@link android.view.Menu} +
- {@link android.view.MenuItem} +
- {@link android.view.ContextMenu} +
- {@link android.view.ActionMode} +
Lihat juga
+ +Menu adalah komponen antarmuka pengguna yang lazim dalam banyak tipe aplikasi. Untuk menyediakan pengalaman pengguna yang sudah akrab +dan konsisten, Anda harus menggunakan API {@link android.view.Menu} untuk menyajikan +tindakan dan opsi lain dalam aktivitas kepada pengguna.
+ +Mulai dengan Android 3.0 (API level 11), perangkat berbasis Android tidak perlu lagi +menyediakan tombol Menu tersendiri. Dengan perubahan ini, aplikasi Android harus bermigrasi dari +dependensi pada panel menu 6 item biasa, dan sebagai ganti menyediakan action-bar untuk menyajikan +berbagai tindakan pengguna yang lazim.
+ +Walaupun desain dan pengalaman pengguna untuk sebagian item menu telah berubah, semantik untuk mendefinisikan +serangkaian tindakan dan opsi masih berdasarkan pada API {@link android.view.Menu}. Panduan ini +menampilkan cara membuat tiga tipe dasar penyajian menu atau tindakan pada semua +versi Android:
+ +-
+
- Menu opsi dan action-bar +
- Menu opsi adalah kumpulan item menu utama untuk suatu
+aktivitas. Inilah tempat Anda harus menempatkan tindakan yang berdampak global pada aplikasi, seperti
+"Cari", "Tulis email", dan "Pengaturan".
+
Jika Anda mengembangkan aplikasi untuk Android 2.3 atau yang lebih rendah, pengguna bisa +menampilkan panel menu opsi dengan menekan tombol Menu.
+Pada Android 3.0 dan yang lebih tinggi, item menu opsi disajikan melalui action-bar sebagai kombinasi item tindakan +di layar dan opsi overflow. Mulai dengan Android 3.0, tombol Menu dihilangkan (sebagian +perangkat +tidak memilikinya), sehingga Anda harus bermigrasi ke penggunaan action-bar untuk menyediakan akses ke tindakan dan +opsi lainnya.
+Lihat bagian tentang Membuat Menu Opsi.
+
+
+ - Menu konteks dan mode tindakan kontekstual + +
- Menu konteks adalah menu mengambang yang muncul saat
+pengguna mengklik lama pada suatu elemen. Menu ini menyediakan tindakan yang memengaruhi konten atau
+bingkai konteks yang dipilih.
+
Saat mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, sebagai gantinya Anda harus menggunakan mode tindakan kontekstual untuk memungkinkan tindakan pada konten yang dipilih. Mode ini menampilkan +item tindakan yang memengaruhi konten yang dipilih dalam baris di bagian atas layar dan memungkinkan pengguna +memilih beberapa item sekaligus.
+Lihat bagian tentang Membuat Menu Kontekstual.
+
+
+ - Menu popup +
- Menu popup menampilkan daftar item secara vertikal yang dipasang pada tampilan yang
+memanggil menu. Ini cocok untuk menyediakan kelebihan tindakan yang terkait dengan konten tertentu atau
+untuk menyediakan opsi bagi bagian kedua dari suatu perintah. Tindakan di menu popup
+tidak boleh memengaruhi secara langsung konten yang bersangkutan—yang diperuntukkan bagi
+tindakan kontekstual. Melainkan, menu popup adalah untuk tindakan tambahan yang terkait dengan wilayah konten dalam
+aktivitas Anda.
+
Lihat bagian tentang Membuat Menu Popup.
+
+
Mendefinisikan Menu dalam XML
+ +Untuk semua tipe menu, Android menyediakan sebuah format XML standar untuk mendefinisikan item menu. +Sebagai ganti membuat menu dalam kode aktivitas, Anda harus mendefinisikan menu dan semua itemnya dalam +sumber daya menu XML. Anda kemudian bisa +memekarkan sumber daya menu (memuatnya sebagai objek {@link android.view.Menu}) dalam aktivitas atau +fragmen.
+ +Menggunakan sumber daya menu adalah praktik yang baik karena beberapa alasan:
+-
+
- Memvisualisasikan struktur menu dalam XML menjadi lebih mudah. +
- Cara ini memisahkan konten untuk menu dari kode perilaku aplikasi Anda. +
- Cara ini memungkinkan Anda membuat konfigurasi menu alternatif untuk berbagai versi platform, +ukuran layar, dan konfigurasi lainnya dengan memanfaatkan kerangka kerja sumber daya aplikasi. +
Untuk mendefinisikan menu, buatlah sebuah file XML dalam direktori res/menu/
+proyek dan buat menu dengan elemen-elemen berikut:
-
+
<menu>
+ - Mendefinisikan {@link android.view.Menu}, yang merupakan sebuah kontainer untuk item menu. Elemen
+
<menu>
harus menjadi simpul akar untuk file dan bisa menampung salah satu atau beberapa dari elemen +<item>
dan<group>
.
+
+ <item>
+ - Membuat {@link android.view.MenuItem}, yang mewakili satu item menu. Elemen ini
+bisa berisi elemen
<menu>
tersarang guna untuk membuat submenu.
+
+ <group>
+ - Kontainer opsional tak terlihat untuk elemen-elemen {@code <item>}. Kontainer ini memungkinkan Anda +mengelompokkan item menu untuk berbagi properti seperti status aktif dan visibilitas. Untuk informasi +selengkapnya, lihat bagian tentang Membuat Grup Menu. +
Berikut ini adalah contoh menu bernama game_menu.xml
:
+<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/new_game" + android:icon="@drawable/ic_new_game" + android:title="@string/new_game" + android:showAsAction="ifRoom"/> + <item android:id="@+id/help" + android:icon="@drawable/ic_help" + android:title="@string/help" /> +</menu> ++ +
Elemen <item>
mendukung beberapa atribut yang bisa Anda gunakan untuk mendefinisikan penampilan dan perilaku
+item. Item menu di atas mencakup atribut berikut:
-
+
- {@code android:id} +
- ID sumber daya unik bagi item, yang memungkinkan aplikasi mengenali item +bila pengguna memilihnya. +
- {@code android:icon} +
- Acuan ke drawable untuk digunakan sebagai ikon item. +
- {@code android:title} +
- Acuan ke string untuk digunakan sebagai judul item. +
- {@code android:showAsAction} +
- Menetapkan waktu dan cara item ini muncul sebagai item tindakan di action-bar. +
Ini adalah atribut-atribut terpenting yang harus Anda gunakan, namun banyak lagi yang tersedia. +Untuk informasi tentang semua atribut yang didukung, lihat dokumen Sumber Daya Menu.
+ +Anda bisa menambahkan submenu ke sebuah item di menu (kecuali submenu) apa saja dengan menambahkan elemen {@code <menu>} +sebagai anak {@code <item>}. Submenu berguna saat aplikasi Anda memiliki banyak +fungsi yang bisa ditata ke dalam topik-topik, seperti item dalam sebuah baris menu aplikasi PC (File, +Edit, Lihat, dsb.). Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/file" + android:title="@string/file" > + <!-- "file" submenu --> + <menu> + <item android:id="@+id/create_new" + android:title="@string/create_new" /> + <item android:id="@+id/open" + android:title="@string/open" /> + </menu> + </item> +</menu> ++ +
Untuk menggunakan menu dalam aktivitas, Anda perlu memekarkan sumber daya menu (mengonversi sumber daya XML +menjadi objek yang bisa diprogram) dengan menggunakan {@link android.view.MenuInflater#inflate(int,Menu) +MenuInflater.inflate()}. Di bagian berikut, Anda akan melihat cara memekarkan menu untuk tiap +tipe menu.
+ + + +Membuat Menu Opsi
+ +Menu opsi adalah tempat Anda harus menyertakan tindakan dan opsi lain yang relevan dengan +konteks aktivitas saat ini, seperti "Cari", "Tulis email", dan "Pengaturan".
+ +Tempat item dalam menu opsi muncul di layar bergantung pada versi aplikasi yang Anda +kembangkan:
+ +-
+
- Jika Anda mengembangkan aplikasi untuk Android 2.3.x (API level 10) atau +yang lebih rendah, konten menu opsi muncul pada bagian bawah layar bila pengguna +menekan tombol Menu, seperti yang ditampilkan dalam gambar 1. Bila dibuka, bagian yang terlihat pertama adalah +menu +ikon, yang menampung hingga enam item menu. Jika menu Anda menyertakan lebih dari enam item, Android akan meletakkan +item keenam dan sisanya ke dalam menu kelebihan, yang bisa dibuka pengguna dengan memilih +More. + +
- Jika Anda mengembangkan aplikasi untuk Android 3.0 (API level 11) dan
+yang lebih tinggi, item menu opsi tersedia dalam action-bar. Secara default, sistem
+meletakkan semua item dalam kelebihan tindakan, yang bisa ditampilkan pengguna dengan ikon kelebihan tindakan di
+sisi kanan action-bar (atau dengan menekan tombol Menu perangkat, jika tersedia). Untuk
+mengaktifkan
+akses cepat ke tindakan penting, Anda bisa mempromosikan beberapa item agar muncul pada action-bar dengan menambahkan
+{@code android:showAsAction="ifRoom"} ke elemen-elemen {@code <item>} yang bersangkutan (lihat gambar
+2).
Untuk informasi selengkapnya tentang item tindakan dan perilaku action-bar lainnya, lihat panduan Action-Bar.
+Catatan: Sekalipun Anda tidak mengembangkan aplikasi untuk Android 3.0 atau +yang lebih tinggi, Anda bisa membuat layout action-bar sendiri untuk mendapatkan efek serupa. Untuk contoh cara +mendukung versi Android yang lebih lama dengan action-bar, lihat contoh Kompatibilitas Action-Bar +.
+
+
Anda bisa mendeklarasikan item untuk menu opsi dari subkelas {@link android.app.Activity} +atau subkelas {@link android.app.Fragment}. Jika aktivitas maupun fragmen Anda +mendeklarasikan item menu opsi, keduanya akan dikombinasikan dalam UI. Item aktivitas akan muncul +lebih dahulu, diikuti oleh item tiap fragmen sesuai dengan urutan penambahan fragmen ke +aktivitas. Jika perlu, Anda bisa menyusun ulang item menu dengan atribut {@code android:orderInCategory} +dalam setiap {@code <item>} yang perlu Anda pindahkan.
+ +Untuk menetapkan menu opsi suatu aktivitas, kesampingkan {@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragmen-fragmen menyediakan +callback {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} sendiri). Dalam metode ini +, Anda bisa memekarkan sumber daya menu (yang didefinisikan dalam XML) menjadi {@link +android.view.Menu} yang disediakan dalam callback. Misalnya:
+ ++@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = {@link android.app.Activity#getMenuInflater()}; + inflater.inflate(R.menu.game_menu, menu); + return true; +} ++ +
Anda juga bisa menambahkan item menu dengan menggunakan {@link android.view.Menu#add(int,int,int,int) +add()} dan mengambil item dengan {@link android.view.Menu#findItem findItem()} untuk merevisi propertinya +dengan API {@link android.view.MenuItem}.
+ +Jika Anda mengembangkan aplikasi untuk Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} untuk membuat menu opsi +bila pengguna membuka menu untuk pertama kali. Jika Anda mengembangkan aplikasi untuk Android 3.0 dan yang lebih tinggi, +sistem akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} saat +memulai aktivitas, untuk menampilkan item menu pada action-bar.
+ + + +Menangani kejadian klik
+ +Bila pengguna memilih item dari menu opsi (termasuk item tindakan dalam action-bar), +sistem akan memanggil metode {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()} aktivitas Anda. Metode ini meneruskan {@link android.view.MenuItem} yang dipilih. Anda +bisa mengidentifikasi item dengan memanggil {@link android.view.MenuItem#getItemId()}, yang menghasilkan +ID unik untuk item menu itu (yang didefinisikan oleh atribut {@code android:id} dalam sumber daya menu atau dengan +integer yang diberikan ke metode {@link android.view.Menu#add(int,int,int,int) add()}). Anda bisa mencocokkan +ID ini dengan item menu yang diketahui untuk melakukan tindakan yang sesuai. Misalnya:
+ ++@Override +public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.new_game: + newGame(); + return true; + case R.id.help: + showHelp(); + return true; + default: + return super.onOptionsItemSelected(item); + } +} ++ +
Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu +, Anda harus memanggil implementasi superkelas {@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (implementasi default +menghasilkan false).
+ +Jika aktivitas Anda menyertakan fragmen, sistem akan memanggil lebih dahulu {@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} untuk aktivitas, kemudian +untuk setiap fragmen (sesuai dengan urutan penambahan fragmen) hingga satu fragmen mengembalikan +{@code true} atau semua fragmen telah dipanggil.
+ +Tip: Android 3.0 menambahkan kemampuan mendefinisikan perilaku on-click +untuk item menu dalam XML, dengan menggunakan atribut {@code android:onClick}. Nilai atribut +harus berupa nama metode yang didefinisikan aktivitas dengan menggunakan menu. Metode +harus bersifat publik dan menerima satu parameter {@link android.view.MenuItem}—bila sistem +memanggilnya, metode ini akan meneruskan item menu yang dipilih. Untuk informasi selengkapnya dan contoh, lihat dokumen Sumber Daya Menu.
+ +Tip: Jika aplikasi Anda berisi banyak aktivitas dan +sebagian menyediakan menu opsi yang sama, pertimbangkan untuk membuat +aktivitas yang tidak mengimplementasikan apa-apa kecuali metode {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} dan {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()}. Kemudian perluas kelas ini untuk setiap aktivitas yang harus menggunakan +menu opsi yang sama. Dengan begini, Anda bisa mengelola satu set kode untuk menangani tindakan menu +dan setiap kelas turunan mewarisi perilaku menu. +Jika ingin menambahkan item menu ke salah satu aktivitas turunan, +kesampingkan {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} dalam aktivitas itu. Panggil {@code super.onCreateOptionsMenu(menu)} agar +item menu asli dibuat, kemudian tambahkan item menu yang baru dengan {@link +android.view.Menu#add(int,int,int,int) menu.add()}. Anda juga bisa mengesampingkan +perilaku superkelas untuk setiap item menu.
+ + +Mengubah item menu saat runtime
+ +Setelah sistem memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()}, sistem akan mempertahankan instance {@link android.view.Menu} yang Anda tempatkan dan +tidak akan memanggil {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} +lagi kecuali menu diinvalidkan karena suatu alasan. Akan tetapi, Anda harus menggunakan {@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} hanya untuk membuat +status menu awal dan tidak untuk membuat perubahan selama daur hidup aktivitas.
+ +Jika Anda ingin mengubah menu opsi berdasarkan +kejadian yang terjadi selama daur hidup aktivitas, Anda bisa melakukannya dalam metode +{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}. Metode ini +meneruskan objek {@link android.view.Menu} sebagaimana adanya saat ini sehingga Anda bisa mengubahnya, +seperti menambah, menghapus, atau menonaktifkan item. (Fragmen juga menyediakan callback {@link +android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()}.)
+ +Pada Android 2.3.x dan yang lebih rendah, sistem akan memanggil {@link +android.app.Activity#onPrepareOptionsMenu(Menu) +onPrepareOptionsMenu()} setiap kali pengguna membuka menu opsi (menekan tombol Menu +).
+ +Pada Android 3.0 dan yang lebih tinggi, menu opsi dianggap sebagai selalu terbuka saat item menu +ditampilkan pada action-bar. Bila ada kejadian dan Anda ingin melakukan pembaruan menu, Anda harus +memanggil {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} untuk meminta +sistem memanggil {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.
+ +Catatan: +Anda tidak boleh mengubah item dalam menu opsi berdasarkan {@link android.view.View} yang saat ini +difokus. Saat dalam mode sentuh (bila pengguna tidak sedang menggunakan trackball atau d-pad), tampilan +tidak bisa mengambil fokus, sehingga Anda tidak boleh menggunakan fokus sebagai dasar untuk mengubah +item dalam menu opsi. Jika Anda ingin menyediakan item menu yang peka konteks pada {@link +android.view.View}, gunakan Menu Konteks.
+ + + + +Membuat Menu Kontekstual
+ +Menu kontekstual menawarkan tindakan yang memengaruhi item atau bingkai konteks tertentu dalam UI. Anda +bisa menyediakan menu konteks untuk setiap tampilan, tetapi menu ini paling sering digunakan untuk item pada {@link +android.widget.ListView}, {@link android.widget.GridView}, atau kumpulan tampilan lainnya yang bisa digunakan +pengguna untuk melakukan tindakan langsung pada setiap item.
+ +Ada dua cara menyediakan tindakan kontekstual:
+-
+
- Dalam menu konteks mengambang. Menu muncul sebagai +daftar item menu mengambang (serupa dengan dialog) bila pengguna mengklik lama (menekan dan +menahan) pada tampilan yang mendeklarasikan dukungan bagi menu konteks. Pengguna bisa melakukan +tindakan kontekstual pada satu item untuk setiap kalinya. + +
- Dalam mode tindakan kontekstual. Mode ini adalah implementasi sistem +{@link android.view.ActionMode} yang menampilkan action-bar kontekstual di bagian atas +layar dengan item tindakan yang memengaruhi item(-item) yang dipilih. Bila mode ini aktif, pengguna +bisa melakukan tindakan pada beberapa item sekaligus (jika aplikasi Anda mengizinkannya). +
Catatan: Mode tindakan kontekstual tersedia pada Android 3.0 (API +level 11) dan yang lebih tinggi dan merupakan teknik yang lebih disukai untuk menampilkan tindakan kontekstual bila +tersedia. Jika aplikasi Anda mendukung versi yang lebih rendah daripada 3.0, maka Anda harus mundur ke +menu konteks mengambang pada perangkat-perangkat itu.
+ + +Membuat menu konteks mengambang
+ +Untuk menyediakan menu konteks mengambang:
+-
+
- Daftarkan {@link android.view.View} ke menu konteks yang harus dikaitkan dengan
+memanggil {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} dan teruskan
+{@link android.view.View} ke menu itu.
+
Jika aktivitas Anda menggunakan {@link android.widget.ListView} atau {@link android.widget.GridView} dan +Anda ingin setiap item untuk menyediakan menu konteks yang sama, daftarkan semua item ke menu konteks dengan +meneruskan {@link android.widget.ListView} atau {@link android.widget.GridView} ke {@link +android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.
+
+
+ - Implementasikan metode {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+dalam {@link android.app.Activity} atau {@link android.app.Fragment} Anda.
+
Bila tampilan yang terdaftar menerima kejadian klik-lama, sistem akan memanggil metode {@link +android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} +Anda. Inilah tempat Anda mendefinisikan item menu, biasanya dengan memekarkan sumber daya menu. Misalnya: +
++@Override +public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); +} +
+ +{@link android.view.MenuInflater} memungkinkan Anda untuk memekarkan menu konteks sumber daya menu. Parameter metode callback +menyertakan {@link android.view.View} +yang dipilih pengguna dan objek {@link android.view.ContextMenu.ContextMenuInfo} yang menyediakan +informasi tambahan tentang item yang dipilih. Jika aktivitas Anda memiliki beberapa tampilan yang masing-masingnya menyediakan +menu konteks berbeda, Anda bisa menggunakan parameter ini untuk menentukan menu konteks yang harus +dimekarkan.
+
+
+ - Implementasikan {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}.
+
Bila pengguna memilih item menu, sistem akan memanggil metode ini sehingga Anda bisa melakukan +tindakan yang sesuai. Misalnya:
+ ++@Override +public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + switch (item.getItemId()) { + case R.id.edit: + editNote(info.id); + return true; + case R.id.delete: + deleteNote(info.id); + return true; + default: + return super.onContextItemSelected(item); + } +} +
+ +Metode {@link android.view.MenuItem#getItemId()} melakukan query ID untuk +item menu yang dipilih, yang harus Anda tetapkan ke setiap item menu dalam XML dengan menggunakan atribut {@code +android:id}, seperti yang ditampilkan di bagian tentang Mendefinisikan Menu dalam +XML.
+ +Bila Anda berhasil menangani sebuah item menu, kembalikan {@code true}. Jika tidak menangani item menu, +Anda harus meneruskan item menu ke implementasi superkelas. Jika aktivitas Anda menyertakan fragmen, +aktivitas akan menerima callback ini lebih dahulu. Dengan memanggil superkelas bila tidak ditangani, sistem +meneruskan kejadian ke metode callback di setiap fragmen, satu per satu (sesuai dengan urutan +penambahan fragmen) hingga {@code true} atau {@code false} dikembalikan. (Implementasi default +untuk {@link android.app.Activity} dan {@code android.app.Fragment} mengembalikan {@code +false}, sehingga Anda harus selalu memanggil superkelas bila tidak ditangani.)
+
+
Menggunakan mode tindakan kontekstual
+ +Mode tindakan kontekstual adalah implementasi sistem {@link android.view.ActionMode} yang +memfokuskan interaksi pengguna pada upaya melakukan tindakan kontekstual. Bila seorang +pengguna mengaktifkan mode ini dengan memilih item, action-bar kontekstual akan muncul di bagian atas +layar untuk menampilkan tindakan yang bisa dilakukan pengguna pada item yang dipilih saat ini. Selagi mode ini +diaktifkan, pengguna bisa memilih beberapa item (jika Anda mengizinkan), membatalkan pilihan item, dan melanjutkan +penelusuran dalam aktivitas (sebanyak yang ingin Anda izinkan). Mode tindakan dinonaktifkan +dan action-bar kontekstual menghilang bila pengguna membatalkan pilihan semua item, menekan tombol BACK, +atau memilih tindakan Done di sisi kiri action-bar.
+ +Catatan: Action-bar kontekstual tidak harus +terkait dengan action-bar. Action-bar ini beroperasi +secara independen, walaupun action-bar kontekstual secara visual mengambil alih +posisi action-bar.
+ +Jika Anda mengembangkan aplikasi untuk Android 3.0 (API level 11) atau yang lebih tinggi, Anda +biasanya harus menggunakan mode tindakan kontekstual untuk menampilkan tindakan kontekstual, sebagai ganti menu konteks mengambang.
+ +Untuk tampilan yang menyediakan tindakan kontekstual, Anda biasanya harus memanggil mode tindakan kontekstual +pada salah satu dari dua kejadian (atau keduanya):
+-
+
- Pengguna mengklik-lama pada tampilan. +
- Pengguna memilih kotak cek atau komponen UI yang serupa dalam tampilan. +
Cara aplikasi memanggil mode tindakan kontekstual dan mendefinisikan perilaku setiap +tindakan bergantung pada desain Anda. Pada dasarnya ada dua desain:
+-
+
- Untuk tindakan kontekstual pada tampilan individual dan tak didukung. +
- Untuk tindakan kontekstual batch pada grup item dalam {@link +android.widget.ListView} atau {@link android.widget.GridView} (memungkinkan pengguna memilih beberapa +item dan melakukan tindakan pada semua item itu). +
Bagian berikut ini menjelaskan penyiapan yang diperlukan untuk setiap skenario.
+ + +Mengaktifkan mode tindakan kontekstual untuk tampilan individual
+ +Jika Anda ingin memanggil mode tindakan kontekstual hanya bila pengguna memilih +tampilan tertentu, Anda harus:
+-
+
- Mengimplementasikan antarmuka {@link android.view.ActionMode.Callback}. Dalam metode callback-nya, Anda +bisa menetapkan tindakan untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan +menangani kejadian daur hidup lainnya untuk mode tindakan itu. +
- Memanggil {@link android.app.Activity#startActionMode startActionMode()} bila Anda ingin menampilkan +action-bar (seperti saat pengguna mengklik-lama pada tampilan). +
Misalnya:
+ +-
+
- Implementasikan antarmuka {@link android.view.ActionMode.Callback ActionMode.Callback}:
+
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { + + // Called when the action mode is created; startActionMode() was called + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate a menu resource providing context menu items + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); + return true; + } + + // Called each time the action mode is shown. Always called after onCreateActionMode, but + // may be called multiple times if the mode is invalidated. + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; // Return false if nothing is done + } + + // Called when the user selects a contextual menu item + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + shareCurrentItem(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + // Called when the user exits the action mode + @Override + public void onDestroyActionMode(ActionMode mode) { + mActionMode = null; + } +}; +
+ +Perhatikan bahwa kejadian callback ini hampir persis sama dengan callback untuk menu opsi, hanya saja setiap callback ini juga meneruskan objek {@link +android.view.ActionMode} yang terkait dengan kejadian. Anda bisa menggunakan API {@link +android.view.ActionMode} untuk membuat berbagai perubahan pada CAB, seperti merevisi judul dan +subjudul dengan {@link android.view.ActionMode#setTitle setTitle()} dan {@link +android.view.ActionMode#setSubtitle setSubtitle()} (berguna untuk menunjukkan jumlah item +yang dipilih).
+ +Juga perhatikan bahwa contoh di atas mengatur variabel {@code mActionMode} ke nol bila +mode tindakan dimusnahkan. Dalam langkah berikutnya, Anda akan melihat cara variabel diinisialisasi dan kegunaan menyimpan +variabel anggota dalam aktivitas atau fragmen.
+
+
+ - Panggil {@link android.app.Activity#startActionMode startActionMode()} untuk mengaktifkan
+mode tindakan kontekstual bila sesuai, seperti saat merespons klik-lama pada {@link
+android.view.View}:
+
+
+someView.setOnLongClickListener(new View.OnLongClickListener() { + // Called when the user long-clicks on someView + public boolean onLongClick(View view) { + if (mActionMode != null) { + return false; + } + + // Start the CAB using the ActionMode.Callback defined above + mActionMode = getActivity().startActionMode(mActionModeCallback); + view.setSelected(true); + return true; + } +}); +
+ +Bila Anda memanggil {@link android.app.Activity#startActionMode startActionMode()}, sistem akan mengembalikan +{@link android.view.ActionMode} yang dibuat. Dengan menyimpannya dalam variabel anggota, Anda bisa +membuat perubahan ke action-bar kontekstual sebagai respons terhadap kejadian lainnya. Dalam contoh di atas, +{@link android.view.ActionMode} digunakan untuk memastikan bahwa instance {@link android.view.ActionMode} +tidak dibuat kembali jika sudah aktif, dengan memeriksa apakah anggota bernilai nol sebelum memulai +mode tindakan.
+
+
Mengaktifkan tindakan kontekstual batch dalam ListView atau GridView
+ +Jika Anda memiliki sekumpulan item dalam {@link android.widget.ListView} atau {@link +android.widget.GridView} (atau ekstensi {@link android.widget.AbsListView} lainnya) dan ingin +mengizinkan pengguna melakukan tindakan batch, Anda harus:
+ +-
+
- Mengimplementasikan antarmuka {@link android.widget.AbsListView.MultiChoiceModeListener} dan mengaturnya +untuk grup tampilan dengan {@link android.widget.AbsListView#setMultiChoiceModeListener +setMultiChoiceModeListener()}. Dalam metode callback listener, Anda bisa menetapkan tindakan +untuk action-bar kontekstual, merespons kejadian klik pada item tindakan, dan menangani callback lainnya +yang diwarisi dari antarmuka {@link android.view.ActionMode.Callback}. + +
- Panggil {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} dengan argumen {@link +android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL}. +
Misalnya:
+ ++ListView listView = getListView(); +listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); +listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, + long id, boolean checked) { + // Here you can do something when items are selected/de-selected, + // such as update the title in the CAB + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // Respond to clicks on the actions in the CAB + switch (item.getItemId()) { + case R.id.menu_delete: + deleteSelectedItems(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate the menu for the CAB + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context, menu); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Here you can make any necessary updates to the activity when + // the CAB is removed. By default, selected items are deselected/unchecked. + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // Here you can perform updates to the CAB due to + // an {@link android.view.ActionMode#invalidate} request + return false; + } +}); ++ +
Demikian saja. Kini bila pengguna memilih item dengan klik-lama, sistem akan memanggil metode {@link +android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()} +dan menampilkan action-bar kontekstual bersama tindakan yang ditetapkan. Saat +action-bar kontekstual terlihat, pengguna bisa memilih item tambahan.
+ +Dalam beberapa kasus di mana tindakan kontekstual menyediakan item tindakan umum, Anda mungkin +ingin menambahkan kotak cek atau elemen UI serupa yang memungkinkan pengguna memilih item, karena pengguna +mungkin tidak menemukan perilaku klik-lama. Bila pengguna memilih kotak cek itu, Anda +bisa memanggil mode tindakan kontekstual dengan mengatur item daftar yang bersangkutan ke +status diberi tanda cek dengan {@link android.widget.AbsListView#setItemChecked setItemChecked()}.
+ + + + +Membuat Menu Popup
+ +Gambar 4. Menu popup dalam aplikasi Gmail, dikaitkan pada +tombol kelebihan di sudut kanan atas.
+{@link android.widget.PopupMenu} adalah menu modal yang dikaitkan pada {@link android.view.View}. +Menu ini muncul di bawah tampilan jangkar jika ada ruang, atau di atas tampilan jika tidak ada. Menu ini berguna untuk:
+-
+
- Menyediakan menu bergaya kelebihan (overflow) untuk tindakan yang berkaitan dengan konten tertentu (seperti
+header email Gmail, yang ditampilkan dalam gambar 4).
+
Catatan: Ini tidak sama dengan menu konteks, yang umumnya +untuk tindakan yang memengaruhi konten yang dipilih. Untuk tindakan yang memengaruhi +konten yang dipilih, gunakan mode tindakan kontekstual atau menu konteks mengambang.
+ - Menyediakan bagian kedua dari kalimat perintah (seperti tombol bertanda "Tambah" +yang menghasilkan menu popup dengan berbagai opsi "Tambah"). +
- Menyediakan daftar menurun yang serupa dengan {@link android.widget.Spinner} yang tidak mempertahankan +pilihan persisten. +
Catatan: {@link android.widget.PopupMenu} tersedia dengan API +level 11 dan yang lebih tinggi.
+ +Jika Anda mendefinisikan menu dalam XML, berikut ini adalah cara Anda menampilkan menu popup:
+-
+
- Buat instance {@link android.widget.PopupMenu} bersama konstruktornya, yang mengambil +aplikasi saat ini {@link android.content.Context} dan {@link android.view.View} yang akan menjadi tempat mengaitkan +menu. +
- Gunakan {@link android.view.MenuInflater} untuk memekarkan sumber daya menu Anda ke dalam objek {@link +android.view.Menu} yang dikembalikan oleh {@link +android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. Pada API level 14 ke atas, Anda bisa menggunakan +{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} sebagai gantinya. +
- Panggil {@link android.widget.PopupMenu#show() PopupMenu.show()}. +
Misalnya, berikut ini adalah tombol dengan atribut {@link android.R.attr#onClick android:onClick} +yang menampilkan menu popup:
+ ++<ImageButton + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_overflow_holo_dark" + android:contentDescription="@string/descr_overflow_button" + android:onClick="showPopup" /> ++ +
Aktivitas nanti bisa menampilkan menu popup seperti ini:
+ ++public void showPopup(View v) { + PopupMenu popup = new PopupMenu(this, v); + MenuInflater inflater = popup.getMenuInflater(); + inflater.inflate(R.menu.actions, popup.getMenu()); + popup.show(); +} ++ +
Dalam API level 14 dan yang lebih tinggi, Anda bisa menggabungkan dua baris yang memekarkan menu dengan {@link +android.widget.PopupMenu#inflate PopupMenu.inflate()}.
+ +Menu akan menghilang bila pengguna memilih item atau menyentuh di luar +area menu. Anda bisa mendengarkan kejadian menghilangkan dengan menggunakan {@link +android.widget.PopupMenu.OnDismissListener}.
+ +Menangani kejadian klik
+ +Untuk melakukan suatu +tindakan bila pengguna memilih item menu, Anda harus mengimplementasikan antarmuka {@link +android.widget.PopupMenu.OnMenuItemClickListener} dan mendaftarkannya pada {@link +android.widget.PopupMenu} dengan memanggil {@link android.widget.PopupMenu#setOnMenuItemClickListener +setOnMenuItemclickListener()}. Bila pengguna memilih item, sistem akan memanggil callback {@link +android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} dalam +antarmuka Anda.
+ +Misalnya:
+ ++public void showMenu(View v) { + PopupMenu popup = new PopupMenu(this, v); + + // This activity implements OnMenuItemClickListener + popup.setOnMenuItemClickListener(this); + popup.inflate(R.menu.actions); + popup.show(); +} + +@Override +public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.archive: + archive(item); + return true; + case R.id.delete: + delete(item); + return true; + default: + return false; + } +} ++ + +
Membuat Grup Menu
+ +Grup menu adalah sekumpulan item menu yang sama-sama memiliki ciri (trait) tertentu. Dengan grup, Anda +bisa:
+-
+
- Menampilkan atau menyembunyikan semua item dengan {@link android.view.Menu#setGroupVisible(int,boolean) +setGroupVisible()} +
- Mengaktifkan atau mennonaktifkan semua item dengan {@link android.view.Menu#setGroupEnabled(int,boolean) +setGroupEnabled()} +
- Menetapkan apakah semua item bisa diberi tanda cek dengan {@link +android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()} +
Anda bisa membuat grup dengan menyarangkan elemen-elemen {@code <item>} dalam elemen {@code <group>} +dalam sumber daya menu atau dengan menetapkan ID grup dengan metode {@link +android.view.Menu#add(int,int,int,int) add()}.
+ +Berikut ini adalah contoh sumber daya menu yang berisi sebuah grup:
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_save" + android:icon="@drawable/menu_save" + android:title="@string/menu_save" /> + <!-- menu group --> + <group android:id="@+id/group_delete"> + <item android:id="@+id/menu_archive" + android:title="@string/menu_archive" /> + <item android:id="@+id/menu_delete" + android:title="@string/menu_delete" /> + </group> +</menu> ++ +
Item yang berada dalam grup akan muncul pada level yang sama dengan item pertama—ketiga item +dalam menu adalah bersaudara. Akan tetapi, Anda bisa memodifikasi ciri kedua +item dalam grup dengan mengacu ID grup dan menggunakan metode yang tercantum di atas. Sistem +juga tidak akan memisahkan item yang telah dikelompokkan. Misalnya, jika Anda mendeklarasikan {@code +android:showAsAction="ifRoom"} untuk tiap item, item tersebut akan muncul dalam +action-bar atau dalam kelebihan tindakan.
+ + +Menggunakan item menu yang bisa diberi tanda cek
+ +Menu bisa digunakan sebagai antarmuka untuk mengaktifkan dan menonaktifkan opsi, menggunakan kotak cek untuk +opsi mandiri, atau tombol radio untuk grup +opsi yang saling eksklusif. Gambar 5 menampilkan submenu dengan item yang bisa diberi tanda cek dengan +tombol radio.
+ +Catatan: Item menu dalam Icon Menu (dari menu opsi) tidak bisa +menampilkan kotak cek atau tombol radio. Jika Anda memilih untuk membuat item dalam Icon Menu yang bisa diberi tanda cek, +Anda harus menandai status diberi tanda cek secara manual dengan menukar ikon dan/atau teks +tiap kali statusnya berubah.
+ +Anda bisa mendefinisikan perilaku yang bisa diberi tanda cek untuk tiap item menu dengan menggunakan atribut {@code +android:checkable} dalam elemen {@code <item>}, atau untuk seluruh grup dengan +atribut {@code android:checkableBehavior} dalam elemen {@code <group>}. Misalnya +, semua item dalam grup menu ini bisa diberi tanda cek dengan tombol radio:
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:checkableBehavior="single"> + <item android:id="@+id/red" + android:title="@string/red" /> + <item android:id="@+id/blue" + android:title="@string/blue" /> + </group> +</menu> ++ +
Atribut {@code android:checkableBehavior} menerima: +
-
+
- {@code single} +
- Hanya satu item dari grup ini yang bisa diberi tanda cek (tombol radio) +
- {@code all} +
- Semua item bisa diberi tanda cek (kotak cek) +
- {@code none} +
- Tidak ada item yang bisa diberi tanda cek +
Anda bisa menerapkan status diberi tanda cek default pada suatu item dengan menggunakan atribut {@code android:checked} dalam +elemen {@code <item>} dan mengubahnya dalam kode dengan metode {@link +android.view.MenuItem#setChecked(boolean) setChecked()}.
+ +Bila item yang bisa diberi tanda cek dipilih, sistem akan memanggil metode callback setiap item yang dipilih +(seperti {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}). Di sinilah +Anda harus mengatur status kotak cek itu, karena kotak cek atau tombol radio tidak +mengubah statusnya secara otomatis. Anda bisa melakukan query status saat ini suatu item (seperti sebelum +pengguna memilihnya) dengan {@link android.view.MenuItem#isChecked()} kemudian mengatur status diberi tanda cek dengan +{@link android.view.MenuItem#setChecked(boolean) setChecked()}. Misalnya:
+ ++@Override +public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.vibrate: + case R.id.dont_vibrate: + if (item.isChecked()) item.setChecked(false); + else item.setChecked(true); + return true; + default: + return super.onOptionsItemSelected(item); + } +} ++ +
Jika Anda tidak mengatur status diberi tanda cek dengan cara ini, maka status item (kotak cek atau +tombol radio) yang terlihat tidak akan +berubah bila pengguna memilihnya. Bila Anda telah mengatur status, aktivitas akan menjaga status diberi tanda cek +suatu item sehingga bila nanti pengguna membuka menu, status diberi tanda cek yang Anda +atur akan terlihat.
+ +Catatan: +Item menu yang bisa diberi tanda cek dimaksudkan untuk digunakan hanya atas dasar per sesi dan tidak disimpan setelah +aplikasi dimusnahkan. Jika Anda memiliki pengaturan aplikasi yang ingin disimpan untuk pengguna, +Anda harus menyimpan data dengan menggunakan Shared Preferences.
+ + + +Menambahkan Item Menu Berdasarkan Intent
+ +Kadang-kadang Anda ingin supaya item menu menjalankan aktivitas dengan menggunakan {@link android.content.Intent} +(baik aktivitas berada dalam aplikasi Anda maupun di aplikasi lain). Bila Anda mengetahui intent +yang ingin digunakan dan memiliki item menu tertentu yang harus memulai intent, Anda bisa mengeksekusi +intent dengan {@link android.app.Activity#startActivity(Intent) startActivity()} selama +metode callback bila-item-dipilih yang sesuai (seperti callback {@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}).
+ +Akan tetapi, jika Anda tidak yakin apakah perangkat pengguna +berisi aplikasi yang menangani intent, maka menambahkan item menu yang memanggilnya bisa mengakibatkan +item menu tidak berfungsi, karena intent tidak bisa diterjemahkan menjadi +aktivitas. Untuk mengatasi hal ini, Android memungkinkan Anda menambahkan item menu secara dinamis ke menu +bila Android menemukan aktivitas pada perangkat yang menangani intent Anda.
+ +Untuk menambahkan item menu berdasarkan aktivitas tersedia yang menerima intent:
+-
+
- Definisikan +intent dengan kategori {@link android.content.Intent#CATEGORY_ALTERNATIVE} dan/atau +{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE}, plus kebutuhan lainnya. +
- Panggil {@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +Menu.addIntentOptions()}. Android kemudian akan mencari setiap aplikasi yang bisa melakukan intent +dan menambahkannya ke menu Anda. +
Jika tidak ada aplikasi terinstal +yang memenuhi intent, maka tidak ada item menu yang ditambahkan.
+ +Catatan: +{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} digunakan untuk menangani +elemen yang saat ini dipilih pada layar. Jadi, metode hanya digunakan saat membuat Menu dalam {@link +android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) +onCreateContextMenu()}.
+ +Misalnya:
+ ++@Override +public boolean onCreateOptionsMenu(Menu menu){ + super.onCreateOptionsMenu(menu); + + // Create an Intent that describes the requirements to fulfill, to be included + // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. + Intent intent = new Intent(null, dataUri); + intent.addCategory(Intent.CATEGORY_ALTERNATIVE); + + // Search and populate the menu with acceptable offering applications. + menu.addIntentOptions( + R.id.intent_group, // Menu group to which new items will be added + 0, // Unique item ID (none) + 0, // Order for the items (none) + this.getComponentName(), // The current activity name + null, // Specific items to place first (none) + intent, // Intent created above that describes our requirements + 0, // Additional flags to control items (none) + null); // Array of MenuItems that correlate to specific items (none) + + return true; +}+ +
Untuk setiap aktivitas yang diketahui menyediakan filter intent yang cocok dengan intent yang didefinisikan, item menu
+akan ditambahkan, menggunakan nilai dalam filter intent android:label
sebagai
+judul item menu dan ikon aplikasi sebagai ikon item menu. Metode
+{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()} mengembalikan jumlah item menu yang ditambahkan.
Catatan: Bila Anda memanggil {@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +addIntentOptions()}, metode ini akan mengesampingkan setiap dan semua item menu menurut grup menu yang ditetapkan dalam argumen +pertama.
+ + +Memungkinkan aktivitas Anda ditambahkan ke menu lain
+ +Anda juga bisa menawarkan layanan aktivitas Anda pada aplikasi lainnya, sehingga +aplikasi Anda bisa disertakan dalam menu aplikasi lain (membalik peran yang dijelaskan di atas).
+ +Agar bisa dimasukkan dalam menu aplikasi lain, Anda perlu mendefinisikan +filter intent seperti biasa, tetapi pastikan menyertakan nilai-nilai {@link android.content.Intent#CATEGORY_ALTERNATIVE} +dan/atau {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} untuk +kategori filter intent. Misalnya:
++<intent-filter label="@string/resize_image"> + ... + <category android:name="android.intent.category.ALTERNATIVE" /> + <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> + ... +</intent-filter> ++ +
Baca selengkapnya tentang penulisan filter intent dalam dokumen +Intent dan Filter Intent.
+ +Untuk contoh aplikasi yang menggunakan teknik ini, lihat contoh kode +Note +Pad.
diff --git a/docs/html-intl/intl/in/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/in/guide/topics/ui/notifiers/notifications.jd new file mode 100644 index 0000000000000000000000000000000000000000..9033b9f744f3ec34d46dc4ca5d6b180c92e55b5a --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/notifiers/notifications.jd @@ -0,0 +1,979 @@ +page.title=Pemberitahuan +@jd:body + +Dalam dokumen ini
+-
+
- Pertimbangan Desain +
- Membuat Pemberitahuan + + +
- Mengelola Pemberitahuan + + +
- Mempertahankan Navigasi saat Memulai Aktivitas + + +
- Menampilkan Kemajuan dalam Pemberitahuan + + +
- Metadata Pemberitahuan +
- Pemberitahuan Pendahuluan +
- Pemberitahuan Layar Kunci + +
- Layout Pemberitahuan Custom +
Kelas-kelas utama
+-
+
- {@link android.app.NotificationManager} +
- {@link android.support.v4.app.NotificationCompat} +
Video
+-
+
- + + Pemberitahuan di 4.1 + +
Lihat juga
+-
+
- + Desain Android: Pemberitahuan + +
+ Pemberitahuan adalah pesan yang bisa Anda tampilkan kepada pengguna di luar + UI normal aplikasi. Bila Anda memberi tahu sistem untuk mengeluarkan pemberitahuan, pemberitahuan akan muncul lebih dahulu sebagai ikon dalam + area pemberitahuan. Untuk melihat detail pemberitahuan, pengguna membuka + laci pemberitahuan. Baik area pemberitahuan maupun laci pemberitahuan + adalah area-area yang dikontrol sistem yang bisa dilihat pengguna kapan saja. +
+ + + + + +Catatan: Kecuali disebutkan, panduan ini mengacu pada +kelas {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} +dalam Support Library versi 4. +Kelas {@link android.app.Notification.Builder Notification.Builder} telah ditambahkan pada Android +3.0 (API level 11).
+ +Pertimbangan Desain
+ +Pemberitahuan, sebagai bagian penting dari antarmuka pengguna Android, memiliki panduan desainnya sendiri. +Perubahan desain materi yang diperkenalkan dalam Android 5.0 (API level 21) adalah sangat +penting, dan Anda harus meninjau pelatihan Desain Bahan +untuk informasi selengkapnya. Untuk mengetahui cara mendesain pemberitahuan dan interaksinya, bacalah panduan desain +Pemberitahuan.
+ +Membuat Pemberitahuan
+ +Anda menetapkan informasi dan tindakan UI bagi pemberitahuan dalam +objek {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}. +Untuk membuat pemberitahuan itu sendiri, panggil +{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()}, +yang akan mengembalikan objek {@link android.app.Notification} berisi spesifikasi Anda. Untuk mengeluarkan +pemberitahuan, Anda meneruskan objek {@link android.app.Notification} ke sistem dengan memanggil +{@link android.app.NotificationManager#notify NotificationManager.notify()}.
+ +Isi pemberitahuan yang diperlukan
++ Objek {@link android.app.Notification} harus berisi yang berikut ini: +
+-
+
- + Ikon kecil, yang diatur dengan + {@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()} + +
- + Judul, yang diatur dengan + {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} + +
- + Teks detail, yang diatur dengan + {@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()} + +
Isi dan pengaturan pemberitahuan opsional
++ Semua isi dan pengaturan pemberitahuan lainnya bersifat opsional. Untuk mengetahui selengkapnya tentang semua itu, + lihat dokumentasi acuan untuk {@link android.support.v4.app.NotificationCompat.Builder}. +
+ +Tindakan pemberitahuan
++ Walaupun bersifat opsional, Anda harus menambahkan setidaknya satu tindakan pada pemberitahuan. + Tindakan memungkinkan pengguna beralih langsung dari pemberitahuan ke + {@link android.app.Activity} dalam aplikasi Anda, tempat pengguna bisa melihat satu atau beberapa kejadian + atau melakukan pekerjaan lebih jauh. +
++ Pemberitahuan bisa menyediakan beberapa tindakan sekaligus. Anda harus selalu mendefinisikan tindakan yang + akan diaktifkan bila pengguna mengklik pemberitahuan; biasanya tindakan ini akan membuka + {@link android.app.Activity} dalam aplikasi Anda. Anda juga bisa menambahkan tombol pada pemberitahuan + yang melakukan tindakan tambahan seperti mendiamkan alarm atau segera merespons + pesan teks; fitur ini tersedia mulai Android 4.1. Jika menggunakan tombol tindakan tambahan, Anda + juga harus membuat fungsionalitasnya tersedia dalam {@link android.app.Activity} di aplikasi Anda; lihat + bagian Menangani kompatibilitas untuk detail selengkapnya. +
++ Dalam {@link android.app.Notification}, tindakan itu sendiri didefinisikan oleh + {@link android.app.PendingIntent} berisi + {@link android.content.Intent} yang memulai + {@link android.app.Activity} dalam aplikasi Anda. Untuk mengaitkan + {@link android.app.PendingIntent} dengan gestur, panggil metode + {@link android.support.v4.app.NotificationCompat.Builder} yang sesuai. Misalnya, jika ingin memulai + {@link android.app.Activity} bila pengguna mengklik teks pemberitahuan pada + laci pemberitahuan, tambahkan {@link android.app.PendingIntent} dengan memanggil + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}. +
++ Memulai {@link android.app.Activity} bila pengguna mengklik pemberitahuan adalah + skenario tindakan yang paling umum. Anda juga bisa memulai {@link android.app.Activity} bila pengguna + menghilangkan pemberitahuan. Dalam Android 4.1 dan yang lebih baru, Anda bisa memulai + {@link android.app.Activity} dari tombol tindakan. Untuk mengetahui selengkapnya, bacalah panduan acuan untuk + {@link android.support.v4.app.NotificationCompat.Builder}. +
+ +Prioritas pemberitahuan
++ Jika diinginkan, Anda bisa mengatur prioritas pemberitahuan. Prioritas berfungsi + sebagai petunjuk bagi UI perangkat tentang cara menampilkan pemberitahuan. + Untuk mengatur prioritas pemberitahuan, panggil {@link + android.support.v4.app.NotificationCompat.Builder#setPriority(int) + NotificationCompat.Builder.setPriority()} dan teruskan salah satu konstanta prioritas {@link + android.support.v4.app.NotificationCompat}. Ada + lima level prioritas, mulai dari {@link + android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) hingga {@link + android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); jika tidak diatur, + prioritas default akan ditetapkan {@link + android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0). +
+Untuk informasi tentang mengatur level prioritas, lihat "Mengatur + dan mengelola prioritas pemberitahuan dengan benar" dalam panduan +Desain Pemberitahuan. +
+ +Membuat pemberitahuan sederhana
++ Cuplikan berikut mengilustrasikan pemberitahuan sederhana yang menetapkan aktivitas untuk dibuka bila + pengguna mengklik pemberitahuan. Perhatikan bahwa kode ini membuat + objek {@link android.support.v4.app.TaskStackBuilder} dan menggunakannya untuk membuat + {@link android.app.PendingIntent} untuk tindakan. Pola ini dijelaskan secara lebih detail + di bagian + Mempertahankan Navigasi saat Memulai Aktivitas: +
++NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("My notification") + .setContentText("Hello World!"); +// Creates an explicit intent for an Activity in your app +Intent resultIntent = new Intent(this, ResultActivity.class); + +// The stack builder object will contain an artificial back stack for the +// started Activity. +// This ensures that navigating backward from the Activity leads out of +// your application to the Home screen. +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack for the Intent (but not the Intent itself) +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent that starts the Activity to the top of the stack +stackBuilder.addNextIntent(resultIntent); +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); +mBuilder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// mId allows you to update the notification later on. +mNotificationManager.notify(mId, mBuilder.build()); ++
Demikian saja. Pengguna Anda kini telah diberi tahu.
+ +Menerapkan layout yang diperluas pada pemberitahuan
++ Agar pemberitahuan muncul dalam tampilan yang diperluas, buat dahulu + objek {@link android.support.v4.app.NotificationCompat.Builder} dengan opsi tampilan normal + yang Anda inginkan. Berikutnya, panggil {@link android.support.v4.app.NotificationCompat.Builder#setStyle + Builder.setStyle()} dengan objek layout yang diperluas sebagai argumennya. +
++ Ingatlah bahwa pemberitahuan yang diperluas tidak tersedia pada platform-platform sebelum Android 4.1. Untuk + mengetahui cara menangani pemberitahuan untuk Android 4.1 dan untuk platform-platform sebelumnya, bacalah + bagian Menangani kompatibilitas. +
++ Misalnya, cuplikan kode berikut memperagakan cara mengubah pemberitahuan yang dibuat + dalam cuplikan sebelumnya untuk menggunakan layout yang diperluas: +
++NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("Event tracker") + .setContentText("Events received") +NotificationCompat.InboxStyle inboxStyle = + new NotificationCompat.InboxStyle(); +String[] events = new String[6]; +// Sets a title for the Inbox in expanded layout +inboxStyle.setBigContentTitle("Event tracker details:"); +... +// Moves events into the expanded layout +for (int i=0; i < events.length; i++) { + + inboxStyle.addLine(events[i]); +} +// Moves the expanded layout object into the notification object. +mBuilder.setStyle(inBoxStyle); +... +// Issue the notification here. ++ +
Menangani kompatibilitas
+ ++ Tidak semua fitur pemberitahuan tersedia untuk versi tertentu, walaupun + metode untuk mengaturnya ada dalam kelas pustaka dukungan + {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}. + Misalnya, tombol tindakan, yang bergantung pada pemberitahuan yang diperluas, hanya muncul pada Android + 4.1 dan lebih tinggi, karena pemberitahuan yang diperluas itu sendiri hanya tersedia pada + Android 4.1 dan yang lebih tinggi. +
++ Untuk memastikan kompatibilitas terbaik, buatlah pemberitahuan dengan + {@link android.support.v4.app.NotificationCompat NotificationCompat} dan subkelasnya, + khususnya {@link android.support.v4.app.NotificationCompat.Builder + NotificationCompat.Builder}. Selain itu, ikutilah proses ini bila Anda mengimplementasikan pemberitahuan: +
+-
+
-
+ Sediakan semua fungsionalitas pemberitahuan kepada semua pengguna, terlepas dari versi
+ yang mereka gunakan. Caranya, pastikan semua fungsionalitas tersedia dari
+ {@link android.app.Activity} dalam aplikasi Anda. Anda mungkin perlu menambahkan sebuah
+ {@link android.app.Activity} baru untuk melakukannya.
+
+ Misalnya, jika Anda ingin menggunakan + {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} untuk + menyediakan kontrol yang menghentikan dan memulai pemutaran media, implementasikan dahulu + kontrol ini pada {@link android.app.Activity} dalam aplikasi Anda. +
+
+ - + Pastikan semua pengguna bisa memperoleh fungsionalitas dalam {@link android.app.Activity}, + dengan memulainya bila pengguna mengklik pemberitahuan. Caranya, + buatlah {@link android.app.PendingIntent} + untuk {@link android.app.Activity}. Panggil + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent + setContentIntent()} untuk menambahkan {@link android.app.PendingIntent} pada pemberitahuan. + +
- + Kini tambahkan fitur pemberitahuan diperluas yang ingin Anda gunakan pada pemberitahuan. Ingatlah + bahwa setiap fungsionalitas yang Anda tambahkan juga harus tersedia dalam {@link android.app.Activity} + yang akan dimulai bila pengguna mengklik pemberitahuan. + +
Mengelola Pemberitahuan
++ Bila perlu mengeluarkan pemberitahuan beberapa kali untuk tipe kejadian yang sama, +hindari membuat pemberitahuan yang sama sekali baru. Sebagai gantinya, Anda harus mempertimbangkan untuk memperbarui + pemberitahuan sebelumnya, baik dengan mengubah sebagian nilainya atau dengan menambahkan nilai, atau keduanya. +
++ Misalnya, Gmail akan memberi tahu pengguna bila ada email baru dengan menambah hitungan + pesan tidak terbaca dan dengan menambahkan rangkuman tiap email ke pemberitahuan. Ini disebut dengan + "stacking" (menumpuk) pemberitahuan; hal ini dijelaskan lebih detail dalam panduan + Desain Pemberitahuan. +
++ Catatan: Fitur Gmail ini mensyaratkan layout "kotak masuk" diperluas, yang merupakan + bagian dari fitur pemberitahuan diperluas yang tersedia mulai Android 4.1. +
++ Bagian berikut menjelaskan cara memperbarui pemberitahuan dan cara menghapusnya. +
+Memperbarui pemberitahuan
++ Untuk menyiapkan pemberitahuan agar bisa diperbarui, keluarkan pemberitahuan bersama ID pemberitahuan dengan + memanggil {@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}. + Untuk memperbarui pemberitahuan ini setelah Anda + mengeluarkan, memperbarui, atau membuat objek {@link android.support.v4.app.NotificationCompat.Builder}, + buat objek {@link android.app.Notification} darinya, dan keluarkan + {@link android.app.Notification} bersama ID yang sama dengan yang Anda gunakan sebelumnya. Jika + pemberitahuan sebelumnya tetap terlihat, sistem akan memperbaruinya dari konten + objek {@link android.app.Notification}. Jika pemberitahuan sebelumnya telah dihilangkan, sebuah + pemberitahuan baru akan dibuat. +
++ Cuplikan berikut memperagakan pemberitahuan yang diperbarui untuk mencerminkan + jumlah kejadian yang telah terjadi. Cuplikan ini menumpuk pemberitahuan, yang menampilkan rangkuman: +
++mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Sets an ID for the notification, so it can be updated +int notifyID = 1; +mNotifyBuilder = new NotificationCompat.Builder(this) + .setContentTitle("New Message") + .setContentText("You've received new messages.") + .setSmallIcon(R.drawable.ic_notify_status) +numMessages = 0; +// Start of a loop that processes data and then notifies the user +... + mNotifyBuilder.setContentText(currentText) + .setNumber(++numMessages); + // Because the ID remains unchanged, the existing notification is + // updated. + mNotificationManager.notify( + notifyID, + mNotifyBuilder.build()); +... ++ + +
Menghapus pemberitahuan
++ Pemberitahuan tetap terlihat hingga salah satu kejadian berikut terjadi: +
+-
+
- + Pengguna menghilangkan pemberitahuan satu per satu atau dengan menggunakan "Clear All" (jika + pemberitahuan bisa dihapus). + +
- + Pengguna mengklik pemberitahuan, dan Anda memanggil + {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} bila + Anda telah membuat pemberitahuan. + +
- + Anda memanggil {@link android.app.NotificationManager#cancel(int) cancel()} untuk + ID pemberitahuan tertentu. Metode ini juga menghapus pemberitahuan yang berjalan. + +
- + Anda memanggil {@link android.app.NotificationManager#cancelAll() cancelAll()}, yang menghapus + semua pemberitahuan yang dikeluarkan sebelumnya. + +
Mempertahankan Navigasi saat Memulai Aktivitas
++ Bila memulai {@link android.app.Activity} dari pemberitahuan, Anda harus mempertahankan + pengalaman navigasi yang diharapkan pengguna. Mengklik Back harus membawa pengguna kembali melalui + aliran pekerjaan normal aplikasi ke layar Home, dan mengklik Recents harus menampilkan + {@link android.app.Activity} sebagai tugas terpisah. Untuk mempertahankan pengalaman navigasi, Anda + harus memulai {@link android.app.Activity} dalam tugas baru. Cara menyiapkan + {@link android.app.PendingIntent} untuk memberi Anda tugas baru bergantung pada sifat + {@link android.app.Activity} yang Anda mulai. Ada dua situasi umum: +
+-
+
- + Aktivitas rutin + +
-
+ Anda memulai {@link android.app.Activity} yang merupakan bagian dari aliran pekerjaan normal
+ aplikasi. Dalam situasi ini, siapkan {@link android.app.PendingIntent} untuk
+ memulai tugas baru, dan sediakan {@link android.app.PendingIntent} bersama back-stack
+ yang meniru perilaku Back biasa.
+
+ Pemberitahuan dari aplikasi Gmail memperagakan hal ini. Bila Anda mengklik pemberitahuan untuk + satu pesan email, Anda akan melihat pesan itu sendiri. Menyentuh Back akan membawa Anda + kembali melalui Gmail ke layar Home, persis seperti jika memasuki Gmail dari + layar Home bukannya memasukinya dari pemberitahuan. +
++ Hal ini terjadi terlepas dari aplikasi tempat Anda berada saat menyentuh + pemberitahuan. Misalnya, jika Anda dalam Gmail sedang menulis pesan, dan Anda mengklik + pemberitahuan untuk satu email, Anda akan segera dibawa ke email itu. Menyentuh Back + akan membawa Anda ke kotak masuk kemudian layar Home, bukannya membawa Anda ke + pesan yang sedang ditulis. +
+
+ - + Aktivitas khusus + +
- + Pengguna hanya melihat {@link android.app.Activity} ini jika dimulai dari pemberitahuan. + Dalam beberapa hal, {@link android.app.Activity} akan memperluas pemberitahuan dengan menyediakan + informasi yang akan sulit untuk ditampilkan dalam pemberitahuan itu sendiri. Untuk situasi ini, + siapkan {@link android.app.PendingIntent} untuk dimulai dalam tugas baru. Tidak perlu + membuat back-stack, karena {@link android.app.Activity} yang dimulai bukan bagian dari + aliran aktivitas aplikasi. Mengklik Back tetap akan membawa pengguna ke + layar Home. + +
Menyiapkan PendingIntent aktivitas biasa
++ Untuk menyiapkan {@link android.app.PendingIntent} yang memulai entri langsung + {@link android.app.Activity}, ikuti langkah-langkah ini: +
+-
+
-
+ Definisikan hierarki {@link android.app.Activity} aplikasi Anda dalam manifes.
+
-
+
-
+ Tambahkan dukungan untuk Android 4.0.3 dan yang terdahulu. Caranya, tetapkan induk
+ {@link android.app.Activity} yang Anda mulai dengan menambahkan elemen
+
<meta-data>
+ sebagai anak +<activity>
. ++ Untuk elemen ini, atur +
+android:name="android.support.PARENT_ACTIVITY"
. + Atur +android:value="<parent_activity_name>"
+ dengan<parent_activity_name>
sebagai nilai +android:name
+ untuk elemen induk +<activity>
+. Lihat XML berikut sebagai contoh. +
+ -
+ Juga tambahkan dukungan untuk Android 4.1 dan yang lebih baru. Caranya, tambahkan atribut
+
android:parentActivityName
+ pada elemen +<activity>
+ dari {@link android.app.Activity} yang Anda mulai. +
+
+ XML akhir akan terlihat seperti ini: +
++<activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +<activity + android:name=".ResultActivity" + android:parentActivityName=".MainActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".MainActivity"/> +</activity> +
+
+ -
+ Tambahkan dukungan untuk Android 4.0.3 dan yang terdahulu. Caranya, tetapkan induk
+ {@link android.app.Activity} yang Anda mulai dengan menambahkan elemen
+
-
+ Buat back-stack berdasarkan {@link android.content.Intent} yang memulai
+ {@link android.app.Activity}:
+
-
+
- + Buat {@link android.content.Intent} untuk memulai {@link android.app.Activity}. + +
- + Buat stack-builder (pembangun tumpukan) dengan memanggil {@link android.app.TaskStackBuilder#create + TaskStackBuilder.create()}. + +
-
+ Tambahkan back-stack ke stack-builder dengan memanggil
+ {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}.
+ Untuk setiap {@link android.app.Activity} dalam hierarki yang telah Anda definisikan dalam
+ manifes, back-stack berisi objek {@link android.content.Intent} yang
+ memulai {@link android.app.Activity}. Metode ini juga menambahkan flag yang memulai
+ back-stack dalam tugas baru.
+
+ Catatan: Walaupun argumen untuk + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} + adalah acuan ke {@link android.app.Activity} yang dimulai, panggilan metode + tidak akan menambahkan {@link android.content.Intent} yang memulai + {@link android.app.Activity}. Sebagai gantinya, hal itu ditangani dalam langkah berikutnya. +
+
+ - + Tambahkan {@link android.content.Intent} yang memulai {@link android.app.Activity} + dari pemberitahuan, dengan memanggil + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}. + Teruskan {@link android.content.Intent} yang Anda buat dalam langkah pertama sebagai + argumen ke + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}. + +
- + Jika perlu, tambahkan argumen ke objek {@link android.content.Intent} pada + back-stack dengan memanggil {@link android.support.v4.app.TaskStackBuilder#editIntentAt + TaskStackBuilder.editIntentAt()}. Kadang-kadang perlu memastikan apakah + {@link android.app.Activity} target menampilkan data bermakna saat pengguna menelusurinya + dengan menggunakan Back. + +
- + Dapatkan {@link android.app.PendingIntent} untuk back-stack ini dengan memanggil + {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}. + Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent + setContentIntent()}. + +
+
+ Cuplikan kode berikut memperagakan prosesnya: +
++... +Intent resultIntent = new Intent(this, ResultActivity.class); +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent to the top of the stack +stackBuilder.addNextIntent(resultIntent); +// Gets a PendingIntent containing the entire back stack +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); +... +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +builder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mNotificationManager.notify(id, builder.build()); ++ +
Menyiapkan PendingIntent aktivitas khusus
++ Bagian berikut menjelaskan cara menyiapkan aktivitas khusus + {@link android.app.PendingIntent}. +
++ {@link android.app.Activity} khusus tidak memerlukan back-stack, sehingga Anda tidak perlu + mendefinisikan hierarki {@link android.app.Activity}-nya dalam manifes, dan Anda tidak perlu + memanggil + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} untuk membuat + back-stack. Sebagai gantinya, gunakan manifes untuk menyiapkan opsi tugas {@link android.app.Activity}, + dan buat {@link android.app.PendingIntent} dengan memanggil + {@link android.app.PendingIntent#getActivity getActivity()}: +
+-
+
-
+ Dalam manifes, tambahkan atribut berikut pada elemen
+
<activity>
+ untuk {@link android.app.Activity} +-
+
-
+
android:name="activityclass"
+
+ - + Nama kelas mutlak (fully qualified) aktivitas. + +
-
+
android:taskAffinity=""
+
+ - + Dikombinasikan dengan flag + {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} + yang Anda atur dalam kode, ini memastikan bahwa {@link android.app.Activity} ini tidak + masuk ke dalam tugas default aplikasi. Setiap tugas yang ada yang memiliki + afinitas default aplikasi tidak terpengaruh. + +
-
+
android:excludeFromRecents="true"
+
+ - + Mengecualikan tugas baru dari Recents, sehingga pengguna tidak bisa tanpa sengaja + mengarahkan kembali. + +
+ Cuplikan ini menampilkan elemen: +
++<activity + android:name=".ResultActivity" +... + android:launchMode="singleTask" + android:taskAffinity="" + android:excludeFromRecents="true"> +</activity> +... +
+
+ -
+
-
+ Buat dan keluarkan pemberitahuan:
+
-
+
- + Buat {@link android.content.Intent} yang memulai + {@link android.app.Activity}. + +
- + Atur {@link android.app.Activity} untuk dimulai dalam tugas kosong yang baru dengan memanggil + {@link android.content.Intent#setFlags setFlags()} dengan flag + {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} + dan + {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}. + +
- + Atur setiap opsi lain yang Anda perlukan untuk {@link android.content.Intent}. + +
- + Buat {@link android.app.PendingIntent} dari {@link android.content.Intent} + dengan memanggil {@link android.app.PendingIntent#getActivity getActivity()}. + Anda nanti bisa menggunakan {@link android.app.PendingIntent} ini sebagai argumen untuk + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent + setContentIntent()}. + +
+ Cuplikan kode berikut memperagakan prosesnya: +
++// Instantiate a Builder object. +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +// Creates an Intent for the Activity +Intent notifyIntent = + new Intent(this, ResultActivity.class); +// Sets the Activity to start in a new, empty task +notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); +// Creates the PendingIntent +PendingIntent notifyPendingIntent = + PendingIntent.getActivity( + this, + 0, + notifyIntent, + PendingIntent.FLAG_UPDATE_CURRENT +); + +// Puts the PendingIntent into the notification builder +builder.setContentIntent(notifyPendingIntent); +// Notifications are issued by sending them to the +// NotificationManager system service. +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Builds an anonymous Notification object from the builder, and +// passes it to the NotificationManager +mNotificationManager.notify(id, builder.build()); +
+
+
Menampilkan Kemajuan dalam Pemberitahuan
++ Pemberitahuan bisa menyertakan indikator kemajuan beranimasi yang menampilkan status +operasi yang berjalan kepada pengguna. Jika Anda bisa memperkirakan lamanya operasi berlangsung dan berapa banyak + yang sudah selesai pada suatu waktu, gunakan bentuk indikator yang "pasti" + (baris kemajuan). Jika Anda tidak bisa memperkirakan lamanya operasi, gunakan + bentuk indikator "tidak pasti" (indikator aktivitas). +
++ Indikator kemajuan ditampilkan bersama implementasi platform + kelas {@link android.widget.ProgressBar}. +
++ Untuk menggunakan indikator kemajuan pada platform mulai dari Android 4.0, panggil + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. Untuk + versi sebelumnya, Anda harus membuat layout pemberitahuan custom sendiri yang +menyertakan tampilan {@link android.widget.ProgressBar}. +
++ Bagian berikut ini menjelaskan cara menampilkan kemajuan dalam pemberitahuan dengan menggunakan + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. +
+ +Menampilkan indikator kemajuan berdurasi tetap
+
+ Untuk menampilkan baris kemajuan pasti, tambahkan baris itu ke pemberitahuan dengan memanggil
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress
+ setProgress(max, progress, false)}, kemudian keluarkan pemberitahuan. Selagi operasi berlangsung,
+ tambah progress
, dan perbarui pemberitahuan. Di akhir operasi,
+ progress
harus sama dengan max
. Satu cara umum memanggil
+ {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
+ adalah mengatur max
ke 100, kemudian tambah progress
sebagai
+ nilai "persen selesai"untuk operasi itu.
+
+ Anda bisa membiarkan baris kemajuan ditampilkan saat operasi selesai, atau menghilangkannya. Dalam + hal apa pun, ingatlah memperbarui teks pemberitahuan untuk menampilkan bahwa operasi telah selesai. + Untuk menghapus baris kemajuan, panggil + {@link android.support.v4.app.NotificationCompat.Builder#setProgress + setProgress(0, 0, false)}. Misalnya: +
++... +mNotifyManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mBuilder = new NotificationCompat.Builder(this); +mBuilder.setContentTitle("Picture Download") + .setContentText("Download in progress") + .setSmallIcon(R.drawable.ic_notification); +// Start a lengthy operation in a background thread +new Thread( + new Runnable() { + @Override + public void run() { + int incr; + // Do the "lengthy" operation 20 times + for (incr = 0; incr <= 100; incr+=5) { + // Sets the progress indicator to a max value, the + // current completion percentage, and "determinate" + // state + mBuilder.setProgress(100, incr, false); + // Displays the progress bar for the first time. + mNotifyManager.notify(0, mBuilder.build()); + // Sleeps the thread, simulating an operation + // that takes time + try { + // Sleep for 5 seconds + Thread.sleep(5*1000); + } catch (InterruptedException e) { + Log.d(TAG, "sleep failure"); + } + } + // When the loop is finished, updates the notification + mBuilder.setContentText("Download complete") + // Removes the progress bar + .setProgress(0,0,false); + mNotifyManager.notify(ID, mBuilder.build()); + } + } +// Starts the thread by calling the run() method in its Runnable +).start(); ++ + +
Menampilkan indikator aktivitas berlanjut
++ Untuk menampilkan indikator aktivitas tidak pasti, tambahkan aktivitas ke pemberitahuan dengan + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)} + (dua argumen pertama akan diabaikan), dan keluarkan pemberitahuan. Hasilnya adalah indikator + yang memiliki gaya yang sama dengan baris kemajuan, hanya saja animasinya terus berjalan. +
++ Keluarkan pemberitahuan di awal operasi. Animasi akan berjalan hingga Anda + memodifikasi pemberitahuan. Bila operasi selesai, panggil + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} + kemudian perbarui pemberitahuan untuk menghapus indikator aktivitas. + Selalu lakukan ini; jika makan animasi akan terus berjalan sekalipun operasi telah selesai. Juga + ingatlah mengubah teks pemberitahuan untuk menunjukkan bahwa operasi telah selesai. +
++ Untuk melihat cara kerja indikator aktivitas, lihat cuplikan terdahulu. Cari lokasi baris-baris berikut: +
++// Sets the progress indicator to a max value, the current completion +// percentage, and "determinate" state +mBuilder.setProgress(100, incr, false); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); ++
+ Ganti baris yang telah Anda temukan dengan baris berikut: +
++ // Sets an activity indicator for an operation of indeterminate length +mBuilder.setProgress(0, 0, true); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); ++ +
Metadata Pemberitahuan
+ +Pemberitahuan dapat disortir sesuai metadata yang Anda tetapkan dengan +metode {@link android.support.v4.app.NotificationCompat.Builder} berikut:
+ +-
+
- {@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()} + memberi tahu sistem cara menangani pemberitahuan aplikasi Anda bila perangkat berada dalam mode Priority + (misalnya, jika pemberitahuan menyatakan suatu panggilan masuk, pesan instan, atau alarm). +
- {@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} menyebabkan + pemberitahuan dengan bidang prioritas diatur ke {@code PRIORITY_MAX} atau {@code PRIORITY_HIGH} + muncul dalam jendela kecil mengambang jika pemberitahuan juga memiliki suara atau getaran. +
- {@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()} + memungkinkan Anda menambahkan daftar orang ke pemberitahuan. Aplikasi Anda bisa menggunakannya untuk memberi isyarat pada + sistem bahwa sistem harus mengelompokkan bersama pemberitahuan dari orang-orang yang ditetapkan, atau memberi peringkat lebih penting pada pemberitahuan + untuk orang-orang ini. +
Pemberitahuan Pendahuluan
+ +Dengan Android 5.0 (API level 21), pemberitahuan bisa muncul dalam jendela kecil mengambang +(yang disebut juga dengan pemberitahuan pendahuluan) saat perangkat aktif +(yakni, perangkat dibuka kuncinya dan layarnya menyala). Pemberitahuan ini +muncul seperti bentuk ringkas pemberitahuan Anda, hanya saja +pemberitahuan pendahuluan juga menampilkan tombol tindakan. Pengguna bisa menindaklanjuti atau mengabaikan, +pemberitahuan pendahuluan tanpa meninggalkan aplikasi saat ini.
+ +Contoh-contoh kondisi yang dapat memicu pemberitahuan pendahuluan antara lain:
+ +-
+
- Aktivitas pengguna berada dalam mode layar penuh (aplikasi menggunakan +{@link android.app.Notification#fullScreenIntent}), atau +
- Pemberitahuan memiliki prioritas tinggi dan menggunakan nada dering atau + getaran +
Pemberitahuan Layar Kunci
+ +Dengan rilis Android 5.0 (API level 21), pemberitahuan kini dapat muncul pada +layar kunci. Aplikasi Anda bisa menggunakan fungsionalitas ini untuk menyediakan kontrol pemutaran media dan +tindakan umum lainnya. Pengguna bisa memilih lewat Settings apakah akan menampilkan pemberitahuan pada layar kunci, dan +Anda bisa mendesain apakah pemberitahuan aplikasi akan terlihat pada layar kunci.
+ +Mengatur Visibilitas
+ +Aplikasi Anda bisa mengatur level detail terlihat pada pemberitahuan yang ditampilkan di +layar kunci aman. Anda memanggil {@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()} +dan menetapkan salah satu nilai berikut:
+ +-
+
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} menampilkan isi lengkap + pemberitahuan. +
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} tidak menampilkan bagian apa pun dari + pemberitahuan ini pada layar kunci. +
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} menampilkan informasi dasar, + misalnya ikon dan judul isi pemberitahuan, namun menyembunyikan isi lengkap pemberitahuan. +
Bila {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} telah diatur, Anda juga bisa +menyediakan versi alternatif isi pemberitahuan yang menyembunyikan detail tertentu. Misalnya, +aplikasi SMS dapat menampilkan pemberitahuan yang menampilkan Anda memiliki 3 pesan teks baru, namun menyembunyikan +isi dan pengirim pesan. Untuk menyediakan pemberitahuan alternatif ini, buat dahulu pemberitahuan +pengganti menggunakan {@link android.support.v4.app.NotificationCompat.Builder}. Bila Anda membuat +objek pemberitahuan privat, lampirkan pemberitahuan pengganti melalui metode +{@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()} +.
+ +Mengontrol Pemutaran Media pada Layar Kunci
+ +Dalam Android 5.0 (API level 21) layar kunci tidak lagi menampilkan kontrol media +berdasarkan {@link android.media.RemoteControlClient}, yang sekarang telah dihilangkan. Sebagai gantinya, gunakan +template {@link android.app.Notification.MediaStyle} dengan metode +{@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} +, yang mengubah tindakan menjadi ikon yang bisa diklik.
+ +Catatan: Template dan metode {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} +tidak disertakan dalam pustaka dukungan, sehingga fitur-fitur ini berjalan pada Android 5.0 dan yang lebih tinggi +saja.
+ +Untuk menampilkan kontrol pemutaran media di layar kunci dalam Android 5.0, atur visibilitas +ke {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC}, seperti dijelaskan di atas. Kemudian tambahkan +tindakan dan atur template {@link android.app.Notification.MediaStyle}, seperti dijelaskan dalam contoh kode +berikut:
+ ++Notification notification = new Notification.Builder(context) + // Show controls on lock screen even when user hides sensitive content. + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setSmallIcon(R.drawable.ic_stat_player) + // Add media control buttons that invoke intents in your media service + .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 + .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 + .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 + // Apply the media style template + .setStyle(new Notification.MediaStyle() + .setShowActionsInCompactView(1 /* #1: pause button */) + .setMediaSession(mMediaSession.getSessionToken()) + .setContentTitle("Wonderful music") + .setContentText("My Awesome Band") + .setLargeIcon(albumArtBitmap) + .build(); ++ +
Catatan: Dihilangkannya {@link android.media.RemoteControlClient} +memiliki implikasi lebih jauh untuk mengontrol media. Lihat +Kontrol Pemutaran Media +untuk informasi selengkapnya tentang API baru untuk mengelola sesi media dan mengontrol pemutaran.
+ + + +Layout Pemberitahuan Custom
++ Kerangka kerja pemberitahuan memungkinkan Anda mendefinisikan layout pemberitahuan custom, yang + mendefinisikan penampilan pemberitahuan dalam objek {@link android.widget.RemoteViews}. + Pemberitahuan dengan layout custom serupa pemberitahuan normal, namun dibuat berdasarkan + {@link android.widget.RemoteViews} yang didefinisikan dalam file layout XML. +
++ Tinggi yang tersedia untuk layout pemberitahuan custom bergantung pada tampilan pemberitahuan. Layout + tampilan normal dibatasi hingga 64 dp, dan layout tampilan yang diperluas dibatasi hingga 256 dp. +
++ Untuk mendefinisikan layout pemberitahuan custom, mulailah dengan membuat instance + objek {@link android.widget.RemoteViews} yang memekarkan file layout XML. Kemudian, + sebagai ganti memanggil metode seperti + {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}, + panggil {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Untuk mengatur + detail isi pemberitahuan custom, gunakan metode dalam + {@link android.widget.RemoteViews} untuk mengatur nilai anak tampilan: +
+-
+
-
+ Buat layout XML untuk pemberitahuan di file terpisah. Anda bisa menggunakan nama file
+apa saja yang diinginkan, namun Anda harus menggunakan ekstensi
.xml
+
+ - + Dalam aplikasi Anda, gunakan metode {@link android.widget.RemoteViews} untuk mendefinisikan + ikon dan teks pemberitahuan. Masukkan objek {@link android.widget.RemoteViews} ini ke dalam + {@link android.support.v4.app.NotificationCompat.Builder} Anda dengan memanggil + {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Hindari + mengatur {@link android.graphics.drawable.Drawable} latar belakang pada + objek {@link android.widget.RemoteViews} Anda, karena warna teks bisa menjadi tidak terbaca. + +
+ Kelas {@link android.widget.RemoteViews} juga menyertakan metode yang bisa Anda gunakan untuk + menambahkan {@link android.widget.Chronometer} atau {@link android.widget.ProgressBar} +dengan mudah ke layout pemberitahuan Anda. Untuk informasi selengkapnya tentang cara membuat layout custom + pemberitahuan Anda, lihat dokumentasi acuan {@link android.widget.RemoteViews}. +
++ Perhatian: Bila Anda menggunakan layout pemberitahuan custom, berhati-hatilah + untuk memastikan bahwa layout custom itu bekerja pada berbagai orientasi dan resolusi perangkat. Walaupun + berlaku bagi semua layout View, nasihat ini khususnya penting untuk pemberitahuan karena + ruang di laci pemberitahuan sangat terbatas. Jangan buat layout custom terlalu + kompleks, dan pastikan mengujinya di berbagai konfigurasi. +
+ +Menggunakan sumber daya gaya untuk teks pemberitahuan custom
++ Selalu gunakan sumber daya gaya untuk teks pemberitahuan custom. Warna latar belakang + pemberitahuan bisa bervariasi di berbagai perangkat dan versi, dan menggunakan sumber daya gaya + membantu Anda menangani hal ini. Mulai Android 2.3, sistem mendefinisikan sebuah gaya untuk + teks layout pemberitahuan standar. Jika Anda menggunakan gaya yang sama dalam aplikasi yang menargetkan Android + 2.3 atau yang lebih tinggi, Anda akan memastikan bahwa teks terlihat pada latar belakang tampilan. +
diff --git a/docs/html-intl/intl/in/guide/topics/ui/overview.jd b/docs/html-intl/intl/in/guide/topics/ui/overview.jd new file mode 100644 index 0000000000000000000000000000000000000000..a0b2b0645a900aa1fd20cfaf49f011e33c0352c7 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/overview.jd @@ -0,0 +1,71 @@ +page.title=Ikhtisar UI +@jd:body + + +Semua elemen antarmuka pengguna dalam aplikasi Android dibangun menggunakan objek {@link android.view.View} dan +{@link android.view.ViewGroup}. {@link android.view.View} adalah objek yang menarik +sesuatu di layar dan dapat berinteraksi dengan pengguna. {@link android.view.ViewGroup} merupakan sebuah +objek yang menyimpan objek {@link android.view.View} lainnya (dan {@link android.view.ViewGroup}) untuk +mendefinisikan layout antarmuka.
+ +Android menyediakan sekumpulan subkelas {@link android.view.View} dan {@link +android.view.ViewGroup} yang menawarkan kontrol input umum (seperti tombol dan bidang +teks) serta berbagai model layout (seperti layout linear atau relatif).
+ + +Layout Antarmuka Pengguna
+ +Antarmuka pengguna untuk setiap komponen aplikasi Anda didefinisikan menggunakan hierarki objek {link +android.view.View} dan {@link android.view.ViewGroup}, seperti yang ditampilkan dalam gambar 1. Setiap kelompok tampilan +merupakan kontainer tak terlihat yang mengelola tampilan anak, sementara tampilan anak ini dapat menjadi kontrol +input atau widget lain yang +menarik sebagian dari UI. Pohon hierarki ini bisa sederhana atau bisa juga kompleks bergantung kebutuhan +(namun yang sederhana paling baik untuk kinerja).
+ + + + +Untuk mendeklarasikan layout, Anda dapat menyediakan objek {@link android.view.View} dalam kode dan mulai +membangun pohon, namun cara termudah dan terefektif untuk mendefinisikan layout adalah dengan file XML. +XML menawarkan struktur layout yang dapat dibaca manusia, serupa dengan HTML.
+ +Nama elemen XML untuk tampilan sesuai dengan kelas Android yang diwakilinya. Dengan demikian elemen
+<TextView>
membuat widget {@link android.widget.TextView} dalam UI Anda,
+dan elemen <LinearLayout>
membuat kelompok tampilan {@link android.widget.LinearLayout}
+.
Misalnya, layout vertikal sederhana dengan tampilan teks dan tombol akan tampak seperti ini:
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a Button" /> +</LinearLayout> ++ +
Saat Anda memuat sumber daya layout di aplikasi, Android akan menginisialisasi setiap simpul layout menjadi +objek runtime yang bisa Anda gunakan untuk mendefinisikan perilaku tambahan, query status objek, atau memodifikasi +layout.
+ +Untuk mendapatkan panduan lengkap mengenai pembuatan layout UI, lihat Layout +XML. + + +
Komponen Antarmuka Pengguna
+ +Anda tidak harus membuat semua UI menggunakan objek {@link android.view.View} dan {link +android.view.ViewGroup}. Android menyediakan beberapa komponen aplikasi yang menawarkan +layout UI standar yang tinggal Anda definisikan kontennya. Komponen UI ini masing-masing +memiliki set API unik yang dijelaskan dalam masing-masing dokumennya, seperti Action-Bar, Dialog, dan Pemberitahuan Status.
+ + diff --git a/docs/html-intl/intl/in/guide/topics/ui/settings.jd b/docs/html-intl/intl/in/guide/topics/ui/settings.jd new file mode 100644 index 0000000000000000000000000000000000000000..5ac61f928c19e9993b52b99aff77720543584e53 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/settings.jd @@ -0,0 +1,1202 @@ +page.title=Pengaturan +page.tags=preference,preferenceactivity,preferencefragment + +@jd:body + + +Dalam dokumen ini
+-
+
- Ikhtisar
+
-
+
- Preferensi +
+ - Mendefinisikan Preferensi dalam XML + + +
- Membuat Aktivitas Preferensi +
- Menggunakan Fragmen Preferensi +
- Mengatur Nilai Default +
- Menggunakan Header Preferensi + + +
- Preferensi Membaca + + +
- Mengelola Penggunaan Jaringan +
- Membangun Preferensi Custom + + +
Kelas-kelas utama
+-
+
- {@link android.preference.Preference} +
- {@link android.preference.PreferenceActivity} +
- {@link android.preference.PreferenceFragment} +
Lihat juga
+ +Aplikasi sering kali menyertakan pengaturan yang memungkinkan pengguna memodifikasi fitur dan perilaku aplikasi. Misalnya, +beberapa aplikasi memungkinkan pengguna untuk menetapkan apakah pemberitahuan diaktifkan atau menetapkan seberapa sering +aplikasi menyinkronkan data dengan cloud.
+ +Jika ingin menyediakan pengaturan untuk aplikasi, Anda harus menggunakan +API Android {@link android.preference.Preference} untuk membangun antarmuka yang konsisten dengan +pengalaman pengguna di aplikasi Android yang lain (termasuk pengaturan sistem). Dokumen ini menjelaskan +cara membangun pengaturan aplikasi Anda menggunakan API {@link android.preference.Preference}.
+ +Desain Pengaturan
+Untuk informasi tentang cara mendesain pengaturan Anda, bacalah panduan desain Pengaturan.
+Ikhtisar
+ +Sebagai ganti menggunakan objek {@link android.view.View} untuk membangun antarmuka pengguna, pengaturan +dibangun menggunakan berbagai subkelas dari kelas {@link android.preference.Preference} yang Anda +deklarasikan dalam file XML.
+ +Objek {@link android.preference.Preference} adalah blok pembangun untuk pengaturan +tunggal. Setiap {@link android.preference.Preference} muncul sebagai item dalam daftar dan menyediakan UI +yang sesuai bagi pengguna untuk memodifikasi pengaturan. Misalnya, {@link +android.preference.CheckBoxPreference} membuat item daftar yang menampilkan kotak cek, dan {@link +android.preference.ListPreference} membuat item yang membuka dialog berisi daftar pilihan.
+ +Setiap {@link android.preference.Preference} yang Anda tambahkan memiliki pasangan nilai-kunci yang sesuai yang +digunakan sistem untuk menyimpan pengaturan dalam file {@link android.content.SharedPreferences} +default untuk pengaturan aplikasi Anda. Bila pengguna mengubah pengaturan, sistem akan memperbarui nilai +yang bersangkutan dalam file {@link android.content.SharedPreferences} untuk Anda. Satu-satunya saat di mana Anda harus +berinteraksi langsung dengan file {@link android.content.SharedPreferences} yang terkait adalah bila Anda +perlu membaca nilai untuk menentukan perilaku aplikasi berdasarkan pengaturan pengguna.
+ +Nilai yang tersimpan di {@link android.content.SharedPreferences} untuk setiap pengaturan bisa berupa +tipe data berikut:
+ +-
+
- Boolean +
- Float +
- Int +
- Long +
- String +
- String {@link java.util.Set} +
Oleh karena UI pengaturan aplikasi Anda dibangun menggunakan objek {@link android.preference.Preference} +sebagai ganti +objek {@link android.view.View}, Anda perlu menggunakan {@link android.app.Activity} khusus atau +subkelas {@link android.app.Fragment} untuk menampilkan pengaturan daftar:
+ +-
+
- Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0 (API level 10 dan yang lebih rendah), Anda harus +membangun aktivitas sebagai ekstensi dari kelas {@link android.preference.PreferenceActivity}. +
- Pada Android 3.0 dan yang lebih baru, sebaiknya Anda menggunakan {@link android.app.Activity} biasa +yang menjadi host {@link android.preference.PreferenceFragment} yang menampilkan pengaturan aplikasi Anda. +Akan tetapi, Anda juga bisa menggunakan {@link android.preference.PreferenceActivity} untuk membuat layout dua panel +bagi layar besar bila Anda memiliki beberapa grup pengaturan. +
Cara mengatur {@link android.preference.PreferenceActivity} Anda dan instance {@link +android.preference.PreferenceFragment} dibahas di bagian tentang Membuat Aktivitas Preferensi dan Menggunakan +Fragmen Preferensi.
+ + +Preferensi
+ +Setiap pengaturan untuk aplikasi Anda diwakili oleh subkelas khusus dari kelas {@link +android.preference.Preference}. Setiap subkelas menyertakan seperangkat properti utama yang memungkinkan Anda +untuk menetapkan berbagai hal seperti judul pengaturan dan nilai default. Setiap subkelas juga menyediakan +antarmuka pengguna dan properti khusus miliknya sendiri. Misalnya, gambar 1 menampilkan cuplikan layar dari + pengaturan aplikasi Messaging. Setiap item daftar dalam layar pengaturan didukung oleh objek {@link +android.preference.Preference} berbeda.
+ +Beberapa preferensi yang paling umum adalah:
+ +-
+
- {@link android.preference.CheckBoxPreference} +
- Menampilkan item dengan kotak cek untuk pengaturan yang diaktifkan atau dinonaktifkan. Nilai
+tersimpan adalah boolean (
true
jika diberi tanda cek).
+
+ - {@link android.preference.ListPreference} +
- Membuka dialog berisi daftar tombol radio. Nilai +tersimpan bisa berupa tipe nilai apa pun yang didukung (tercantum di atas). + +
- {@link android.preference.EditTextPreference} +
- Membuka dialog berisi widget {@link android.widget.EditText}. Nilai tersimpan adalah {@link +java.lang.String}. +
Lihat kelas {@link android.preference.Preference} untuk mengetahui daftar subkelas lain dan +propertinya.
+ +Tentu saja, kelas bawaan tidak mengakomodasi setiap kebutuhan dan aplikasi Anda mungkin memerlukan +sesuatu yang lebih khusus. Misalnya, platform saat ini tidak menyediakan kelas {@link +android.preference.Preference} untuk mengambil nomor atau tanggal. Anda mungkin perlu mendefinisikan +subkelas {@link android.preference.Preference} sendiri. Untuk bantuan melakukannya, lihat bagian tentang Membangun Preferensi Custom.
+ + + +Mendefinisikan Preferensi dalam XML
+ +Meskipun bisa membuat instance objek {@link android.preference.Preference} baru saat runtime, Anda +harus mendefinisikan daftar pengaturan dalam XML dengan hierarki objek +{@link android.preference.Preference}. Menggunakan file XML untuk mendefinisikan sekumpulan pengaturan lebih disukai karena file +menyediakan struktur yang mudah dibaca dan diperbarui. Selain itu, pengaturan aplikasi Anda +umumnya telah ditetapkan sebelumnya, meskipun Anda masih bisa memodifikasi kumpulan tersebut saat runtime.
+ +Setiap subkelas {@link android.preference.Preference} bisa dideklarasikan dengan elemen XML yang +cocok dengan nama kelas, seperti {@code <CheckBoxPreference>}.
+ +Anda harus menyimpan file XML dalam direktori {@code res/xml/}. Meskipun bisa memberi nama file +sesuka Anda, biasanya file diberi nama {@code preferences.xml}. Biasanya Anda hanya memerlukan satu file, +karena cabang di hierarki (yang membuka daftar pengaturanny sendiri) dideklarasikan menggunakan instance +tersarang {@link android.preference.PreferenceScreen}.
+ +Catatan: Jika ingin membuat layout multipanel untuk +pengaturan, Anda memerlukan file XML terpisah untuk setiap fragmen.
+ +Simpul akar untuk file XML harus merupakan elemen {@link android.preference.PreferenceScreen +<PreferenceScreen>}. Dalam elemen inilah tempat Anda menambahkan setiap {@link +android.preference.Preference}. Setiap anak yang Anda tambahkan dalam elemen +{@link android.preference.PreferenceScreen <PreferenceScreen>} akan tampak sebagai item +tunggal dalam daftar pengaturan.
+ +Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="pref_sync" + android:title="@string/pref_sync" + android:summary="@string/pref_sync_summ" + android:defaultValue="true" /> + <ListPreference + android:dependency="pref_sync" + android:key="pref_syncConnectionType" + android:title="@string/pref_syncConnectionType" + android:dialogTitle="@string/pref_syncConnectionType" + android:entries="@array/pref_syncConnectionTypes_entries" + android:entryValues="@array/pref_syncConnectionTypes_values" + android:defaultValue="@string/pref_syncConnectionTypes_default" /> +</PreferenceScreen> ++ +
Dalam contoh ini, terdapat {@link android.preference.CheckBoxPreference} dan {@link +android.preference.ListPreference}. Kedua item tersebut menyertakan tiga atribut berikut:
+ +-
+
- {@code android:key} +
- Atribut ini diperlukan untuk preferensi yang mempertahankan nilai data. Ini menetapkan kunci
+unik (string) yang digunakan sistem saat menyimpan nilai pengaturan ini dalam {@link
+android.content.SharedPreferences}.
+
Instance satu-satunya di mana atribut ini tidak diperlukan adalah bila preferensi berupa +{@link android.preference.PreferenceCategory} atau {@link android.preference.PreferenceScreen}, atau +preferensi menetapkan {@link android.content.Intent} untuk dipanggil (dengan elemen {@code <intent>}) atau {@link android.app.Fragment} untuk ditampilkan (dengan atribut {@code +android:fragment}).
+
+ - {@code android:title} +
- Ini menyediakan nama pengaturan yang bisa dilihat oleh pengguna. +
- {@code android:defaultValue} +
- Ini menetapkan nilai awal yang harus diatur sistem dalam file {@link +android.content.SharedPreferences}. Anda harus memberikan nilai default untuk semua +pengaturan. +
Untuk informasi tentang semua atribut lain yang didukung, lihat dokumentasi {@link +android.preference.Preference} (dan subkelas masing-masing).
+ + +Bila daftar pengaturan Anda melebihi sekitar 10 item, Anda mungkin perlu menambahkan judul untuk +mendefinisikan grup pengaturan atau menampilkan grup tersebut di +layar terpisah. Opsi ini dijelaskan di bagian berikut.
+ + +Membuat grup pengaturan
+ +Jika Anda menampilkan daftar 10 pengaturan atau lebih, pengguna +mungkin akan kesulitan dalam memindai, memahami dan memprosesnya. Anda bisa mengatasinya dengan +membagi sebagian atau semua pengaturan ke dalam beberapa grup, yang secara efektif akan mengubah satu daftar panjang menjadi beberapa daftar +yang lebih pendek. Suatu grup pengaturan terkait bisa ditampilkan dalam salah satu dari dua cara:
+ + + +Anda bisa menggunakan salah satu atau keduanya untuk mengelola pengaturan aplikasi Anda. Saat +memutuskan mana yang akan digunakan dan cara membagi pengaturan, Anda harus mengikuti pedoman dalam +Panduan Pengaturan Desain Android.
+ + +Menggunakan judul
+ +Jika ingin menyediakan divider dengan heading di antara grup pengaturan (seperti yang ditampilkan dalam gambar 2), +tempatkan setiap grup objek {@link android.preference.Preference} di dalam {@link +android.preference.PreferenceCategory}.
+ +Misalnya:
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory + android:title="@string/pref_sms_storage_title" + android:key="pref_key_storage_settings"> + <CheckBoxPreference + android:key="pref_key_auto_delete" + android:summary="@string/pref_summary_auto_delete" + android:title="@string/pref_title_auto_delete" + android:defaultValue="false"... /> + <Preference + android:key="pref_key_sms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_sms_delete"... /> + <Preference + android:key="pref_key_mms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_mms_delete" ... /> + </PreferenceCategory> + ... +</PreferenceScreen> ++ + +
Menggunakan sublayar
+ +Jika ingin menempatkan grup pengaturan ke dalam sublayar (seperti yang ditampilkan dalam gambar 3), tempatkan grup +objek {@link android.preference.Preference} di dalam {@link +android.preference.PreferenceScreen}.
+ + + + +Misalnya:
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- opens a subscreen of settings --> + <PreferenceScreen + android:key="button_voicemail_category_key" + android:title="@string/voicemail" + android:persistent="false"> + <ListPreference + android:key="button_voicemail_provider_key" + android:title="@string/voicemail_provider" ... /> + <!-- opens another nested subscreen --> + <PreferenceScreen + android:key="button_voicemail_setting_key" + android:title="@string/voicemail_settings" + android:persistent="false"> + ... + </PreferenceScreen> + <RingtonePreference + android:key="button_voicemail_ringtone_key" + android:title="@string/voicemail_ringtone_title" + android:ringtoneType="notification" ... /> + ... + </PreferenceScreen> + ... +</PreferenceScreen> ++ + +
Menggunakan intent
+ +Dalam beberapa kasus, Anda mungkin ingin item preferensi untuk membuka beberapa aktivitas sebagai ganti +layar pengaturan, seperti browser web untuk melihat halaman web. Untuk memanggil {@link +android.content.Intent} saat pengguna memilih item preferensi, tambahkan elemen {@code <intent>} +sebagai anak dari elemen {@code <Preference>} yang bersangkutan.
+ +Misalnya, berikut ini cara menggunakan item preferensi untuk membuka halaman web:
+ ++<Preference android:title="@string/prefs_web_page" > + <intent android:action="android.intent.action.VIEW" + android:data="http://www.example.com" /> +</Preference> ++ +
Anda bisa membuat intent implisit maupun eksplisit menggunakan atribut berikut:
+ +-
+
- {@code android:action} +
- Tindakan yang akan ditetapkan, sesuai metode +{@link android.content.Intent#setAction setAction()}. +
- {@code android:data} +
- Data yang akan ditetapkan, sesuai metode {@link android.content.Intent#setData setData()}. +
- {@code android:mimeType} +
- Tipe MIME yang akan ditetapkan, sesuai metode +{@link android.content.Intent#setType setType()}. +
- {@code android:targetClass} +
- Bagian kelas dari nama komponen, sesuai metode {@link android.content.Intent#setComponent +setComponent()}. +
- {@code android:targetPackage} +
- Bagian paket dari nama komponen, sesuai metode {@link +android.content.Intent#setComponent setComponent()}. +
Membuat Aktivitas Preferensi
+ +Untuk menampilkan pengaturan Anda dalam suatu aktivitas, perluas kelas {@link +android.preference.PreferenceActivity}. Ini adalah ekstensi dari kelas {@link +android.app.Activity} biasa yang menampilkan daftar pengaturan berdasarkan hierarki objek {@link +android.preference.Preference}. {@link android.preference.PreferenceActivity} +secara otomatis mempertahankan pengaturan yang dikaitkan dengan setiap {@link +android.preference.Preference} bila pengguna membuat perubahan.
+ +Catatan: Jika Anda mengembangkan aplikasi untuk Android 3.0 dan +yang lebih tinggi, sebaiknya gunakan {@link android.preference.PreferenceFragment}. Pindah ke bagian +berikutnya tentang Menggunakan Fragmen Preferensi.
+ +Hal paling penting untuk diingat adalah jangan memuat layout tampilan selama callback {@link +android.preference.PreferenceActivity#onCreate onCreate()}. Sebagai gantinya, panggil {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk +menambahkan preferensi yang telah Anda deklarasikan dalam file XML ke aktivitas. Misalnya, berikut ini adalah kode minimum +polos yang diperlukan untuk {@link android.preference.PreferenceActivity} fungsional:
+ ++public class SettingsActivity extends PreferenceActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } +} ++ +
Ini sebenarnya kode yang cukup untuk beberapa aplikasi, karena segera setelah pengguna memodifikasi preferensi, +sistem akan menyimpan perubahan tersebut ke file {@link android.content.SharedPreferences} default yang +bisa dibaca oleh komponen aplikasi Anda lainnya bila Anda perlu memeriksa pengaturan pengguna. Akan tetapi, +banyak aplikasi, yang memerlukan kode lebih sedikit untuk mendengarkan perubahan yang terjadi pada preferensi. +Untuk informasi tentang mendengarkan perubahan di file {@link android.content.SharedPreferences}, +lihat bagian tentang Preferensi Membaca.
+ + + + +Menggunakan Fragmen Preferensi
+ +Jika Anda mengembangkan Android 3.0 (API level 11) dan yang lebih tinggi, Anda harus menggunakan {@link +android.preference.PreferenceFragment} untuk menampilkan daftar objek {@link android.preference.Preference} +Anda. Anda bisa menambahkan {@link android.preference.PreferenceFragment} ke aktivitas apa pun,—Anda tidak +perlu menggunakan {@link android.preference.PreferenceActivity}.
+ +Fragmen menyediakan arsitektur yang lebih +fleksibel untuk aplikasi Anda, dibandingkan hanya menggunakan aktivitas, apa pun jenis +aktivitas yang Anda bangun. Dengan sendirinya, kami menyarankan Anda menggunakan {@link +android.preference.PreferenceFragment} untuk mengontrol tampilan pengaturan Anda sebagai ganti {@link +android.preference.PreferenceActivity} bila memungkinkan.
+ +Implementasi {@link android.preference.PreferenceFragment} Anda bisa semudah +mendefinisikan metode {@link android.preference.PreferenceFragment#onCreate onCreate()} untuk memuat +file preferensi dengan {@link android.preference.PreferenceFragment#addPreferencesFromResource +addPreferencesFromResource()}. Misalnya:
+ ++public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + } + ... +} ++ +
Anda nanti bisa menambahkan fragmen ini ke {@link android.app.Activity} seperti yang Anda lakukan untuk +{@link android.app.Fragment} lainnya. Misalnya:
+ ++public class SettingsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SettingsFragment()) + .commit(); + } +} ++ +
Catatan: {@link android.preference.PreferenceFragment} tidak memiliki +objek {@link android.content.Context} sendiri. Jika memerlukan objek {@link android.content.Context} +, Anda bisa memanggil {@link android.app.Fragment#getActivity()}. Akan tetapi, berhati-hatilah untuk memanggil +{@link android.app.Fragment#getActivity()} hanya bila fragmen telah dikaitkan dengan aktivitas. Bila +fragmen belum dikaitkan, atau terlepas saat akhir daur hidupnya, {@link +android.app.Fragment#getActivity()} akan mengembalikan nol.
+ + +Mengatur Nilai Default
+ +Preferensi yang Anda buat mungkin mendefinisikan beberapa perilaku penting untuk aplikasi, jadi Anda +perlu menginisialisasi file {@link android.content.SharedPreferences} yang terkait dengan +nilai default untuk setiap {@link android.preference.Preference} bila pengguna menggunakan aplikasi +Anda untuk pertama kali.
+ +Hal pertama yang harus Anda lakukan adalah menetapkan nilai default untuk setiap objek {@link +android.preference.Preference} +di file XML Anda menggunakan atribut {@code android:defaultValue}. Nilainya bisa berupa tipe data +apa saja yang sesuai untuk objek {@link android.preference.Preference} bersangkutan. Misalnya: +
+ ++<!-- default value is a boolean --> +<CheckBoxPreference + android:defaultValue="true" + ... /> + +<!-- default value is a string --> +<ListPreference + android:defaultValue="@string/pref_syncConnectionTypes_default" + ... /> ++ +
Kemudian, dari metode {@link android.app.Activity#onCreate onCreate()} dalam aktivitas utama aplikasi +Anda—dan dalam aktivitas lainnya yang digunakan pengguna untuk masuk ke aplikasi Anda untuk pertama kali +—panggil {@link android.preference.PreferenceManager#setDefaultValues +setDefaultValues()}:
+ ++PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false); ++ +
Memanggil ini selama {@link android.app.Activity#onCreate onCreate()} akan memastikan aplikasi +Anda diinisialisasi dengan pengaturan default, yang mungkin perlu +dibaca oleh aplikasi Anda untuk menentukan beberapa perilaku (seperti apakah akan mengunduh data pada +jaringan seluler).
+ +Metode ini membutuhkan tiga argumen:
+-
+
- {@link android.content.Context} aplikasi Anda. +
- ID sumber daya untuk file XML preferensi yang ingin Anda atur nilai defaultnya. +
- Boolean menunjukkan apakah nilai default harus diatur lebih dari satu kali.
+
Bila
false
, sistem akan mengatur nilai default hanya jika metode ini belum pernah +dipanggil sebelumnya (atau {@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} +dalam file preferensi berbagi nilai default salah).
+
Selama Anda mengatur argumen ketiga ke false
, Anda bisa dengan aman memanggil metode ini
+setiap kali aktivitas Anda memulai tanpa mengesampingkan preferensi tersimpan pengguna dengan mengatur ulang preferensi tersebut ke
+default. Akan tetapi, jika mengatur ke true
, Anda akan mengesampingkan nilai
+sebelumnya dengan default.
Menggunakan Header Preferensi
+ +Dalam kasus yang jarang terjadi, Anda mungkin perlu mendesain pengaturan agar layar pertama +hanya menampilkan daftar sublayar (seperti dalam aplikasi Setting pada sistem, +seperti yang ditampilkan dalam gambar 4 dan 5). Bila mengembangkan desain seperti itu untuk Android 3.0 dan yang lebih tinggi, Anda +harus menggunakan fitur "header" yang baru di Android 3.0, sebagai ganti membangun sublayar dengan elemen +{@link android.preference.PreferenceScreen} tersarang.
+ +Untuk membangun pengaturan dengan header, Anda perlu:
+-
+
- Memisahkan setiap grup pengaturan ke dalam instance {@link +android.preference.PreferenceFragment} terpisah. Ini berarti, setiap grup pengaturan memerlukan file XML +terpisah. +
- Membuat file header XML yang mencantumkan daftar setiap grup pengaturan dan mendeklarasikan fragmen mana +yang berisi daftar pengaturan yang sesuai. +
- Memperluas kelas {@link android.preference.PreferenceActivity} untuk menjadi host pengaturan Anda. +
- Mengimplementasikan callback {@link +android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} untuk menetapkan file +header. +
Manfaat besar dalam menggunakan desain ini adalah karena {@link android.preference.PreferenceActivity} +secara otomatis akan menampilkan layout dua panel yang ditampilkan dalam gambar 4 bila dijalankan pada layar besar.
+ +Bahkan jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda bisa membangun +aplikasi untuk menggunakan {@link android.preference.PreferenceFragment} bagi presentasi dua panel pada perangkat +yang lebih baru sementara tetap mendukung hierarki multilayar biasa pada perangkat +yang lebih lama (lihat bagian tentang Mendukung versi yang lebih lama dengan +header preferensi).
+ + + + + + + + +Membuat file header
+ +Setiap grup pengaturan dalam daftar header Anda akan ditetapkan oleh elemen {@code <header>} +tunggal dalam elemen {@code <preference-headers>} akar. Misalnya:
+ ++<?xml version="1.0" encoding="utf-8"?> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <!-- key/value pairs can be included as arguments for the fragment. --> + <extra android:name="someKey" android:value="someHeaderValue" /> + </header> +</preference-headers> ++ +
Dengan atribut {@code android:fragment}, setiap header mendeklarasikan instance {@link +android.preference.PreferenceFragment} yang harus terbuka saat pengguna memilih header.
+ +Elemen {@code <extras>} memungkinkan Anda meneruskan pasangan nilai-kunci ke fragmen di {@link +android.os.Bundle}. Fragmen bisa mengambil argumen dengan memanggil {@link +android.app.Fragment#getArguments()}. Anda bisa meneruskan argumen ke fragmen dengan berbagai +alasan, namun satu alasan yang baik adalah untuk menggunakan kembali subkelas yang sama dari {@link +android.preference.PreferenceFragment} untuk setiap grup dan menggunakan argumen untuk menetapkan file +XML preferensi mana yang harus dimuat fragmen.
+ +Misalnya, ada fragmen yang bisa digunakan ulang untuk berbagai grup pengaturan, bila setiap +header mendefinisikan argumen {@code <extra>} dengan kunci {@code "settings"}:
+ ++public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String settings = getArguments().getString("settings"); + if ("notifications".equals(settings)) { + addPreferencesFromResource(R.xml.settings_wifi); + } else if ("sync".equals(settings)) { + addPreferencesFromResource(R.xml.settings_sync); + } + } +} ++ + + +
Menampilkan header
+ +Untuk menampilkan header preferensi, Anda harus mengimplementasikan metode callback {@link +android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} dan memanggil +{@link android.preference.PreferenceActivity#loadHeadersFromResource +loadHeadersFromResource()}. Misalnya:
+ ++public class SettingsActivity extends PreferenceActivity { + @Override + public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); + } +} ++ +
Bila pengguna memilih item dari daftar header, sistem akan membuka {@link +android.preference.PreferenceFragment} terkait.
+ +Catatan: Saat menggunakan header preferensi, subkelas {@link +android.preference.PreferenceActivity} Anda tidak perlu mengimplementasikan metode {@link +android.preference.PreferenceActivity#onCreate onCreate()}, karena tugas +yang diperlukan untuk aktivitas hanyalah memuat header.
+ + +Mendukung versi yang lebih lama dengan header preferensi
+ +Jika aplikasi Anda mendukung versi Android yang lebih lama dari 3.0, Anda tetap bisa menggunakan header untuk +menyediakan layout dua panel saat berjalan pada Android 3.0 dan yang lebih tinggi. Anda hanya perlu membuat +file XML preferensi tambahan yang menggunakan elemen {@link android.preference.Preference +<Preference>} dasar yang berperilaku seperti item header (untuk digunakan oleh Android +versi yang lebih lama).
+ +Akan tetapi, sebagai ganti membuka {@link android.preference.PreferenceScreen} baru, setiap elemen {@link +android.preference.Preference <Preference>} mengirimkan {@link android.content.Intent} ke +{@link android.preference.PreferenceActivity} yang menetapkan file XML preferensi mana yang +akan dimuat.
+ +Misalnya, ini adalah file XML untuk header preferensi yang menggunakan Android 3.0 +dan yang lebih tinggi ({@code res/xml/preference_headers.xml}):
+ ++<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" /> +</preference-headers> ++ +
Dan ini adalah file preferensi yang menyediakan header yang sama untuk versi yang lebih lama dari +Android 3.0 ({@code res/xml/preference_headers_legacy.xml}):
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <Preference + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_ONE" /> + </Preference> + <Preference + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_TWO" /> + </Preference> +</PreferenceScreen> ++ +
Karena dukungan untuk {@code <preference-headers>} telah ditambahkan di Android 3.0, sistem akan memanggil +{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} di {@link +android.preference.PreferenceActivity} hanya saat berjalan pada Android 3.0 atau yang lebih tinggi. Untuk memuat +file header "lama" ({@code preference_headers_legacy.xml}), Anda harus memeriksa versi Android +dan, jika versi tersebut lebih lama dari Android 3.0 ({@link +android.os.Build.VERSION_CODES#HONEYCOMB}), panggil {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} untuk +memuat file header lama. Misalnya:
+ ++@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ... + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} + +// Called only on Honeycomb and later +@Override +public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); +} ++ +
Satu-satunya hal yang perlu dilakukan adalah menangani {@link android.content.Intent} yang diteruskan ke +aktivitas untuk mengidentifikasi file preferensi yang akan dimuat. Jadi ambillah tindakan intent dan bandingkan dengan +string tindakan yang diketahui yang telah Anda gunakan dalam tag {@code <intent>} XML preferensi:
+ ++final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE"; +... + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String action = getIntent().getAction(); + if (action != null && action.equals(ACTION_PREFS_ONE)) { + addPreferencesFromResource(R.xml.preferences); + } + ... + + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} ++ +
Ketahuilah bahwa panggilan berturut-turut ke {@link +android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} akan +menumpuk semua preferensi ke dalam satu daftar, jadi pastikan bahwa ini hanya dipanggil sekali dengan mengikatkan syarat +ke pernyataan else-if.
+ + + + + +Preferensi Membaca
+ +Secara default, semua preferensi aplikasi Anda disimpan ke file yang bisa diakses dari mana saja +di dalam aplikasi dengan memanggil metode statis {@link +android.preference.PreferenceManager#getDefaultSharedPreferences +PreferenceManager.getDefaultSharedPreferences()}. Ini akan mengembalikan objek {@link +android.content.SharedPreferences} berisi semua pasangan nilai-kunci yang terkait +dengan objek {@link android.preference.Preference} yang digunakan di {@link +android.preference.PreferenceActivity} Anda.
+ +Misalnya, inilah cara membaca salah satu nilai preferensi dari aktivitas lain dalam aplikasi +Anda:
+ ++SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); +String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, ""); ++ + + +
Mendengarkan perubahan preferensi
+ +Ada beberapa alasan yang membuat Anda perlu mendapatkan pemberitahuan segera setelah pengguna mengubah salah satu +preferensi. Untuk menerima callback saat perubahan terjadi pada salah satu preferensi, +implementasikan antarmuka {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener +SharedPreference.OnSharedPreferenceChangeListener} dan daftarkan listener untuk objek +{@link android.content.SharedPreferences} dengan memanggil {@link +android.content.SharedPreferences#registerOnSharedPreferenceChangeListener +registerOnSharedPreferenceChangeListener()}.
+ +Antarmuka hanya memiliki satu metode callback, {@link +android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged +onSharedPreferenceChanged()}, dan mungkin lebih mudah mengimplementasikan antarmuka sebagai bagian dari +aktivitas Anda. Misalnya:
+ ++public class SettingsActivity extends PreferenceActivity + implements OnSharedPreferenceChangeListener { + public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType"; + ... + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(KEY_PREF_SYNC_CONN)) { + Preference connectionPref = findPreference(key); + // Set summary to be the user-description for the selected value + connectionPref.setSummary(sharedPreferences.getString(key, "")); + } + } +} ++ +
Dalam contoh ini, metode akan memeriksa apakah pengaturan yang diubah adalah untuk kunci preferensi yang diketahui. Ini akan +memanggil {@link android.preference.PreferenceActivity#findPreference findPreference()} untuk mendapatkan objek +{@link android.preference.Preference} yang diubah agar bisa memodifikasi rangkuman item +menjadi keterangan pada pilihan pengguna. Ini berarti, bila pengaturan adalah {@link +android.preference.ListPreference} atau pengaturan multipilihan, Anda harus memanggil {@link +android.preference.Preference#setSummary setSummary()} bila pengaturan berubah ke tampilkan +status saat ini (seperti pengaturan Sleep yang ditampilkan dalam gambar 5).
+ +Catatan: Seperti dijelaskan dalam dokumen Desain Android tentang Pengaturan, kami merekomendasikan Anda untuk memperbarui +rangkuman {@link android.preference.ListPreference} setiap kali pengguna mengubah preferensi untuk +menjelaskan pengaturan saat ini.
+ +Untuk manajemen daur hidup yang baik di aktivitas, kami merekomendasikan Anda untuk mendaftarkan dan mencabut pendaftaran +{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} selama callback {@link +android.app.Activity#onResume} dan {@link android.app.Activity#onPause}:
+ ++@Override +protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); +} + +@Override +protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); +} ++ +
Perhatian: Bila Anda memanggil {@link +android.content.SharedPreferences#registerOnSharedPreferenceChangeListener +registerOnSharedPreferenceChangeListener()}, pengelola preferensi saat ini tidak akan +menyimpan referensi kuat ke listener. Anda harus menyimpan referensi +kuat bagi listener, atau referensi akan rentan terhadap pengumpulan sampah. Kami +merekomendasikan Anda untuk mempertahankan referensi bagi listener dalam data instance objek +yang akan ada selama Anda memerlukan listener tersebut.
+ +Misalnya, dalam kode berikut, caller tidak menyimpan referensi ke +listener. Akibatnya, listener akan dikenakan pengumpulan sampah, +dan suatu saat nanti akan gagal:
+ ++prefs.registerOnSharedPreferenceChangeListener( + // Bad! The listener is subject to garbage collection! + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}); ++ +
Sebagai gantinya, simpan referensi ke listener dalam bidang data instance +objek yang akan ada selama listener dibutuhkan:
+ ++SharedPreferences.OnSharedPreferenceChangeListener listener = + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}; +prefs.registerOnSharedPreferenceChangeListener(listener); ++ +
Mengelola Penggunaan Jaringan
+ + +Mulai Android 4.0, aplikasi Settings untuk sistem memungkinkan pengguna melihat seberapa besar +data jaringan yang digunakan aplikasi mereka saat berada di latar depan dan latar belakang. Kemudian pengguna bisa +menonaktifkan penggunaan data latar belakang untuk aplikasi individual. Agar pengguna tidak menonaktifkan akses +aplikasi ke data dari latar belakang, Anda harus menggunakan koneksi data secara efisien dan mengizinkan +pengguna untuk menyaring penggunaan data aplikasi melalui pengaturan aplikasi Anda.
+ +
Misalnya, Anda bisa mengizinkan pengguna untuk mengontrol seberapa sering aplikasi menyinkronkan data, apakah aplikasi +hanya melakukan pengunggahan/pengunduhan bila ada Wi-Fi, apakah aplikasi menggunakan data saat roaming, dll. Dengan +tersedianya kontrol ini bagi pengguna, mereka kemungkinan besar tidak akan menonaktifkan akses aplikasi ke data +saat mendekati batas yang mereka tetapkan dalam Settings pada sistem, karena mereka bisa mengontrol secara tepat +seberapa besar data yang digunakan aplikasi Anda.
+ +Setelah menambahkan preferensi yang diperlukan dalam {@link android.preference.PreferenceActivity} Anda +untuk mengontrol kebiasaan data aplikasi, Anda harus menambahkan filter intent untuk {@link +android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} dalam file manifes Anda. Misalnya:
+ ++<activity android:name="SettingsActivity" ... > + <intent-filter> + <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> ++ +
Filter intent ini menunjukkan pada sistem bahwa ini adalah aktivitas yang mengontrol penggunaan +data aplikasi Anda. Jadi, saat pengguna memeriksa seberapa banyak data yang digunakan oleh aplikasi dari +aplikasi Settings pada sistem, tombol View application settings akan tersedia dan menjalankan +{@link android.preference.PreferenceActivity} sehingga pengguna bisa menyaring seberapa besar data yang digunakan +aplikasi Anda.
+ + + + + + + +Membangun Preferensi Custom
+ +Kerangka kerja Android menyertakan berbagai subkelas {@link android.preference.Preference} yang +memungkinkan Anda membangun UI untuk beberapa macam tipe pengaturan. +Akan tetapi, Anda mungkin menemukan pengaturan yang diperlukan bila tidak ada solusi bawaan, seperti +picker nomor atau picker tanggal. Dalam hal demikian, Anda akan perlu membuat preferensi custom dengan memperluas +kelas {@link android.preference.Preference} atau salah satu subkelas lainnya.
+ +Bila memperluas kelas {@link android.preference.Preference}, ada beberapa hal +penting yang perlu Anda lakukan:
+ +-
+
- Menetapkan antarmuka pengguna yang akan muncul saat pengguna memilih pengaturan. +
- Menyimpan nilai pengaturan bila perlu. +
- Menginisialisasi {@link android.preference.Preference} dengan nilai saat ini (atau default) +bila muncul di tampilan. +
- Menyediakan nilai default bila diminta oleh sistem. +
- Jika {@link android.preference.Preference} menyediakan UI sendiri (seperti dialog), simpan +dan pulihkan status untuk menangani perubahan daur hidup (seperti saat pengguna memutar layar). +
Bagian berikut menjelaskan cara melakukan setiap tugas ini.
+ + + +Menetapkan antarmuka pengguna
+ +Jika secara langsung memperluas kelas {@link android.preference.Preference}, Anda perlu mengimplementasikan +{@link android.preference.Preference#onClick()} untuk mendefinisikan tindakan yang terjadi bila pengguna +memilih item tersebut. Akan tetapi, sebagian besar pengaturan custom memperluas {@link android.preference.DialogPreference} untuk +menampilkan dialog, sehingga menyederhanakan prosedur. Bila memperluas {@link +android.preference.DialogPreference}, Anda harus memanggil {@link +android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} selama di +konstruktor kelas untuk menetapkan layout dialog.
+ +Misalnya, beri ini konstruktor untuk {@link +android.preference.DialogPreference} custom yang mendeklarasikan layout dan menetapkan teks untuk tombol dialog +negatif dan positif default:
+ ++public class NumberPickerPreference extends DialogPreference { + public NumberPickerPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.numberpicker_dialog); + setPositiveButtonText(android.R.string.ok); + setNegativeButtonText(android.R.string.cancel); + + setDialogIcon(null); + } + ... +} ++ + + +
Menyimpan nilai pengaturan
+ +Anda bisa menyimpan nilai pengaturan kapan saja dengan memanggil salah satu metode {@code persist*()} kelas {@link +android.preference.Preference}, seperti {@link +android.preference.Preference#persistInt persistInt()} jika nilai pengaturan adalah integer atau +{@link android.preference.Preference#persistBoolean persistBoolean()} untuk menyimpan boolean.
+ +Catatan: Setiap {@link android.preference.Preference} hanya bisa menyimpan satu +tipe data, jadi Anda harus menggunakan metode {@code persist*()} yang tepat untuk tipe data yang digunakan +oleh {@link android.preference.Preference} custom Anda.
+ +Bila Anda memilih untuk mempertahankannya, pengaturan bisa bergantung pada kelas {@link +android.preference.Preference} yang Anda perluas. Jika Anda memperluas {@link +android.preference.DialogPreference}, maka Anda harus mempertahankan nilai hanya jika dialog +tertutup karena hasil positif (pengguna memilih tombol "OK").
+ +Bila {@link android.preference.DialogPreference} tertutup, sistem akan memanggil metode {@link
+android.preference.DialogPreference#onDialogClosed onDialogClosed()}. Metode mencakup argumen
+boolean yang menetapkan apakah hasil pengguna "positif"—jika nilainya
+true
, maka pengguna memilih tombol positif dan Anda harus menyimpan nilai baru. Misalnya:
+
+@Override +protected void onDialogClosed(boolean positiveResult) { + // When the user selects "OK", persist the new value + if (positiveResult) { + persistInt(mNewValue); + } +} ++ +
Dalam contoh ini, mNewValue
adalah anggota kelas yang menampung nilai
+pengaturan saat ini. Memanggil {@link android.preference.Preference#persistInt persistInt()} akan menyimpan nilai
+ke file {@link android.content.SharedPreferences} (secara otomatis menggunakan kunci yang
+ditetapkan dalam file XML untuk {@link android.preference.Preference} ini).
Menginisialisasi nilai saat ini
+ +Bila sistem menambahkan {@link android.preference.Preference} Anda ke layar, ia +akan memanggil {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} untuk memberi tahu +Anda apakah pengaturan memiliki nilai yang dipertahankan. Jika tidak ada nilai yang dipertahankan, panggilan ini +akan menyediakan nilai default bagi Anda.
+ +Metode {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} akan meneruskan
+boolean, restorePersistedValue
, untuk menunjukkan apakah nilai dipertahankan
+untuk pengaturan. Jika true
, maka Anda harus mengambil nilai yang dipertahankan dengan memanggil
+salah satu metode {@code getPersisted*()} kelas {@link
+android.preference.Preference}, seperti {@link
+android.preference.Preference#getPersistedInt getPersistedInt()} untuk nilai integer. Anda biasanya
+perlu mengambil nilai yang dipertahankan agar bisa memperbarui UI dengan benar untuk merefleksikan
+nilai yang tersimpan sebelumnya.
Jika restorePersistedValue
adalah false
, maka Anda
+harus menggunakan nilai default yang diteruskan dalam argumen kedua.
+@Override +protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + if (restorePersistedValue) { + // Restore existing state + mCurrentValue = this.getPersistedInt(DEFAULT_VALUE); + } else { + // Set default state from the XML attribute + mCurrentValue = (Integer) defaultValue; + persistInt(mCurrentValue); + } +} ++ +
Setiap metode {@code getPersisted*()} memerlukan argumen yang menetapkan +nilai default untuk digunakan jika tidak ada nilai yang dipertahankan atau kunci tidak ada. Dalam contoh +di atas, konstanta lokal yang digunakan untuk menetapkan nilai default dalam kasus {@link +android.preference.Preference#getPersistedInt getPersistedInt()} tidak bisa mengembalikan nilai yang dipertahankan.
+ +Perhatian: Anda tidak bisa menggunakan
+defaultValue
sebagai nilai default dalam metode {@code getPersisted*()}, karena
+nilainya selalu nol bila restorePersistedValue
adalah true
.
Menyediakan nilai default
+ +Jika instance kelas {@link android.preference.Preference} Anda menetapkan nilai default +(dengan atribut {@code android:defaultValue}), maka +sistem akan memanggil {@link android.preference.Preference#onGetDefaultValue +onGetDefaultValue()} bila membuat instance objek untuk mengambil nilai. Anda harus mengimplementasikan +metode ini agar sistem bisa menyimpan nilai default dalam {@link +android.content.SharedPreferences}. Misalnya:
+ ++@Override +protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, DEFAULT_VALUE); +} ++ +
Argumen metode menyediakan semua hal yang Anda perlukan: larik atribut dan posisi +indeks dari {@code android:defaultValue}, yang harus Anda ambil. Alasan Anda harus +mengimplementasikan metode ini untuk mengekstrak nilai default dari atribut adalah karena Anda harus menetapkan +nilai default lokal untuk atribut jika nilai tidak didefinisikan.
+ + + +Menyimpan dan memulihkan status Preferensi
+ +Seperti halnya {@link android.view.View} di layout, subkelas {@link android.preference.Preference} +Anda bertanggung jawab menyimpan dan memulihkan statusnya jika aktivitas atau fragmen +di-restart (seperti saat pengguna memutar layar). Untuk menyimpan +dan memulihkan status kelas {@link android.preference.Preference} dengan benar, Anda harus mengimplementasikan +metode callback daur hidup {@link android.preference.Preference#onSaveInstanceState +onSaveInstanceState()} dan {@link +android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()}.
+ +Status {@link android.preference.Preference} Anda didefinisikan oleh objek yang mengimplementasikan +antarmuka {@link android.os.Parcelable}. Kerangka kerja Android menyediakan objek seperti itu untuk Anda gunakan +sebagai titik mulai untuk mendefinisikan objek status Anda: kelas {@link +android.preference.Preference.BaseSavedState}.
+ +Untuk mendefinisikan cara kelas {@link android.preference.Preference} menyimpan statusnya, Anda harus +memperluas kelas {@link android.preference.Preference.BaseSavedState}. Anda hanya perlu mengesampingkan + beberapa metode dan mendefinisikan objek {@link android.preference.Preference.BaseSavedState#CREATOR} +.
+ +Untuk sebagian besar aplikasi, Anda bisa menyalin implementasi berikut dan cukup mengubah baris yang +menangani {@code value} jika subkelas {@link android.preference.Preference} Anda menyimpan tipe +data selain integer.
+ ++private static class SavedState extends BaseSavedState { + // Member that holds the setting's value + // Change this data type to match the type saved by your Preference + int value; + + public SavedState(Parcelable superState) { + super(superState); + } + + public SavedState(Parcel source) { + super(source); + // Get the current preference's value + value = source.readInt(); // Change this to read the appropriate data type + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + // Write the preference's value + dest.writeInt(value); // Change this to write the appropriate data type + } + + // Standard creator object using an instance of this class + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; +} ++ +
Dengan implementasi {@link android.preference.Preference.BaseSavedState} di atas yang ditambahkan +ke aplikasi Anda (biasanya sebagai subkelas dari subkelas {@link android.preference.Preference}), Anda +nanti perlu mengimplementasikan metode {@link android.preference.Preference#onSaveInstanceState +onSaveInstanceState()} dan {@link +android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} untuk subkelas +{@link android.preference.Preference} Anda.
+ +Misalnya:
+ ++@Override +protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + // Check whether this Preference is persistent (continually saved) + if (isPersistent()) { + // No need to save instance state since it's persistent, + // use superclass state + return superState; + } + + // Create instance of custom BaseSavedState + final SavedState myState = new SavedState(superState); + // Set the state's value with the class member that holds current + // setting value + myState.value = mNewValue; + return myState; +} + +@Override +protected void onRestoreInstanceState(Parcelable state) { + // Check whether we saved the state in onSaveInstanceState + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save the state, so call superclass + super.onRestoreInstanceState(state); + return; + } + + // Cast state to custom BaseSavedState and pass to superclass + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + + // Set this Preference's widget to reflect the restored state + mNumberPicker.setValue(myState.value); +} ++ diff --git a/docs/html-intl/intl/in/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/in/guide/topics/ui/ui-events.jd new file mode 100644 index 0000000000000000000000000000000000000000..5068176fccaefce46166e9b4aceb85e35cfef955 --- /dev/null +++ b/docs/html-intl/intl/in/guide/topics/ui/ui-events.jd @@ -0,0 +1,291 @@ +page.title=Kejadian Input +parent.title=Antarmuka Pengguna +parent.link=index.html +@jd:body + +
Dalam dokumen ini
+ + +Di Android, ada lebih dari satu cara untuk mencegat kejadian dari interaksi pengguna dengan aplikasi Anda. +Saat mempertimbangkan kejadian dalam antarmuka pengguna Anda, pendekatannya adalah menangkap kejadian +dari objek View tertentu yang digunakan pengguna untuk berinteraksi. Kelas View menyediakan sarana untuk melakukannya.
+ +Dalam berbagai kelas View yang akan digunakan untuk menyusun layout, Anda mungkin melihat beberapa metode callback
+publik yang tampak berguna untuk kejadian UI. Metode ini dipanggil oleh kerangka kerja Android ketika masing-masing
+tindakan terjadi pada objek itu. Misalnya, bila View (seperti Button/Tombol) disentuh,
+metode onTouchEvent()
akan dipanggil pada objek itu. Akan tetapi, untuk mencegatnya, Anda harus memperluas
+kelas dan mengesampingkan metode itu. Akan tetapi, memperluas setiap objek View
+untuk menangani kejadian seperti itu tidaklah praktis. Karena itulah kelas View juga berisi
+sekumpulan antarmuka tersarang dengan callback yang jauh lebih mudah didefinisikan. Antarmuka ini,
+yang disebut event listener, merupakan tiket Anda untuk menangkap interaksi pengguna dengan UI.
Walaupun Anda akan lebih sering menggunakan event listener ini untuk interaksi pengguna, +mungkin ada saatnya Anda ingin memperluas kelas View, untuk membuat komponen custom. +Mungkin Anda ingin memperluas kelas {@link android.widget.Button} +untuk membuat sesuatu yang lebih menarik. Dalam hal ini, Anda akan dapat mendefinisikan perilaku kejadian default untuk kelas Anda dengan menggunakan +kelas event handler.
+ + +Event Listener
+ +Event listener merupakan antarmuka di kelas {@link android.view.View} yang berisi metode +callback tunggal. Metode ini akan dipanggil oleh kerangka kerja Android bila View yang +telah didaftarkan dengan listener dipicu oleh interaksi pengguna dengan item dalam UI.
+ +Yang juga disertakan dalam antarmuka event listener adalah metode callback berikut ini:
+ +-
+
onClick()
+ - Dari {@link android.view.View.OnClickListener}. + Ini dipanggil baik saat pengguna menyentuh item + (bila dalam mode sentuh), maupun memfokuskan pada item dengan tombol navigasi atau trackball dan +menekan tombol "enter" yang sesuai atau menekan trackball. +
onLongClick()
+ - Dari {@link android.view.View.OnLongClickListener}. + Ini dipanggil baik saat pengguna menyentuh dan menahan item (bila dalam mode sentuh), +maupun memfokuskan pada item dengan tombol navigasi atau trackball dan +menekan serta menahan tombol "enter" yang sesuai atau menekan dan menahan trackball (selama satu detik). +
onFocusChange()
+ - Dari {@link android.view.View.OnFocusChangeListener}. + Ini dipanggil saat pengguna menyusuri ke atau dari item, dengan menggunakan tombol navigasi atau trackball. +
onKey()
+ - Dari {@link android.view.View.OnKeyListener}. + Ini dipanggil saat pengguna memfokuskan pada item dan menekan atau melepas tombol fisik pada perangkat. +
onTouch()
+ - Dari {@link android.view.View.OnTouchListener}. + Ini dipanggil saat pengguna melakukan tindakan yang digolongkan sebagai kejadian sentuh, termasuk penekanan, pelepasan, +atau gerak perpindahan pada layar (dalam batasan item itu). +
onCreateContextMenu()
+ - Dari {@link android.view.View.OnCreateContextMenuListener}. + Ini dipanggil saat Menu Konteks sedang dibuat (akibat "klik lama" terus-menerus). Lihat diskusi +tentang menu konteks di panduan pengembang Menu. + +
Metode ini satu-satunya yang menempati antarmukanya masing-masing. Untuk mendefinisikan salah satu metode ini
+dan menangani kejadian Anda, implementasikan antarmuka tersarang dalam Aktivitas Anda atau definisikan sebagai kelas anonim.
+Kemudian, teruskan satu
+instance implementasi Anda pada masing-masing metode View.set...Listener()
. (Misalnya, panggil
+{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}
+dan teruskan implementasi {@link android.view.View.OnClickListener OnClickListener} Anda.)
Contoh di bawah menunjukkan cara mendaftarkan on-click listener untuk Button.
+ ++// Create an anonymous implementation of OnClickListener +private OnClickListener mCorkyListener = new OnClickListener() { + public void onClick(View v) { + // do something when the button is clicked + } +}; + +protected void onCreate(Bundle savedValues) { + ... + // Capture our button from layout + Button button = (Button)findViewById(R.id.corky); + // Register the onClick listener with the implementation above + button.setOnClickListener(mCorkyListener); + ... +} ++ +
Anda juga akan merasa lebih praktis mengimplementasikan OnClickListener sebagai bagian dari Aktivitas. +Ini akan menghindari beban kelas ekstra dan alokasi objek. Misalnya:
++public class ExampleActivity extends Activity implements OnClickListener { + protected void onCreate(Bundle savedValues) { + ... + Button button = (Button)findViewById(R.id.corky); + button.setOnClickListener(this); + } + + // Implement the OnClickListener callback + public void onClick(View v) { + // do something when the button is clicked + } + ... +} ++ +
Perhatikan bahwa callback onClick()
dalam contoh di atas tidak memiliki
+nilai hasil, namun beberapa metode event listener lainnya harus mengembalikan boolean. Sebabnya
+bergantung pada kejadian. Untuk sebagian yang mengembalikan boolean, ini sebabnya:
-
+
{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}
- + Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh. + Yaitu, mengembalikan benar untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini; + mengembalikan salah jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke + on-click listener lainnya.
+ {@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}
- + Ini mengembalikan boolean untuk menunjukkan apakah Anda telah menggunakan kejadian dan tidak boleh dibawa lebih jauh. + Yaitu, mengembalikan benar untuk menunjukkan apakah Anda telah menangani kejadian dan semestinya berhenti di sini; + mengembalikan salah jika Anda tidak menanganinya dan/atau kejadian semestinya berlanjut ke + on-key listener lainnya.
+ {@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}
- + Ini mengembalikan boolean untuk menunjukkan apakah listener Anda telah menggunakan kejadian ini. Yang penting adalah +kejadian ini bisa memiliki beberapa tindakan yang saling mengikuti. Jadi, jika Anda mengembalikan salahsaat +kejadian tindakan turun diterima, itu menunjukkan bahwa Anda belum menggunakan kejadian itu dan juga +tidak tertarik dengan tindakan berikutnya dari kejadian ini. Karena itu, Anda tidak akan diminta untuk melakukan tindakan + lainnya dalam kejadian, seperti gerakan jari, atau kejadian tindakan naik yang akan terjadi.
+
Ingatlah bahwa kejadian tombol fisik selalu disampaikan ke View yang sedang difokus. Kejadian ini dikirim mulai dari atas
+hierarki View, kemudian turun hingga tujuan yang sesuai. Jika View Anda (atau anak View Anda)
+saat ini sedang fokus, maka Anda dapat melihat kejadian berpindah melalui metode.{@link android.view.View#dispatchKeyEvent(KeyEvent)
+dispatchKeyEvent()}
Sebagai pengganti untuk menangkap kejadian penting melalui View, Anda juga dapat menerima
+semua kejadian dalam Aktivitas Anda dengan {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}
+dan {@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}
.
Selain itu, saat memikirkan tentang input teks aplikasi Anda, ingatlah bahwa banyak perangkat yang hanya memiliki
+metode input perangkat lunak. Metode seperti itu tidak harus berbasis tombol; sebagian mungkin menggunakan input suara, tulisan tangan, dan seterusnya. Meskipun
+metode input menyajikan antarmuka seperti keyboard, itu umumnya tidak memicu keluarga kejadian
+{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}
. Anda sama sekali tidak boleh
+membangun UI yang mengharuskan penekanan tombol tertentu dikontrol kecuali jika Anda ingin membatasi aplikasi Anda pada perangkat yang memiliki
+keyboard fisik. Khususnya, jangan mengandalkan metode ini untuk memvalidasi input saat pengguna menekan tombol
+enter; melainkan, gunakan tindakan seperti {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} untuk menandai
+metode input mengenai reaksi yang diharapkan aplikasi Anda, sehingga bisa mengubah UI-nya secara signifikan. Hindari anggapan
+tentang bagaimana metode input perangkat lunak seharusnya bekerja dan percayalah bahwa metode akan menyediakan teks yang sudah diformat bagi aplikasi Anda.
Catatan: Android akan memanggil event handler terlebih dahulu kemudian handler +default yang sesuai dari definisi kelas. Karena itu, mengembalikan benar dari event listener ini akan menghentikan +penyebaran kejadian ke event listener lain dan juga akan memblokir callback ke +event handler default di View. Pastikan bahwa Anda ingin mengakhiri kejadian saat mengembalikan true.
+ + +Event Handler
+ +Jika Anda membuat komponen custom dari View, maka Anda dapat mendefinisikan penggunaan beberapa +metode callback sebagai event handler default. +Dalam dokumen tentang Komponen +Custom, Anda akan melihat penggunaan beberapa callback umum untuk penanganan kejadian, +termasuk:
+-
+
{@link android.view.View#onKeyDown}
- Dipanggil bila terjadi kejadian tombol baru.
+ {@link android.view.View#onKeyUp}
- Dipanggil bila terjadi kejadian tombol naik.
+ {@link android.view.View#onTrackballEvent}
- Dipanggil bila terjadi kejadian gerakan trackball.
+ {@link android.view.View#onTouchEvent}
- Dipanggil bila terjadi kejadian gerakan layar sentuh.
+ {@link android.view.View#onFocusChanged}
- Dipanggil bila View memperoleh atau kehilangan fokus.
+
Ada beberapa metode lain yang harus Anda ketahui, yang bukan bagian dari kelas View, +namun bisa berdampak langsung pada kemampuan Anda menangani kejadian. Jadi, saat mengelola kejadian yang lebih kompleks dalam +layout, pertimbangkanlah metode-metode lain ini:
+-
+
{@link android.app.Activity#dispatchTouchEvent(MotionEvent) + Activity.dispatchTouchEvent(MotionEvent)}
- Ini memungkinkan {@link + android.app.Activity} Anda mencegat semua kejadian sentuh sebelum dikirim ke jendela.
+ {@link android.view.ViewGroup#onInterceptTouchEvent(MotionEvent) + ViewGroup.onInterceptTouchEvent(MotionEvent)}
- Ini memungkinkan {@link + android.view.ViewGroup} memantau kejadian saat dikirim ke View anak.
+ {@link android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean) + ViewParent.requestDisallowInterceptTouchEvent(boolean)}
- Panggil ini + pada View induk untuk menunjukan larangan mencegat kejadian sentuh dengan{@link + android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}
.
+
Mode Sentuh
++Saat pengguna menyusuri antarmuka pengguna dengan tombol pengarah atau trackball, Anda +perlu memberikan fokus pada item tindakan (seperti tombol) agar pengguna bisa mengetahui apa +yang akan menerima input. Akan tetapi jika perangkat memiliki kemampuan sentuh, dan pengguna +mulai berinteraksi dengan antarmuka dengan menyentuhnya, maka Anda tidak perlu lagi +menyorot item, atau memfokuskan pada View tertentu. Karena itu, ada mode +untuk interaksi yang bernama "mode sentuh". +
++Untuk perangkat berkemampuan sentuh, setelah pengguna menyentuh layar, perangkat +akan masuk ke mode sentuh. Dari sini dan selanjutnya, hanya View dengan +{@link android.view.View#isFocusableInTouchMode} benar yang akan dapat difokus, seperti widget pengedit teks. +View lain yang dapat disentuh, seperti tombol, tidak akan difokus bila disentuh; View ini akan +langsung memicu on-click listener bila ditekan. +
++Kapan saja pengguna menekan tombol pengarah atau menggulir dengan trackball, perangkat akan +keluar dari mode sentuh, dan mencari tampilan untuk difokuskan. Kini pengguna bisa melanjutkan interaksi +dengan antarmuka pengguna tanpa menyentuh layar. +
++Status mode sentuh dipertahankan di seluruh sistem (semua jendela dan aktivitas). +Untuk query status saat ini, Anda bisa memanggil +{@link android.view.View#isInTouchMode} untuk mengetahui apakah perangkat saat ini sedang dalam mode sentuh. +
+ + +Menangani Fokus
+ +Kerangka kerja ini akan menangani gerakan fokus rutin sebagai respons input pengguna.
+Ini termasuk mengubah fokus saat View dihapus atau disembunyikan, atau saat tersedia View
+baru. View menunjukkan kesediaannya untuk mengambil fokus
+melalui metode {@link android.view.View#isFocusable()}
. Untuk mengubah apakah View bisa mengambil
+fokus, panggil {@link android.view.View#setFocusable(boolean) setFocusable()}
. Saat dalam mode sentuh,
+Anda dapat me-query apakah View memungkinkan fokus dengan {@link android.view.View#isFocusableInTouchMode()}
.
+Anda bisa mengubahnya dengan {@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}
.
+
Gerakan fokus berdasarkan pada algoritma yang mencari tetangga terdekat dalam +arah yang diberikan. Dalam kasus yang jarang terjadi, algoritma default mungkin +tidak cocok dengan perilaku yang diinginkan pengembang. Dalam situasi ini, Anda bisa memberikan +pengesampingan eksplisit dengan mengikuti atribut XML berikut dalam file layout: +nextFocusDown, nextFocusLeft, nextFocusRight, dan +nextFocusUp. Tambahkan salah satu atribut ini ke View dari mana fokus +meninggalkan. Definisikan nilai atribut untuk menjadi ID View +ke mana fokus harus diberikan. Misalnya:
++<LinearLayout + android:orientation="vertical" + ... > + <Button android:id="@+id/top" + android:nextFocusUp="@+id/bottom" + ... /> + <Button android:id="@+id/bottom" + android:nextFocusDown="@+id/top" + ... /> +</LinearLayout> ++ +
Biasanya, dalam layout vertikal ini, navigasi ke atas dari Button pertama tidak akan membawa ke +mana pun, tidak pula akan menyusuri ke bawah dari Button kedua. Karena sekarang Button atas telah +mendefinisikan Button bawah sebagai nextFocusUp (dan sebaliknya), fokus navigasi akan +silih berganti dari atas ke bawah dan bawah ke atas.
+ +Jika Anda ingin mendeklarasikan View sebagai dapat difokus dalam UI (bila biasanya tidak dapat difokus),
+tambahkan atribut XML android:focusable
ke View, dalam deklarasi layout Anda.
+Atur nilai true. Anda juga bisa mendeklarasikan View
+sebagai dapat difokus saat dalam Mode Sentuh dengan android:focusableInTouchMode
.
Untuk meminta View tertentu difokus, panggil {@link android.view.View#requestFocus()}
.
Untuk mendengarkan kejadian fokus (diberi tahu bila View menerima atau kehilangan fokus), gunakan
+{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}
+, seperti yang dibahas di bagian Event Listener, di atas.
Unduh
+ +Sebelum menginstal Android Studio atau alat SDK mandiri, +Anda harus menyetujui ketentuan dan persyaratan berikut.
+ +Ketentuan dan Persyaratan
+Ini adalah Perjanjian Lisensi Kit Pengembangan Perangkat Lunak Android + +1. Introduction
+1.1 The Android Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK. + +1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time. + +1.3 A "compatible implementation" means any Android device that (i) complies with the Android Compatibility Definition document, which can be found at the Android compatibility website (http://source.android.com/compatibility) and which may be updated from time to time; and (ii) successfully passes the Android Compatibility Test Suite (CTS). + +1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. + + +2. Accepting this License Agreement
+2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License Agreement. + +2.2 By clicking to accept, you hereby agree to the terms of the License Agreement. + +2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. + +2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity. + + +3. SDK License from Google
+3.1 Subject to the terms of the License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable, non-exclusive, and non-sublicensable license to use the SDK solely to develop applications for compatible implementations of Android. + +3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Android) or to develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of Android, provided that this SDK is not used for that purpose. + +3.3 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you. + +3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK. + +3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. + +3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you. + +3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features. + +3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK. + + +4. Use of the SDK by You
+4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. + +4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). + +4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so. + +4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier. + +4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so. + +4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach. + + +5. Your Developer Credentials
+5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials. + + +6. Privacy and Information
+6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected. + +6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy. + + +7. Third Party Applications
+7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources. + +7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners. + +7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. + + +8. Using Android APIs
+8.1 Google Data APIs + +8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service. + +8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so. + + +9. Terminating this License Agreement
+9.1 The License Agreement will continue to apply until terminated by either you or Google as set out below. + +9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials. + +9.3 Google may at any time, terminate the License Agreement with you if: +(A) you have breached any provision of the License Agreement; or +(B) Google is required to do so by law; or +(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or +(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable. + +9.4 When the License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst the License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely. + + +10. DISCLAIMER OF WARRANTIES
+10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. + +10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. + +10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + + +11. LIMITATION OF LIABILITY
+11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. + + +12. Indemnification
+12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with the License Agreement. + + +13. Changes to the License Agreement
+13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available. + + +14. General Legal Terms
+14.1 The License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK. + +14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google. + +14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable. + +14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement. + +14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. + +14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party. + +14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. + +November 20, 2015 +Beberapa saat lagi Anda akan dapat membuat aplikasi untuk Android!
+Sebentar lagi, Anda akan dialihkan ke + Menginstal Android SDK.
+ +Android Studio
+ +Android IDE resmi
+ +-
+
- Android Studio IDE +
- Android SDK Tools +
- Platform Android 6.0 (Marshmallow) +
- Citra sistem emulator Android 6.0 dengan Google API +
+ + +
+Untuk mendapatkan Android Studio atau alat SDK mandiri, kunjungi developer.android.com/sdk/ +
+Editor kode cerdas
+ +Yang menjadi inti Android Studio adalah editor kode cerdas dengan kemampuan + penyelesaian kode, optimalisasi, dan analisis kode yang canggih.
+Editor kode yang andal ini membantu Anda menjadi pengembang aplikasi Android yang lebih produktif.
+Template kode dan integrasi GitHub
+ +Pemandu proyek yang baru membuat proses memulai proyek baru menjadi jauh lebih mudah.
+ +Mulai proyek dengan menggunakan kode template untuk pola seperti navigation-drawer dan view-pager, + dan bahkan impor contoh kode Google dari GitHub.
+Pengembangan aplikasi multilayar
+ +Buat aplikasi untuk ponsel dan tablet Android, Android Wear, + Android TV, Android Auto dan Google Glass.
+Dengan Android Project View yang baru dan dukungan modul di Android Studio, jadi semakin mudah + mengelola proyek dan sumber daya aplikasi. +
Perangkat virtual untuk semua ukuran dan bentuk
+ +Android Studio sudah dikonfigurasi dengan citra emulator yang dioptimalkan.
+Virtual Device Manager yang telah diperbarui dan dibuat lebih efisien menyediakan + profil perangkat yang sudah didefinisikan untuk perangkat Android umum.
++Pembuatan Android berkembang dengan Gradle
+ +Buatlah berbagai APK untuk aplikasi Android Anda dengan aneka fitur menggunakan proyek yang sama.
+Kelola dependensi aplikasi dengan Maven.
+Buat APK dari Android Studio atau baris perintah.
+Selengkapnya tentang Android Studio
+-
+
- Dibuat dengan IntelliJ IDEA Community Edition, JAVA IDE populer karya JetBrains. +
- Sistem pembuatan berbasis Gradle yang fleksibel. +
- Buat berbagai generasi APK dan variannya. +
- Dukungan template bertambah untuk Google Services dan aneka tipe perangkat. +
- Editor layout yang lengkap dengan dukungan untuk pengeditan tema. +
- Alat penambal untuk solusi kinerja, kegunaan, kompatibilitas versi, dan masalah lain. +
- ProGuard dan kemampuan penandatanganan aplikasi. +
- Dukungan bawaan untuk Google Cloud Platform, mempermudah integrasi Google Cloud + Messaging dan App Engine. +
+Untuk detail selengkapnya tentang fitur-fitur yang tersedia di Android Studio, +bacalah panduan Dasar-Dasar Android Studio.
+Jika Anda menggunakan Eclipse dengan ADT, ingatlah bahwa Android Studio sekarang merupakan IDE resmi +untuk Android, jadi Anda harus beralih ke Android Studio untuk menerima semua +pembaruan terakhir IDE. Untuk bantuan dalam memindahkan proyek, +lihat Beralih ke Android +Studio.
+ + + + + + + +Kebutuhan Sistem
+ +Windows
+ +-
+
- Microsoft® Windows® 8/7/Vista/2003 (32 atau 64-bit) +
- RAM minimum 2 GB, RAM yang direkomendasikan 4 GB +
- Ruang hard-disk 400 MB +
- Setidaknya 1 GB untuk Android SDK, citra sistem emulator, dan cache +
- Resolusi layar minimum 1280 x 800 +
- Java Development Kit (JDK) 7 +
- Opsional untuk emulator akselerasi: Prosesor Intel® dengan dukungan untuk Intel® VT-x, Intel® EM64T +(Intel® 64), dan fungsionalitas Execute Disable (XD) Bit +
Mac OS X
+ +-
+
- Mac® OS X® 10.8.5 atau yang lebih tinggi, hingga 10.9 (Mavericks) +
- RAM minimum 2 GB, RAM yang direkomendasikan 4 GB +
- Ruang hard-disk 400 MB +
- Setidaknya 1 GB untuk Android SDK, citra sistem emulator, dan cache +
- Resolusi layar minimum 1280 x 800 +
- Java Runtime Environment (JRE) 6 +
- Java Development Kit (JDK) 7 +
- Opsional untuk emulator akselerasi: Prosesor Intel® dengan dukungan untuk Intel® VT-x, Intel® EM64T +(Intel® 64), dan fungsionalitas Execute Disable (XD) Bit +
Pada Mac OS, jalankan Android Studio dengan Java Runtime Environment (JRE) 6 untuk rendering +font yang dioptimalkan. Kemudian Anda bisa mengonfigurasi proyek untuk menggunakan Java Development Kit (JDK) 6 atau JDK 7.
+ + + +Linux
+ +-
+
- Desktop GNOME atau KDE +
- GNU C Library (glibc) 2.15 atau yang lebih baru +
- RAM minimum 2 GB, RAM yang direkomendasikan 4 GB +
- Ruang hard-disk 400 MB +
- Setidaknya 1 GB untuk Android SDK, citra sistem emulator, dan cache +
- Resolusi layar minimum 1280 x 800 +
- Oracle® Java Development Kit (JDK) 7 +
Telah diuji pada Ubuntu® 14.04, Trusty Tahr (distribusi 64-bit yang mampu menjalankan +aplikasi 32-bit).
+ + + + +Opsi Unduhan Lain
+ + diff --git a/docs/html-intl/intl/in/sdk/installing/adding-packages.jd b/docs/html-intl/intl/in/sdk/installing/adding-packages.jd new file mode 100644 index 0000000000000000000000000000000000000000..2fc5c3eb0cd8b2d38a4b47126de387aa33d34785 --- /dev/null +++ b/docs/html-intl/intl/in/sdk/installing/adding-packages.jd @@ -0,0 +1,226 @@ +page.title=Menambahkan Paket SDK + +page.tags=sdk manager + +@jd:body + + + + ++Secara default, Android SDK tidak mencakup segala sesuatu yang Anda perlukan untuk memulai pengembangan. +SDK memisahkan alat, platform, dan komponen lain ke dalam paket yang bisa Anda +unduh bila diperlukan dengan menggunakan +Android SDK Manager. +Jadi, sebelum Anda bisa memulai, ada beberapa paket yang harus Anda tambahkan ke Android SDK Anda.
+ +Untuk mulai menambahkan paket, jalankan Android SDK Manager dengan salah satu cara berikut:
+-
+
- Di Android Studio, klik SDK Manager + di toolbar. +
- Jika Anda tidak menggunakan Android Studio:
+
-
+
- Windows: Klik ganda file
SDK Manager.exe
pada akar direktori Android +SDK.
+ - Mac/Linux: Buka sebuah terminal dan arahkan ke direktori
tools/
di +lokasi instalasi Android SDK, lalu jalankanandroid sdk
.
+
+ - Windows: Klik ganda file
Bila Anda membuka SDK Manager untuk pertama kali, beberapa paket akan dipilih secara +default. Biarkan dipilih, namun pastikan bahwa Anda mempunyai semua yang Anda perlukan +untuk persiapan dengan mengikuti langkah-langkah ini:
+ + +-
+
-
+
Dapatkan alat-alat SDK terbaru
+ + + +Setidaknya saat menyiapkan Android SDK, + Anda harus mengunduh platform Android dan alat-alat terbaru:
+-
+
- Buka direktori Tools dan pilih:
+
-
+
- Android SDK Tools +
- Android SDK Platform-tools +
- Android SDK Build-tools (versi tertinggi) +
+ - Buka folder Android X.X (versi terbaru) yang pertama dan pilih:
+
-
+
- SDK Platform +
- Sebuah citra sistem untuk emulator, seperti
+ ARM EABI v7a System Image
+
+
+
+ - Buka direktori Tools dan pilih:
+
-
+
Dapatkan pustaka dukungan untuk API tambahan
+ +++ +Pustaka dukungan diperlukan untuk:
+-
+
- Android Wear +
- Android TV +
- Google Cast +
Pustaka ini juga menyediakan API populer:
+ +Android Support Library +menyediakan set API tambahan yang kompatibel dengan sebagian besar versi Android.
+ +Buka direktori Extras dan pilih:
+-
+
- Android Support Repository +
- Android Support Library +
+
+
+ -
+
Dapatkan Google Play services untuk API yang lebih banyak lagi
+ ++ ++ +API Google Play services menyediakan beragam fitur dan layanan untuk aplikasi Android +Anda, misalnya:
+ +Untuk mengembangkan aplikasi dengan Google API, Anda memerlukan paket Google Play services:
+Buka direktori Extras dan pilih:
+-
+
- Google Repository +
- Google Play services +
Catatan: API Google Play services tidak tersedia pada semua +perangkat berbasis Android, namun tersedia pada semua perangkat dengan Google Play Store. Untuk menggunakan API ini + dalam emulator Android, Anda juga harus menginstal citra sistem Google API + dari direktori Android X.X terbaru di SDK Manager.
+
+
+
+ -
+
Instal paket tersebut
+Setelah Anda memilih semua paket yang diinginkan, teruskan untuk menginstal:
+-
+
- Klik Install X packages. +
- Di jendela berikutnya, klik ganda masing-masing nama paket di sebelah kiri + untuk menyetujui perjanjian lisensinya masing-masing. +
- Klik Install. +
Kemajuan pengunduhan diperlihatkan di bagian bawah jendela SDK Manager. + Jangan keluar dari SDK Manager karena hal itu akan membatalkan pengunduhan.
+
+
+ -
+
Bangun sesuatu!
+ +Dengan adanya semua paket di atas di Android SDK, maka Anda siap untuk membangun aplikasi +untuk Android. Dengan tersedianya berbagai alat baru dan API lainnya, maka tinggal jalankan SDK Manager +untuk mengunduh paket baru bagi SDK Anda.
+ +Inilah beberapa opsi cara Anda untuk melanjutkan:
+ +++ + +++Persiapkan
+Jika Anda masih baru dengan pengembangan Android, pelajari dasar-dasar aplikasi Android dengan mengikuti +panduan untuk Membangun Aplikasi Pertama Anda.
+ +++Bangun untuk perangkat wearable
+Jika Anda siap memulai pembangunan aplikasi untuk perangkat wearable Android, lihat panduan untuk +Membangun Aplikasi untuk Android Wear.
+ +++Gunakan Google API
+Untuk mulai menggunakan Google API, seperti Maps atau +layanan Play Game, lihat panduan untuk +Mempersiapkan Google Play +Services.
+ +
+
+
Pelajaran ini mengajarkan Anda cara
+-
+
- Menyesuaikan Umpan Balik Sentuh +
- Menggunakan Reveal Effect +
- Menyesuaikan Transisi Aktivitas +
- Menganimasikan Perubahan Status Tampilan +
- Menganimasikan Drawable Vektor +
Anda juga harus membaca
+ +Animasi dalam desain bahan memberi pengguna umpan balik tentang tindakannya dan menyediakan +kesinambungan visual saat pengguna berinteraksi dengan aplikasi Anda. Tema bahan menyediakan beberapa animasi default +untuk tombol dan transisi aktivitas, dan Android 5.0 (API level 21) ke atas memungkinkan Anda menyesuaikan +animasi ini dan membuat yang baru:
+ +-
+
- Umpan balik sentuh +
- Singkap Melingkar +
- Transisi aktivitas +
- Gerakan melengkung +
- Perubahan status tampilan +
Menyesuaikan Umpan Balik Sentuh
+ +Umpan balik sentuh dalam desain bahan menyediakan konfirmasi visual seketika pada +titik kontak bila pengguna berinteraksi dengan elemen UI. Animasi umpan balik sentuh default +untuk tombol menggunakan kelas {@link android.graphics.drawable.RippleDrawable} baru, yang bertransisi +di antara berbagai status dengan efek riak.
+ +Di sebagian besar kasus, Anda harus menerapkan fungsionalitas ini dalam XML tampilan dengan menetapkan +latar belakang tampilan sebagai:
+ +-
+
?android:attr/selectableItemBackground
untuk riak berbatas.
+?android:attr/selectableItemBackgroundBorderless
untuk riak yang meluas ke luar +tampilan. Latar belakang ini akan digambar di atas, dan dibatasi oleh, induk tampilan terdekat dengan +latar belakang non-null.
+
Catatan: selectableItemBackgroundBorderless
adalah
+atribut baru yang diperkenalkan di API level 21.
Atau, Anda bisa mendefinisikan {@link android.graphics.drawable.RippleDrawable}
+sebagai sumber daya XML dengan menggunakan elemen ripple
.
Anda bisa menetapkan warna ke objek-objek {@link android.graphics.drawable.RippleDrawable}. Untuk mengubah
+warna default umpan balik sentuh, gunakan atribut android:colorControlHighlight
+tema.
Untuk informasi selengkapnya, lihat referensi API bagi kelas {@link +android.graphics.drawable.RippleDrawable}.
+ + +Menggunakan Reveal Effect
+ +Animasi singkap memberi pengguna kesinambungan visual saat menampilkan atau menyembunyikan sekelompok +elemen UI. Metode {@link android.view.ViewAnimationUtils#createCircularReveal +ViewAnimationUtils.createCircularReveal()} memungkinkan Anda menganimasikan lingkaran terpangkas +untuk memperlihatkan atau menyembunyikan tampilan.
+ +Untuk memperlihatkan tampilan yang sebelumnya tidak terlihat dengan menggunakan efek ini:
+ ++// previously invisible view +View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the final radius for the clipping circle +int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); + +// create the animator for this view (the start radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); + +// make the view visible and start the animation +myView.setVisibility(View.VISIBLE); +anim.start(); ++ +
Untuk menyembunyikan sebuah tampilan yang sebelumnya terlihat dengan menggunakan efek ini:
+ ++// previously visible view +final View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the initial radius for the clipping circle +int initialRadius = myView.getWidth(); + +// create the animation (the final radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); + +// make the view invisible when the animation is done +anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + myView.setVisibility(View.INVISIBLE); + } +}); + +// start the animation +anim.start(); ++ + +
Menyesuaikan Transisi Aktivitas
+ + +Transisi aktivitas dalam aplikasi desain bahan memberikan koneksi visual antar berbagai status +melalui gerakan dan transformasi di antara elemen umum. Anda bisa menetapkan animasi custom untuk +masuk ke dan keluar dari transisi dan untuk transisi elemen bersama di antara aktivitas.
+ +-
+
- Transisi masuk menentukan cara tampilan di aktivitas memasuki suatu babak. +misalnya, dalam transisi masuk explode, tampilan memasuki babak dari sisi luar +dan melayang masuk ke arah tengah layar. + +
- Transisi keluar menentukan cara tampilan di aktivitas keluar dari suatu babak. Misalnya +, dalam transisi keluar explode, tampilan akan keluar dari babak dari bagian +tengahnya. + +
- Transisi elemen bersama menentukan cara menggunakan bersama suatu tampilan +oleh dua transisi aktivitas di antara aktivitas-aktivitas ini. Misalnya, jika dua aktivitas memiliki +gambar yang sama dengan posisi dan ukuran berbeda, transisi elemen bersama changeImageTransform +mentransformasikan dan menskalakan gambar secara mulus di antara aktivitas-aktivitas ini. +
Android 5.0 (API level 21) mendukung transisi masuk dan transisi keluar ini:
+ +-
+
- explode - Memindahkan tampilan masuk ke atau keluar dari tengah babak. +
- slide - Memindahkan tampilan masuk ke atau keluar dari salah satu tepi babak. +
- fade - Menambahkan atau menghapus tampilan dari babak dengan mengubah opasitasnya. +
Transisi apa pun yang memperluas kelas {@link android.transition.Visibility} didukung +sebagai transisi masuk atau transisi keluar. Untuk informasi selengkapnya, lihat referensi API untuk kelas +{@link android.transition.Transition}.
+ +Android 5.0 (API level 21) juga mendukung transisi elemen bersama ini:
+ +-
+
- changeBounds - Menganimasikan perubahan pada batas-batas layout tampilan target. +
- changeClipBounds - Menganimasikan perubahan pada batas-batas pemangkasan tampilan target. +
- changeTransform - Menganimasikan perubahan pada skala dan rotasi tampilan target. +
- changeImageTransform - Menganimasikan perubahan pada ukuran dan skala gambar target. +
Bila Anda mengaktifkan transisi aktivitas dalam aplikasi, transisi memudar-silang default akan +diaktifkan di antara aktivitas masuk dan aktivitas keluar.
+ + + + +Menetapkan transisi custom
+ +Pertama, aktifkan transisi konten jendela dengan atribut android:windowContentTransitions
+bila Anda mendefinisikan gaya yang mewarisi tema bahan. Anda juga bisa menetapkan
+transisi-transisi masuk, keluar, dan elemen bersama dalam definisi gaya:
+<style name="BaseAppTheme" parent="android:Theme.Material"> + <!-- enable window content transitions --> + <item name="android:windowContentTransitions">true</item> + + <!-- specify enter and exit transitions --> + <item name="android:windowEnterTransition">@transition/explode</item> + <item name="android:windowExitTransition">@transition/explode</item> + + <!-- specify shared element transitions --> + <item name="android:windowSharedElementEnterTransition"> + @transition/change_image_transform</item> + <item name="android:windowSharedElementExitTransition"> + @transition/change_image_transform</item> +</style> ++ +
Transisi change_image_transform
dalam contoh ini didefinisikan sebagai berikut:
+<!-- res/transition/change_image_transform.xml --> +<!-- (see also Shared Transitions below) --> +<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> + <changeImageTransform/> +</transitionSet> ++ +
Elemen changeImageTransform
menunjukkan
+kelas {@link android.transition.ChangeImageTransform}. Untuk informasi selengkapnya, lihat referensi
+API untuk {@link android.transition.Transition}.
Sebaliknya, untuk mengaktifkan transisi konten jendela dalam kode Anda, panggil +metode {@link android.view.Window#requestFeature Window.requestFeature()}:
+ ++// inside your activity (if you did not enable transitions in your theme) +getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + +// set an exit transition +getWindow().setExitTransition(new Explode()); ++ +
Untuk menetapkan transisi dalam kode Anda, panggil metode-metode ini dengan objek {@link +android.transition.Transition}:
+ +-
+
- {@link android.view.Window#setEnterTransition Window.setEnterTransition()} +
- {@link android.view.Window#setExitTransition Window.setExitTransition()} +
- {@link android.view.Window#setSharedElementEnterTransition + Window.setSharedElementEnterTransition()} +
- {@link android.view.Window#setSharedElementExitTransition + Window.setSharedElementExitTransition()} +
Metode {@link android.view.Window#setExitTransition setExitTransition()} dan {@link +android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} mendefinisikan +transisi keluar untuk aktivitas yang memanggil. Metode {@link android.view.Window#setEnterTransition +setEnterTransition()} dan {@link android.view.Window#setSharedElementEnterTransition +setSharedElementEnterTransition()} mendefinisikan transisi masuk untuk aktivitas yang dipanggil.
+ +Untuk mendapatkan efek penuh sebuah transisi, Anda harus mengaktifkan transisi konten jendela pada +aktivitas yang memanggil maupun aktivitas yang dipanggil. Jika tidak, aktivitas yang memanggil akan memulai transisi keluar, +namun kemudian Anda akan melihat transisi jendela (seperti mengelupas atau memudar).
+ +Untuk memulai transisi masuk sesegera mungkin, gunakan metode +{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} +pada aktivitas yang dipanggil. Ini memungkinkan Anda mendapatkan transisi masuk yang lebih dramatis.
+ +Memulai aktivitas dengan menggunakan transisi
+ +Jika Anda mengaktifkan transisi dan mengatur transisi keluar untuk aktivitas, transisi itu akan diaktifkan +bila Anda menjalankan aktivitas lain sebagai berikut:
+ ++startActivity(intent, + ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); ++ +
Jika Anda telah mengatur transisi masuk untuk aktivitas kedua, transisi juga akan diaktifkan
+bila aktivitas dimulai. Untuk menonaktifkan transisi bila Anda memulai aktivitas lain, sediakan
+bundel opsi null
.
Memulai aktivitas dengan satu elemen bersama
+ +Untuk membuat animasi transisi layar di antara dua aktivitas yang memiliki satu elemen bersama:
+ +-
+
- Aktifkan transisi konten jendela dalam tema Anda. +
- Tetapkan transisi elemen bersama dalam gaya Anda. +
- Definisikan transisi Anda sebagai sumber daya XML. +
- Tetapkan nama umum pada elemen bersama dalam kedua layout dengan
+ atribut
android:transitionName
.
+ - Gunakan metode {@link android.app.ActivityOptions#makeSceneTransitionAnimation +ActivityOptions.makeSceneTransitionAnimation()}. +
+// get the element that receives the click event +final View imgContainerView = findViewById(R.id.img_container); + +// get the common element for the transition in this activity +final View androidRobotView = findViewById(R.id.image_small); + +// define a click listener +imgContainerView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(this, Activity2.class); + // create the transition animation - the images in the layouts + // of both activities are defined with android:transitionName="robot" + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(this, androidRobotView, "robot"); + // start the new activity + startActivity(intent, options.toBundle()); + } +}); ++ +
Untuk tampilan dinamis bersama yang Anda hasilkan dalam kode, gunakan +metode {@link android.view.View#setTransitionName View.setTransitionName()} untuk menetapkan +nama elemen umum di kedua aktivitas.
+ +Untuk membalik animasi transisi babak bila Anda menyelesaikan aktivitas kedua, panggil metode +{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} +sebagai ganti {@link android.app.Activity#finish Activity.finish()}.
+ +Memulai aktivitas dengan beberapa elemen bersama
+ +Untuk membuat animasi transisi babak antara dua aktivitas yang memiliki lebih dari satu
+elemen bersama, definisikan elemen bersama di kedua layout dengan atribut android:transitionName
+ (atau gunakan metode {@link android.view.View#setTransitionName View.setTransitionName()}
+di kedua aktivitas), dan buat sebuah objek {@link android.app.ActivityOptions} sebagai berikut:
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, + Pair.create(view1, "agreedName1"), + Pair.create(view2, "agreedName2")); ++ + +
Menggunakan Gerakan Melengkung
+ +Animasi dalam desain bahan mengandalkan kurva untuk pola interpolasi waktu dan +gerakan spasial. Dengan Android 5.0 (API level 21) ke atas, Anda bisa mendefinisikan kurva pewaktuan custom dan +pola gerakan melengkung untuk animasi.
+ +Kelas {@link android.view.animation.PathInterpolator} adalah interpolator baru berdasarkan sebuah +kurva Bézier atau objek {@link android.graphics.Path}. Interpolator ini menetapkan kurva gerakan +dalam bujur sangkar 1x1, dengan titik-titik jangkar di (0,0) dan (1,1) dan titik-titik kontrol sebagaimana ditetapkan menggunakan +argumen konstruktor. Anda juga bisa mendefinisikan interpolator path sebagai sumber daya XML:
+ ++<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.4" + android:controlY1="0" + android:controlX2="1" + android:controlY2="1"/> ++ +
Sistem menyediakan sumber daya XML untuk tiga kurva dasar dalam +spesifikasi desain bahan:
+ +-
+
@interpolator/fast_out_linear_in.xml
+ @interpolator/fast_out_slow_in.xml
+ @interpolator/linear_out_slow_in.xml
+
Anda bisa meneruskan objek {@link android.view.animation.PathInterpolator} ke metode {@link +android.animation.Animator#setInterpolator Animator.setInterpolator()}.
+ +Kelas {@link android.animation.ObjectAnimator} memiliki konstruktor-konstruktor baru yang memungkinkan Anda menganimasikan +koordinat bersama sebuah path dengan menggunakan dua atau beberapa properti sekaligus. Misalnya, animator berikut +menggunakan objek {@link android.graphics.Path} untuk menganimasikan properti X dan Y sebuah tampilan:
+ ++ObjectAnimator mAnimator; +mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); +... +mAnimator.start(); ++ + +
Menganimasikan Perubahan Status Tampilan
+ +Kelas {@link android.animation.StateListAnimator} memungkinkan Anda mendefinisikan animator yang berjalan bila +status tampilan berubah. Contoh berikut menampilkan cara mendefinisikan {@link +android.animation.StateListAnimator} sebagai sumber daya XML:
+ ++<!-- animate the translationZ property of a view when pressed --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="@android:integer/config_shortAnimTime" + android:valueTo="2dp" + android:valueType="floatType"/> + <!-- you could have other objectAnimator elements + here for "x" and "y", or other properties --> + </set> + </item> + <item android:state_enabled="true" + android:state_pressed="false" + android:state_focused="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="100" + android:valueTo="0" + android:valueType="floatType"/> + </set> + </item> +</selector> ++ +
Untuk menyertakan animasi status tampilan custom ke tampilan, definisikan animator menggunakan
+elemen selector
dalam sumber daya file XML sebagaimana dalam contoh ini, dan tetapkan ke
+tampilan Anda dengan atribut android:stateListAnimator
. Untuk menetapkan animator daftar status
+ke sebuah tampilan dalam kode Anda, gunakan metode {@link android.animation.AnimatorInflater#loadStateListAnimator
+AnimationInflater.loadStateListAnimator()}, dan tetapkan animator ke tampilan dengan
+metode {@link android.view.View#setStateListAnimator View.setStateListAnimator()}.
Bila tema Anda memperluas tema bahan, tombol-tombol akan memiliki animasi Z secara default. Untuk menghindari
+perilaku ini di tombol Anda, aturlah atribut android:stateListAnimator
ke
+@null
.
Kelas {@link android.graphics.drawable.AnimatedStateListDrawable} memungkinkan Anda membuat drawable +yang menampilkan animasi di antara perubahan status tampilan terkait. Sebagian widget sistem di +Android 5.0 menggunakan animasi ini secara default. Contoh berikut menampilkan cara +mendefinisikan {@link android.graphics.drawable.AnimatedStateListDrawable} sebagai sumber daya XML:
+ ++<!-- res/drawable/myanimstatedrawable.xml --> +<animated-selector + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- provide a different drawable for each state--> + <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" + android:state_pressed="true"/> + <item android:id="@+id/focused" android:drawable="@drawable/drawableF" + android:state_focused="true"/> + <item android:id="@id/default" + android:drawable="@drawable/drawableD"/> + + <!-- specify a transition --> + <transition android:fromId="@+id/default" android:toId="@+id/pressed"> + <animation-list> + <item android:duration="15" android:drawable="@drawable/dt1"/> + <item android:duration="15" android:drawable="@drawable/dt2"/> + ... + </animation-list> + </transition> + ... +</animated-selector> ++ + +
Menganimasikan Drawable Vektor
+ +Drawable Vektor +bisa diubah skalanya tanpa kehilangan definisi. Kelas {@link android.graphics.drawable.AnimatedVectorDrawable} +memungkinkan Anda menganimasikan properti drawable vektor.
+ +Anda biasanya mendefinisikan drawable vektor yang dianimasikan dalam tiga file XML:
+ +-
+
- Drawable vektor dengan elemen
<vector>
dalam +res/drawable/
+ - Drawable vektor animasi dengan elemen
<animated-vector>
dalam +res/drawable/
+ - Satu atau beberapa animator objek dengan elemen
<objectAnimator>
dalam +res/anim/
+
Drawable vektor yang dianimasikan bisa menganimasikan atribut elemen <group>
dan
+<path>
. Elemen <group>
mendefinisikan satu set
+path atau subgrup, dan elemen <path>
mendefinisikan path yang harus digambar.
Bila Anda mendefinisikan drawable vektor yang ingin dianimasikan, gunakan atribut android:name
+untuk menetapkan nama unik ke grup dan path, sehingga Anda bisa merujuknya dari
+definisi animator Anda. Misalnya:
+<!-- res/drawable/vectordrawable.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600"> + <group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:name="v" + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + </group> +</vector> ++ +
Definisi drawable vektor yang dianimasikan merujuk pada grup dan path dalam drawable vektor +berdasarkan namanya:
+ ++<!-- res/drawable/animvectordrawable.xml --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vectordrawable" > + <target + android:name="rotationGroup" + android:animation="@anim/rotation" /> + <target + android:name="v" + android:animation="@anim/path_morph" /> +</animated-vector> ++ +
Definisi animasi menyatakan objek {@link android.animation.ObjectAnimator} atau {@link +android.animation.AnimatorSet}. Animator pertama dalam contoh ini memutar +grup target sebanyak 360 derajat:
+ ++<!-- res/anim/rotation.xml --> +<objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360" /> ++ +
Animator kedua dalam contoh ini perlahan-lahan mengubah bentuk path drawable vektor dari satu bentuk ke +bentuk yang lain. Kedua path harus kompatibel untuk morphing: keduanya harus memiliki jumlah perintah yang sama +dan jumlah parameter yang sama untuk setiap perintah.
+ ++<!-- res/anim/path_morph.xml --> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="3000" + android:propertyName="pathData" + android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" + android:valueType="pathType" /> +</set> ++ +
Untuk informasi selengkapnya, lihat referensi API bagi {@link +android.graphics.drawable.AnimatedVectorDrawable}.
diff --git a/docs/html-intl/intl/in/training/material/compatibility.jd b/docs/html-intl/intl/in/training/material/compatibility.jd new file mode 100644 index 0000000000000000000000000000000000000000..d57c7bef181029aa42886c00d45435f40e8085c5 --- /dev/null +++ b/docs/html-intl/intl/in/training/material/compatibility.jd @@ -0,0 +1,168 @@ +page.title=Mempertahankan Kompatibilitas + +@jd:body + +Pelajaran ini mengajarkan Anda cara
+-
+
- Mendefinisikan Gaya Alternatif +
- Menyediakan Layout Alternatif +
- Menggunakan Support Library +
- Memeriksa Versi Sistem +
Anda juga harus membaca
+ +Sebagian fitur desain bahan seperti tema bahan dan transisi aktivitas custom +hanya tersedia pada Android 5.0 (API level 21) ke atas. Akan tetapi, Anda bisa mendesain aplikasi untuk menggunakan +fitur-fitur ini saat dijalankan pada perangkat yang mendukung desain bahan dan tetap kompatibel +dengan perangkat yang menjalankan rilis Android sebelumnya.
+ + +Mendefinisikan Gaya Alternatif
+ +Anda bisa mengonfigurasi aplikasi untuk menggunakan tema bahan pada perangkat yang mendukungnya dan mengembalikan +ke tema lama pada perangkat yang menjalankan versi Android terdahulu:
+ +-
+
- Definisikan tema yang mewarisi tema lama (seperti Holo) di
+
res/values/styles.xml
.
+ - Definisikan tema bernama sama yang mewarisi tema bahan di
+
res/values-v21/styles.xml
.
+ - Atur tema ini sebagai tema aplikasi Anda dalam file manifes. +
Catatan: +Jika aplikasi Anda menggunakan tema bahan namun tidak menyediakan tema alternatif dengan cara ini, +aplikasi itu tidak akan berjalan pada versi Android sebelum 5.0. +
+ + +Menyediakan Layout Alternatif
+ +Jika layout yang Anda desain sesuai dengan panduan desain bahan tidak menggunakan salah satu +atribut XML baru yang diperkenalkan di Android 5.0 (API level 21), layout itu akan berfungsi pada +versi Android sebelumnya. Jika tidak, Anda bisa menyediakan layout alternatif. Anda juga bisa menyediakan +layout alternatif untuk menyesuaikan cara aplikasi ditampilkan pada versi Android terdahulu.
+ +Buatlah file layout untuk Android 5.0 (API level 21) dalam res/layout-v21/
dan
+file layout alternatif untuk versi Android terdahulu dalam res/layout/
.
+Misalnya, res/layout/my_activity.xml
adalah layout alternatif untuk
+res/layout-v21/my_activity.xml
.
Untuk menghindari duplikasi kode, definisikan gaya dalam res/values/
, modifikasi
+gaya di res/values-v21/
untuk API baru, dan gunakan pewarisan gaya, dengan mendefinisikan
+gaya dasar di res/values/
dan mewarisi gaya di res/values-v21/
.
Menggunakan Support Library
+ +v7 Support Library +r21 ke atas menyertakan fitur desain bahan berikut:
+ +-
+
- Gaya desain bahan untuk beberapa widget sistem
+ bila Anda menerapkan salah satu tema
Theme.AppCompat
.
+ - Atribut tema palet warna
+ dalam tema
Theme.AppCompat
.
+ - Widget {@link android.support.v7.widget.RecyclerView} untuk +menampilkan kumpulan data. +
- Widget {@link android.support.v7.widget.CardView} untuk membuat kartu. +
- Kelas {@link android.support.v7.graphics.Palette} untuk mengekstrak warna mencolok dari + gambar. +
Widget sistem
+ +Tema-tema Theme.AppCompat
menyediakan gaya desain bahan untuk widget ini:
-
+
- {@link android.widget.EditText} +
- {@link android.widget.Spinner} +
- {@link android.widget.CheckBox} +
- {@link android.widget.RadioButton} +
- {@link android.support.v7.widget.SwitchCompat} +
- {@link android.widget.CheckedTextView} +
Palet Warna
+ +Untuk memperoleh gaya desain bahan dan menyesuaikan palet warna dengan Android v7 Support
+Library, terapkan salah satu tema Theme.AppCompat
:
+<!-- extend one of the Theme.AppCompat themes --> +<style name="Theme.MyTheme" parent="Theme.AppCompat.Light"> + <!-- customize the color palette --> + <item name="colorPrimary">@color/material_blue_500</item> + <item name="colorPrimaryDark">@color/material_blue_700</item> + <item name="colorAccent">@color/material_green_A200</item> +</style> ++ +
Daftar dan Kartu
+ +Widget {@link android.support.v7.widget.RecyclerView} dan {@link +android.support.v7.widget.CardView} tersedia di versi Android terdahulu melalui +Android v7 Support Library dengan pembatasan ini:
+-
+
- {@link android.support.v7.widget.CardView} memundurkan ke implementasi bayangan terprogram + dengan menggunakan pengisi tambahan. +
- {@link android.support.v7.widget.CardView} tidak memangkas tampilan anaknya yang berpotongan + dengan sudut melengkung. +
Dependensi
+ +Untuk menggunakan fitur-fitur ini di versi Android sebelum 5.0 (API level 21), sertakan +Android v7 Support Library dalam proyek Anda sebagai dependensi Gradle:
+ ++dependencies { + compile 'com.android.support:appcompat-v7:21.0.+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} ++ + +
Memeriksa Versi Sistem
+ +Fitur berikut hanya tersedia di Android 5.0 (API level 21) ke atas:
+ +-
+
- Transisi aktivitas +
- Umpan balik sentuh +
- Animasi membuka +
- Animasi berbasis path +
- Drawable vektor +
- Pewarnaan drawable +
Untuk menjaga kompatibilitas dengan versi Android terdahulu, periksa {@link +android.os.Build.VERSION#SDK_INT version} sistem saat runtime sebelum Anda memanggil API untuk salah satu +fitur ini:
+ ++// Check if we're running on Android 5.0 or higher +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // Call some material design APIs here +} else { + // Implement this feature without material design +} ++ +
Catatan: Untuk menetapkan versi Android yang didukung aplikasi Anda,
+gunakan atribut android:minSdkVersion
dan android:targetSdkVersion
+dalam file manifes. Untuk menggunakan fitur desain bahan di Android 5.0, atur
+atribut android:targetSdkVersion
ke 21
. Untuk informasi selengkapnya, lihat
+panduan API
+<uses-sdk>.
Pelajaran ini mengajarkan Anda cara
+-
+
- Mewarnai Sumber Daya Drawable +
- Mengekstrak Warna Mencolok dari Gambar +
- Membuat Drawable Vektor +
Anda juga harus membaca
+ +Kemampuan berikut untuk drawable membantu Anda mengimplementasikan desain bahan dalam aplikasi Anda:
+ +-
+
- Pewarnaan drawable +
- Ekstraksi warna mencolok +
- Drawable vektor +
Pelajaran ini menampilkan cara menggunakan fitur-fitur ini dalam aplikasi Anda.
+ + +Mewarnai Sumber Daya Drawable
+ +Dengan Android 5.0 (API level 21) ke atas, Anda bisa mewarnai bitmap dan sembilan-tambalan yang didefinisikan sebagai
+alpha-mask. Anda bisa mewarnainya dengan sumber daya warna atau atribut tema yang mencocokkan ke
+sumber daya warna (misalnya, ?android:attr/colorPrimary
). Biasanya, Anda membuat aset ini
+hanya sekali dan mewarnainya secara otomatis agar cocok dengan tema Anda.
Anda bisa menerapkan warna ke objek {@link android.graphics.drawable.BitmapDrawable} atau {@link
+android.graphics.drawable.NinePatchDrawable} dengan metode {@code setTint()}. Anda juga bisa
+mengatur warna dan mode dalam layout dengan atribut android:tint
dan
+android:tintMode
.
Mengekstrak Warna Mencolok dari Gambar
+ +Android Support Library r21 ke atas menyertakan kelas {@link +android.support.v7.graphics.Palette}, yang memungkinkan Anda mengekstrak warna mencolok dari gambar. +Kelas ini mengekstrak warna mencolok berikut:
+ +-
+
- Menyala +
- Menyala pekat +
- Menyala pucat +
- Pudar +
- Pudar pekat +
- Pudar pucat +
Untuk mengekstrak warna-warna ini, teruskan objek {@link android.graphics.Bitmap} ke +metode statis {@link android.support.v7.graphics.Palette#generate Palette.generate()} dalam +thread latar belakang tempat Anda memuat gambar. Jika Anda tidak bisa menggunakan thread itu, panggil metode +{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} dan +sediakan listener sebagai gantinya.
+ +Anda bisa mengambil warna mencolok dari gambar dengan metode getter di kelas
+Palette
, misalnya Palette.getVibrantColor
.
Untuk menggunakan kelas {@link android.support.v7.graphics.Palette} dalam proyek Anda, tambahkan +dependensi Gradle berikut ke +modul aplikasi Anda:
+ ++dependencies { + ... + compile 'com.android.support:palette-v7:21.0.0' +} ++ +
Untuk informasi selengkapnya, lihat referensi API untuk kelas {@link android.support.v7.graphics.Palette}. +
+ + +Membuat Drawable Vektor
+ + + +Video
+Grafis Vektor Android
+Di Android 5.0 (API Level 21) ke atas, Anda bisa mendefinisikan drawable vektor, yang berubah skala tanpa
+kehilangan definisi. Anda hanya memerlukan satu file aset per gambar vektor, bukan file aset untuk
+setiap densitas layar seperti pada gambar bitmap. Untuk membuat gambar vektor, Anda mendefinisikan detail
+bentuknya dalam sebuah elemen XML <vector>
.
Contoh berikut mendefinisikan gambar vektor berbentuk hati:
+ ++<!-- res/drawable/heart.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + <!-- intrinsic size of the drawable --> + android:height="256dp" + android:width="256dp" + <!-- size of the virtual canvas --> + android:viewportWidth="32" + android:viewportHeight="32"> + + <!-- draw a path --> + <path android:fillColor="#8fff" + android:pathData="M20.5,9.5 + c-1.955,0,-3.83,1.268,-4.5,3 + c-0.67,-1.732,-2.547,-3,-4.5,-3 + C8.957,9.5,7,11.432,7,14 + c0,3.53,3.793,6.257,9,11.5 + c5.207,-5.242,9,-7.97,9,-11.5 + C25,11.432,23.043,9.5,20.5,9.5z" /> +</vector> ++ +
Gambar vektor direpresentasikan di Android sebagai objek {@link android.graphics.drawable.VectorDrawable}.
+ Untuk informasi selengkapnya tentang sintaks pathData
, lihat Referensi Path SVG. Untuk informasi selengkapnya
+tentang menganimasikan properti drawable vektor, lihat
+Menganimasikan Drawable Vektor.
Pelajaran ini mengajarkan Anda cara
+-
+
- Menerapkan Tema Bahan +
- Mendesain Layout Anda +
- Menetapkan Ketinggian di Tampilan Anda +
- Membuat Daftar dan Kartu +
- Menyesuaikan Animasi Anda +
Anda juga harus membaca
+ +Untuk membuat aplikasi dengan desain bahan:
+ +-
+
- + Tinjaulah spesifikasi desain bahan. +
- + Terapkan tema bahan ke aplikasi Anda. +
- + Buat layout agar mengikuti panduan desain bahan. +
- + Tetapkan ketinggian tampilan Anda untuk menghasilkan bayangan. +
- + Gunakan widget sistem untuk daftar dan kartu. +
- + Sesuaikan animasi di aplikasi Anda. +
Mempertahankan kompatibilitas mundur
+ +Anda bisa menambahkan banyak fitur desain bahan ke aplikasi sekaligus mempertahankan kompatibilitas dengan +versi Android sebelum 5.0. Untuk informasi selengkapnya, lihat +Mempertahankan Kompatibilitas.
+ +Memperbarui aplikasi dengan desain bahan
+ +Untuk memperbarui aplikasi yang ada guna memasukkan desain bahan, perbarui layout Anda dengan mengikuti +panduan desain bahan. Juga pastikan memasukkan kedalaman, umpan balik sentuh, dan +animasi.
+ +Membuat aplikasi baru dengan desain bahan
+ +Jika Anda sedang membuat aplikasi baru dengan fitur desain bahan, panduan desain bahan akan memberi Anda +kerangka kerja desain yang kohesif. Ikuti panduan itu dan gunakan fungsionalitas baru di +kerangka kerja Android untuk mendesain dan mengembangkan aplikasi Anda.
+ + +Menerapkan Tema Bahan
+ +Untuk menerapkan tema bahan dalam aplikasi Anda, tetapkan gaya yang mewarisi
+android:Theme.Material
:
+<!-- res/values/styles.xml --> +<resources> + <!-- your theme inherits from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- theme customizations --> + </style> +</resources> ++ +
Tema bahan menyediakan widget sistem terbaru yang memungkinkan Anda mengatur palet warnanya dan +animasi default untuk umpan balik sentuh dan transisi aktivitas. Untuk detail selengkapnya, lihat +Menggunakan Tema Bahan.
+ + +Mendesain Layout Anda
+ +Selain menerapkan dan menyesuaikan tema bahan, layout Anda harus mematuhi +panduan desain bahan. Bila Anda mendesain +layout, berikan perhatian khusus pada hal-hal berikut:
+ +-
+
- Petak patokan +
- Garis utama +
- Pengaturan Jarak +
- Ukuran target sentuh +
- Struktur layout +
Menetapkan Ketinggian di Tampilan Anda
+ +Tampilan bisa menghasilkan bayangan, dan nilai ketinggian tampilan
+menentukan ukuran bayangan dan urutan penggambarannya. Untuk mengatur ketinggian tampilan, gunakan
+atribut android:elevation
dalam layout:
+<TextView + android:id="@+id/my_textview" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/next" + android:background="@color/white" + android:elevation="5dp" /> ++ +
Properti translationZ
baru memungkinkan Anda membuat animasi yang mencerminkan
+perubahan sementara pada ketinggian tampilan. Perubahan ketinggian bisa berguna saat
+merespons
+gerakan sentuh.
Untuk detail selengkapnya, lihat Mendefinisikan +Bayangan dan Memangkas Tampilan.
+ + +Membuat Daftar dan Kartu
+ +{@link android.support.v7.widget.RecyclerView} adalah versi {@link +android.widget.ListView} yang lebih mudah dimasukkan dan mendukung beragam tipe layout serta memberikan peningkatan kinerja. +{@link android.support.v7.widget.CardView} memungkinkan Anda menampilkan potongan informasi dalam kartu dengan +tampilan konsisten di seluruh aplikasi. Contoh kode berikut memperagakan cara menyertakan +{@link android.support.v7.widget.CardView} dalam layout Anda:
+ ++<android.support.v7.widget.CardView + android:id="@+id/card_view" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="3dp"> + ... +</android.support.v7.widget.CardView> ++ +
Untuk informasi selengkapnya, lihat Membuat Daftar +dan Kartu.
+ + +Menyesuaikan Animasi Anda
+ +Android 5.0 (API level 21) menyertakan API baru untuk membuat animasi custom di aplikasi Anda. +Misalnya, Anda bisa mengaktifkan transisi aktivitas dan mendefinisikan transisi keluar di +aktivitas:
+ ++public class MyActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // enable transitions + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + setContentView(R.layout.activity_my); + } + + public void onSomeButtonClicked(View view) { + getWindow().setExitTransition(new Explode()); + Intent intent = new Intent(this, MyOtherActivity.class); + startActivity(intent, + ActivityOptions + .makeSceneTransitionAnimation(this).toBundle()); + } +} ++ +
Bila Anda memulai aktivitas lain dari aktivitas ini, transisi keluar akan diaktifkan.
+ +Untuk mengetahui selengkapnya tentang API animasi yang baru, lihat Mendefinisikan Animasi Custom.
diff --git a/docs/html-intl/intl/in/training/material/index.jd b/docs/html-intl/intl/in/training/material/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..53697d2ea6669c1765e2b9e8a4ac5caa0b7b6247 --- /dev/null +++ b/docs/html-intl/intl/in/training/material/index.jd @@ -0,0 +1,60 @@ +page.title=Desain Bahan untuk Pengembang +page.image=images/cards/material_2x.png +page.metaDescription=Pelajari cara menerapkan desain bahan pada aplikasi Anda. + + +@jd:body + +Dependensi dan Prasyarat
+-
+
- Android 5.0 (API Level 21) +
Desain bahan adalah panduan komprehensif untuk desain visual, gerak, dan interaksi di +berbagai platform dan perangkat. Untuk menggunakan desain bahan di aplikasi Android, ikuti panduan +yang dijelaskan dalam +spesifikasi desain bahan + dan gunakan komponen serta fungsionalitas baru yang tersedia di Android 5.0 +(API level 21).
+ +Kelas ini menampilkan kepada Anda cara membuat aplikasi desain bahan dengan elemen-elemen berikut:
+ +-
+
- Tema bahan +
- Widget untuk kartu dan daftar +
- Bayangan custom dan pemangkasan tampilan +
- Drawable vektor +
- Animasi custom +
Kelas ini juga mengajarkan cara mempertahankan kompatibilitas dengan versi Android sebelum +5.0 (API level 21) bila Anda menggunakan fitur desain bahan dalam aplikasi.
+ +Pelajaran
+ +-
+
- Memulai +
- Pelajari cara memperbarui aplikasi Anda dengan fitur desain bahan. + +
- Menggunakan Tema Bahan +
- Pelajari cara menerapkan gaya desain bahan pada aplikasi Anda. + +
- Membuat Daftar dan Kartu +
- Pelajari cara membuat daftar dan kartu dengan tampilan dan cara kerja yang konsisten menggunakan widget sistem. + +
- Mendefinisikan Bayangan dan Memangkas Tampilan +
- Pelajari cara mengatur elevasi tampilan Anda untuk membuat bayangan custom dan cara memangkas tampilan. + +
- Bekerja dengan Drawable +
- Pelajari cara membuat drawable vektor dan cara mewarnai sumber daya drawable. + +
- Mendefinisikan Animasi Custom +
- Pelajari cara membuat animasi custom untuk tampilan dan transisi aktivitas dengan elemen bersama. + +
- Mempertahankan Kompatibilitas +
- Pelajari cara mempertahankan kompatibilitas dengan versi platform sebelum Android 5.0. +
Pelajaran ini mengajarkan Anda cara
+ +Anda juga harus membaca
+ +Untuk membuat daftar dan kartu yang kompleks dengan gaya desain bahan di aplikasi, Anda bisa menggunakan widget +{@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView}. +
+ + +Membuat Daftar
+ +Widget {@link android.support.v7.widget.RecyclerView} adalah +versi {@link android.widget.ListView} yang lebih maju dan fleksibel. Widget ini adalah kontainer untuk menampilkan set data +besar yang bisa digulir secara sangat efisien dengan mempertahankan tampilan dalam jumlah terbatas. Gunakan +widget {@link android.support.v7.widget.RecyclerView} bila Anda memiliki kumpulan data dengan elemen +yang berubah saat runtime berdasarkan tindakan pengguna atau kejadian jaringan.
+ +Kelas {@link android.support.v7.widget.RecyclerView} menyederhanakan penampilan dan penanganan +set data yang besar dengan menyediakan:
+ +-
+
- Pengelola layout untuk memosisikan item +
- Animasi default untuk operasi item umum, misalnya penghapusan atau penambahan item +
Anda juga memiliki keluwesan untuk mendefinisikan pengelola layout custom dan animasi untuk widget {@link +android.support.v7.widget.RecyclerView}.
+ + + + +Untuk menggunakan widget {@link android.support.v7.widget.RecyclerView}, Anda harus menetapkan +adaptor dan pengelola layout. Untuk membuat adaptor, perluas kelas {@link +android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}. Detail +implementasi bergantung pada detail set data Anda dan tipe tampilan. Untuk informasi selengkapnya, + lihat contoh-contoh di bawah.
+ +Pengelola layout memosisikan tampilan item dalam {@link +android.support.v7.widget.RecyclerView} dan menentukan waktu untuk menggunakan ulang tampilan item yang tidak +lagi terlihat oleh pengguna. Untuk menggunakan ulang (atau mendaur ulang) tampilan, pengelola layout bisa meminta +adaptor untuk mengganti konten tampilan dengan elemen lain dalam dataset. Mendaur ulang +tampilan dengan cara ini akan meningkatkan kinerja karena menghindari pembuatan tampilan yang tidak diperlukan atau +melakukan pencarian {@link android.app.Activity#findViewById findViewById()} yang mahal.
+ +{@link android.support.v7.widget.RecyclerView} menyediakan semua pengelola layout bawaan ini:
+ +-
+
- {@link android.support.v7.widget.LinearLayoutManager} menampilkan item dalam +daftar gulir vertikal atau horizontal. +
- {@link android.support.v7.widget.GridLayoutManager} menampilkan item dalam petak. +
- {@link android.support.v7.widget.StaggeredGridLayoutManager} menampilkan item dalam petak zigzag. +
Untuk membuat pengelola layout custom, perluas kelas {@link +android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager}.
+ +Animasi
+ +Animasi untuk menambahkan dan menghapus item diaktifkan secara default di {@link +android.support.v7.widget.RecyclerView}. Untuk menyesuaikan animasi ini, perluas kelas +{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator}dan gunakan +metode {@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()}. +
+ +Contoh
+ +Contoh kode berikut memperagakan cara menambahkan +{@link android.support.v7.widget.RecyclerView} ke layout:
+ ++<!-- A RecyclerView with some commonly used attributes --> +<android.support.v7.widget.RecyclerView + android:id="@+id/my_recycler_view" + android:scrollbars="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"/> ++ +
Begitu Anda menambahkan widget {@link android.support.v7.widget.RecyclerView} ke layout, +dapatkan pengatur atau handle objek itu, hubungkan dengan pengelola layout, dan sertakan adaptor untuk data +yang akan ditampilkan:
+ ++public class MyActivity extends Activity { + private RecyclerView mRecyclerView; + private RecyclerView.Adapter mAdapter; + private RecyclerView.LayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.my_activity); + mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); + + // use this setting to improve performance if you know that changes + // in content do not change the layout size of the RecyclerView + mRecyclerView.setHasFixedSize(true); + + // use a linear layout manager + mLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setLayoutManager(mLayoutManager); + + // specify an adapter (see also next example) + mAdapter = new MyAdapter(myDataset); + mRecyclerView.setAdapter(mAdapter); + } + ... +} ++ +
Adaptor menyediakan akses ke item dataset Anda, membuat tampilan untuk item, dan +mengganti konten sebagian tampilan dengan item data baru bila item semula tidak lagi +terlihat. Contoh kode berikut menampilkan implementasi sederhana untuk sebuah dataset yang terdiri dari +larik string yang ditampilkan dengan menggunakan widget {@link android.widget.TextView}:
+ ++public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { + private String[] mDataset; + + // Provide a reference to the views for each data item + // Complex data items may need more than one view per item, and + // you provide access to all the views for a data item in a view holder + public static class ViewHolder extends RecyclerView.ViewHolder { + // each data item is just a string in this case + public TextView mTextView; + public ViewHolder(TextView v) { + super(v); + mTextView = v; + } + } + + // Provide a suitable constructor (depends on the kind of dataset) + public MyAdapter(String[] myDataset) { + mDataset = myDataset; + } + + // Create new views (invoked by the layout manager) + @Override + public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + // create a new view + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.my_text_view, parent, false); + // set the view's size, margins, paddings and layout parameters + ... + ViewHolder vh = new ViewHolder(v); + return vh; + } + + // Replace the contents of a view (invoked by the layout manager) + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + // - get element from your dataset at this position + // - replace the contents of the view with that element + holder.mTextView.setText(mDataset[position]); + + } + + // Return the size of your dataset (invoked by the layout manager) + @Override + public int getItemCount() { + return mDataset.length; + } +} ++ + +
Membuat Kartu
+ +{@link android.support.v7.widget.CardView} memperluas kelas {@link android.widget.FrameLayout} +dan memungkinkan Anda menampilkan informasi dalam kartu yang memiliki tampilan konsisten lintas platform. Widget {@link +android.support.v7.widget.CardView} bisa memiliki bayangan dan sudut membulat.
+ +Untuk membuat kartu dengan bayangan, gunakan atribut card_view:cardElevation
.
+{@link android.support.v7.widget.CardView} menggunakan elevasi nyata dan bayangan dinamis pada Android 5.0
+(API level 21) ke atas dan memundurkan ke implementasi bayangan terprogram pada versi terdahulu.
+Untuk informasi selengkapnya, lihat Mempertahankan
+Kompatibilitas.
Gunakan properti-properti ini untuk menyesuaikan penampilan +widget {@link android.support.v7.widget.CardView}:
+ +-
+
- Untuk mengatur radius sudut pada layout Anda, gunakan atribut
card_view:cardCornerRadius
. +
+ - Untuk mengatur radius sudut dalam kode Anda, gunakan metode
CardView.setRadius
.
+ - Untuk mengatur warna latar belakang kartu, gunakan atribut
card_view:cardBackgroundColor
. +
+
Contoh kode berikut menampilkan cara menyertakan widget {@link android.support.v7.widget.CardView} +dalam layout:
+ ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:card_view="http://schemas.android.com/apk/res-auto" + ... > + <!-- A CardView that contains a TextView --> + <android.support.v7.widget.CardView + xmlns:card_view="http://schemas.android.com/apk/res-auto" + android:id="@+id/card_view" + android:layout_gravity="center" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="4dp"> + + <TextView + android:id="@+id/info_text" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </android.support.v7.widget.CardView> +</LinearLayout> ++ +
Untuk informasi selengkapnya, lihat referensi API untuk {@link android.support.v7.widget.CardView}.
+ + +Menambahkan Dependensi
+ +Widget {@link android.support.v7.widget.RecyclerView} dan {@link android.support.v7.widget.CardView} +adalah bagian dari v7 Support +Library. Untuk menggunakan widget dalam proyek Anda, tambahkan +dependensi Gradle ini ke +modul aplikasi Anda:
+ ++dependencies { + ... + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} +diff --git a/docs/html-intl/intl/in/training/material/shadows-clipping.jd b/docs/html-intl/intl/in/training/material/shadows-clipping.jd new file mode 100644 index 0000000000000000000000000000000000000000..5431926721593e203e420d2b3cb97a55f175ad8b --- /dev/null +++ b/docs/html-intl/intl/in/training/material/shadows-clipping.jd @@ -0,0 +1,133 @@ +page.title=Mendefinisikan Bayangan dan Memangkas Tampilan + +@jd:body + +
Pelajaran ini mengajarkan Anda cara
+-
+
- Menetapkan Elevasi pada Tampilan Anda +
- Menyesuaikan Bayangan dan Garis Luar Tampilan +
- Memangkas Tampilan +
Anda juga harus membaca
+ +Desain bahan memperkenalkan elevasi untuk elemen-elemen UI. Elevasi membantu pengguna memahami +arti penting relatif masing-masing elemen dan memfokuskan perhatian pada tugas yang ada.
+ +Elevasi tampilan, yang dinyatakan dengan properti Z, menentukan tampilan visual +bayangannya: tampilan dengan nilai Z lebih tinggi menghasilkan bayangan lebih besar dan lebih halus. Tampilan dengan nilai Z lebih tinggi menutupi +tampilan dengan nilai Z lebih rendah; akan tetapi, nilai Z tampilan tidak memengaruhi ukuran tampilan.
+ +Bayangan digambar oleh induk tampilan yang dinaikkan, sehingga terkena pemangkasan standar tampilan, +yang dipangkas oleh induk secara default.
+ +Elevasi juga berguna untuk membuat animasi tempat memunculkan widget untuk sementara di atas +bidang tampilan saat melakukan beberapa tindakan.
+ +Untuk informasi selengkapnya tentang elevasi dalam desain bahan, lihat +Objek +di ruang 3D.
+ + +Menetapkan Elevasi pada Tampilan Anda
+ +Nilai Z untuk tampilan memiliki dua komponen: + +
-
+
- Elevasi: Komponen statis. +
- Transformasi: Komponen dinamis yang digunakan untuk animasi. +
Z = elevation + translationZ
Untuk mengatur elevasi tampilan dalam definisi layout, gunakan atribut android:elevation
.
+ Untuk mengatur elevasi tampilan dalam kode aktivitas, gunakan
+metode {@link android.view.View#setElevation View.setElevation()}.
Untuk mengatur transformasi tampilan, gunakan metode {@link android.view.View#setTranslationZ +View.setTranslationZ()}.
+ +Metode {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} dan {@link +android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} yang baru memudahkan +Anda menganimasikan elevasi tampilan. Untuk informasi selengkapnya, lihat referensi API untuk +{@link android.view.ViewPropertyAnimator} dan panduan pengembang Animasi Properti. +
+ +Anda juga bisa menggunakan {@link android.animation.StateListAnimator} +untuk menetapkan animasi ini secara deklaratif. Ini khususnya berguna bila +perubahan status memicu animasi, seperti saat seorang pengguna menekan tombol. Untuk informasi selengkapnya, lihat +Menganimasikan Perubahan Status Tampilan.
+ +Nilai Z diukur dengan satuan dp (density-independent pixel).
+ + +Menyesuaikan Bayangan dan Garis Luar Tampilan
+ +Batas-batas drawable latar belakang tampilan menentukan bentuk default bayangannya. +Garis luar menyatakan bentuk luar objek grafis dan mendefinisikan +bidang riak untuk umpan balik sentuh.
+ +Perhatikan tampilan ini, yang didefinisikan dengan drawable latar belakang:
+ ++<TextView + android:id="@+id/myview" + ... + android:elevation="2dp" + android:background="@drawable/myrect" /> ++ +
Drawable latar belakang didefinisikan sebagai persegi panjang dengan sudut membulat:
+ ++<!-- res/drawable/myrect.xml --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#42000000" /> + <corners android:radius="5dp" /> +</shape> ++ +
Tampilan ini menghasilkan bayangan dengan sudut membulat, karena drawable latar belakang mendefinisikan +garis luar tampilan. Memberikan garis luar custom akan mengesampingkan bentuk default bayangan tampilan.
+ +Untuk mendefinisikan garis luar custom suatu tampilan dalam kode Anda:
+ +
-
+
- Perluas kelas {@link android.view.ViewOutlineProvider}. +
- Kesampingkan metode {@link android.view.ViewOutlineProvider#getOutline getOutline()}. +
- Tetapkan penyedia garis luar baru untuk tampilan Anda dengan metode {@link +android.view.View#setOutlineProvider View.setOutlineProvider()}. +
Anda bisa membuat garis luar lonjong dan persegi panjang yang bersudut membulat dengan menggunakan metode dalam
+kelas {@link android.graphics.Outline}. Penyedia garis luar default untuk tampilan memperoleh garis luar
+dari latar belakang tampilan. Untuk mencegah tampilan menghasilkan bayangan, atur penyedia garis luarnya
+ke null
.
Memangkas Tampilan
+ +Memangkas tampilan memudahkan Anda mengubah bentuk tampilan. Anda bisa memangkas tampilan agar
+konsistensi dengan elemen desain lainnya atau mengubah bentuk tampilan untuk merespons input pengguna.
+Anda bisa memangkas tampilan hingga area garis luarnya dengan menggunakan metode {@link android.view.View#setClipToOutline
+View.setClipToOutline()} atau atribut android:clipToOutline
. Hanya
+garis-garis luar persegi panjang, lingkaran, dan persegi panjang bersudut bulat yang mendukung pemangkasan, seperti yang ditentukan oleh
+metode {@link android.graphics.Outline#canClip Outline.canClip()}.
Untuk memangkas tampilan ke bentuk drawable, atur drawable sebagai latar belakang tampilan +(seperti yang ditampilkan di atas) dan panggil metode {@link android.view.View#setClipToOutline View.setClipToOutline()}. +
+ +Memangkas tampilan adalah operasi yang mahal; jadi, jangan animasikan bentuk yang Anda gunakan +untuk memangkas tampilan. Untuk memperoleh efek ini, gunakan animasi Reveal Effect.
diff --git a/docs/html-intl/intl/in/training/material/theme.jd b/docs/html-intl/intl/in/training/material/theme.jd new file mode 100644 index 0000000000000000000000000000000000000000..5acdcd2d0692c5941dfdacff8e874fb17e1395a1 --- /dev/null +++ b/docs/html-intl/intl/in/training/material/theme.jd @@ -0,0 +1,131 @@ +page.title=Menggunakan Tema Bahan + +@jd:body + +Pelajaran ini mengajarkan Anda cara
+ +Anda juga harus membaca
+ +Tema bahan yang baru menyediakan:
+ +-
+
- Widget sistem yang memungkinkan Anda mengatur palet warnanya +
- Animasi umpan balik sentuh untuk widget sistem +
- Animasi transisi aktivitas +
Anda bisa menyesuaikan tampilan tema bahan +sesuai dengan identitas merek Anda dengan palet warna yang Anda kontrol. Anda bisa mewarnai action-bar dan +baris status dengan menggunakan atribut tema, seperti yang ditampilkan dalam Gambar 3.
+ +Widget sistem memiliki desain baru dan animasi umpan balik sentuh. Anda bisa menyesuaikan +palet warna, animasi umpan balik sentuh, dan transisi aktivitas untuk aplikasi.
+ +Tema bahan didefinisikan sebagai:
+ +-
+
@android:style/Theme.Material
(versi gelap)
+ @android:style/Theme.Material.Light
(versi terang)
+ @android:style/Theme.Material.Light.DarkActionBar
+
Untuk daftar gaya bahan yang bisa Anda gunakan, lihat referensi API untuk +{@link android.R.style R.style}.
+ + +Gambar 1. Tema bahan gelap
+Gambar 2. Tema bahan terang
++
+Catatan: Tema bahan hanya tersedia di Android 5.0 (API level 21) +ke atas. v7 Support Library +menyediakan tema dengan gaya desain bahan untuk beberapa widget dan dukungan untuk menyesuaikan +palet warna. Untuk informasi selengkapnya, lihat +Mempertahankan Kompatibilitas. +
+ + +Menyesuaikan Palet Warna
+ +Untuk menyesuaikan warna dasar tema agar cocok dengan merek Anda, definisikan +warna custom menggunakan atribut tema saat Anda mewariskan dari tema bahan:
+ ++<resources> + <!-- inherit from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- Main theme colors --> + <!-- your app branding color for the app bar --> + <item name="android:colorPrimary">@color/primary</item> + <!-- darker variant for the status bar and contextual app bars --> + <item name="android:colorPrimaryDark">@color/primary_dark</item> + <!-- theme UI controls like checkboxes and text fields --> + <item name="android:colorAccent">@color/accent</item> + </style> +</resources> ++ +
Menyesuaikan Baris Status
+ +Tema bahan memungkinkan Anda menyesuaikan baris status dengan mudah; jadi Anda bisa menetapkan
+warna yang cocok dengan merek Anda dan memberikan kontras yang cukup untuk menampilkan ikon status putih. Untuk
+mengatur warna custom bagi baris status, gunakan atribut android:statusBarColor
bila
+Anda memperluas tema bahan. Secara default, android:statusBarColor
mewarisi
+nilai android:colorPrimaryDark
.
Anda juga bisa menggambar sendiri di belakang baris status. Misalnya, jika Anda ingin menampilkan
+baris status secara transparan di atas foto, dengan gradasi gelap yang halus untuk memastikan
+ikon status putih tetap terlihat. Caranya, atur atribut android:statusBarColor
ke
+@android:color/transparent
dan sesuaikan flag jendela seperti yang diperlukan. Anda juga bisa
+menggunakan metode {@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} untuk
+animasi atau pemudaran.
+Catatan: Baris status harus selalu memiliki delineasi yang jelas dari +toolbar utama, kecuali bila Anda menampilkan gambar detail atau konten media tepi-ke-tepi di belakang +baris ini dan bila Anda menggunakan gradasi untuk memastikan ikon tetap terlihat. +
+ +Bila Anda menyesuaikan baris navigasi dan baris status, jadikan keduanya transparan atau modifikasi +baris status saja. Baris navigasi harus tetap hitam di semua kasus lainnya.
+ + +Tampilan Setiap Tema + +
Elemen dalam definisi layout XML bisa menetapkan atribut android:theme
,
+yang merujuk sumber daya tema. Atribut ini memodifikasi tema untuk elemen itu dan setiap
+elemen anak, yang berguna untuk mengubah palet warna tema dalam porsi tertentu
+pada antarmuka.
このデザイン指針は、ユーザーがもっとも知りたいと思われることを中心に、Android User Experience Team により、またその活動を統一的なものにするために作成されたものです。Android デベロッパーとデザイナーに対しては各種端末向けのより詳細なデザイン ガイドラインがあります。 - +
このデザインの原則は、ユーザーがもっとも知りたいと思われることを中心に、Android User Experience Team により、またその活動を統一的なものにするために作成されたものです。 +Android デベロッパーとデザイナーに対しては各種端末向けのより詳細なデザイン ガイドラインがあります。
-ご自身の創造性やデザインについて考える際、この指針を考慮に入れてください。 +ご自身のクリエイティビティやデザインについて考える際、この原則を考慮に入れてください。 何を当てはめるかは目的に応じて調整してください。
ユーザーを引きつける
-サプライズで楽しませる
-美しい画面、考え抜かれて配置されたアニメーション、タイミングの良いサウンド エフェクトは、使っていて楽しくなります。 +
美しい画面、思慮深く配置されたアニメーション、タイミングの良いサウンド エフェクトは、使っていて楽しくなります。 わずかな効果でも、ユーザーを楽しませ、力を得たように感じてもらえます。
ボタンやメニューよりもリアルなオブジェクトでさらに楽しく
-ユーザーがアプリでオブジェクトを直接タップしたり操作したりできるようになります。タスクを実行するために必要な認知の労力が軽減され、感覚的な満足度も上がります。 +
アプリでオブジェクトを直接タップしたり操作したりできます。タスクを試行錯誤しながら実行する必要はなく、アプリの満足度も上がります。
自分らしさを加える
-ユーザーは自分でカスタマイズすることを好みます。これにより、くつろいだ気分や自分の思いのままできる自由な気分を味わうことができます。デフォルトで実用的で美しいものを取りそろえ、それに加えてメイン タスクの妨げにならない、楽しいカスタマイズも任意で加えられます。 +
アプリに自分らしさをプラス
+誰もがアプリで自分らしさを出したいと思っています。好きなようにアプリを操作できるからです。実用的で美しい機能があらかじめ用意されており、それに加えてメイン タスクの邪魔にならない、楽しいカスタマイズもできます。
ユーザーについて知る
-徐々にユーザーの好みを学習していきます。同じ選択を繰り返す手間をかけず、前に選択したものをすぐに選べるようになります。 +
ユーザーの好みを学習
+徐々にユーザーの好みを学習していきます。ユーザーに何度も同じ選択をさせるのではなく、前に選択したものをすぐに選べるようにします。
よりシンプルに
+生活をシンプルに
-常に簡潔に
-シンプルな言葉を並べた短いフレーズを用います。長い文章は好まれません。
+簡潔を心がける
+シンプルで短いフレーズを用います。長い文章は好まれません。
画像は言葉よりもわかりやすい
-画像を使ってアイデアを説明してみましょう。ユーザーの興味を引くことができ、言葉よりも効率的です。 +
画像を使ってアイデアを説明してみましょう。ユーザーの興味を引くことができ、言葉よりも効果的です。
選択は最小限に、最終決定はユーザーに
-最初からユーザーにすべて尋ねるのではなく、もっとも適切と思われる項目を提示します。選択肢や決定事項が多すぎると面倒に感じます。 -推測が間違っていた場合に備え、「やり直し」も可能にします。
+最初からユーザーに選ばせるのではなく、適切と思われる項目を提示します。選択肢や決定事項が多すぎるとユーザーは面倒に感じます。 +間違った選択をしても、「やり直し」ができます。
必要なものを必要なときにだけ表示する
+必要なものを必要なときに
一度に表示される内容が多すぎると疲れてしまいます。タスクや情報はいくつかに小さくまとめてわかりやすくします。 その時点で必要のないオプションは非表示にして、必要なときだけ表示します。
全体像から現在の位置を示す
-ユーザーがはっきりと自分の現在の場所を把握できるようにします。アプリのどの場所にいるかを明示し、遷移して画面の関係を認識できるようにします。 -実行しているタスクに対して応答し続けます。
+現在位置を把握する
+ユーザーが現在アプリのどこにいるのかがすぐに分かります。アプリ内における現在位置を明示し、遷移を使用して画面間の関係を表示します。 +実行中のタスクにフィードバックを返します。
作成したものは失くさない
-ユーザーが時間をかけて作ったものは保存して、どこからでもアクセスできるようにします。設定、独自のカスタマイズ、電話、タブレット、コンピュータで作成したものを記録します。 -アップグレードも簡単になります。 +
作成物を失くさない
+ユーザーが時間をかけて作ったものは保存して、どこからでもアクセスできるようにします。設定、独自のカスタマイズ、および携帯端末、タブレット、コンピュータで作成したものを保存します。 +アップグレードも簡単にできます。
見た目が同じ場合は機能も同じにする
-視覚的な違いを際立たせ、ユーザーが機能の違いをはっきり区別できるようにします。同じような外観、同じ入力で機能が異なるようなモードは避けます。 -
+見た目が同じなら機能も同じ
+機能の違いがはっきり分かるように、特徴的なビジュアルにします。 +同じような外観、同じ入力方法なのに機能が異なるということのないようにします。
割り込みは重要なときにだけ行う
-優秀な個人秘書のように、重要ではない些細なことでユーザーをわずらわせることのないよう配慮します。集中したいユーザーにとって、重要で一刻を争うようなものでない限り、割り込まれると面倒で不快に感じる可能性があります。 +
割り込みは必要な場合のみ
+優秀な個人秘書のように、ユーザーを些細なことでわずらわせないようにします。ユーザーは実行中の操作に専念したいと考えており、重要で一刻を争うようなものでない限り、割り込みは面倒で不快と感じます。
操作を楽しく
-あらゆる場所に工夫を仕込む
-自分で理解すると嬉しく感じられます。Android アプリで広く使われている視覚や操作のパターンを生かし、アプリの操作をわかりやすいものにします。 -たとえばスワイプ操作は便利なナビゲーションのショートカットとして使えます。 +
あらゆる場所に工夫を凝らす
+理解できれば楽しくなります。Android アプリで広く使われている視覚や操作のパターンを生かし、アプリの操作をわかりやすいものにします。 +たとえばスワイプ操作は、ナビゲーションのショートカットとして使えるので便利です。
解決は簡単に
-ユーザーに修正を促す場合はその方法に注意します。アプリではスマートに問題を解決できるようにします。うまくいかなかったときは解決方法を明確に示し、技術的な詳細を表示する必要はありません。自動的に修正できる問題はユーザーに通知する必要すらありません。 - -
+ユーザーの責任にしない
+ユーザーに修正を促す場合はその方法に注意します。ユーザーはアプリをスマートに使いこなしたいと考えています。 +うまくいかなかったときの解決方法は明確でなければなりませんが、技術的に詳細である必要はありません。 +自動的に修正できる問題については、通知も不要です。
操作を促すしかけを散りばめる
-複雑なタスクは分割し、それぞれ簡単に達成できるようにします。1 つ 1 つにフィードバックすることで、ユーザーの満足度は高まります。 +
複雑なタスクは分割し、簡単に達成できるようにします。1 つ 1 つのアクションにフィードバックすることで、ユーザーの満足度は高まります。
作業の手間はかけない
-できると思っていなかったことをできるようにすることで、知識がなくても専門家のような気分を味わってもらえます。たとえば複数の写真効果を組み合わせたショートカットを使うことで、わずかな手順でプロのような写真に仕上げられます。 +
手間のかかる作業は不要
+できないと思っていたことができるようになれば、初心者でもエキスパートの気分が味わえます。たとえば複数の写真効果を組み合わせるショートカットを使うことで、わずかな手順でプロのような写真に仕上げられます。
重要なことはすみやかに
-すべてのアクションが同じ優先度とは限りません。アプリのアクションには優先度を設定し、重要なものはたとえばカメラのシャッター ボタンや音楽プレイヤーの一時停止ボタンのように、簡単に見つけられすぐに使えるようにします。 +
すべてのアクションが同じ優先度とは限りません。アプリのアクションに優先度を設定し、カメラのシャッター ボタンや音楽プレイヤーの一時停止ボタンのように重要なものは、簡単に見つけてすぐに使えるようにします。
デベロッパー文書
-マテリアル デザインを使ったアプリの作成
+デベロッパー ドキュメント
+マテリアル デザインを使用したアプリの作成
ビデオ
-紙とインク:重要なマテリアル
+紙とインク: 重要なマテリアル
マテリアル デザインは、視覚や動作と、複数のプラットフォームや端末間でのインタラクション デザインに関する包括的な指針です。 +
マテリアル デザインは、複数のプラットフォームや端末の視覚、モーション、インタラクション デザインの包括的な指針です。 Android はマテリアル デザイン アプリに対応するようになりました。 -Android アプリでマテリアル デザインを使うには、マテリアル デザインの仕様で説明されているガイドラインに従い、Android 5.0(API レベル 21)以降の新しいコンポーネントや機能を使用します。 +Android アプリでマテリアル デザインを使うには、マテリアル デザインの仕様で定義されているガイドラインに従い、Android 5.0(API レベル 21)以降の新しいコンポーネントや機能を使用します。
-Android にはマテリアル デザインの作成に使うことができる次の要素が用意されています。
+Android にはマテリアル デザインのアプリのビルドに使用できる次の要素が用意されています。
- 新しいテーマ -
- 複雑なビュー用の新しいウィジェット +
- 複雑なビューに対応した新しいウィジェット
- カスタムのシャドウとアニメーション用の新しい API
Android でのマテリアル デザインの実装については、マテリアル デザインを使ったアプリの作成をご覧ください。 +
Android でのマテリアル デザインの実装については、マテリアル デザインを使用したアプリの作成をご覧ください。
マテリアル テーマ
-マテリアル テーマはアプリの新しいスタイルである、システム ウィジェットを提供します。システム ウィジェットを使ってカラーパレット、タッチ フィードバックやアクティビティ遷移のためのデフォルトのアニメーションを指定できます。 +
マテリアル テーマには、アプリの新しいスタイルであるシステム ウィジェットがあります。このシステム ウィジェットを使うと、システム ウィジェットのカラーパレットを設定したり、タッチ フィードバックやアクティビティ遷移のためのデフォルトのアニメーションを設定したりできます。
@@ -67,13 +66,13 @@ Android アプリでマテリアル デザインを使うには、暗色マテリアル テーマ
+暗い色のマテリアル テーマ
明色マテリアル テーマ
+明るい色のマテリアル テーマ
@@ -85,19 +84,19 @@ Android アプリでマテリアル デザインを使うには、
RecyclerView
ウィジェットは ListView
のさらに柔軟なバージョンで、さまざまなレイアウト タイプをサポートしてパフォーマンスを向上します。
-
新しい RecyclerView
ウィジェットは ListView
+ に比べてさらに柔軟に機能を追加できるようになっており、さまざまなレイアウト タイプをサポートしてパフォーマンスを向上させます。
新しい CardView
ウィジェットでは、外観や使用感が一貫しているカード内に重要な情報を表示できます。
+
新しい CardView
ウィジェットではカードの外観や操作性が統一され、カード内の重要な情報を表示できるようになりました。
@@ -109,12 +108,12 @@ Android アプリでマテリアル デザインを使うには、 @@ -136,33 +135,33 @@ Android アプリでマテリアル デザインを使うには、 -タッチ フィードバック アニメーションを使ってビューのタップイベントに応答します。 +タッチ フィードバック アニメーションでビューのタップ イベントに応答する。
タッチ フィードバック アニメーションはボタンなどの複数の標準ビューに組み込まれます。新しい API を使ってこれらのアニメーションをカスタマイズし、それらをカスタム ビューに追加できます。 +
タッチ フィードバック アニメーションはボタンなどの複数の標準ビューに組み込まれています。新しい API を使うと、これらのアニメーションをカスタマイズして、カスタム ビューに追加できます。
詳細については、カスタム アニメーションの定義をご覧ください。
@@ -171,12 +170,12 @@ Android アプリでマテリアル デザインを使うには、
+ 異なる端末のサポートデベロッパー ドキュメント
+
Android 3.0 での大きな変更点には、以下のような点があります。
+-
+
- 仮想コントロール(Back、Home、Recents)のナビゲーション処理の導入によるナビゲーション ハードウェア キー(Back、Menu、Search、Home)の廃止 + +
- アクションバーでメニュー項目を使用する際の表現パターンの強化 +
Android 4.0 では、こういったタブレット向けの変更点が携帯端末プラットフォームにも導入されました。
+ +古いハードウェアやアプリへの Android 4.0 の対応
+ +仮想ナビゲーション コントロールのある携帯端末
+Android 3.0 以降をターゲットにした Android アプリは、アクションをアクションバーに表示します。アクションバーに収まらないアクションや、トップレベルに表示するほど重要ではないアクションは、アクション オーバーフローに表示されます。 + +
+ユーザーは、アクションバーをタップすることで、アクション オーバーフローにアクセスできます。
+ +物理ナビゲーション キーのある携帯端末
+従来型のナビゲーション ハードウェア キーのある Android 携帯端末では、画面下部に仮想ナビゲーション バーは表示されません。 +代わりに、メニュー ハードウェア キーからアクション オーバーフローを利用できます。そのため、ポップアップするアクションは先ほどの例と同じように利用できますが、画面の下部に表示される点が異なります。 +
+ +仮想ナビゲーション コントロールのある携帯端末でのレガシー アプリ
+Android 2.3 以前をターゲットにビルドされたアプリを仮想ナビゲーション コントロールのある携帯端末で実行すると、仮想ナビゲーション バーの右側にアクション オーバーフロー コントロールが表示されます。 +コントロールをタップすると、アプリのアクションを従来型の Android メニュー形式で表示できます。 +
+ +状況に応じて、ユーザーがアプリでアクションを呼び出したときに、テキストを使ってそのアクションを確認したり通知したりするのは良い方法です。
+アプリでアクションを呼び出すときに、テキストでそのアクションを確認または通知するとよい場合があります。
-確認とは、呼び出したアクションを続けるかどうかをユーザーに確認してもらうことです。場合によって、確認は考慮する必要があるアクションに関連する警告や重要情報とともに表示されることがあります。
+確認とは、呼び出したアクションを本当に続行してもよいかどうかをユーザーにたずねることです。検討を要するアクションがあれば、それに関する警告や重要情報とともに表示されることもあります。
通知とは、呼び出したアクションが完了したことをユーザーにお知らせするテキストを表示することです。これによって、システムが実行している暗黙的な処理の不明瞭さをなくすことができます。場合によって、通知はアクションを元に戻すオプションとともに表示されることがあります。
+通知とは、呼び出したアクションが完了したことをユーザーに知らせるテキストを表示することです。システムにより実行中であり、ユーザーには表示されない操作を確認できます。アクションを元に戻すオプションとともに表示されることもあります。
このような方法でユーザーに情報を伝えると、実行された処理やこれから実行される処理についての不明瞭さを軽減できます。確認や通知によって、後悔するような間違いをするのを防ぐこともできます。
+このような機能を使用すれば、実行済みの処理やこれから実行される処理を明確に把握できます。確認や通知を表示することで、後悔するような間違いを防ぐこともできます。
-ユーザーのアクションを確認または通知する場合
-すべてのアクションに確認または通知が必要なわけではありません。デザインを決定する際の指針として次のチャートを使用してください。
+ユーザーのアクションを確認または通知するタイミング
+すべてのアクションに確認または通知が必要なわけではありません。確認や通知が必要かどうかを判断するには、次のチャートを使用してください。
確認
-例: Google Play ブックス
-この例では、ユーザーが Google Play ライブラリから書籍を削除することを要求しています。その書籍が今後端末で使えなくなることを知ってもらうことが重要であるため、このアクションを確認するアラートが表示されます。
-確認のダイアログを作成するときは、要求されたアクションがすぐわかるようなタイトルにします。
+この例では、ユーザーは Google Play ライブラリから書籍を削除するよう要求しています。この書籍が今後いずれの端末でも使用できなくなるということを知らせる必要があるため、このアクションを確認するアラートが表示されます。
+確認ダイアログは、要求されたアクションをタイトルに記述するなどして、わかりやすく作成します。
例: Android Beam
+例: Android ビーム
-確認は、必ずしも 2 つのボタンの付いたアラートで示す必要はありません。Android Beam を開始した後に、ユーザーには共有するコンテンツ(この例では写真)にタップするように求めるメッセージが表示されます。共有を続行しない場合は、電話を離すだけです。
+確認は、必ずしも 2 つのボタンが付いたアラートで行う必要はありません。Android ビームを開始した後、共有するコンテンツ(この例では写真)をタップするようメッセージが表示されます。共有を続行しない場合は、携帯端末を離すだけです。
通知
-例: 放置した Gmail 下書きの保存
+例: 途中まで書いた Gmail の下書きの保存
-この例では、ユーザーが Gmail 作成画面から前の画面に戻ったり、上位画面に移動したりするときに、予測しないことが起こる可能性があるため、現在の下書きが自動的に保存されます。トースト形式の通知によってその状態が明らかになります。この通知は数秒後にフェードします。
+この例では、ユーザーが Gmail 作成画面から前の画面に戻ったり、画面の上部に移動したりすると、予測しないことが起こることもあるため、現在の下書きが自動的に保存されています。この動作はトースト形式で通知され、数秒後に消えます。
この場合、保存操作はユーザーではなくアプリによって行われるため、元に戻す操作は適切ではありません。また、下書きのリストに移動するだけでメッセージの作成をすぐに再開できます。
例: Gmail スレッドの削除
-ユーザーが Gmail のリストからスレッドを削除した後に、元に戻すオプションとともに通知が表示されます。ユーザーがリストのスクロールなど関連しないアクションを実行するまで通知は表示されたままになります。
+ユーザーが Gmail のリストから会話を削除した後に、元に戻すオプションとともに認定が表示されます。リストのスクロールなど無関係なアクションをユーザーが実行するまで、通知の表示は消えません。
確認または通知を行わない場合
-例: +1 操作
-確認は不要。ユーザーが誤って +1 ボタンをタップしても、大きな問題にはなりません。ボタンをもう一度タップすればアクションを元に戻すことができます。
-通知は不要。+1 ボタンがバウンスし、赤に変わります。これは非常にわかりやすいシグナルです。
+確認は不要です。ユーザーが誤って [+1] ボタンをタップしても、あまり問題ではありません。ボタンをもう一度タップすれば、アクションを元に戻すことができるからです。
+通知は不要です。[+1] ボタンがバウンドして赤に変わります。これは非常にわかりやすいシグナルです。
例: ホームスクリーンからアプリを削除
+例: ホームスクリーンからアプリを削除する場合
-確認は不要。これは意図的なアクションです。ユーザーはアイテムを比較的大きな分離されたターゲットにドラッグ アンド ドロップする必要があります。そのため、不測の問題が発生することはほとんどありません。ユーザーがこの決定を元に戻したい場合は、ほんの数秒で元に戻すことができます。
-通知は不要。ユーザーは自分でアプリをドラッグして削除するため、アプリがホームスクリーンから消えることがわかっています。
+確認は不要です。このアクションは賢明に設計されており、ユーザーはアイテムを比較的離れたところにある大きいターゲットにドラッグ アンド ドロップする必要があります。そのため、アクシデントが発生することはほとんどありません。しかもこの操作を取り消したい場合は、ほんの数秒で元に戻すことができるようになっています。
+通知は不要です。ユーザーが自分でアプリをドラッグして削除しているので、アプリがホームスクリーンから消えるのがわかっているからです。
デベロッパー文書
-効果的なナビゲーションを実装する
+デベロッパー ドキュメント
+効果的なナビゲーションの実装
一貫したナビゲーションは全体的なユーザーの操作性を向上するために欠かせない重要な要素です。一貫性がなく予測できない動作ほどユーザーにとって不快なものはありません。 -Android 3.0 では、全体的なナビゲーション動作が大きく変更されました。 -注意深く Back と Up のガイドラインに従うことで、アプリのナビゲーションをユーザーにとって予測可能で信頼できるものにすることができます。 +
使いやすいアプリでは、ナビゲーションに統一性があります。統一性がなく、動作の読めないアプリほど使いにくいものはありません。 +Android 3.0 では、全体的なナビゲーション動作が大きく変わりました。 +Back ボタンと Up ボタンのガイドラインに従えば、ユーザーにとってわかりやすく、信頼できるナビゲーションを実装できます。
-Android 2.3 以前のアプリ内でのナビゲーションはシステムの Back ボタンを使って行われてきました。Android 3.0 よりアクションバーが導入され、第 2 のナビゲーション メカニズムとして Up ボタンが登場しました。このボタンはアプリアイコンと左向きのキャラットで構成されています。 - +
Android 2.3 以前のアプリのナビゲーションはシステムの Back ボタンで行っていました。 +Android 3.0 よりアクションバーが導入され、第 2 のナビゲーション メカニズムとして Up ボタンが登場しました。このボタンはアプリアイコンと左向きのキャレットで表されています。
-Up と Back
+Up ボタンと Back ボタンの違い
Up ボタンは、画面間の階層関係に基づいてアプリ内を移動するために使います。 -たとえば、画面 A がアイテムのリストを表示し、アイテムを選択すると(そのアイテムの詳細を表示する)画面 B に移動する場合、画面 B には画面 A に戻るための Up ボタンを用意する必要があります。 +たとえば、画面 A でアイテムのリストを表示し、アイテムを選択すると(そのアイテムの詳細を表示する)画面 B に移動する場合、画面 B には画面 A に戻るための Up ボタンが必要です。
-画面がアプリの最上位(つまり、アプリのホーム)であれば、Up ボタンを表示すべきではありません。 +
画面がアプリのトップ レベル(アプリのホーム)であれば、Up ボタンを表示する必要はありません。
-システムの Back ボタンはユーザーが最近使用した画面を、さかのぼって順番に移動する場合に使用されます。 -通常このナビゲーションはアプリの階層ではなく、画面を表示した順番に基づいています。 +
システムの Back ボタンは、最近使用した画面をさかのぼって順番に移動する場合に使用します。 +通常、このナビゲーションはアプリの階層ではなく、画面を表示した順番に基づいています。
-前に表示していた画面が現在の画面の親階層となる場合は、Back ボタンを押すとUp ボタンを押したときと同じ結果になります — これはよくある動作です。 +
前に表示していた画面が現在の画面の親階層となる場合は、Back ボタンを押すと Up ボタンを押したときと同じ結果になります — これは一般的な動作です。 -ただし、Up ボタンではユーザーが確実にアプリ内に留まるのに対して、Back ボタンを使えばホームスクリーンに、さらには別のアプリに戻ることさえできます。 +ただし、Up ボタンではユーザーの移動がアプリ内に限られるのに対して、Back ボタンではホーム画面や、別のアプリにも戻れます。
-Back ボタンは、画面間を直接ナビゲーションするだけでなく、次のような動作もサポートします。 +
Back ボタンは、画面間を直接ナビゲーションするだけでなく、次のような動作にも対応しています。
- フローティング ウィンドウ(ダイアログ、ポップアップ)を閉じる
- コンテキスト アクションバーを閉じて、選択したアイテムのハイライト表示を解除する -
- オンスクリーン キーボード(IME)を非表示にする +
- 画面上のキーボード(IME)を非表示にする
アプリ内でのナビゲーション
-複数のエントリ ポイントのある画面のナビゲーション
-画面にアプリ階層内の正確な位置がなく、アプリ内の他のどの画面からでもアクセスできる設定画面などのように複数のエントリ ポイントからアクセスできる場合があります。この場合、Up ボタンは参照元の画面に戻ることを選択する必要があります。これは Back も同様です。 -— +
エントリ ポイントが複数ある画面へのナビゲート
+設定画面のように、アプリ内の他のどの画面からでもアクセスでき、アプリ階層内に定位置がなく、複数のエントリ ポイントからアクセスできる画面もあります。 +この場合、Up ボタンは Back ボタンと同じように元の画面に戻ります。
-画面内でビューを変更する
-画面のビュー オプションを変更しても Up と Back の動作は変わりません。画面はアプリの階層内の同じ位置に留まり、新しいナビゲーション履歴は作成されません。 +
画面内でのビューの変更
+画面のビュー オプションを変更しても Up ボタンと Back ボタンの動作は変わりません。画面はアプリの階層内の同じ位置にあり、新しいナビゲーション履歴は作成されません。
このようなビューの変更には次のようなものがあります。
-
-
- タブや左右のスワイプを使ってビューを切り替える -
- ドロップダウン(折りたたみタブ)を使ってビューを切り替える -
- リストにフィルタをかける -
- リストをソートする -
- 表示の方法を変える(ズームなど) +
- タブや左右のスワイプを使ったビューの切り替え +
- ドロップダウン(折りたたみタブ)を使ったビューの切り替え +
- リストへのフィルタの適用 +
- リストの並び替え +
- 表示方法の変更(ズームなど)
兄弟画面間のナビゲーション
-アプリでアイテムのリストから 1 つのアイテム詳細画面に移動するとき、そのアイテムからリスト内の前後にある別のアイテムへのナビゲーションをサポートするのが望ましいことがよくあります。 +
アプリでアイテムのリストから選択して、あるアイテムの詳細画面に移動するとき、そのアイテムからリストの前後にある別のアイテムにナビゲーションできるようにすると使いやすくなる場合があります。 -たとえば、Gmail では、スワイプすることで、ある会話から同じ受信トレイの新しいまたは古い会話へ左右に簡単に移動できます。 -画面内でビューを変更する場合と同じように、このようなナビゲーションによって Up または Back の動作は変わりません。 +たとえば、Gmail で左か右にスワイプすると、同じ受信トレイのある会話から新しい会話や古い会話に簡単に移動できます。 +画面内でビューを変更する場合と同様に、このナビゲーションでも Up ボタンまたは Back ボタンの動作は変わりません。
-しかし、参照リストで結び付けられていない関連詳細ビュー間をブラウジングする場合 — たとえば Play ストアで同じデベロッパーのアプリや同じアーティストのアルバム間をブラウジング場合、その動作はこれとは明らかに異なります。 +
ただし、参照リストで結び付けられていない関連詳細ビュー間をブラウジングする場合は例外です。たとえば Play Store で同じデベロッパーのアプリや同じアーティストのアルバム間をブラウジングする場合です。 この場合、各リンクをたどると履歴が作成され、Back ボタンで以前に表示した各画面に戻ることになります。 -Up では常にこれらの関連画面をバイパスして、直前に表示したコンテナ画面に移動します。 +Up ボタンを使用するとこれらの関連画面をバイパスして、直前に表示したコンテナ画面に移動します。
-Up の動作を詳細ビューの知識に基づいてより使いやすくすることができます。 -前述の Play ストアの例で、ユーザーが直前に表示した書籍から映画版の詳細に移動したとします。 -その場合、Up でユーザーが前に表示していないコンテナ(映画)に戻ることができます。 +
詳細ビューを応用すれば、Up ボタンを使いやすくできます。 +前述の Play Store の例で、直前に表示した書籍から映画版の詳細に移動したとします。 +その場合、Up ボタンを使用すると前に表示していないコンテナ(映画)に戻ることができます。
-ホームスクリーンのウィジェットと通知によるアプリへのナビゲーション
+ホーム画面のウィジェットと通知を使用したアプリへのナビゲーション
-ホームスクリーンのウィジェットや通知を使ってユーザーがアプリ階層内の深い階層にある画面に直接移動できるようにします。 -たとえば、Gmail の受信ボックスのウィジェットと新しいメッセージ通知はどちらも受信トレイ画面をバイパスし、会話ビューを直接表示できます。 +
ホーム画面のウィジェットや通知を使用して、アプリの深い階層にある画面に直接移動できるようにします。 +たとえば、Gmail の受信トレイのウィジェットと新しいメッセージ通知をタップすると、どちらも受信トレイ画面をバイパスし、会話ビューを直接表示できます。
この両方の機能で、Up ボタンを次のように処理します。
-
-
- 通常アプリ内の特定の画面から移動先画面に移動する場合、Up でその画面に移動します。 +
- 通常どおりにアプリの特定の画面から移動先画面に移動する場合、Up ボタンを使用するとその画面に移動します。 -
- それ以外の場合は、Up でアプリの最上位(「ホーム」)画面に移動します。 +
- それ以外の場合は、Up ボタンを使用するとアプリのトップレベル([ホーム])の画面に移動します。
Back ボタンの場合は、アプリの最上位画面への完全な上向きナビゲーション パスをタスクのバックスタックに挿入してナビゲーションをより予測可能なものにする必要があります。 -この設定によって、アプリにどのように入ったか忘れたユーザーは、終了前のアプリの最上位画面に移動できます。 +
Back ボタンの場合は、アプリのトップ レベルの画面に直接ナビゲートできるパスをタスクのバック スタックに挿入して、わかりやすいナビゲーションにします。 +こうすることで、アプリをどのように起動したか覚えていなくても、トップ レベルの画面に移動してから終了できます。
-たとえば Gmail のホームスクリーンのウィジェットには、その作成画面に直接移動するボタンがあります。 -作成画面の Up または Back で受信トレイが表示され、そこから Back ボタンでホームに移動します。 +
たとえば Gmail のホーム画面のウィジェットには、作成画面に直接移動するボタンがあります。 +作成画面の Up ボタンまたは Back ボタンで受信トレイが表示され、そこから Back ボタンでホームに移動します。
間接通知
-アプリで複数のイベントに関する情報を同時に表示する必要がある場合、1 つの通知を使ってユーザーをインタースティシャル画面に導くことができます。 -この画面にはこれらのイベントがまとめてあり、アプリのさらに深い階層に移動するためのパスが示されます。このスタイルの通知を間接通知と呼びます。 - +
アプリで複数のイベントに関する情報を同時に表示する必要がある場合、通知を 1 つにまとめてそこからインタースティシャル画面に遷移させることができます。 +この画面にはこれらのイベントの要約が表示されており、アプリのさらに深い階層に移動するパスが示されます。 +このスタイルの通知を間接通知と呼びます。
-標準(直接)通知とは異なり、間接通知のインタースティシャル画面から Back を押すとユーザーは通知がトリガーされた地点に戻ります — バックスタックには追加の画面は挿入されません。 +
標準(直接)通知とは異なり、間接通知のインタースティシャル画面で Back ボタンを押すと、通知がトリガーされた画面に戻ります。バックスタックには追加の画面は挿入されません。 -ユーザーがインタースティシャル画面からアプリに移動すると、Up および Back は前述した標準通知の場合と同様に動作します。つまりインタースティシャル画面に戻るのではなくアプリ内でナビゲーションします。 +ユーザーがインタースティシャル画面からアプリに移動すると、Up ボタンと Back ボタンは前述の標準通知と同様に動作します。つまり、インタースティシャル画面に戻るのではなくアプリ内で遷移します。
-たとえば Gmail のユーザーがカレンダーから間接通知を受け取ったとします。この通知をタップするとインタースティシャル画面が開き、複数の異なるイベントに関するリマインダーが表示されます。 +
たとえば Gmail がカレンダーから間接通知を受け取ったとします。この通知をタップするとインタースティシャル画面が開き、複数の異なるイベントのリマインダーが表示されます。 -インタースティシャル画面で Back をタップすると Gmail に戻ります。特定のイベントをタップすると、インタースティシャル画面から完全なカレンダー アプリに移動し、そのイベントの詳細が表示されます。 +インタースティシャル画面で Back ボタンをタップすると Gmail に戻ります。特定のイベントをタップすると、インタースティシャル画面からカレンダー アプリに移動し、そのイベントの詳細が表示されます。 -イベントの詳細から、Up および Back を使うとカレンダーの最上位ビューが表示されます。
+イベントの詳細画面で Up ボタンや Back ボタンを使うと、カレンダーのトップ ビューに移動します。ポップアップ通知
-ポップアップ通知は通知ドロワーをバイパスしてユーザーの前に直接表示されます。 -ポップアップ通知はめったに使われません。タイムリーな応答が要求され、ユーザーのコンテキストの中断が必要な場合に使われます。 -たとえばトークでは、このスタイルを使って友人からのビデオチャットへの参加に関する招待状についてユーザーに通知します。というのも、この招待状は数秒後に自動的に期限切れになるからです。 +
ポップアップ通知は通知ドロワーをバイパスし、直接表示される通知です。 +ポップアップ通知はほとんど使われません。タイムリーな応答が要求され、ユーザーの操作の中断が必要な場合にのみ使うべきです。 +たとえばトークでは、友人からのビデオチャットへの招待が数秒後に自動的に期限切れとなる場合、このスタイルを使ってユーザーに通知します。
-ナビゲーション動作の点から、ポップアップ通知は間接通知のインタースティシャル画面の動作に厳密に従います。 -Back でポップアップ通知は閉じます。ユーザーがポップアップから通知元のアプリに移動すると、Up と Back は標準通知のルールに従い、アプリ内でナビゲーションします。 +
ナビゲーションでは、間接通知のインタースティシャル画面の動作に慎重に従ってポップアップ通知を行います。 +Back ボタンでポップアップ通知を閉じます。ポップアップから通知対象のアプリに移動すると、Up ボタンと Back ボタンは標準通知のルールに従って、そのアプリ内で通常のナビゲーションを実行します。
-アプリ間のナビゲーション
- -Android システムの基本的な利点の 1 つにアプリ同士がそれぞれをアクティブにできる機能があります。これによりユーザーは特定のアプリから別のアプリへ直接移動できます。 -たとえば写真を撮影する必要があるアプリでは、カメラアプリをアクティブにすることができます。カメラアプリは写真を参照元のアプリに戻します。これはデベロッパーにとっては他のアプリのコードを簡単に利用できるという点で、またユーザーにとっては通常実行するアクションに対して一貫した操作を実行できるという点で大きなメリットです。 +
アプリ間ナビゲーション
+Android システムの基本的な利点の 1 つに、アプリが別のアプリを起動できる機能があります。これを使用すると、あるアプリから別のアプリへ直接移動できます。 +たとえば、写真をキャプチャするアプリで、カメラアプリを起動できます。カメラアプリは写真を起動元のアプリに返します。 +デベロッパーにとっては他のアプリのコードを簡単に利用できるという点で、ユーザーにとってはよく実行するアクションを常に同じ操作で実行できるという点で大きなメリットです。
-アプリ間のナビゲーションを理解するには、次に説明する Android フレームワークの動作を理解することが重要です。 +
アプリ間ナビゲーションを理解するには、次に説明する Android フレームワークの動作を理解する必要があります。
アクティビティ、タスク、インテント
-Android におけるアクティビティとは情報の画面と、ユーザーが実行できるすべての関連アクションを定義するアプリケーション コンポーネントです。 -アプリはアクティビティのコレクションで、作成したアクティビティと他のアプリから再利用するアクティビティの両方で構成されています。 +
Android におけるアクティビティとは、情報を表示する画面と、実行できるすべての関連アクションを定義するアプリケーション コンポーネントのことです。 +アプリはアクティビティの集まりで構成され、作成したアクティビティと他のアプリから再利用するアクティビティで構成されています。
-タスクとは目標を実現するためにユーザーが従う一連のアクティビティです。1 つのタスクで 1 つのアプリだけのアクティビティを利用することも、複数のアプリのアクティビティを利用することもできます。 +
タスクとは目的の動作を遂行するために実行する、一連のアクティビティのことです。1 つのタスクで 1 つのアプリだけのアクティビティを利用することも、複数のアプリのアクティビティを利用することもできます。
-インテントとは、あるアプリがアクションの実行に関して別のアプリのサポートが必要であることを示すメカニズムです。 -アプリのアクティビティでそれらのアプリが対応できるインテントを示すことができます。 -「共有」などの一般的なインテントの場合、ユーザーはその要求を実現できる多くのアプリをインストールしている場合があります。 +
インテントとは、アプリがあるアクションを実行するために、別のアプリにアシストを要求するためのシグナルを出すメカニズムです。 +アプリのアクティビティは、どのようなインテントに応答できるか決めることができます。 +「共有」などの一般的なインテントの場合、その要求に対応できるアプリが複数インストールされていることもあります。
-例: 共有をサポートするアプリ間のナビゲーション
- -アクティビティ、タスク、インテントの連携を理解するには、1 つのアプリが別のアプリを使ってユーザーによるコンテンツの共有を可能にする仕組みを知る必要があります。たとえばホームから Play ストアのアプリを起動すると、新しいタスク A が開始されるとします(以下の図を参照)。 +
例: アプリ間をナビゲートして共有をサポートする
-Play ストア内をナビゲートし、プロンプトで表示された書籍をタップしてその詳細を表示した後もユーザーは同じタスク内に留まり、アクティビティを追加するとタスクは拡張されます。 -「共有」アクションをトリガーすると、共有インテントを処理するよう登録されている(さまざまなアプリの)各アクティビティを示すダイアログがユーザー表示されます。 +アクティビティ、タスク、インテントの連携を理解するには、あるアプリが別のアプリを使ってコンテンツを共有する仕組みについて理解する必要があります。 +たとえば、ホームから Play Store のアプリを起動すると、新しいタスク A が開始されるとします(以下の図を参照)。 +Play Store 内をナビゲートし、おすすめの書籍をタップしてその詳細を表示した後もユーザーは同じタスク内に留まり、アクティビティを追加するとタスクが拡張されます。 +「共有」アクションをトリガーすると、共有インテントを処理するよう登録されている(さまざまなアプリの)各アクティビティを一覧表示するダイアログが表示されます。
-ユーザーが Gmail 経由で共有することを選択すると、Gmail の作成アクティビティがタスク A の続きとして追加されます — 新しいタスクは作成されません。 -Gmail にバックグラウンドで実行中の独自のタスクがある場合、そのタスクは影響を受けません。 +
Gmail で共有するよう選択すると、Gmail の作成アクティビティがタスク A の続きとして追加され、新しいタスクは作成されません。 +Gmail にバックグラウンドで実行中のタスクがある場合、そのタスクは影響を受けません。
-作成アクティビティからメッセージを送信するか、Back ボタンをタップするとユーザーは書籍の詳細アクティビティに戻ります。 -Back を連続してタップすると Play ストアに戻り、最終的にはホームが表示されます。 +
作成アクティビティからメッセージを送信するか、Back ボタンをタップすると書籍の詳細アクティビティに戻ります。 +Back ボタンを連続してタップすると Play Store に戻り、最後にホーム画面が表示されます。
-ただし、作成アクティビティから Up をタップすると、ユーザーは Gmail 内に留まる意思を示すことになります。 -Gmail の会話リストのアクティビティが表示され、新しいタスク B が作成されます。新しいタスクは常にホームをルートとしているため、会話リストからBack をタップするとホームに戻ります。 +
ただし、作成アクティビティで Up ボタンをタップすると、Gmail で引き続き作業することになります。 +Gmail の会話リストのアクティビティが表示され、新しいタスク B が作成されます。新しいタスクでは常にホーム画面がルートになるため、会話リストから Back ボタンをタップするとホーム画面に戻ります。
-タスク A はバックグラウンドで維持され、ユーザー後から(たとえば [最近使ったアプリ] 画面経由で)このタスクに戻ることができます。 -Gmail にバックグラウンドで実行中の独自のタスクが既にある場合、そのタスクはタスク B に置き換えられます — 前のコンテキストはユーザーの新しい目標の導入より破棄されます。 +
タスク A はバックグラウンドで待機しているので、後から(たとえば [最近使ったアプリ] 画面から)このタスクに戻ることができます。 +Gmail にバックグラウンドで実行中のタスクが既にある場合、そのタスクはタスク B に置き換えられます。新しいタスクが選択され、前のコンテキストは破棄されます。
-アプリがアプリ階層内の深い階層にあるアクティビティでインテントを処理するように登録されている場合は、Up ナビゲーションの指定方法についてホームスクリーンのウィジェットと通知によるアプリへのナビゲーションをご覧ください。 +
深い階層にあるアクティビティでインテントを処理するようアプリで登録されている場合は、Up ナビゲーションの指定方法については、ホーム画面のウィジェットと通知を使用したアプリへのナビゲーションをご覧ください。
diff --git a/docs/html-intl/intl/ja/distribute/index.jd b/docs/html-intl/intl/ja/distribute/index-ja.jd similarity index 100% rename from docs/html-intl/intl/ja/distribute/index.jd rename to docs/html-intl/intl/ja/distribute/index-ja.jd diff --git a/docs/html-intl/intl/ja/guide/components/activities.jd b/docs/html-intl/intl/ja/guide/components/activities.jd new file mode 100644 index 0000000000000000000000000000000000000000..9b06d2c838bbc93e2a1cc7f94b962aaedcfafc55 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/activities.jd @@ -0,0 +1,756 @@ +page.title=アクティビティ +page.tags=activity,intent +@jd:body + +本書の内容
+-
+
- アクティビティを作成する + + +
- アクティビティを開始する + + +
- アクティビティをシャットダウンする +
- アクティビティのライフサイクルを管理する + + +
キークラス
+-
+
- {@link android.app.Activity} +
関連ドキュメント
+-
+
- タスクとバックスタック + +
{@link android.app.Activity} は、電話をかける、写真を撮影する、メールを送る、マップを閲覧するといった操作をユーザーができる画面を提供するアプリケーション コンポーネントです。 + +各アクティビティには、ユーザー インターフェースを描画できるウィンドウがあります。一般的にはウィンドウは画面と同じ大きさになりますが、画面より小さくしたり、他のウィンドウ上にフローティングさせたりすることもできます。 + +
+ +通常、アプリケーションは複数のアクティビティで構成されており、各アプリケーションはそれぞれ緩やかにつながっています。 +一般的には、アプリケーションの 1 つのアクティビティが「メイン」アクティビティとして指定され、ユーザーが初めてアプリケーションを起動したときに表示されるのがこのアクティビティになります。 +その後、各アクティビティで別のアクティビティを開始して別の操作を実行できます。 +新しいアクティビティの開始時には、前のアクティビティは停止しますが、そのアクティビティはシステムによってスタック(「バックスタック」)に維持されます + +新しいアクティビティが開始すると、それがバックスタックに入ってユーザーに表示されます。 +バックスタックは「後入れ先出し」の基本的なスタック メカニズムを順守するため、ユーザーが現在のアクティビティを完了して [戻る] ボタンを押すと、そのアクティビティはスタックから消え(破棄され)、前のアクティビティが再開します。 + +(バックスタックの詳細については、タスクとバックスタックドキュメントで説明します)。 + +
+ +新しいアクティビティが開始したことで、別のアクティビティが停止した場合、その状態の変化がアクティビティのライフサイクル コールバック メソッド経由で通知されます。システムがアクティビティを作成しているのか、停止しているのか、再開しているのか、破棄しているのかという状態の変化によって、アクティビティが受け取るコールバック メソッドにはいくつかの種類があり、各コールバックではユーザーがその状態の変化に応じた特定の操作を実行できます。 + + +—— + +たとえば、アクティビティが停止した場合は、ネットワーク接続やデータベース接続などの大きなオブジェクトを解放することになります。 +アクティビティが再開した場合は、必要なリソースを再度取得し、中断したところから操作を再開できます。 +このような状態の推移はすべて、アクティビティのライフサイクルの一部です。 +
+ +このドキュメントでは、さまざまなアクティビティの状態間の切り替えを正しく管理できるよう、アクティビティのライフサイクルの仕組みについてさらに詳しく説明する他、アクティビティのビルド方法と使用方法の基本について解説します。 + +
+ + + +アクティビティを作成する
+ +アクティビティを作成するには、{@link android.app.Activity} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +サブクラスでは、アクティビティのライフサイクルの状態の切り替え時(アクティビティの作成、停止、再開、破棄など)にシステムが呼び出すコールバック メソッドを実装する必要があります。 + +最も重要なコールバック メソッドは次の 2 つです。 +
+ +-
+
- {@link android.app.Activity#onCreate onCreate()} +
- このメソッドは必ず実装してください。システムはアクティビティ作成の際にこのメソッドを呼び出します。 +実装の際には、アクティビティの必須コンポーネントを初期化する必要があります。 + + さらに重要な点は、ここで {@link android.app.Activity#setContentView + setContentView()} を呼び出してアクティビティのユーザー インターフェースのレイアウトを定義する必要があるということです。 +
- {@link android.app.Activity#onPause onPause()} +
- システムは、ユーザーがアクティビティを終了したことを始めて示すときに、このメソッドを呼び出します(アクティビティが破棄されていない場合も含む)。 +通常はここで、現在のユーザー セッション後も維持する必要のある変更点を保存しておきます(ユーザーが戻ってこない可能性があるため)。 + + +
アクティビティ間の滑らかな操作感を実現し、アクティビティが停止したり破棄されたりする可能性のある予想外の中断に対応するために使用できるライフサイクル コールバック メソッドは他にもいくつかあります。 + +すべてのライフサイクル コールバック メソッドについては、アクティビティのライフサイクルを管理するのセクションで説明します。 +
+ + + +ユーザー インターフェースを実装する
+ +アクティビティのユーザー インターフェースは、ビューの階層、 {@link android.view.View} から派生したオブジェクトから提供されます。— +各ビューはアクティビティ ウィンドウ内の特定の長方形のエリアを制御し、ユーザーの操作に応答します。 +たとえば、1 つのビューが、ユーザーがタップしたときに操作を開始するボタンである場合があります。 +
+ +Android には、レイアウトのデザインや整理に使用できる既成のビューが多数用意されています。 +「ウィジェット」は、ボタン、テキスト フィールド、チェックボックス、画像といった画像の視覚的(操作可能な)要素を提供するビューです。 +「レイアウト」は、{@link +android.view.ViewGroup} から派生したビューで、線形レイアウト、グリッド レイアウト、相対レイアウトなど、子ビューの特有のレイアウト モデルを提供するものです。 +また、{@link android.view.View} クラスと {@link android.view.ViewGroup} クラス(または既存のサブクラス)のサブクラスを作成し、独自のウィジェットやレイアウトを作ってアクティビティのレイアウトに適用することもできます。 + +
+ +ビューを使用したレイアウトの定義で最も一般的なのは、XML レイアウト ファイルをアプリケーション リソースに保存する方法です。 +この方法では、ユーザー インターフェースのデザインを、アクティビティの挙動を定義するソース コードとは別に維持できます。 +{@link android.app.Activity#setContentView(int) setContentView()} を使用して、レイアウトのリソース ID を渡すと、アクティビティの UI としてレイアウトを設定できます。 + +ただし、アクティビティ コードに新しい {@link android.view.View} を作成して、{@link android.view.ViewGroup} に新しい {@link +android.view.View} を挿入してビュー階層をビルドし、ルートの {@link android.view.ViewGroup} を {@link android.app.Activity#setContentView(View) +setContentView()} に渡して、そのレイアウトを使うこともできます。 + +
+ +ユーザー インターフェースの作成の詳細については、「ユーザー インターフェース」のドキュメントをご覧ください。
+ + + +マニフェストでアクティビティを宣言する
+ +アクティビティがシステムにアクセスできるようにするには、マニフェストでアクティビティを宣言する必要があります。 +アクティビティを宣言するには、マニフェスト ファイルを開いて、{@code <activity>} 要素を {@code <application>} の子要素として追加します。 + +次に例を示します。
+ ++<manifest ... > + <application ... > + <activity android:name=".ExampleActivity" /> + ... + </application ... > + ... +</manifest > ++ +
この要素には他にも、アクティビティのラベル、アクティビティのアイコン、アクティビティの UI を決めるテーマなどのプロパティを定義する属性を含めることができます。{@code android:name} 属性は、アクティビティのクラス名を指定するもので、唯一の必須属性です。 + + +—アプリケーションを発行したら、この名前は変更できません。変更すると、アプリケーションのショートカットなどの一部の機能が破損する可能性があります(ブログの投稿「Things That Cannot Change」をご覧ください)。 + + +
+ +マニフェストでのアクティビティの宣言に関する詳細については、{@code <activity>} 要素のリファレンスをご覧ください。 +
+ + +インテント フィルタを使用する
+ +{@code +<activity>} 要素でも — {@code +<intent-filter>} 要素を使用してさまざまなインテント フィルタを指定して — 他のアプリケーション コンポーネントでのアクティベート方法を宣言できます。 +
+ +Android SDK ツールを使用して新しいアプリケーションを作成する際、自動的に作成されるスタブ アクティビティには、「メイン」アクションに応答するアクティビティで、「ランチャー」カテゴリに置かれるべきものを宣言するインテント フィルタが含まれます。 + +インテント フィルタは次のように表示されます。 +
+ ++<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> ++ +
{@code +<action>} 要素は、これがアプリケーションへの「メイン」エントリ ポイントであることを指定します。{@code +<category>} 要素は、アクティビティをシステムのアプリケーション ランチャーに入れるべきであると指定します(ユーザーがこのアクティビティを起動できるようにします)。 +
+ +アプリケーションを自己完結型にして、他のアプリケーションでアクティビティをアクティベートできないようにする場合は、他のインテント フィルタは必要ありません。 +前の例のように、「メイン」アクションを持ち、「ランチャー」カテゴリにできるのは 1 つのアクティビティのみです。 +アクティビティを他のアプリケーションで利用できないようにする場合は、そのアクティビティにはインテント フィルタを使用せず、明示的なインテントを使用して自身でアクティビティを開始するようにできます(次のセクションで説明します)。 + +
+ +ただし、他のアプリケーション(と自身のアプリケーション)から派生した暗黙的なインテントにアクティビティが応答するようにする場合は、アクティビティで追加のインテント フィルタを定義する必要があります。 + +応答するインテントのタイプごとに、{@code +<action>} 要素を含む {@code +<intent-filter>} と、任意で {@code +<category>} 要素や {@code +<data>} 要素を含める必要があります。 +これらの要素は、アクティビティが応答できるインテントのタイプを指定します。 +
+ +アクティビティがインテントに応答する方法の詳細については、「インテントとインテント フィルタ」のドキュメントをご覧ください。 +
+ + + +アクティビティを開始する
+ +@link android.app.Activity#startActivity + startActivity()} を呼び出して、開始するアクティビティを記述する {@link android.content.Intent} を渡すと、新しいアクティビティを開始できます。 +インテントは開始するアクティビティを正確に指定するか、実行する操作のタイプを記述します(システムが適切なアクティビティを選択しますが、それが他のアプリケーションのアクティビティである場合もあります)。 + + +また、インテントには開始したアクティビティで使用する少量のデータを含めることもできます。 +
+ +自身のアプリケーションを操作するとき、既知のアクティビティを起動することが頻繁にあります。 + そのような場合、クラス名を使用して開始するアクティビティを明示的に定義するインテントを作成できます。 +例として、1 つのアクティビティで {@code +SignInActivity} という名前の他のアクティビティを開始する方法を次に示します。
+ ++Intent intent = new Intent(this, SignInActivity.class); +startActivity(intent); ++ +
ただし、アクティビティからのデータを使用して、アプリケーションでメールやテキスト メッセージの送信、ステータスのアップデートといった操作を実行する場合もあります。 +アプリケーションにそのような操作を実行できるアクティビティがない場合、代わりに、端末上の他のアプリケーションによるアクティビティを活用できます。 + +ここが、インテントがその存在意義を発揮する場面です。実行する操作を記述するインテントを作成し、システムが適切なアクティビティを他のアプリケーションから起動します。 +— + +インテントを処理できるアクティビティが複数ある場合は、使用するアクティビティを 1 つユーザーが選択できます。 +たとえば、メールを送信できるようにする場合は、次のようなインテントを作成します。 + +
+ ++Intent intent = new Intent(Intent.ACTION_SEND); +intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); +startActivity(intent); ++ +
インテントに追加された {@link android.content.Intent#EXTRA_EMAIL} のエクストラは、メールの送信先となるメールアドレスの文字列配列です。 +メール アプリケーションがこのインテントに応答するとき、エクストラにある文字列配列を読み取り、それをメール作成フォームの「宛先」フィールドに置きます。 + +この場合、メール アプリケーションのアクティビティが開始してユーザーが操作を完了したときにアクティビティが再開します。 +
+ + + + +結果待ちのアクティビティを開始する
+ +開始するアクティビティから結果を受け取りたい場合は、{@link android.app.Activity#startActivityForResult + startActivityForResult()}({@link android.app.Activity#startActivity + startActivity()} の代わりに)を呼び出してアクティビティを開始します。 +その後のアクティビティから結果を受け取るには、 +{@link android.app.Activity#onActivityResult onActivityResult()} コールバック メソッドを実装します。 +後続のアクティビティが完了すると、{@link +android.content.Intent} の結果を {@link android.app.Activity#onActivityResult onActivityResult()} メソッドに返します。 +
+ +たとえば、連絡先を 1 つ受け取って、アクティビティでその連絡先情報を使用する場合は、 +次のようにインテントを作成して結果を処理できます。 +
+ ++private void pickContact() { + // Create an intent to "pick" a contact, as defined by the content provider URI + Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); + startActivityForResult(intent, PICK_CONTACT_REQUEST); +} + +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // If the request went well (OK) and the request was PICK_CONTACT_REQUEST + if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { + // Perform a query to the contact's content provider for the contact's name + Cursor cursor = getContentResolver().query(data.getData(), + new String[] {Contacts.DISPLAY_NAME}, null, null, null); + if (cursor.moveToFirst()) { // True if the cursor is not empty + int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); + String name = cursor.getString(columnIndex); + // Do something with the selected contact's name... + } + } +} ++ +
この例では、アクティビティの結果を処理するために {@link +android.app.Activity#onActivityResult onActivityResult()} メソッドで使用すべき基本ロジックを示しています。 +1 つ目の条件では、要求が成功したかどうかを確認し、成功した場合は {@code resultCode} が{@link android.app.Activity#RESULT_OK} になり、この結果への要求が応答しているかどうかが判明します。この場合、{@code requestCode} が {@link android.app.Activity#startActivityForResult +startActivityForResult()} で送信された 2 つ目のパラメータに一致しています。— +—— + +そこから、コードが {@link android.content.Intent}({@code data} パラメータ)に返されたデータを照会することでアクティビティの結果を処理します。 +
+ +ここで、{@link +android.content.ContentResolver} がコンテンツ プロバイダに対してクエリを実行し、照会されたデータを読み取れるようにする {@link android.database.Cursor} が返されます。 +詳細については、「コンテンツ プロバイダ」のドキュメントをご覧ください。 +
+ +インテントの使用に関する詳細については、「インテントとインテント フィルタ」のドキュメントをご覧ください。 +
+ + +アクティビティをシャットダウンする
+ +アクティビティは、{@link android.app.Activity#finish +finish()} メソッドを呼び出すことでシャットダウンできます。また、{@link android.app.Activity#finishActivity finishActivity()} を呼び出すと以前に開始した別のアクティビティをシャットダウンすることもできます。 +
+ +注: ほとんどの場合、これらのメソッドを用いてアクティビティを明示的に終了しないでください。 +後述のアクティビティのライフサイクルでも説明していますが、Android システム自体がアクティビティのライフサイクルを管理するため、アクティビティを自身で終了させる必要はありません。 + +これらのメソッドを呼び出すと、期待された操作性に影響を与えることがあるため、ユーザーが絶対にアクティビティのこのインスタンスに戻らないようにする場合にのみ使用するようにしてください。 + +
+ + +アクティビティのライフサイクルを管理する
+ +コールバック メソッドを実装したアクティビティのライフサイクルの管理は、強固で柔軟なアプリケーションの開発にとって重要です。 + +アクティビティのライフサイクルは、他のアクティビティ、タスク、バックスタックとの関連による影響を直接受けます。 +
+ +基本的に、アクティビティには次の 3 つの状態があります。
+ +-
+
- 再開状態 +
- アクティビティが画面のフォアグラウンドにあり、ユーザー フォーカスのある状態。(この状態は「実行中」とも呼ばれます)。 + + +
- 一時停止状態 +
- 他のアクティビティがフォアグラウンドにあり、メインに表示されているが、このアクティビティも表示されている。つまり、このアクティビティの上に他のアクティビティが表示されており、他方のアクティビティは一部が透明であるか、画面全体を覆ってはいない状態です。 + +一時停止状態のアクティビティは完全に生きている状態ですが({@link android.app.Activity} オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持され、ウィンドウ マネージャーにもアタッチされたまま)、メモリ量が極端に低下した場合にはシステムによって強制停止される場合もあります。 + + + +
- 停止状態 +
- アクティビティは、他のアクティビティによって完全に見えない状態です(アクティビティが「バックグラウンド」にある)。 +停止状態のアクティビティもまだ生きていますが({@link android.app.Activity} オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持されているが、ウィンドウ マネージャーにはアタッチされていない状態です)。 + +ただし、ユーザーには表示されておらず、別の場所でメモリが必要になればシステムによって強制終了される場合もあります。 + +
アクティビティが一時停止か停止状態の場合、システムはアクティビティに終了するかどうかを尋ねる({@link android.app.Activity#finish finish()} メソッドを呼び出す)か、単純にプロセスを強制終了してメモリから解放できます。 + +アクティビティを再度開くとき(終了や強制終了後)は、もう一度最初から作成する必要があります。 +
+ + + +ライフサイクル コールバックを実装する
+ +アクティビティが上記の異なる状態の間を遷移するとき、さまざまなコールバック メソッドを介して通知されます。 +すべてのコールバック メソッドは、アクティビティの状態が変化したときに必要な操作を実行するようオーバーライドできるフックになります。 +次のスケルトン アクティビティには、基本的なライフサイクル メソッドがそれぞれ含まれています。 +
+ + ++public class ExampleActivity extends Activity { + @Override + public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // The activity is being created. + } + @Override + protected void {@link android.app.Activity#onStart onStart()} { + super.onStart(); + // The activity is about to become visible. + } + @Override + protected void {@link android.app.Activity#onResume onResume()} { + super.onResume(); + // The activity has become visible (it is now "resumed"). + } + @Override + protected void {@link android.app.Activity#onPause onPause()} { + super.onPause(); + // Another activity is taking focus (this activity is about to be "paused"). + } + @Override + protected void {@link android.app.Activity#onStop onStop()} { + super.onStop(); + // The activity is no longer visible (it is now "stopped") + } + @Override + protected void {@link android.app.Activity#onDestroy onDestroy()} { + super.onDestroy(); + // The activity is about to be destroyed. + } +} ++ +
注: これらのライフサイクル メソッドを実装する際は、上記の例のように、すべての操作の前にスーパークラスの実装を呼び出す必要があります。 +
+ +これらのメソッドすべてで、アクティビティのライフサイクル全体を定義します。これらのメソッドを実装すると、アクティビティのライフサイクル内の次の 3 つのネストされたループを監視できます。 +
+ +-
+
- アクティビティの entire lifetime は、{@link +android.app.Activity#onCreate onCreate()} の呼び出しから、{@link +android.app.Activity#onDestroy} の呼び出しまでの間です。アクティビティは、{@link android.app.Activity#onCreate onCreate()} で「グローバル」状態のセットアップ(レイアウトの定義など)を実行し、{@link android.app.Activity#onDestroy} に残っているすべてのリソースを解放する必要があります。 + +たとえば、アクティビティにネットワークからデータをダウンロードするためバックグラウンドで実行しているスレッドがある場合、そのスレッドが {@link android.app.Activity#onCreate onCreate()} に作成され、{@link +android.app.Activity#onDestroy} のスレッドが停止される場合があります。 + + + +
アクティビティのvisible lifetime は、{@link +android.app.Activity#onStart onStart()} の呼び出しから、{@link +android.app.Activity#onStop onStop()} の呼び出しまでの間です。この間、アクティビティは画面上に表示され、ユーザーが操作できる状態です。 +たとえば {@link android.app.Activity#onStop onStop()} は、新たなアクティビティが開始してこのアクティビティが表示されなくなったときに呼び出されます。 +これらの 2 つのメソッド間で、アクティビティをユーザーに表示するのに必要なリソースは保持できます +たとえば、{@link android.content.BroadcastReceiver} を {@link +android.app.Activity#onStart onStart()} に登録して UI に影響のある変更を監視し、ユーザーが表示内容の閲覧をやめたときに {@link android.app.Activity#onStop onStop()} で登録解除できます + + +アクティビティがユーザーに表示されたり、非表示になったりとアクティビティの状態が変化する場合、アクティビティの entire lifetime 中にシステムが {@link android.app.Activity#onStart onStart()} と {@link +android.app.Activity#onStop onStop()} を複数回呼び出すこともあります。 +
+
+アクティビティの foreground lifetime は {@link +android.app.Activity#onResume onResume()} の呼び出しから、{@link android.app.Activity#onPause +onPause()} の呼び出しまでの間です。この間、アクティビティは画面上の他のすべてのアクティビティの前面にあり、ユーザーの入力フォーカスがある状態です。 +アクティビティは フォアグラウンドにある状態からそうでない状態に頻繁に遷移する可能性があります。たとえば、端末がスリープ状態になったり、ダイアログが表示されたりしたときには{@link android.app.Activity#onPause onPause()} が呼び出されます。 +— +この状態遷移は頻繁に起こるため、この 2 つのメソッドのコードはユーザーを待たせてしまうような遅い遷移にならないよう、適正な軽い処理にしておく必要があります。 +
+
図 1 では、状態間でアクティビティがたどる可能性のあるループと経路を表しています。長方形はアクティビティが状態間で遷移したときの処理用に実装できるコールバック メソッドを表しています。 + +
+ + +
+ +表 1 には同じライフサイクル コールバック メソッドがリストされており、各コールバック メソッドの詳細と、アクティビティのライフサイクル全体でのそれぞれの位置関係、コールバック メソッドの完了後にシステムによってアクティビティが強制終了されるかどうかを示しています。 + + +
+ + + +メソッド | 説明 | 完了後の強制終了 | 次のメソッド | ||
---|---|---|---|---|---|
{@link android.app.Activity#onCreate onCreate()} |
+ アクティビティが最初に作成されるときに呼び出されます。
+ ここで、ビューの作成、リストとのデータバインドといった、通常の静的なセットアップを行います。—
+アクティビティの前の状態を含む Bundle オブジェクトを取り出せた場合、それをメソッドに渡します(後半のアクティビティの状態を保存するをご覧ください)。
+
+
+
+ 常に {@code onStart()} が後に続きます。 |
+ いいえ | +{@code onStart()} | +||
+ | {@link android.app.Activity#onRestart
+onRestart()} |
+ アクティビティが停止した後、再開する直前に呼び出されます。
+
+ 常に {@code onStart()} が後に続きます。 |
+ いいえ | +{@code onStart()} | +|
{@link android.app.Activity#onStart onStart()} |
+ アクティビティがユーザーに見える状態になる直前に呼び出されます。
+ アクティビティがフォアグラウンドになったときは {@code onResume()} が後に続き、アクティビティが非表示になったときは {@code onStop()} が後に続きます。 + |
+ いいえ | +{@code onResume()} または {@code onStop()} |
+||
+ | {@link android.app.Activity#onResume onResume()} |
+ アクティビティとユーザーとの操作が開始する直前に呼び出されます。
+この時点で、アクティビティはアクティビティ スタックの先頭にあり、ユーザー入力の準備ができています。
+
+ 常に {@code onPause()} が後に続きます。 |
+ いいえ | +{@code onPause()} | +|
{@link android.app.Activity#onPause onPause()} |
+ システムが別のアクティビティを再開する直前に呼び出されます。
+通常、このメソッドは永続化データへの未保存の変更をコミットしたり、アニメーションや CPU を消費する可能性のあるその他の動作を停止したりする際に使用されます。
+
+それが完了するまで次のアクティビティが再開できないため、それらの操作は迅速に行う必要があります。
+
+ アクティビティが前面に戻るときは {@code onResume()} が後に続き、アクティビティが非表示になるときは {@code onStop()} が後に続きます。 + + |
+ はい | +{@code onResume()} または {@code onStop()} |
+||
{@link android.app.Activity#onStop onStop()} |
+ アクティビティがユーザーに見えなくなると呼び出されます。これは、アクティビティが破棄されたか、別のアクティビティ(既存のアクティビティや新しいアクティビティ)が再開されてこのアクティビティを覆っている場合に起こります。
+
+
+ アクティビティのユーザー操作が可能に戻るときは {@code onRestart()} が後に続き、アクティビティがなくなるときは {@code onDestroy()} が後に続きます。 + + |
+ はい | +{@code onRestart()} または {@code onDestroy()} |
+||
{@link android.app.Activity#onDestroy
+onDestroy()} |
+ アクティビティが破棄される前に呼び出されます。これはアクティビティが受け取る最後の呼び出しです。
+アクティビティが終了した({@link android.app.Activity#finish
+ finish()} が呼び出された)か、アクティビティ領域を節約するためにシステムが一時的にこのアクティビティを破棄した場合に呼び出されます。
+
+この 2 つのシナリオは、{@link
+ android.app.Activity#isFinishing isFinishing()} メソッドで区別できます。
+ |
+ はい | +なし | +
「完了後の強制終了」の列は、メソッドが戻った後に、アクティビティのコードの後続行を実行することなく、アクティビティをホストするプロセスをシステムが強制終了できるかどうかを示しています。 + +3 つのメソッド({@link +android.app.Activity#onPause +onPause()}、{@link android.app.Activity#onStop onStop()}、{@link android.app.Activity#onDestroy +onDestroy()})が「はい」になっています。{@link android.app.Activity#onPause onPause()} は 3 つのなかで最初であるため、アクティビティが作成された後は{@link android.app.Activity#onPause onPause()} がプロセスが強制終了される可能性がある前に呼び出されることが保証される最後のメソッドです。システムが緊急でメモリを空ける必要がある場合は、{@link +android.app.Activity#onStop onStop()} と {@link android.app.Activity#onDestroy onDestroy()} は呼び出されない場合があります。 + +— + +そのため、重要な永続的データ(ユーザーの編集内容など)をストレージに書き込む際は、{@link android.app.Activity#onPause onPause()} を使用する必要があります。 +ただし、このメソッドで後続のアクティビティへの遷移をブロックしてしまい、ユーザー操作の速度を送らせてしまうことから、{@link android.app.Activity#onPause onPause()} 中にどんな情報を保持するかについては吟味する必要があります。 + + +
+ +「強制終了」列で「いいえ」となっているメソッドでは、アクティビティが呼び出された時点から、アクティビティをホストするプロセスが強制終了されないよう保護します。 +つまり、アクティビティが強制終了される可能性があるのは、{@link android.app.Activity#onPause onPause()} が戻ってから、{@link android.app.Activity#onResume onResume()} が呼び出されるまでの間です。 + +{@link android.app.Activity#onPause onPause()} が再度呼び出されて戻るまでは、再度強制終了されることはありません。 +
+ +注: 表 1 の定義では技術的に「強制終了」できないアクティビティでも、システムによって強制終了されることがありますが、そうなるのはリソース不足などの緊急時のみです。 +— +アクティビティが強制終了されるケースについては、Processes and Threading のドキュメントで説明しています。 + +
+ + +アクティビティの状態を保存する
+ +アクティビティのライフサイクルを管理するでも簡単に説明したように、アクティビティが一時停止や停止したとき、アクティビティの状態は保持されます。 + +これは、一時停止や停止されたときも {@link android.app.Activity} オブジェクトがメモリに保持されるためです — メンバーや現在の状態といったすべての情報は残っています。 + +つまり、アクティビティ内でユーザーが加えた変更点は保持されるため、アクティビティがフォアグラウンドに戻ったとき(「再開」したとき)、それらの変更点はそのまま表示されます。 + +
+ +ただし、メモリを確保するためにシステムがアクティビティを破棄すると、 {@link +android.app.Activity} オブジェクトが破棄されるため、システムはそれをそのままの状態で再開できなくなります。 +代わりに、ユーザーがそれに戻る操作を行った場合、システムは {@link android.app.Activity} オブジェクトを再作成します。 +ユーザーにはシステムがアクティビティを破棄して再作成したことはわからないため、アクティビティが以前の状態のままであることを期待します。 + +この場合、アクティビティの状態情報を保存できる追加のコールバック メソッド({@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()})を実装することで、アクティビティの状態に関する重要な情報を維持できます。 + +
+ +アクティビティが破棄されるような状態になる前に、システムが {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} を呼び出します。 +システムはこのメソッドを {@link android.os.Bundle} に渡し、そこでアクティビティの状態情報を名前と値のペアとして {@link +android.os.Bundle#putString putString()} や {@link +android.os.Bundle#putInt putInt()} などのメソッドを使用して保存できます。 + +その後、システムがアプリケーション プロセスを強制終了して、ユーザーがアクティビティに戻った場合、システムはアクティビティを再作成して {@link android.os.Bundle} を {@link android.app.Activity#onCreate onCreate()} と {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} の両方に渡します。 + +いずれのメソッドを使った場合でも、保存した状態を {@link android.os.Bundle} から抽出してアクティビティの状態を復元できます。 + +復元する状態情報がない場合は、{@link +android.os.Bundle} は null で渡されます(アクティビティを最初に作成した場合がこれにあたります)。 +
+ + + + +注: アクティビティが破棄される前に {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} が呼び出される保証はありません。これは、状態を保存する必要がないケースがあるためです(ユーザーが [戻る] ボタンを使用してアクティビティを離れることで明示的にアクティビティを閉じた場合など)。 + + + +システムが {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} を呼び出す場合、呼び出しは常に {@link +android.app.Activity#onStop onStop()} の前、場合によっては {@link android.app.Activity#onPause +onPause()} の前に行われます。
+ +ただし、何もせず {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} も実装しない場合でも、{@link android.app.Activity} クラスの {@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装によって、アクティビティの状態が復元されるものもあります。 +具体的には、デフォルトの実装がレイアウト内のすべての {@link +android.view.View} の {@link +android.view.View#onSaveInstanceState onSaveInstanceState()} を呼び出すことで、各ビューが保存すべき情報を提供できるようになります。 + +Android フレームワークの大半のウィジェットが必要に応じてこのメソッドを実装しており、UI への視覚的な変更は自動的に保存され、アクティビティが再作成されると復元されるようになっています。 + +たとえば、{@link android.widget.EditText} ウィジェットではユーザーが入力したすべてのテキストを保存し、{@link android.widget.CheckBox} ウィジェットはオンにされたかどうかを保存するようになっています。 + +ここで必要な作業は、状態を保存する各ウィジェット用の一意の ID({@code android:id})を提供するだけです。 +ウィジェットに ID がないと、システムは状態を保存できません。 +
+ +また、レイアウトのビューでの状態の保存を明示的に停止するには、{@link android.R.attr#saveEnabled android:saveEnabled} 属性を {@code "false"} に設定するか、{@link android.view.View#setSaveEnabled setSaveEnabled()} メソッドを呼び出します。 + +通常はこの機能を無効にしませんが、アクティビティ UI の状態を別の方法で復元する場合には無効にできます。 +
+{@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装によってアクティビティの UI に関する有用な情報は保存されますが、追加の情報を保存するようそれをオーバーライドすることもできます。例としては、アクティビティの期間に変更されたメンバー値を保存する必要があるケースなどがあります。(UI で復元された値に関連している場合でも、それらの UI 値を持つメンバーはデフォルトでは復元されません)。 + + + +
+ +{@link +android.app.Activity#onSaveInstanceState onSaveInstanceState()} のデフォルトの実装で UI の状態を保存できるため、状態の追加情報を保存するようメソッドをオーバーライドする場合は、常に作業前に {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} のスーパークラス実装を呼び出す必要があります。 + + +同様に、オーバーライドする場合はデフォルトの実装でビューの状態を復元できるよう、{@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} のスーパークラスの実装も呼び出す必要があります。 +
+ +注: {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} は呼び出される保証がないため、これはアクティビティの一時的な状態の記録用にのみ使用し、永続的データの保存には使用しないようにします。 + +—代わりに {@link +android.app.Activity#onPause onPause()} を使用して、ユーザーがアクティビティを離れたときの永続的データ(データベースに保存するインストール必要のあるデータなど)を保存します。 +
+ +アプリケーションが状態を復元できるかどうかテストするには、端末を回転してみて、方向が変化するかを確認します +画面の方向が変わるとき、システムがアクティビティを破棄して再作成し、新しい画面構成に利用可能な別のリソースを適用します。 + +アプリケーションの使用中にユーザーが端末を回転させるという場面は日常的にあるため、アクティビティが再作成されたときに状態を完全に復元することは非常に重要です。 + +
+ + +構成の変更を処理する
+ +端末の構成の中には、実行の際に変化するものがあります(画面の向き、キーボードの可用性、言語など)。 +そのような変化が生じたとき、Android は実行中のアクティビティを再作成します(システムが {@link android.app.Activity#onDestroy} を呼び出し、その後すぐに {@link +android.app.Activity#onCreate onCreate()})を呼び出します。 +この動作は、提供した別のリソース(異なる画面の向きやサイズに応じたレイアウトなど)を使用してアプリケーションを自動的にリロードすることで、アプリケーションを新しい構成に適応させることを目的としています。 + + +
+ +前述のように画面の向きの変化による再起動を処理して、アクティビティの状態を復元するようアプリケーションを適切にデザインしていれば、アプリケーションはアクティビティのライフサイクルでの予期しない他のイベントに対しても回復力を持つことができます。 + +
+ +このような再起動を処理するのに最適な方法は、前のセクションで説明したように、{@link + android.app.Activity#onSaveInstanceState onSaveInstanceState()} と {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}(または {@link +android.app.Activity#onCreate onCreate()})を使用してアクティビティの状態を保存、復元する方法です。 +
+ +実行の際に起こる構成の変更と、その処理方法の詳細については、「実行時の変更の処理」のガイドをご覧ください。 + +
+ + + +アクティビティを連携する
+ +1 つのアクティビティで別のアクティビティを開始すると、双方でライフサイクルの遷移が生じます。1 つ目のアクティビティが一時停止したり停止したりすると(バックグラウンドにある場合は停止しません)、もう一方のアクティビティが作成されます。 + +これらのアクティビティでディスクなどに保存されているデータを共有している場合は、2 つ目のアクティビティが作成される前に 1 つ目のアクティビティが完全に停止することはないということを理解しておくことが重要です。むしろ、2 つ目の開始プロセスは、1 つ目の停止プロセスにオーバーラップします。 + + +
+ +特に 2 つのアクティビティが同じプロセスにあって 1 つが別のアクティビティを開始する場合、ライフサイクル コールバックの順序は厳密に定義されています。 +アクティビティ A がアクティビティ B を開始する場合の動作の順序を次に示します。 +
+ +-
+
- アクティビティ A の {@link android.app.Activity#onPause onPause()} メソッドが実行されます。 + +
- アクティビティ B の {@link android.app.Activity#onCreate onCreate()}、{@link +android.app.Activity#onStart onStart()}、{@link android.app.Activity#onResume onResume()} メソッドが順次実行されます +(このとき、ユーザー フォーカスはアクティビティ B にあります)。 + +
- 次に、アクティビティ A が画面から消えた場合、{@link +android.app.Activity#onStop onStop()} メソッドが実行されます。 +
このライフサイクル コールバックの順序を予測しておくことで、1 つのアクティビティから他のアクティビティへの情報の遷移を管理できるようになります。 +たとえば、1 つ目のアクティビティが停止したときに、後続のアクティビティが読み取れるようにデータベースに書き込む必要がある場合、データベースに書き込むタイミングは {@link +android.app.Activity#onStop onStop()} ではなく {@link android.app.Activity#onPause onPause()} の間になります。 + +
+ + diff --git a/docs/html-intl/intl/ja/guide/components/bound-services.jd b/docs/html-intl/intl/ja/guide/components/bound-services.jd new file mode 100644 index 0000000000000000000000000000000000000000..d115e76ed04b9723d4161478c405abde5df83bb4 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/bound-services.jd @@ -0,0 +1,658 @@ +page.title=バインドされたサービス +parent.title=サービス +parent.link=services.html +@jd:body + + +-
+
- 基本 +
- バインドされたサービスを作成する
+
-
+
- Binder クラスを拡張する +
- メッセンジャーを使用する +
+ - サービスにバインドする +
- バインドされたサービスのライフサイクルを管理する +
- {@link android.app.Service} +
- {@link android.content.ServiceConnection} +
- {@link android.os.IBinder} +
- サービス +
本書の内容
+-
+
キークラス
+-
+
サンプル
+ + +関連ドキュメント
+-
+
バインドされたサービスは、クライアントサーバー インターフェースにおけるサーバーになります。バインドされたサービスでは、コンポーネント(アクティビティなど)をサービスにバインドしたり、送信を要求したり、受信を応答したり、さらにはプロセス間通信(IPC)を実行したりできるようにします。 + +通常、バインドされたサービスは他のアプリケーション コンポーネントを提供している間だけ機能し、バックグラウンドで無期限に実行されることはありません。 +
+ +このドキュメントでは、他のアプリケーション コンポーネントからのサービスにバインドする方法を含む、バインドされたサービスの作成方法について説明します。 +ただし、サービスから通知を配信する方法や、フォアグラウンドでサービスを実行するよう設定する方法など、サービス全般の詳細については、「サービス」のドキュメントをご覧ください。 + +
+ + +基本
+ +バインドされたサービスは、他のアプリケーションのバインドとやり取りを可能にする {@link android.app.Service} クラスの実装です。 +サービスのバインドを提供するには、{@link android.app.Service#onBind onBind()} コールバック メソッドを実装する必要があります。 +このメソッドでは {@link android.os.IBinder} オブジェクトが返されます。このオブジェクトはクライアントがサービスとのやり取りに使用するプログラミング インターフェースを定義します。 + +
+ +開始されたサービスにバインドする
+ +サービス ドキュメントで説明されているように、開始されるサービスとバインドされるサービスの両方を作成できます。 +つまり、{@link android.content.Context#startService startService()} を呼び出して開始されるサービスは無期限に実行でき、クライアントが {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドできます。 + + +
サービスの開始とバインドを許可すると、サービスが開始するとすべてのクライアントがアンバインドしても、システムによってサービスが破棄されることはありません。 +代わりに、{@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} を呼び出して、サービスを明示的に停止する必要があります。 +
+ +通常実装するのは、{@link android.app.Service#onBind onBind()} + か {@link android.app.Service#onStartCommand onStartCommand()} のどちらかですが、両方の実装が必要な場合もあります。 +たとえば、音楽プレーヤーの場合はサービスを無期限に実行しつつ、バインドも提供できると便利な場合があります。 +この方法であれば、アクティビティがサービスを開始して音楽を再生し、ユーザーがアプリケーションから離れた場合も音楽を再生し続けることができます。 +次にユーザーがアプリケーションに戻ったとき、アクティビティがサービスにバインドして再生のコントロールをもう一度行えるようになります。 +
+ +開始されたサービスにバインドを追加する際のサービスのライフサイクルの詳細については、バインドされたサービスのライフサイクルを管理するを必ずご覧ください。 + +
+クライアントは、{@link android.content.Context#bindService +bindService()} を呼び出せばサービスにバインドできます。バインドするときは、サービスとの接続を監視する {@link +android.content.ServiceConnection} を実装する必要があります。{@link +android.content.Context#bindService bindService()} メソッドは値なしですぐに返されますが、Android システムがクライアントとサービス間の接続を作成すると {@link +android.content.ServiceConnection} の {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} が呼び出され、クライアントがサービスとの通信に使用できる {@link android.os.IBinder} が配信されます。 + + +
+ +複数のクライアントが同時にサービスに接続できます。ただし、1 つ目のクライアントのバインドの際にのみ、システムはサービスの {@link android.app.Service#onBind onBind()} メソッドを呼び出して{@link android.os.IBinder} を取得します。 + +その後システムは {@link android.app.Service#onBind onBind()} を呼び出すことなく、同じ {@link android.os.IBinder} をバインドしたすべてのクライアントに配信します。 +
+ +最後のクライアントがサービスからアンバインドされると、システムはサービスを破棄します(サービスが {@link android.content.Context#startService startService()} でも開始された場合を除く)。 +
+ +バインドされたサービスを実装するときに最も重要なのは、{@link android.app.Service#onBind onBind()} コールバック メソッドが返すインターフェースを定義することです。 +サービスの {@link android.os.IBinder} インターフェースの定義には複数の方法があり、次のセクションではそれぞれのテクニックについて説明していきます。 + +
+ + + +バインドされたサービスを作成する
+ +バインドを提供するサービスを作成するとき、クライアントがサービスとのやり取りに使用するプログラミング インターフェースを提供する {@link android.os.IBinder} を提示する必要があります。 +インターフェースを定義するには、次の 3 つの方法があります。 +
+ +-
+
- Binder クラスを拡張する +
- サービスが独自のアプリケーション専用であり、クライアントと同じプロセスで実行する場合(ほとんどのケースに該当)、{@link android.os.Binder} クラスを拡張して {@link android.app.Service#onBind onBind()} からそのインスタンスを返すことでインターフェースを作成します。
+
+
+クライアントは {@link android.os.Binder} を受け取り、それを使用して {@link android.os.Binder} の実装や {@link android.app.Service} で利用できる public メソッドに直接アクセスできます。
+
+
+
サービスが単にアプリケーションのバックグラウンド ワーカーである場合は、この方法が適しています。 +この方法が適していない唯一のケースは、サービスが他のアプリケーションや、別のプロセス間で使用されている場合です。 +
+
+ - メッセンジャーを使用する +
- 別のプロセス間で動作するインターフェースが必要な場合は、{@link android.os.Messenger} を使用してサービス用のインターフェースを作成できます。
+この方法では、サービスが異なるタイプの {@link
+android.os.Message} オブジェクトに応答する {@link android.os.Handler} を定義します。
+この {@link android.os.Handler} を基本として {@link android.os.Messenger} は {@link android.os.IBinder} をクライアントと共有でき、 クライアントは {@link
+android.os.Message} オブジェクトを使用してサービスにコマンドを送信できるようになります。
+
+さらに、クライアントはサービスがメッセージを返信できるように独自の {@link android.os.Messenger} を定義できます。
+
+
これは、最も簡単にプロセス間通信(IPC)を実行する方法であり、{@link +android.os.Messenger} がすべてのリクエストを 1 つのスレッドにキューイングするため、サービスをスレッドセーフにデザインする必要がありません。 +
+
+
+ - AIDL を使用する +
- AIDL(Android インターフェース定義言語)は、オブジェクトをオペーレーティングシステムが理解できるプリミティブに分解するためのすべての処理のを実行し、プロセス間でそれを整理して IPC 実行します。{@link android.os.Messenger} を使用する前の方法は、実際には AIDL を基本構造としています。
+
+
+前述したように、{@link android.os.Messenger} はすべてのクライアントの要求のキューを 1 つのスレッドに作成するため、サービスは要求を一度に受け取ります。
+ただし、サービスで複数の要求を同時に処理する場合は、AIDL を直接使用できます。
+
+その場合、サービスがマルチスレッドに対応しており、スレッドセーフで構築されている必要があります。
+
AIDL を直接使用するには、プログラミング インターフェースを定義する {@code .aidl} ファイルを作成する必要があります。 +Android SDK ツールはこのファイルを使用して、インターフェースを実装して IPC を処理する抽象クラスを生成し、それをサービス内に拡張できます。 + +
+
+
注: ほとんどのアプリケーションにおいて、マルチスレッド化が必要な点や、結果的により複雑な実装となってしまうことから、AIDL を使ったバインドされたサービスの作成はお勧めしません。 + +AIDL はほとんどのアプリケーションに適していないため、このドキュメントではサービスでの AIDL の使用方法については取り上げません。 +どうしても AIDL の直接使用が必要な場合は、「AIDL」のドキュメントをご覧ください。 + +
+ + + + +Binder クラスを拡張する
+ +サービスがローカルのアプリケーションでのみ使用されていて、プロセス間での作業が必要ない場合は、クライアントがサービスの public メソッドに直接アクセスできるようにする独自の {@link android.os.Binder} クラスを実装できます。 + +
+ +注: この方法は、クライアントとサービスが同じアプリケーションとプロセスにある場合(最も一般的なケース)のみ使用できます。 +たとえば、バックグラウンドで音楽を再生する独自のサービスに、アクティビティをバインドする必要のある音楽アプリケーションに適しています。 + +
+ +セットアップ方法は次のとおりです。
+-
+
- サービスで次のいずれかに該当する {@link android.os.Binder} のインスタンスを作成します。
+
-
+
- クライアントが呼び出せる public メソッドを含んでいる +
- クライアントが呼び出せる public メソッドのある現在の {@link android.app.Service} インスタンスを返す + +
- クライアントが呼び出せる public メソッドのあるサービスでホストされた他のクラスのインスタンスを返す + +
- {@link android.os.Binder} のインスタンスを {@link +android.app.Service#onBind onBind()} コールバック メソッドから返します。 +
- クライアントで、{@link android.os.Binder} を {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバック メソッドから受け取り、提供されたメソッドを使用してバインドされたサービスを呼び出します。 + +
注: サービスとクライアントが同じアプリケーションになければならない理由は、クライアントが返されたオブジェクトをキャストでき、その API を適切に呼び出せるようにするためです。 +また、サービスとクライアントが同じプロセスになければならない理由は、この方法ではプロセス間の整理が一切行われないためです。 + +
+ +以下は、{@link android.os.Binder} の実装を介してサービスのメソッドにクライアントアクセスを提供するサービスの例です。 +
+ ++public class LocalService extends Service { + // Binder given to clients + private final IBinder mBinder = new LocalBinder(); + // Random number generator + private final Random mGenerator = new Random(); + + /** + * Class used for the client Binder. Because we know this service always + * runs in the same process as its clients, we don't need to deal with IPC. + */ + public class LocalBinder extends Binder { + LocalService getService() { + // Return this instance of LocalService so clients can call public methods + return LocalService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + /** method for clients */ + public int getRandomNumber() { + return mGenerator.nextInt(100); + } +} ++ +
{@code LocalBinder} が {@code LocalService} の現在のインスタンスを取り出すための {@code getService()}メソッドをクライアントに提供します。 +これにより、クライアントがサービス内の public メソッドを呼び出せるようになります。 +たとえば、クライアントはサービスから {@code getRandomNumber()} を呼び出すことができます。
+ +以下は、{@code LocalService} にバインドして、ボタンがクリックされたときに {@code getRandomNumber()} を呼び出すアクティビティの例です。 +
+ ++public class BindingActivity extends Activity { + LocalService mService; + boolean mBound = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to LocalService + Intent intent = new Intent(this, LocalService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } + + /** Called when a button is clicked (the button in the layout file attaches to + * this method with the android:onClick attribute) */ + public void onButtonClick(View v) { + if (mBound) { + // Call a method from the LocalService. + // However, if this call were something that might hang, then this request should + // occur in a separate thread to avoid slowing down the activity performance. + int num = mService.getRandomNumber(); + Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); + } + } + + /** Defines callbacks for service binding, passed to bindService() */ + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mBound = false; + } + }; +} ++ +
上の例は、{@link android.content.ServiceConnection} の実装と {@link +android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバックを使用してクライアントがサービスにバインドする方法を示しています。 +次のセクションでは、サービスへのバインドのプロセスについて詳しく説明していきます。 +
+ +注: 上記の例ではサービスから明示的にアンバウンドしていませんが、すべてのクライアントは適切なタイミング(アクティビティが一時停止したときなど)でアンバウンドする必要があります。 +
+ +他のサンプル コードについては、ApiDemos の {@code +LocalService.java} クラスと {@code +LocalServiceActivities.java} クラスをご覧ください。
+ + + + + +メッセンジャーを使用する
+ +AIDL との比較
+IPC を実行する必要がある場合、インターフェースで {@link android.os.Messenger} を使う方が AIDL で実装するよりも簡単です。{@link android.os.Messenger} がすべての呼び出しをサービスにキューイングするのに対して、純粋な AIDL インターフェースでは同時に複数の要求をサービスに送るため、マルチスレッドの処理が必要になるためです。 + + +
+ほとんどのアプリケーションにおいて、サービスはマルチスレッドを実行する必要がないため、{@link +android.os.Messenger} を使用することでサービスが一度に 1 つの呼び出しを処理できます。サービスのマルチスレッド化が重視されている場合は、AIDL を使用してインターフェースを定義してください。 +
+リモート プロセスと通信するサービスが必要な場合は、{@link android.os.Messenger} を使用してサービスのインターフェースを提供できます。 +この方法では、AIDL を使用する必要なくプロセス間通信(IPC)を実行できます。 +
+ +{@link android.os.Messenger} の使用方法の概要は以下のとおりです。
+ +-
+
- クライアントからの呼び出しごとにコールバックを受け取る{@link android.os.Handler} をサービスが実装します。 + +
- {@link android.os.Handler} を使用して {@link android.os.Messenger} オブジェクトを作成します( +{@link android.os.Handler} への参照になります)。 +
- {@link android.os.Messenger} が、サービスが {@link android.app.Service#onBind onBind()} からクライアントに返す {@link android.os.IBinder} を作成します。 + +
- クライアントが {@link android.os.IBinder} を使用して、(サービスの {@link android.os.Handler} を参照する){@link android.os.Messenger} をインスタンス化し、これを使用してクライアントが {@link android.os.Message} オブジェクトをサービスに送ります。 + + +
- サービスが {@link +android.os.Handler}、具体的には、{@link android.os.Handler#handleMessage +handleMessage()} メソッドで、それぞれの {@link android.os.Message} を受け取ります。— +
この方法には、クライアントがサービスで呼び出す「メソッド」はありません。代わりに、クライアントはサービスが {@link android.os.Handler} で受け取る「メッセージ({@link android.os.Message} オブジェクト)」を配信します。 + +
+ +以下は、{@link android.os.Messenger} インターフェースを使用するサービスの簡単な例です。
+ ++public class MessengerService extends Service { + /** Command to the service to display a message */ + static final int MSG_SAY_HELLO = 1; + + /** + * Handler of incoming messages from clients. + */ + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SAY_HELLO: + Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Target we publish for clients to send messages to IncomingHandler. + */ + final Messenger mMessenger = new Messenger(new IncomingHandler()); + + /** + * When binding to the service, we return an interface to our messenger + * for sending messages to the service. + */ + @Override + public IBinder onBind(Intent intent) { + Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); + return mMessenger.getBinder(); + } +} ++ +
{@link android.os.Handler} の {@link android.os.Handler#handleMessage handleMessage()} メソッドが、サービスが {@link android.os.Message} を受け取る場所であり、{@link android.os.Message#what} メンバーに基づいてその後の操作を決める場面であることに注目してください。 + +
+ +クライアントで必要な操作は、サービスから返された {@link +android.os.IBinder} に基づいて {@link android.os.Messenger} を作成し、{@link +android.os.Messenger#send send()} を使用してメッセージを送信するだけです。例として、サービスにバインドして {@code MSG_SAY_HELLO} メッセージをサービスに送信する簡単なアクティビティを次に示します。 +
+ ++public class ActivityMessenger extends Activity { + /** Messenger for communicating with the service. */ + Messenger mService = null; + + /** Flag indicating whether we have called bind on the service. */ + boolean mBound; + + /** + * Class for interacting with the main interface of the service. + */ + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the object we can use to + // interact with the service. We are communicating with the + // service using a Messenger, so here we get a client-side + // representation of that from the raw IBinder object. + mService = new Messenger(service); + mBound = true; + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + mService = null; + mBound = false; + } + }; + + public void sayHello(View v) { + if (!mBound) return; + // Create and send a message to the service, using a supported 'what' value + Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); + try { + mService.send(msg); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } + + @Override + protected void onStart() { + super.onStart(); + // Bind to the service + bindService(new Intent(this, MessengerService.class), mConnection, + Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + // Unbind from the service + if (mBound) { + unbindService(mConnection); + mBound = false; + } + } +} ++ +
この例では、サービスがクライアントにどのように応答できるのかは示されていません。サービスが応答するようにするには、クライアントで {@link android.os.Messenger} も作成する必要があります。 +その後、クライアントが {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} コールバックを受け取るとき、{@link android.os.Messenger#send send()} メソッドの {@link android.os.Message#replyTo} パラメータにクライアントの{@link android.os.Messenger} を含めてサービスに {@link android.os.Message} を送信します。 + + +
+ +双方向メッセージを提供する方法のサンプルについては、{@code +MessengerService.java}(サービス)と {@code +MessengerServiceActivities.java}(クライアント)のサンプルをご覧ください。
+ + + + + +サービスにバインドする
+ +アプリケーションのコンポーネント(クライアント)は、{@link android.content.Context#bindService bindService()} を呼び出してサービスにバインドできます。 +次に Android システムがサービスの {@link android.app.Service#onBind +onBind()} メソッドを呼び出し、そこからサービスとのやり取りに必要な {@link android.os.IBinder} が返されます。 +
+ +バインドは非同期的に行われます。{@link android.content.Context#bindService +bindService()} は瞬時に返され、{@link android.os.IBinder} はクライアントには返されません。 +{@link android.os.IBinder} を受け取るには、クライアントが {@link +android.content.ServiceConnection} のインスタンスを作成し、それを {@link android.content.Context#bindService +bindService()} に渡す必要があります。{@link android.content.ServiceConnection} にはシステムが {@link android.os.IBinder} の配信用に呼び出すコールバック メソッドが含まれています。 +
+ +注: サービスにバインドできるのは、アクティビティ、サービス、コンテンツ プロバイダのみです。ブロードキャスト レシーバーからサードパーティビスにはバインドできません。 +—
+ +そのため、クライアントからサービスにバインドするには次の操作が必要です。
+-
+
- {@link android.content.ServiceConnection} を実装する。
+
実装では次の 2 つのコールバック メソッドをオーバーライドする必要があります。
+-
+
- {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} +
- システムがこれを呼び出して、サービスの {@link android.app.Service#onBind onBind()} メソッドから返された {@link android.os.IBinder} を配信します。 + +
- {@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()} +
- サービスがクラッシュしたり強制終了されたりした場合など、サービスへの接続が予期せず失われたときに、Android システムがこれを呼び出します。 +これは、クライアントのアンバウンドの際には呼び出されません。 + +
+ - {@link +android.content.Context#bindService bindService()} を呼び出して、{@link +android.content.ServiceConnection} の実装を渡します。 +
- システムが {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} コールバック メソッドを呼び出すと、インターフェースで定義されたメソッドを使用してサービスへの呼び出しを開始できます。 + +
- サービスとの接続を切断するには、{@link
+android.content.Context#unbindService unbindService()} を呼び出します。
+
クライアントが破棄されたときにはサービスからアンバウンドしますが、サービスが使用されていないときはシャットダウンできるよう、サービスとのやり取りが終了したときや、アクティビティが停止したときは常にアンバウンドする必要があります + +(バインドとアンバインドの適切なタイミングについては後半でさらに詳しく説明します)。 +
+
+
たとえば、次のスニペットは Binder クラスを拡張して先ほど作成したサービスにクライアントを接続しており、返された {@link android.os.IBinder} を {@code LocalService} クラスにキャストして、{@code +LocalService} インスタンスを要求することだけが必要になります。 + +
+ ++LocalService mService; +private ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + // Because we have bound to an explicit + // service that is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + mBound = true; + } + + // Called when the connection with the service disconnects unexpectedly + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "onServiceDisconnected"); + mBound = false; + } +}; ++ +
この {@link android.content.ServiceConnection} を使用して、クライアントは {@link android.content.Context#bindService bindService()} に渡すことでサービスにバインドできます。 +次に例を示します。
+ ++Intent intent = new Intent(this, LocalService.class); +bindService(intent, mConnection, Context.BIND_AUTO_CREATE); ++ +
-
+
- {@link android.content.Context#bindService bindService()} の最初のパラメータは、バインドするサービス名を明示的に指定する {@link android.content.Intent} です(インテントは暗黙的である場合があります)。 + + +
- 2 つ目のパラメータは {@link android.content.ServiceConnection} オブジェクトです。 +
- 3 つ目のパラメータはバインドのオプションを示すフラグです。通常は {@link +android.content.Context#BIND_AUTO_CREATE} でサービスがまだ存在していない場合にサービスを作成します。他の有効な値は、{@link android.content.Context#BIND_DEBUG_UNBIND} と {@link android.content.Context#BIND_NOT_FOREGROUND} か、未指定の {@code 0} です。 + + +
その他の注意点
+ +サービスへのバインドに関する重要な注意点は次のとおりです。
+-
+
- 接続が切れたときに投げられる {@link android.os.DeadObjectException} 例外は、常に処理する必要があります。 +リモート メソッドから投げられる例外はこれのみです。 +
- オブジェクトはプロセス間で有効な参照です。 +
- 通常は、クライアントのライフサイクルの立ち上がりと終了のタイミングに合わせて、その間でバインドとアンバインドをペア設定します。
+次に例を示します。
+
-
+
- アクティビティが見えている間のみサービスとやり取りする必要がある場合は、 +{@link android.app.Activity#onStart onStart()} の間にバインドし、{@link +android.app.Activity#onStop onStop()} の間にアンバインドします。 +
- アクティビティがバックグラウンドで停止している間も応答を受け取りたい場合は、{@link android.app.Activity#onCreate onCreate()} の間にバインドし、{@link android.app.Activity#onDestroy onDestroy()} の間にアンバインドします。 + +つまり、アクティビティの実行中は(バックグラウンドも含む)常にサービスを使用する必要があるため、サービスが別のプロセスにある場合は、プロセスの重みを上げて、システムに強制終了させやすいようにします。 + + + +
注: 通常、アクティビティの {@link android.app.Activity#onResume onResume()} と {@link +android.app.Activity#onPause onPause()} の間にはバインドとアンバインドは行いません。これは、これらのコールバックがライフサイクルの遷移すべてで発生するため、その遷移で発生するプロセスを最小限に抑える必要があるためです。 + +また、アプリケーションの複数のアクティビティが同一サービスにバインドしていて、そのなかの 2 つのアクティビティ間の遷移が生じる場合、現在のアクティビティは次のアクティビティがバインドする(再開中)前にアンバインドされる(停止中)ため、サービスが破棄されて再作成される場合があります + + +(ライフサイクルと連携したアクティビティの遷移の詳細については、「Activities」のドキュメントをご覧ください)。 + +
+
他のサンプル コードについては、 ApiDemos の {@code +RemoteService.java} クラスをご覧ください。
+ + + + + +バインドされたサービスのライフサイクルを管理する
+ +サービスがすべてのクライアントからアンバインドされると、Android システムがそれを破棄します({@link android.app.Service#onStartCommand onStartCommand()} でも開始された場合を除く)。 +純粋にバインドされたサービスであれば、サービスのライフサイクルを管理する必要はありません。サービスがクライアントにバインドされているかどうかに基づいて Android システムがそれを管理します。 + +—
+ +ただし、{@link android.app.Service#onStartCommand +onStartCommand()} コールバック メソッドを実装する場合は、サービスは 開始されたとみなされるため、明示的に停止する必要があります。 +この場合、クライアントにバインドされているかどうかにかかわらず、サービスが {@link android.app.Service#stopSelf()} で自ら停止するまで、または他のコンポーネントが {@link +android.content.Context#stopService stopService()} を呼び出すまで実行し続けます。 + +
+ +さらに、サービスが開始されてバインドを許可する場合、システムが {@link android.app.Service#onUnbind onUnbind()} メソッドを呼び出すとき、次回クライアントがサービスにバインドするときに {@link android.app.Service#onRebind +onRebind()} への呼び出しを受け取りたい場合は、{@code true} を返すようにすることもできます({@link +android.app.Service#onBind onBind()} への呼び出しを受け取る代わりに)。{@link android.app.Service#onRebind +onRebind()} からは void が返されますが、クライアントは {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} コールバックで {@link android.os.IBinder} を受け取ります。下の図 1 は、ライフサイクルのこの種の論理を表しています。 + + + +
+ + + + + + +開始されたサービスのライフサイクルの詳細については、「サービス」のドキュメントをご覧ください。
+ + + + diff --git a/docs/html-intl/intl/ja/guide/components/fragments.jd b/docs/html-intl/intl/ja/guide/components/fragments.jd new file mode 100644 index 0000000000000000000000000000000000000000..31fb7f5020b22bdf40a70f8a8ec871c5ccebe218 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/fragments.jd @@ -0,0 +1,812 @@ +page.title=フラグメント +parent.title=アクティビティ +parent.link=activities.html +@jd:body + +本書の内容
+-
+
- デザインの指針 +
- フラグメントを作成する + + +
- フラグメントを管理する +
- フラグメントのトランザクションを実行する +
- アクティビティと通信する + + +
- フラグメントのライフサイクルを処理する + + +
- 例 +
キークラス
+-
+
- {@link android.app.Fragment} +
- {@link android.app.FragmentManager} +
- {@link android.app.FragmentTransaction} +
関連ドキュメント
+ +{@link android.app.Fragment} は、{@link android.app.Activity} でのユーザー インターフェースの挙動や部位を表すものです。 +1 つのアクティビティに複数のフラグメントを組み合わせてマルチペインの UI をビルドしたり、複数のアクティビティでフラグメントを再利用したりできます。 +フラグメントとは、アクティビティのモジュール型セクションのようなもので、独自のライフサイクルを持ち、独自の入力イベントを受信します。フラグメントはアクティビティの実行中に追加したり削除したりできます(別のアクティビティで再利用できる「サブ アクティビティ」のようなものです)。 + + +
+ +フラグメントは常にアクティビティに埋め込まれている必要があり、フラグメントのライフサイクルはホストのアクティビティのライフサイクルの影響を直接受けます。 +たとえば、アクティビティが一時停止しているとき、その中のすべてのフラグメントも一時停止し、アクティビティが破棄されると、すべてのフラグメントも破棄されます。 +ただし、アクティビティの実行中(ライフサイクルで再開された状態)は、追加や削除といった操作は各フラグメントだけで行うことができます。 + +このようなフラグメントのトランザクションを実行するとき、アクティビティで管理されているバックスタックにそれを追加することもできます。アクティビティの各バックスタック エントリは、発生したフラグメントのトランザクションの記録になります。 + +— +バックスタックでは、[戻る] ボタンを押すとフラグメントのトランザクションを戻す(前に戻る)ことができます。 +
+ +アクティビティのレイアウトの一部としてフラグメントを追加すると、フラグメントはアクティビティのビュー階層の {@link +android.view.ViewGroup} に置かれ、フラグメントが自身のビュー レイアウトを定義します。フラグメントをアクティビティのレイアウトに挿入するには、アクティビティのレイアウト ファイルでフラグメントを {@code <fragment>} として定義するか、アプリケーション コードで既存の {@link android.view.ViewGroup} に追加します。 + + + +ただし、フラグメントは必ずしもアクティビティの一部になる必要はなく、アクティビティの目に見えないワーカーとして、フラグメント独自の UI なしで使用することもできます。 + +
+ +このドキュメントでは、アクティビティのバックスタックに追加した時のフラグメントの状態を維持する方法、アクティビティ内でアクティビティと他のフラグメントとイベントを共有する方法、アクティビティのアクションバーへの影響など、フラグメントを使用してアプリケーションをビルドする方法について説明します。 + + +
+ + +デザインの指針
+ +Android では、タブレットなどの大画面でのよりダイナミックで柔軟な UI デザインに対応するため、Android 3.0(API レベル 11)でフラグメントが採用されました。 +タブレットの画面はハンドセットよりもかなり大きいため、UI コンポーネントを組み合わせたり入れ替えたりできる領域が広くなります。 + +フラグメントでは、ビュー階層に複雑な変更を加えることなく、そのようなデザインを実現できます。 +アクティビティのレイアウトをフラグメントに分割することで、アクティビティの外観を実行時に変更でき、それらの変更をアクティビティが管理するバックスタックに保持できます。 + +
+ +たとえば新しいアプリケーションでは、1 つのフラグメントを使って左側に記事の一覧を表示したり、別のフラグメントを使って右側に記事の内容を表示したりできます。両方のフラグメントが 1 つのアクティビティに横並びに表示され、それぞれのフラグメントには自身のライフサイクル メソッドがあり、それぞれのユーザー入力イベントを処理します。 +— + +つまり、1 つのアクティビティで記事を選択して、別のアクティビティで記事を閲覧するのではなく、図 1 のタブレットのレイアウトのように 1 つのアクティビティ内で記事を選択して閲覧できるようになります。 + +
+ +各フラグメントはモジュール型の、再利用可能なアクティビティ コンポーネントとしてデザインする必要があります。各フラグメントは独自のライフサイクル コールバックを使用して自身のレイアウトと挙動とを定義するため、1 つのフラグメントを複数のアクティビティに含めることができます。このことから、再利用可能なデザインを用いることに加えて、1 つのフラグメントを他のフラグメントから直接操作しないようにする必要があります。 + + +これは、モジュール型のフラグメントでは画面のサイズごとにフラグメントの組み合わせを変更できる点からも、特に重要です。 +タブレットとハンドセットの両方に対応したアプリケーションをデザインする場合、異なるレイアウト構成でフラグメントを再利用することで、利用可能な画面の領域に応じて最適な使い心地を実現できます。 + +たとえばハンドセットの場合、同一のアクティビティ内に 2 つ以上のフラグメントが収まりきらないときは、フラグメントを分割してシングルペインの UI を提示する必要があることもあります。 + +
+ + + + +引き続きニュース アプリケーションの例を使うと、アプリケーションがタブレット サイズの端末で実行中は、 2 つのフラグメントをアクティビティ A に埋め込むことができます。—— +しかし、ハンドセット サイズの画面では両方のフラグメントを表示する領域が足りないため、アクティビティ A には記事の一覧のフラグメントだけが含まれます。記事を選択すると、記事を閲覧するための 2 つ目のフラグメントが含まれるアクティビティ B が開始されます。 + + +そのため、図 1 のようにアプリケーションはフラグメントを異なる組み合わせで再利用することで、タブレットとハンドセットの両方に対応できるようになります。 + +
+ +異なる画面構成ごとに異なるフラグメントの組み合わせを用いたアプリケーションのデザインの詳細については、「Supporting Tablets and Handsets」のガイドをご覧ください。 +
+ + + +フラグメントを作成する
+ +フラグメントを作成するには、{@link android.app.Fragment} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +{@link android.app.Fragment} クラスには、{@link android.app.Activity} に非常に似ているコードがあります。 +これには、{@link android.app.Fragment#onCreate onCreate()}、{@link android.app.Fragment#onStart onStart()}、{@link android.app.Fragment#onPause onPause()}、{@link android.app.Fragment#onStop onStop()} のようなアクティビティと同様のコールバック メソッドが含まれています。 + +実際に、既存の Android アプリケーションを変換してフラグメントを使用するには、アクティビティのコールバック メソッドから、フラグメントの各コールバック メソッドにコードを移動させるだけで。 + + +
+ +通常は、少なくとも次のライフサイクル メソッドを実装する必要があります。
+ +-
+
- {@link android.app.Fragment#onCreate onCreate()} +
- フラグメントの作成時にシステムが呼び出します。実装内で、フラグメントが一時停止、停止、再開されたときに保持するフラグメントの必須コンポーネントを初期化する必要があります。 + + +
- {@link android.app.Fragment#onCreateView onCreateView()} +
- フラグメントが初めてユーザー インターフェースを描画するタイミングでシステムがこれを呼び出します。 +フラグメントの UI を描画するには、このメソッドからフラグメントのレイアウトのルートとなっている {@link android.view.View} を返す必要があります。 +フラグメントが UI を提示しない場合は、null を返すことができます。 + +
- {@link android.app.Activity#onPause onPause()} +
- ユーザーがフラグメントから離れたことを初めて示すときに、このメソッドを呼び出します(フラグメントが破棄されていない場合も含む)。 +通常はここで、現在のユーザー セッション後も維持する必要のある変更点を保存しておきます(ユーザーが戻ってこない可能性があるため)。 + + +
ほとんどのアプリケーションでは、各フラグメントで少なくともこれら 3 つのメソッドを実装する必要がありますが、フラグメントのライフサイクルのさまざまなステージを処理する際に使用する他のコールバック メソッドもいくつかあります。 + +すべてのライフサイクル コールバック メソッドについては、フラグメントのライフサイクルの処理のセクションで説明します。 +
+ + +基本の {@link +android.app.Fragment} クラスの代わりに拡張できるサブクラスもいくつかあります。
+ +-
+
- {@link android.app.DialogFragment} +
- フローティング ダイアログを表示します。{@link android.app.Activity} のダイアログ ヘルパー メソッド代わりにこのクラスを使用してダイアログを作成すると、アクティビティで管理されるフラグメントのバックスタックにフラグメント ダイアログを組み込むことができるため、ユーザーは終了したフラグメントに戻ることが可能になります。 + + + + +
- {@link android.app.ListFragment} +
- {@link android.app.ListActivity} と同様に、アダプタで管理されるアイテムのリストを表示します({@link +android.widget.SimpleCursorAdapter} など)。クリック イベントを処理するための {@link +android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} コールバックなど、リスト ビューを管理するメソッドがいくつか提供されます。 + + + +
- {@link android.preference.PreferenceFragment} +
- {@link android.preference.PreferenceActivity} と同様に、{@link android.preference.Preference} オブジェクトの階層をリストとして表示します。 +アプリケーションの「設定」アクティビティの作成時に便利です。 + +
ユーザー インターフェースを追加する
+ +通常、フラグメントはアクティビティのユーザー インターフェースの一部であり、独自のレイアウトをアクティビティに提示します。 +
+ +フラグメントのレイアウトを提供するには、{@link +android.app.Fragment#onCreateView onCreateView()} コールバック メソッドを実装する必要があります。これは、フラグメントがレイアウトを描画するタイミングで Android システムが呼び出します。 +このメソッドの実装では、フラグメントのレイアウトのルートである {@link android.view.View} を返す必要があります。 +
+ +注: フラグメントは {@link +android.app.ListFragment} のサブクラスの場合、デフォルトの実装で {@link android.widget.ListView} が{@link android.app.Fragment#onCreateView onCreateView()} から返されるため、これを実装する必要はありません。 +
+ +{@link +android.app.Fragment#onCreateView onCreateView()} からレイアウトを返すには、XML で定義したレイアウト リソースからインフレートできます。これを行うため、{@link android.app.Fragment#onCreateView onCreateView()} から {@link android.view.LayoutInflater} オブジェクトが提供されます。 + +
+ +たとえば、次の例では {@link android.app.Fragment} のサブクラスが {@code example_fragment.xml} ファイルからレイアウトをロードします。 +
+ ++public static class ExampleFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.example_fragment, container, false); + } +} ++ +
レイアウトを作成する
+上の例では、{@code R.layout.example_fragment} はアプリケーション リソースに保存されている {@code example_fragment.xml} という名前のレイアウト リソースへの参照です。 +XML でレイアウトを作成する方法の詳細いついては、「ユーザー インターフェース」のドキュメントをご覧ください。 + +
+{@link android.app.Fragment#onCreateView +onCreateView()} に渡される {@code container} パラメータは、フラグメントのレイアウトが挿入される {@link android.view.ViewGroup} の親になります(アクティビティのレイアウトから)。 + +{@code savedInstanceState} パラメータは、フラグメントが再開された場合にフラグメントの前のインスタンスに関する情報を提供する {@link android.os.Bundle} です(状態の復元の詳細については、フラグメントのライフサイクルの処理で説明します)。 + + +
+ +{@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} メソッドは、次の 3 つの引数を受け取ります。 +
+-
+
- 拡張するレイアウトのリソース ID。 +
- インフレートされたレイアウトの親となる {@link android.view.ViewGroup}。システムがインフレートされたレイアウトのルートビュー(親ビューが指定)にレイアウト パラメータ適用するには、{@code +container} を渡すことが重要です。 + +
- インフレート中に、インフレートされたレイアウトを {@link +android.view.ViewGroup}(2 つ目のパラメータ)にアタッチすべきかどうかを示すブール値(この場合、システムが既にインフレートされたレイアウトを {@code +container} に挿入しているため、false になります。true を渡すと、最終レイアウトに余分なビューグループが作成されます。 +— +
ここまで、レイアウトを提供するフラグメントの作成方法について説明しました。次は、フラグメントをアクティビティに追加する必要があります。 +
+ + + +フラグメントをアクティビティに追加する
+ +通常、フラグメントはホスト アクティビティに UI の一部を提供し、アクティビティの全体的なビュー階層の一部として埋め込まれます。 +アクティビティのレイアウトにフラグメントを追加する方法は 2 つあります。 +
+ +-
+
- アクティビティのレイアウト ファイル内でフラグメントを宣言する
+
この場合、フラグメントがビューであるかのようにレイアウト プロパティを指定できます。 +以下は、2 つのフラグメントを持つアクティビティのレイアウト ファイルです。 +
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <fragment android:name="com.example.news.ArticleListFragment" + android:id="@+id/list" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="match_parent" /> + <fragment android:name="com.example.news.ArticleReaderFragment" + android:id="@+id/viewer" + android:layout_weight="2" + android:layout_width="0dp" + android:layout_height="match_parent" /> +</LinearLayout> +
+{@code <fragment>} の {@code android:name} 属性は、{@link +android.app.Fragment} クラスを指定してレイアウトにインスタンスを作成します。
+ +システムがこのアクティビティ レイアウトを作成するとき、レイアウトで指定された各フラグメントのインスタンスを作成し、それぞれの {@link android.app.Fragment#onCreateView onCreateView()} メソッドを呼び出して、各フラグメントのレイアウトを取得します。 + +システムがフラグメントから返された{@link android.view.View} を {@code <fragment>} 要素の代わりに挿入します。 +
+ +++注: 各フラグメントには、アクティビティの再開時にフラグメントを復元するためにシステムが使用できる(そしてフラグメントをキャプチャして削除などのトランザクションを実行する際に使用できる)一意の識別子が必要です + +フラグメントの ID を提供するには、次の 3 つの方法があります。 +
+-
+
- {@code android:id} 属性に一意の ID を提供する。 +
- {@code android:tag} 属性に一意の文字列を提供する。 +
- 上記のいずれも提供しない場合、システムはコンテナビューの ID を使用します。 + +
+
+ - または、既存の {@link android.view.ViewGroup} にプログラムを使用してフラグメントを追加します。
+
アクティビティの実行中は、いつでもフラグメントをアクティビティ レイアウトに追加できます。必要なのは、フラグメントを配置する場所に {@link +android.view.ViewGroup} を指定するだけです。 +
+アクティビティ内にフラグメントのトランザクション(フラグメントの追加、削除、置換など)を作るには、{@link android.app.FragmentTransaction} からの API を使用する必要があります。 +{@link android.app.FragmentTransaction} のインスタンスは、{@link android.app.Activity} から次のようにして取得できます。 +
+ ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()} +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; +
+ +次に、{@link +android.app.FragmentTransaction#add(int,Fragment) add()} メソッドを使用して、追加するフラグメントと挿入するビューを指定してフラグメントを追加できます。 +次に例を示します。
+ ++ExampleFragment fragment = new ExampleFragment(); +fragmentTransaction.add(R.id.fragment_container, fragment); +fragmentTransaction.commit(); +
+ +{@link android.app.FragmentTransaction#add(int,Fragment) add()} に渡される最初の引数はフラグメントを配置する {@link android.view.ViewGroup} でリソース ID で指定されており、2 つ目のパラメータは追加するフラグメントです。 + +
+{@link android.app.FragmentTransaction} で変更を加えたら、{@link android.app.FragmentTransaction#commit} を呼び出して変更を適用する必要があります。 + +
+
+
UI のないフラグメントを追加する
+ +上の例では、UI を提供するためにフラグメントをアクティビティに追加する方法を紹介しましたが、UI を提示せずにアクティビティのバックグラウンド動作を提供するためにフラグメントを使うこともできます。 + +
+ +UI のないフラグメントを追加するには、{@link +android.app.FragmentTransaction#add(Fragment,String)} を使用してアクティビティからフラグメントを追加します(ビュー ID ではなくフラグメントの一意の文字列である「タグ」を提供します)。 +これでフラグメントが追加されますが、アクティビティ レイアウトのビューには関連付けられていないため、{@link +android.app.Fragment#onCreateView onCreateView()} への呼び出しは受け取りません。 +そのため、このメソッドを実装する必要はありません。
+ +フラグメントに文字列のタグを提供するのは UI のないフラグメントの場合だけではありません。UI のあるフラグメントにも文字列のタグを提供することはできますが、UI のないフラグメントにとっては、文字列のタグがフラグメントを識別する唯一の手段になります。— +— +後でアクティビティからフラグメントを取得する場合は、 {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()} を使用する必要があります。 +
+ +たとえば、フラグメントを UI を持たないバックグラウンド ワーカーとして使用するアクティビティの場合は、SDK サンプルに含まれている(Android SDK マネージャーで利用可能){@code
+FragmentRetainInstance.java} のサンプルでシステムに <sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java
として置かれているものをご覧ください。
+
+
フラグメントを管理する
+ +アクティビティのフラグメントを管理するには、{@link android.app.FragmentManager} を使用する必要があります。フラグメントを取得するには、アクティビティから {@link android.app.Activity#getFragmentManager()} を呼び出します。 +
+ +{@link android.app.FragmentManager} では、次の操作が可能です。
+ +-
+
- {@link +android.app.FragmentManager#findFragmentById findFragmentById()}(アクティビティ レイアウトで UI を提供するフラグメントの場合)や {@link android.app.FragmentManager#findFragmentByTag +findFragmentByTag()}(UI を提供しないフラグメントの場合)を使用して、アクティビティにあるフラグメントを取得する。 + +
- {@link +android.app.FragmentManager#popBackStack()} を使用してフラグメントをバックスタックから取り出す(ユーザーによる [戻る] コマンドをシミュレートする)。 +
- {@link +android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()} を使用して、バックスタックの変更に対するリスナを登録する。 +
これらのメソッドや他のメソッドの詳細については、{@link +android.app.FragmentManager} クラスのドキュメントをご覧ください。
+ +前のセクションで説明したように、{@link android.app.FragmentManager} を使用して {@link android.app.FragmentTransaction} を開くことで、フラグメントの追加や削除といったトランザクションを実行することもできます。 + +
+ + +フラグメントのトランザクションを実行する
+ +アクティビティでのフラグメントの使用における優れた機能として、フラグメントを追加、削除、置換したり、ユーザー操作への応答にフラグメントを使用して他のアクションを実行したりできる点が挙げられます。 +アクティビティに加える変更はそれぞれ 1 つのトランザクションとして、{@link +android.app.FragmentTransaction} の API を使用して実行できます。 +各トランザクションはアクティビティが管理するバックスタックに保存でき、ユーザーはフラグメントの変更を元に戻すことができます(アクティビティ間で元に戻す動作と似ています)。 + +
+ +{@link android.app.FragmentTransaction} のインスタンスは、次のように {@link +android.app.FragmentManager} から作成できます。
+ ++FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()}; +FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()}; ++ +
各トランザクションは、同時に実行する一連の変更点です。{@link +android.app.FragmentTransaction#add add()}、{@link android.app.FragmentTransaction#remove remove()}、{@link android.app.FragmentTransaction#replace replace()} などのメソッドを使って、トランザクションで実行するすべての変更点をセットアップできます。 + +次に、トランザクションをアクティビティに適用するには、{@link android.app.FragmentTransaction#commit()} を呼び出す必要があります。 +
+ + +ただし、{@link +android.app.FragmentTransaction#commit()} を呼び出す前に、{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出して、フラグメントのトランザクションのバックスタックにトランザクションを追加することもできます。 +このバックスタックはアクティビティによって管理され、ユーザーが [戻る] ボタンを押して前のフラグメントの状態に戻れるようにします。 +
+ +例として、フラグメントを別のフラグメントに置き換えて、バックスタックで前の状態を保持する方法を次に示します。 +
+ ++// Create new fragment and transaction +Fragment newFragment = new ExampleFragment(); +FragmentTransaction transaction = getFragmentManager().beginTransaction(); + +// Replace whatever is in the fragment_container view with this fragment, +// and add the transaction to the back stack +transaction.replace(R.id.fragment_container, newFragment); +transaction.addToBackStack(null); + +// Commit the transaction +transaction.commit(); ++ +
この例では、{@code R.id.fragment_container} ID で識別されるレイアウト コンテナに現在あるフラグメント(存在する場合)を {@code newFragment} が置き換えます。{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出すと、置き換えのトランザクションがバックスタックに保存されるため、ユーザーはトランザクションを元に戻して、[戻る] ボタンを押すことで前のフラグメントに戻れるようになります。 + + +
+ +トランザクションに複数の変更を加えて({@link +android.app.FragmentTransaction#add add()} や {@link android.app.FragmentTransaction#remove +remove()} など)、{@link +android.app.FragmentTransaction#addToBackStack addToBackStack()} を呼び出した場合、{@link android.app.FragmentTransaction#commit commit()} を呼び出す前に適用されたすべての変更点が 1 つのトランザクションとしてバックスタックに追加され、[戻る] ボタンを押すとすべてが同時に元に戻るようになります。 + +
+ +次の場合を除き、{@link android.app.FragmentTransaction} に加える変更の順序は影響しません。 +
+-
+
- {@link android.app.FragmentTransaction#commit()} は最後に呼び出す必要があります。 +
- 複数のフラグメントを同じコンテナに追加する場合、追加する順序がビュー階層に表示される順序になります。 + +
フラグメントを削除するトランザクションの実行時に {@link android.app.FragmentTransaction#addToBackStack(String) +addToBackStack()} を呼び出さない場合、トランザクションの実行時にそのフラグメントは破棄され、ユーザーは操作を元に戻すことができなくなります。 +一方で、フラグメントの削除時に {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} を呼び出した場合、フラグメントは停止状態になり、ユーザーが元に戻した時に再開します。 + + +
+ +ヒント: それぞれのフラグメントのトランザクションでは、コミットする前に {@link android.app.FragmentTransaction#setTransition setTransition()} と呼ばれる遷移のアニメーションを適用できます。 + +
+ +{@link android.app.FragmentTransaction#commit()} を呼び出してもトランザクションはすぐには実行されません。 +具体的には、アクティビティの UI スレッド(「メイン」スレッド)で実行可能になったときにすぐに実行されるようスケジュールされます。 +ただし、必要であれば UI スレッドから {@link +android.app.FragmentManager#executePendingTransactions()} を呼び出して、{@link android.app.FragmentTransaction#commit()} から送信されたトランザクションをすぐに実行することもできます。 +通常、トランザクションが他のスレッドのジョブに依存していない限り、この操作は必要ありません。 +
+ +警告: {@link +android.app.FragmentTransaction#commit commit()} を使用したトランザクションをコミットできるのは、アクティビティが状態を保存する前(ユーザーがアクティビティを離れるとき)にのみに限定されます。 +それ以降にコミットしようとすると、例外がスローされます。 +これは、アクティビティの復元が必要な場合に、コミット後のステータスが失われてしまう可能性があるためです。 +コミットが失われてもよい場合は、{@link +android.app.FragmentTransaction#commitAllowingStateLoss()} を使用します。
+ + + + +アクティビティと通信する
+ +{@link android.app.Fragment} が {@link android.app.Activity} から独立したフラグメントとして実行されていて、複数のアクティビティ内で使用可能であっても、フラグメントの特定のインスタンスは、それが含まれるアクティビティに直接結び付いています。 + +
+ +具体的には、フラグメントは {@link +android.app.Fragment#getActivity()} を使用して {@link android.app.Activity} インスタンスにアクセスでき、アクティビティのレイアウトでビューを見つけるなどのタスクを簡単に実行できます。 +
+ ++View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list); ++ +
同様に、アクティビティが {@link +android.app.FragmentManager#findFragmentById findFragmentById()} や {@link +android.app.FragmentManager#findFragmentByTag findFragmentByTag()} を使って {@link android.app.FragmentManager} から {@link android.app.Fragment} への参照を取得することで、フラグメント内のメソッドを呼び出すこともできます。 +次に例を示します。
+ ++ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment); ++ + +
アクティビティへのイベント コールバックを作成する
+ +アクティビティとイベントを共有するフラグメントが必要になる場面もあります。これを実現するには、フラグメント内でコールバック インターフェースを定義して、ホスト アクティビティがそれを実装するよう要求します。 + +アクティビティがインターフェースを介してコールバックを受け取ると、必要に応じてレイアウト内の他のフラグメントと情報を共有します。 +
+ +たとえば、新しいアプリケーションでアクティビティ内に、記事のリストを表示するフラグメント(フラグメント A)と、記事を表示するフラグメント(フラグメント B)の 2 つのフラグメントがある場合、リストのアイテムが選択されたときに、フラグメント B に記事を表示するよう伝えるため、フラグメント A から選択されたことをアクティビティに伝える必要があります。— +— +ここでは、{@code OnArticleSelectedListener} インターフェースがフラグメント A で宣言されています。 +
+ ++public static class FragmentA extends ListFragment { + ... + // Container Activity must implement this interface + public interface OnArticleSelectedListener { + public void onArticleSelected(Uri articleUri); + } + ... +} ++ +
次に、フラグメントのホストであるアクティビティが {@code OnArticleSelectedListener} インターフェースを実装して {@code onArticleSelected()} をオーバーライドし、フラグメント B にフラグメント A からのイベントを通知します。ホスト アクティビティがこのインターフェースを確実に実装するようにするため、フラグメント A の {@link +android.app.Fragment#onAttach onAttach()} コールバック メソッド(フラグメントをアクティビティに追加するときにシステムが呼び出すメソッド)が、{@link android.app.Fragment#onAttach +onAttach()} に渡される {@link android.app.Activity} をキャストして {@code OnArticleSelectedListener} のインスタンスを登録します。 + + + + +
+ ++public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnArticleSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); + } + } + ... +} ++ +
アクティビティがインターフェースを実装していない場合は、フラグメントは {@link java.lang.ClassCastException} をスローします。成功すると、{@code mListener} メンバーがアクティビティの {@code OnArticleSelectedListener} の実装への参照を保持でき、フラグメント A が {@code OnArticleSelectedListener} インターフェースで定義されたコールバック メソッドを呼び出すことでアクティビティとイベントを共有できるようになります。 + + + +たとえば、フラグメント A は {@link android.app.ListFragment} の拡張で、ユーザーがリストアイテムをクリックするたびに、システムがフラグメントの {@link android.app.ListFragment#onListItemClick +onListItemClick()} を呼び出し、それが{@code onArticleSelected()} を呼び出してアクティビティとイベントを共有します。 + + +
+ ++public static class FragmentA extends ListFragment { + OnArticleSelectedListener mListener; + ... + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + // Append the clicked item's row ID with the content provider Uri + Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id); + // Send the event and Uri to the host activity + mListener.onArticleSelected(noteUri); + } + ... +} ++ +
{@link +android.app.ListFragment#onListItemClick onListItemClick()} に渡される {@code id} パラメータはクリックされたアイテムの行 ID で、アクティビティ(または他のフラグメント)がアプリケーションの {@link +android.content.ContentProvider} から記事を取得する際に使用します。 +
+ +コンテンツ プロバイダの使用に関する詳細については、「コンテンツ プロバイダ」のドキュメントをご覧ください。 +
+ + + +アクションバーにアイテムを追加する
+ +フラグメントは、{@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()} を実装することでアクティビティのオプション メニュー(とそのアクション バー)にメニュー アイテムを提供することができます。 +ただし、このメソッドが呼び出しを受け取るには、{@link +android.app.Fragment#onCreate(Bundle) onCreate()} の間に {@link +android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} を呼び出して、フラグメントがオプション メニューにアイテムを追加することを示す必要があります(これを行わない場合、フラグメントは {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} への呼び出しを受け取りません)。 + + +
+ +フラグメントから追加するアイテムはすべて、既存のメニュー アイテムに追加されます。 +また、メニュー アイテムが選択されたとき、フラグメントは {@link +android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} へのコールバックも受け取ります。 +
+ +また、{@link +android.app.Fragment#registerForContextMenu(View) registerForContextMenu()} を呼び出して、フラグメントのレイアウトにビューを登録してコンテキスト メニューを提供することもできます。ユーザーがコンテキスト メニューを開くと、フラグメントは {@link +android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) +onCreateContextMenu()} への呼び出しを受け取ります。 +ユーザーがアイテムを選択すると、フラグメントは {@link +android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()} への呼び出しを受け取ります。
+ +注: 追加するメニュー アイテムごとにフラグメントは on-item-selected コールバックを受け取りますが、ユーザーがメニュー アイテムを選択したときに最初にそれぞれのコールバックを受け取るのはアクティビティになります。 + +アクティビティの on-item-selected コールバックの実装で、選択されたアイテムが処理されなかった場合、イベントはフラグメントのコールバックに渡されます。 +この挙動は、オプション メニューとコンテキスト メニューの両方に適用されます。 +
+ +メニューの詳細については、デベロッパー ガイドの「メニュー」と「アクションバー」をご覧ください。
+ + + + +フラグメントのライフサイクルを処理する
+ +フラグメントのライフサイクルの管理は、アクティビティのライフサイクルの管理によく似ています。アクティビティと同様に、フラグメントには次の 3 つの状態があります。 +
+ +-
+
- 再開状態 +
- フラグメントが実行中のアクティビティで表示されている。 + +
- 一時停止状態 +
- 他のアクティビティがフォアグラウンドにあり、フォーカスがあるが、このアクティビティも表示されている(フォアグラウンドにある別のアクティビティは半透明になっているか、全画面をカバーしていない)。 + + + +
- 停止状態 +
- フラグメントは表示されていない。ホスト アクティビティが停止状態か、フラグメントがアクティビティから削除されたが、バックスタックに追加されている。 +停止状態のフラグメントはまだ存続しています(すべての状態とメンバー情報がシステムで保持されています)。 +ただし、アクティビティが破棄されるとユーザーには表示されなくなり、フラグメントも破棄されます。 + +
さらに、アクティビティと同様に、アクティビティのプロセスが破棄されて、アクティビティが再作成されたときにフラグメントの状態を復元する必要がある場合は、 {@link +android.os.Bundle} を使用してフラグメントの状態を保持できます。 +フラグメントの {@link +android.app.Fragment#onSaveInstanceState onSaveInstanceState()} コールバックの間に状態を保存して、{@link android.app.Fragment#onCreate onCreate()}、{@link +android.app.Fragment#onCreateView onCreateView()}、{@link +android.app.Fragment#onActivityCreated onActivityCreated()} の間にそれを復元できます。 +状態の保存の詳細については、「Activities」のドキュメントをご覧ください。 + +
+ +アクティビティとフラグメントのライフサイクルの最も重要な違いは、バックスタックでのそれぞれの保存方法です。 +アクティビティは、デフォルトで停止状態の時にシステムが管理するアクティビティのバックスタックに置かれますが(タスクとバックスタック で説明したようにユーザーが [戻る] ボタンで前に戻ることができるように)、フラグメントの場合は、フラグメントを削除するトランザクションの間に {@link +android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} を呼び出してインスタンスを保存するよう明示的に要求した場合のみ、ホスト アクティビティが管理するバックスタックに置かれます。 + + + + +
+ +これ以外については、フラグメントのライフサイクルの管理は、アクティビティのライフサイクルの管理とほとんど同じです。 +そのため、アクティビティのライフサイクルの管理におけるベスト プラクティスがフラグメントにも適用されます。 +もう 1 つ理解しておくべき事項は、アクティビティの寿命がどのようにフラグメントの寿命に影響を与えるかという点です。 +
+ +警告: {@link android.app.Fragment} 内に {@link android.content.Context} オブジェクトが必要な場合は、{@link android.app.Fragment#getActivity()} を呼び出すことができます。ただし、{@link android.app.Fragment#getActivity()} はフラグメントがアクティビティにアタッチされている場合にのみ呼び出すようにしてください。 + + +フラグメントがまだアタッチされていない場合や、ライフサイクルの終了時にデタッチされた場合は、{@link android.app.Fragment#getActivity()} は null を返します。 +
+ + +アクティビティのライフサイクルと連携する
+ +フラグメントが含まれるアクティビティのライフサイクルは、フラグメントのライフサイクルに直接影響し、アクティビティに対する各ライフサイクル コールバックは、各フラグメントに対して同様のコールバックをもたらします。 + +たとえば、アクティビティが {@link android.app.Activity#onPause} を受け取ると、アクティビティ内の各フラグメントが {@link android.app.Fragment#onPause} を受け取ります。 +
+ +ただし、フラグメントにはフラグメントの UI をビルドしたり破棄したりするアクションを実行する際のアクティビティとの独自のやり取りを処理する追加のライフサイクル コールバックがいくつかあります。これらの追加のコールバック メソッドは次のとおりです。 + +
+ +-
+
- {@link android.app.Fragment#onAttach onAttach()} +
- フラグメントがアクティビティと関連付けられたときに呼び出されます(ここで {@link +android.app.Activity} が渡されます)。 +
- {@link android.app.Fragment#onCreateView onCreateView()} +
- フラグメントに関連付けられたビュー階層を作成する際に呼び出されます。 +
- {@link android.app.Fragment#onActivityCreated onActivityCreated()} +
- アクティビティの {@link android.app.Activity#onCreate +onCreate()} メソッドが戻ったときに呼び出されます。 +
- {@link android.app.Fragment#onDestroyView onDestroyView()} +
- フラグメントに関連付けられたビュー階層が削除されたときに呼び出されます。 +
- {@link android.app.Fragment#onDetach onDetach()} +
- フラグメントとアクティビティとの関連付けが解除されたときに呼び出されます。 +
図 3 は、ホスト アクティビティの影響を受けたフラグメントのライフサイクルのフローを表しています。 +この図から、アクティビティの一連の状態によって、フラグメントが受け取るコールバック メソッドがどのように決められているかがわかります。 +たとえば、アクティビティが {@link +android.app.Activity#onCreate onCreate()} コールバックを受け取ると、アクティビティ内のフラグメントは {@link android.app.Fragment#onActivityCreated onActivityCreated()} コールバックまでを受け取ります。 +
+ +アクティビティが再開状態になると、アクティビティでのフラグメントの追加や削除を自由に行えます。 +つまり、アクティビティが再開された状態が、フラグメントのライフサイクルを独立して変更できる唯一の期間になります。 +
+ +ただし、アクティビティが再開状態でなくなると、フラグメントはアクティビティによって再度ライフサイクル間を通過することになります。 +
+ + + + +例
+ +このドキュメントで解説した内容をすべて網羅するため、2 つのフラグメントを使用して 2 つのペインのレイアウトを作成するアクティビティの例を紹介します。 +次のアクティビティには、シェイクスピア劇のタイトル リストを表示するフラグメントと、リストから劇が選択されたときに劇のあらすじを表示するフラグメントがあります。 + +また、ここでは画面構成によって異なるフラグメント構成を提供する方法も示しています。 +
+ +注: このアクティビティのすべてのソース コードは、{@code +FragmentLayout.java} で入手できます。 +
+ +メイン アクティビティでは、通常の方法で {@link +android.app.Activity#onCreate onCreate()} の間にレイアウトを適用します。
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main} + +適用されるレイアウトは {@code fragment_layout.xml} です。
+ +{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout} + +このレイアウトを使って、アクティビティがレイアウトをロードするとすぐにシステムが {@code TitlesFragment}(これが劇のタイトルをリストします)のインスタンスを作成します。このとき、{@link android.widget.FrameLayout} (劇のあらすじを表示するフラグメントの目的地)が画面右側を使用し、残りは空白の状態です。 + + +ご覧のように、フラグメントが {@link android.widget.FrameLayout} に置かれるのはユーザーがアイテムを選択してからになります。 +
+ +ただし、画面構成によっては、劇の一覧とあらすじを横並びに表示するほどの幅がない場合もあります。 +そのため、上記のレイアウトは横方向の画面構成の場合のみ使用され、{@code res/layout-land/fragment_layout.xml} に保存されます。 +
+ +画面が縦方向の場合、システムは次のレイアウトを適用して {@code res/layout/fragment_layout.xml} に保存します。 +
+ +{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} + +このレイアウトには、{@code TitlesFragment} のみが含まれます。つまり、端末が縦方向の場合、劇のタイトルのみが表示されます。 +そのため、この構成時にユーザーがリストのアイテムをクリックしたとき、アプリケーションは 2 つ目のフラグメントをロードする代わりに新しいアクティビティを開始してあらすじを表示します。 + +
+ +次に、フラグメントのクラスでこれをどう実現するのかを見ていきます。まず、{@code +TitlesFragment} はシェイクスピア劇のタイトル リストを表示します。このフラグメントは {@link +android.app.ListFragment} を拡張し、リスト ビューの動作の処理のほとんどを委ねます。
+ +このコードをよく見ると、ユーザーがリストのアイテムをクリックしたときの挙動が 2 つ考えられます。2 つのレイアウトのどちらがアクティブになっているかによって、新しいフラグメントを作成して表示することで同じアクティビティで詳細を表示するか({@link +android.widget.FrameLayout} にフラグメントを追加する)、新しいアクティビティを(フラグメントを表示できる場所に)開始するかのいずれかになります。 + +
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles} + +2 つ目のフラグメントである {@code DetailsFragment} は、{@code TitlesFragment} のリストで選択された劇のあらすじを表示します。 +
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details} + +{@code TitlesFragment} クラスで説明したように、ユーザーがリストアイテムをクリックしたときに、現在のレイアウトに{@code R.id.details} ビュー({@code DetailsFragment} が属する場所)が含まれていない場合、アプリケーションは {@code DetailsActivity} のアクティビティを開始してアイテムのコンテンツを表示します。 + + +
+ +次の {@code DetailsActivity} では、画面が縦方向のときに単純に {@code DetailsFragment} を埋め込んで選択された劇のあらすじを表示します。 +
+ +{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java +details_activity} + +構成が横方向の場合はアクティビティは自ら終了するため、メイン アクティビティが引き継いで {@code DetailsFragment} を {@code TitlesFragment} の横に表示できます。これは、ユーザーが縦方向のときに {@code DetailsActivity} を開始し、その後横方向に回転した(ここで現在のアクティビティが再開される)ときに起こることがあります。 + + +
+ + +フラグメントを使用したその他のサンプルとこの例の完全なソース ファイルについては、ApiDemos(SDK コンポーネントのサンプルから入手可能)にある API デモサンプルをご覧ください。 + +
+ + diff --git a/docs/html-intl/intl/ja/guide/components/fundamentals.jd b/docs/html-intl/intl/ja/guide/components/fundamentals.jd new file mode 100644 index 0000000000000000000000000000000000000000..46e98689a3ecc23aa6955577a8811ade1acedd0b --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/fundamentals.jd @@ -0,0 +1,480 @@ +page.title=アプリケーションの基礎 +@jd:body + +本書の内容
+-
+
- アプリのコンポーネント + + +
- マニフェスト ファイル
+
-
+
- コンポーネントを宣言する +
- アプリの要件を宣言する +
+ - アプリのリソース +
Android アプリは Java プログラミング言語で記述されています。APKAndroid SDK ツールがコードを—データとリソース ファイルと共に、 +—APK (Android パッケージ)にコンパイルします。これは、 +{@code .apk} という接尾語の付いたアーカイブ ファイルです。1 つの APK ファイルにはAndroid アプリのすべてのコンテンツが含まれており、Android 端末はアプリをインストールする際にこのファイルを使用します。 +
+ +端末にインストールすると、各 Android アプリはそれぞれのセキュリティ サンドボックス内で動作します。
+ +-
+
- Android オペレーティング システムはマルチユーザーの Linux システムであり、各アプリが異なるユーザーになります。 + + +
- デフォルトで、システムは各アプリに一意の Linux ユーザー ID を割り当てます(ID はシステムのみが使用し、アプリは ID を関知しません)。 +アプリが割り当てられたユーザー ID のみがアプリ内のすべてのファイルにアクセスできるよう、システムがパーミッションを設定します。 + + +
- 各プロセスにはそれぞれ独自の仮想マシン(VM)があるため、アプリのコードは他のアプリとは分離して実行します。 + + +
- デフォルトで、すべてのアプリは独自の Linux プロセス上で実行します。Android はアプリのコンポーネントのいずれかを実行する必要があるときにプロセスを開始し、それが必要なくなったときや、システムが他のアプリ用にメモリを回復させる必要があるときにプロセスをシャットダウンします。 + + +
このようにして、Android システムは最小権限の原則を実装しています。つまり、デフォルトでは各アプリにはコンポーネントの動作に必要な分だけのアクセス権が与えられます。 + +これにより、パーミッションの与えられていないシステムの一部にアプリはアクセスできないという非常に安全性の高い環境が作り出されます。 +
+ +ただし、アプリが他のアプリとデータを共有したり、システムのサービスにアクセスしたりする方法もあります。 +
+ +-
+
- 2 つのアプリで同一の Linux ユーザー ID を共有して、お互いのファイルにアクセスできるようにすることも可能です。 +システム リソースを節約するため、同じユーザー ID を持つアプリを同じ Linux プロセス上で実行し、同じ VM を共有するよう設定することもできます(アプリを同じ証明書で署名する必要があります)。 + + +
- アプリから、ユーザーの連絡先、SMS メッセージ、マウント可能なストレージ(SD カード)、カメラ、Bluetooth といった端末データにアクセスするためのパーミッションを要求できます。 +アプリのすべてのパーミッションは、インストール時にユーザーから付与される必要があります。 + +
以上が、システム内の Android アプリの基本的な仕組みです。続いて、このドキュメントでは次の内容について説明します。 +
+-
+
- アプリを定義するコア フレームワーク コンポーネント。 +
- コンポーネントを宣言し、アプリの端末機能に必要なマニフェスト ファイル。 + +
- アプリでさまざまな端末構成の動作を最適化できるようにする、アプリコードから分離されたリソース。 + +
アプリのコンポーネント
+ +アプリのコンポーネントは、Android アプリに不可欠な構成要素です。各コンポーネントは、システムがアプリにアクセスするためのさまざまなエントリ ポイントになります。すべてのコンポーネントがユーザーの実際のエントリ ポイントになるわけではなく、中にはお互いに依存関係にあるものもありますが、それぞれが独自のエンティティとして存在し、特定の役割を担っています。各コンポーネントはアプリの全体的な動作を定義する固有の構成要素となっています。 + + +— +
+ +アプリのコンポーネントには、4 つのタイプがあります。それぞれのタイプは、まったく異なる目的を果たし、コンポーネントの作成や破棄方法を定義するライフサイクルもそれぞれ異なります。 +
+ +アプリのコンポーネントのタイプは次の 4 つです。
+ +-
+
+
- アクティビティ + +
- アクティビティ は 1 つのユーザー インターフェースで 1 つの画面を表すものです。たとえば、メール アプリには新着メールの一覧を表示する 1 つのアクティビティと、メールを作成するアクティビティ、メールを閲覧するアクティビティがそれぞれ別にあります。
+
+メールアプリでは、複数のアクティビティが一体となって結合したユーザー操作を実現しますが、それぞれは他のものから独立しています。
+
+それにより、別のアプリで複数のアクティビティの中から、1 つのアクティビティを開始できるようになります(メールアプリが許可している場合)。
+たとえば、カメラアプリでは写真を他のユーザーと共有するために、メール アプリの新規メールを作成するアクティビティを開始できます。
+
+
+
アクティビティは {@link android.app.Activity} のサブクラスとして実装されます。詳細については、デベロッパー ガイドの「Activities」をご覧ください。 + +
+
+
+
+ - サービス + +
- サービス は、 長期間の操作やリモート プロセスを処理するためにバックグラウンドで実行するコンポーネントです。
+サービスは、ユーザー インターフェースを提供しません。
+たとえば、サービスはユーザーが別のアプリを使用している間にバックグラウンドで音楽を再生したり、ユーザーが別のアクティビティを操作している間にそれを妨げることなくネットワークからデータを取得したりします。
+
+アクティビティなどの別のコンポーネントは、サービスを開始して実行したり、それをバインドしたりして操作することもできます。
+
+
+
サービスは {@link android.app.Service} のサブクラスとして実装されます。詳細については、デベロッパー ガイドの「サービス」をご覧ください。 + +
+
+
+
+ - コンテンツ プロバイダ + +
- コンテンツ プロバイダ は 共有されているアプリデータを管理します。データは、ファイル システム、SQLite データベース、ウェブ、アプリがアクセスできる、あらゆる永続性のストレージに保存できます。
+
+コンテンツ プロバイダを介して、他のアプリがデータをクエリしたり、修正したりすることもできます(コンテンツ プロバイダが許可している場合)。
+たとえば、Android システムではユーザーの連絡先情報を管理するコンテンツ プロバイダを提供しています。
+このように、適切なパーミッションさえあれば、アプリからコンテンツ プロバイダの一部({@link
+android.provider.ContactsContract.Data}など)に問い合わせて、特定の人物に関する情報を読み取ったり書き込んだりできます。
+
+
+
コンテンツ プロバイダは、アプリで非公開扱いの共有されていないデータを閲覧したり書き込んだりする場合にも役立ちます。 +たとえば、Note Pad のサンプル アプリでは、コンテンツ プロバイダを使用してメモを保存します。 +
+ +コンテンツ プロバイダは {@link android.content.ContentProvider} のサブクラスとして実装され、他のアプリがトランザクションを実行できるようにする API の標準セットを実装する必要があります。 + +詳細については、デベロッパー ガイドの「Contetns Providers」をご覧ください。 +
+
+
+
+ - ブロードキャスト レシーバー + +
- ブロードキャスト レシーバー は システム全体のブロードキャスト アナウンスに応答するコンポーネントです。
+たとえば、画面がオフになった、バッテリ残量が低い、写真が撮影されたなど、システムに起因するブロードキャストはたくさんあります。アプリでもブロードキャストを開始でき、たとえば他のアプリに、一部のデータが端末にダウンロードされ、利用可能になったことを伝えることもできます。—
+
+—
+ブロードキャスト レシーバーがユーザー インターフェースを表示することはありませんが、ステータスバー通知を作成して、ブロードキャスト イベントの発生時にユーザーに警告できます。
+
+一般的には、ブロードキャスト レシーバーは他のコンポーネントへの単なる「入り口」であり、最小限の操作を行うことが前提となっています。
+たとえば、イベントに基づいた何らかの作業を実行するサービスを開始する場合などに適しています。
+
+
+
ブロードキャスト レシーバーは、{@link android.content.BroadcastReceiver} のサブクラスとして実装され、各ブロードキャストは {@link android.content.Intent} オブジェクトとして配信されます。 +詳細については、{@link android.content.BroadcastReceiver} クラスをご覧ください。 +
+
+
+
Android ならではのシステムデザインによって、どのアプリケーションからでも別のアプリケーションを開始できます。 +たとえば、ユーザーが端末のカメラで写真を撮影できるようにする場合、既にその機能を備えた別のアプリがあることを想定して、写真を撮影するアクティビティを自身で開発する代わりに、アプリがそれを使用できます。 + +カメラアプリを組み込んだり、コードにリンクしたりする必要もなく、単純に写真を撮影するカメラアプリのアクティビティを開始するだけです。 + + +完了後、写真はアプリに戻り、それを使用することもできます。ユーザー側には、カメラがアプリの一部であるかのように見えます。 +
+ +システムがコンポーネントを開始すると、そのアプリのプロセスを開始し(まだ実行していない場合)、コンポーネントが必要とするクラスをインスタンス化します。 +たとえば、アプリで写真を撮影するカメラアプリのアクティビティを開始すると、そのアクティビティはアプリのプロセスではなく、カメラアプリのプロセスで実行します。そのため、他のシステムのアプリとは異なり、Android アプリのエントリ ポイントは 1 つではありません(たとえば、{@code main()} 関数はありません)。 + + + +
+ +システムは、他のアプリへのアクセスを制限するファイル許可を使用して各アプリを別々のプロセスで実行するため、アプリから直接他のアプリのコンポーネントはアクティベートできませんが、Android システムはそれが可能です。 + +そのため、他のアプリのコンポーネントをアクティベートするには、特定のコンポーネントを開始するインテントを指定するメッセージをシステムに配信する必要があります。 + +その後、システムが代わりにコンポーネントをアクティベートします。
+ + +コンポーネントをアクティベートする
+ +4 つのコンポーネント タイプのなかで、アクティビティ、サービス、ブロードキャスト レシーバーの 3 つは、インテントと呼ばれる非同期メッセージによってアクティベートされます。コンポーネントがアプリに属していても他のものに属していても、インテントにより実行時に個別のコンポーネントがお互いに結び付けられます(他のコンポーネントからのアクションを要求するメッセンジャーのようなものです)。—— + + + +
+ +インテントは {@link android.content.Intent} オブジェクトを使用して作成されます。このオブジェクトは特定のコンポーネントや特定のタイプのコンポーネントをアクティベートするようにメッセージを定義します。インテントはそれぞれ明示的、暗黙的のいずれかになります。— + +
+ +アクティビティとサービスでは、インテントが実行するアクション(「閲覧」したり「送信」したりする)を定義し、操作に使うデータ(特に、開始されるコンポーネントが知っておく必要があるデータ)の URI を指定することもできます。 + +たとえば、インテントはアクティビティに画像を表示したり、ウェブページを開いたりするアクティビティに対して要求を伝達します。 +場合によっては、結果を受け取るアクティビティを開始でき、この場合にアクティビティが返す結果も {@link android.content.Intent} になります(たとえば、ユーザーが個人の連絡先を取り出し、それを返してくれるインテントを発行できます。返されたインテントには選択された連絡先を指す URI が含まれています)。 +— + + +
+ +ブロードキャスト レシーバーの場合、インテントは単純にブロードキャストするアナウンスを定義します(たとえば、端末のバッテリ残量が少ないことを示すブロードキャストには、「バッテリが少ない」ことを示す既知のアクション文字列が含まれます)。 + +
+ +他のコンポーネント タイプであるコンテンツ プロバイダは、インテントではアクティベートされず、{@link android.content.ContentResolver} からの要求の対象となったときにアクティベートされます。 +コンテンツリゾルバが、コンテンツプロバイダを使ってすべてのトランザクションを直接処理することで、プロバイダを使ってトランザクションを実行しているコンポーネントは処理する必要がなくなり、代わりに {@link +android.content.ContentResolver} オブジェクトのメソッドを呼び出します。 + +これによりコンテンツ プロバイダと情報を要求しているコンポーネントとの間に(セキュリティ目的で)抽象的な層ができます。 +
+ +各コンポーネント タイプのアクティベート用に、個別のメソッドが用意されています。
+-
+
- アクティビティを開始する(または新しい作業を与える)場合は、{@link android.content.Intent} を {@link android.content.Context#startActivity +startActivity()} や {@link android.app.Activity#startActivityForResult startActivityForResult()} (アクティビティに結果を求める場合)に渡します。 + + +
- サービスを開始する(または継続中のサービスに新しい指示を与える)には、{@link android.content.Intent} を {@link android.content.Context#startService +startService()} に渡します。 +または、{@link android.content.Intent} を {@link android.content.Context#bindService bindService()} に渡してサービスにバインドできます。 + +
- ブロードキャストを開始するには、{@link android.content.Intent} を {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、{@link +android.content.Context#sendOrderedBroadcast(Intent, String) sendOrderedBroadcast()}、{@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()} などのメソッドに渡します。 + +
- コンテンツ プロバイダへのクエリを実行するには、{@link android.content.ContentResolver} の {@link +android.content.ContentProvider#query query()} を呼び出します。 +
インテントの使用に関する詳細については、「インテントとインテント フィルタ」のドキュメントをご覧ください。 +特定のコンポーネントのアクティベートの詳細については、 +アクティビティ、サービス、{@link +android.content.BroadcastReceiver}、コンテンツ プロバイダ のドキュメントでも説明しています。
+ + +マニフェスト ファイル
+ +Android システムがコンポーネントを開始する前に、システムはアプリの {@code AndroidManifest.xml} ファイル(「マニフェスト」ファイル)を読み取って、コンポーネントの存在を認識する必要があります。 + +アプリはこのファイルですべてのコンポーネントを宣言し、このファイルはアプリ プロジェクトのディレクトリのルートに置く必要があります。 +
+ +マニフェストはアプリのコンポーネントを宣言する他にも、次のようにさまざまな役割があります。 +
+-
+
- インターネット アクセスや、ユーザーの連絡先への読み取りアクセスなど、アプリに必要なユーザー パーミッションを識別する。 + +
- アプリが使用する API に基づいた、アプリが必要とする最小 API レベルを宣言する。 + +
- カメラ、Bluetooth サービス、マルチタッチ スクリーンなど、アプリで使用されるか必要とされるハードウェア機能やソフトウェア機能を宣言する。 + +
- Google マップ ライブラリなど、アプリにリンクする必要のある API ライブラリ(Android フレームワーク API は除く)。 + + +
- その他の役割 +
コンポーネントを宣言する
+ +マニフェストの主なタスクは、システムにアプリ コンポーネントに関する情報を与えることです。たとえば、マニフェスト ファイルではアクティビティを次のように宣言できます。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<manifest ... > + <application android:icon="@drawable/app_icon.png" ... > + <activity android:name="com.example.project.ExampleActivity" + android:label="@string/example_label" ... > + </activity> + ... + </application> +</manifest>+ +
<application>
要素では、{@code android:icon} 属性でアプリを特定するアイコンのリソースを指します。
+
+
<activity>
要素では、{@code android:name} 属性で{@link
+android.app.Activity} サブクラスの完全修飾k裏スパイウェア名を指定し、{@code android:label} 属性でアクティビティのユーザーに表示するラベルとして使用する文字列を指定しています。
+
+
すべてのアプリ コンポーネントは、次の方法で宣言する必要があります。
+-
+
<activity>
アクティビティ用の要素 +
+ <service>
サービス用の要素 +
+ <receiver>
ブロードキャスト レシーバー用の要素 +
+ <provider>
コンテンツ プロバイダ用の要素 +
+
ソースに含まれていながら、マニフェスト ファイルでは定義されていないアクティビティ、サービス、コンテンツ プロバイダはシステムには見えないため、実行されることはありません。 +ただし、ブロードキャスト レシーバーはマニフェストで宣言するか、コードで動的に作成({@link android.content.BroadcastReceiver} オブジェクトとして)して {@link android.content.Context#registerReceiver registerReceiver()} を呼び出すことでシステムに登録できます。 + + + +
+ +アプリのマニフェスト ファイルの構築方法の詳細については、「The AndroidManifest.xml File」のドキュメントをご覧ください。 +
+ + + +コンポーネントの機能を宣言する
+ +コンポーネントをアクティベートするで説明したように、{@link android.content.Intent} を使用してアクティビティ、サービス、ブロードキャスト レシーバーを開始できます。 +開始するには、インテントでターゲットのコンポーネントの名前を(コンポーネントのクラス名を使って)明示的に指定する必要があります。 +ただし、インテントの本来の能力は、暗黙的インテントの概念にあります。 +暗黙的インテントは、単に実行するアクションのタイプを記述し(どのデータ上でアクションを実行するかも任意で記述できます)、それによりシステムがそのアクションを実行できる端末上のコンポーネントを見つけて開始できます。 + + +インテントで記述されたアクションを実行できるコンポーネントが複数ある場合は、使用するコンポーネントを 1 つ選択できます。 +
+ +システムは、端末の他のアプリのマニフェスト ファイルに提供されたインテント フィルタが受け取った + インテントを比較して、 インテントに応答できるコンポーネントを識別します。 +
+ +アプリのマニフェストでアクティビティを宣言するとき、任意でアクティビティの機能を宣言するインテント フィルタを含めて、他のアプリからのインテントに応答できるようにできます。 + +{@code +<intent-filter>} 要素を、コンポーネントを宣言している要素の子として追加することで、コンポーネントのインテント フィルタを宣言できます。 +
+ +たとえば、新規メールを作成するアクティビティを持つメールアプリをビルドした場合、次のように「送信」インテント(新規メールを送信するための)に応答するインテント フィルタを宣言できます。 +
++<manifest ... > + ... + <application ... > + <activity android:name="com.example.project.ComposeEmailActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <data android:type="*/*" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> ++ +
次に、別のアプリが {@link +android.content.Intent#ACTION_SEND} アクションを持つインテントを作成し、{@link android.app.Activity#startActivity +startActivity()} に渡す場合、ユーザーがメールを下書きして送信できるよう、システムがアクティビティを開始する場合があります。 +
+ +インテント フィルタの作成の詳細については、「インテントとインテント フィルタ」のドキュメントをご覧ください。 +
+ + + +アプリの要件を宣言する
+ +Android が搭載された端末は数多くありますが、すべての端末が同じ機能や性能を備えているわけではありません。 +アプリに必要な機能を搭載していない端末にアプリをインストールしてしまわないよう、アプリがサポートする端末のタイプについてプロファイルで明確に定義し、マニフェスト ファイルで端末の要件やソフトウェア要件を宣言しておくことが重要です。 + + +これらの宣言のほとんどはただの情報で、システムがそれを読み取ることはありませんが、Google Play などの外部サービスはそれを読み取って、ユーザーが端末からアプリを検索したときにフィルタを提供します。 + +
+ +たとえば、アプリでカメラを使用する必要があり、Android 2.1 で採用された API(API レベル 7)を使用する場合、次のようにマニフェスト ファイルでそれを要件として宣言する必要があります。 +
+ ++<manifest ... > + <uses-feature android:name="android.hardware.camera.any" + android:required="true" /> + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> + ... +</manifest> ++ +
カメラのない端末で、Android バージョンが 2.1 以下の場合は、Google Play からアプリをインストールできません。 +
+ +ただし、アプリでカメラを使用するが、それが必須ではないということを宣言することもできます。 +この場合、アプリで {@code required} 属性を {@code "false"} に設定し、端末にカメラがあるかどうかを実行時に確認して、必要に応じてすべてのカメラ機能を無効にする必要があります。 + +
+ +異なる端末でのアプリの互換性を管理する方法については、「Device Compatibility」をご覧ください。 + +
+ + + +アプリのリソース
+ +Android アプリは、コードだけで構成されているわけではありません。ソース コードから分離された画像、オーディオ ファイル、その他アプリの外観に関連するあらゆるリソースが必要です。たとえば、アクティビティのアニメーション、メニュー、スタイル、色、レイアウトなどを XML ファイルで定義する必要があります。— + + +アプリのリソースを使用すると、コードを修正することなく別のリソースセットを提供することで、アプリのあらゆる特性を簡単にアップデートできるようになります。これにより、さまざまな端末の設定用(別の言語や画面サイズなど)にアプリを最適化できます。 +— +— +
+ +Android プロジェクトに含めるすべてのリソースに対し、SDK ビルド ツールが一意の整数 ID を定義し、アプリコードや XML で定義された他のリソースからリソースにそれを使って参照できます。 + +たとえば、アプリに {@code +logo.png} という名前の画像ファイルがある場合({@code res/drawable/} ディレクトリ内に保存)、SDK ツールが {@code R.drawable.logo} という名前のリソース ID を生成し、これを使って画像を参照してユーザー インターフェースに挿入できます。 + +
+ +リソースとソース コードを分離して提供する方法の最も重要な側面は、さまざまな端末設定に合わせて別のリソースを提供できるという点です。 + +たとえば、XML で UI 文字列を定義することで、その文字列を他の言語に翻訳して、それらの文字列を別のファイルに保存しておくことができます。 +それを、リソースのディレクトリ名に付けた言語の修飾子(フランス語の文字列値なら {@code res/values-fr/} のように)とユーザーの言語設定に基づいて、Android システムによって UI に適切な言語の文字列が適用されます。 + + +
+ +Android では代替リソース用に多様な修飾子をサポートしています。修飾子は、リソースのディレクトリ名に含める短い文字列で、そのリソースを使用する端末構成を定義するものです。 + +例をもう 1 つ挙げると、端末の画面の向きやサイズによって、アクティビティのレイアウトを複数作成する必要があります。 + +たとえば、端末が縦方向(縦長)の場合、ボタンの付いたレイアウトを縦に並べ、端末が横方向(横長)の場合はボタンを横並びにする、といった場合です。 + +画面の方向によってレイアウトを変更するには、2 つの異なるレイアウトを定義して、それぞれのレイアウトのディレクトリ名に適切な修飾子を適用します。 + +そうすることで、現在の端末の向きによってシステムが自動的に適切なレイアウトを適用できます。 +
+ +アプリケーションに含めることのできるリソースの種類や、異なる端末設定用の代替リソースの作成方法については、「リソースの提供」をご覧ください。 +
+ + + +こちらもご覧ください。
+-
+
- インテントとインテント フィルタ + +
- {@link android.content.Intent} API を使用して、アクティビティやサービスなどのアプリのコンポーネントをアクティベートする方法や、アプリのコンポーネントを他のアプリで利用できるようにする方法について説明しています。 + + +
- Activities +
- ユーザー インターフェースを使って独特のアプリケーション画面を提供する {@link android.app.Activity} + クラスのインスタンスの作成方法について説明しています。 +
- リソースの提供 +
- 特定の端末構成に対して代替リソースを提供する方法など、Android アプリでアプリのリソースをアプリコードから分離する仕組みについて説明しています。 + + + +
関連ドキュメント
+-
+
- Device Compatibility +
- あらゆるタイプの端末での Android の動作と、端末ごとにアプリを最適化したり、別の端末でのアプリの利用を制限したりする方法について説明しています。 + + +
- System Permissions +
- アプリが特定の API を使用するのにユーザーの同意を必要とするパーミッション システムを使用して、アプリから特定の API へのアクセスを Android が制限する仕組みについて説明しています。 + +
コンポーネント +page.landing=true +page.landing.intro=Android のアプリケーション フレームワークでは、再利用可能なコンポーネント セットを使用して豊富な内容を備えた斬新なアプリを作成できます。このセクションでは、アプリの構成要素を定義するコンポーネントのビルド方法と、インテントを使用してそれらをつなぎ合わせる方法について説明します。 +page.metaDescription=Android のアプリケーション フレームワークでは、再利用可能なコンポーネント セットを使用して豊富な内容を備えた斬新なアプリを作成できます。このセクションでは、アプリの構成要素を定義するコンポーネントのビルド方法と、インテントを使用してそれらをつなぎ合わせる方法について説明します。 +page.landing.image=images/develop/app_components.png +page.image=images/develop/app_components.png + +@jd:body + +
ブログの記事
+ + +DialogFragments の使用
+この投稿では、DialogFragments を v4 サポート ライブラリで使用して(Honeycomb 以前の端末での下方互換性のため)ダイアログを編集したり、インターフェースを使用して呼び出し元の Activity に結果を返したりする方法について説明します。
+ + + +すべてに Fragments を
+本日、同じ Fragments API を利用できる静的なライブラリが公開され、Android 1.6 以降でもフラグメントを使用してタブレット対応のユーザー インターフェースを作成できるようになりました。
+ + + +マルチスレッドでパフォーマンス向上
+応答の速いアプリケーションを作成する上で重要なのは、メイン UI スレッドが最小限の作業を行うようにすることです。 +アプリケーションのハングにつながる可能性のある長期的なタスクは、別のスレッドで処理するようにします。 +
+ +トレーニング
+ + +アクティビティのライフサイクルの管理
+このレッスンでは、各 Activity インスタンスが受け取る重要なライフサイクル コールバック メソッドについて、それらを使用してユーザーの予期する内容でアクティビティを動作させる方法と、アクティビティがそれらを必要としないときに、システムのリソースを消費しないようにする方法について学習します。 + +
+ + + +フラグメントで動的 UI を構築
+このレッスンでは、Android 1.6 以降の旧バージョンを実行する端末に対応しながら、フラグメントを使用して動きのある使用感を実現し、異なる画面サイズでのアプリの操作感を最適化する方法について説明します。 + +
+ + + +コンテンツの共有
+このレッスンでは、Intent API と ActionProvider オブジェクトを使用して、アプリケーション間でコンテンツを送受信する際の一般的な方法について説明します。 +
+ +本書の内容
+-
+
- インテントのタイプ +
- インテントを作成する
+
-
+
- 明示的インテントの例 +
- 暗黙的インテントの例 +
- アプリチューザを表示する +
+ - 暗黙的インテントを受け取る
+
-
+
- フィルタの例 +
+ - ペンディング インテントを使用する +
- インテント解決
+
-
+
- アクションのテスト +
- カテゴリのテスト +
- データのテスト +
- インテントのマッチング +
+
関連ドキュメント
+ + +{@link android.content.Intent} は、他のアプリ コンポーネントからのアクションを要求するときに使用するメッセージング オブジェクトです。インテントを使用することでコンポーネント間の通信を促進する方法はいくつかありますが、基本的な使用例は次の 3 つです。 + + +
+ +-
+
- アクティビティを開始するには:
+
{@link android.app.Activity} はアプリ内の 1 つの画面を表します。{@link android.app.Activity} の新しいインスタンスを開始するには、{@link android.content.Intent} を {@link android.content.Context#startActivity startActivity()} に渡します。 + +{@link android.content.Intent} は、開始するアクティビティを記述し、必要なデータすべてを含んでいます。 +
+ +アクティビティの完了時に結果を受け取る場合は、{@link android.app.Activity#startActivityForResult +startActivityForResult()} を呼び出します。 +アクティビティは、結果を別の {@link android.content.Intent} オブジェクトとして、アクティビティの {@link +android.app.Activity#onActivityResult onActivityResult()} コールバック内に受け取ります。詳細については、「Activities」のガイドをご覧ください。 + +
+
+ - サービスを開始するには:
+
{@link android.app.Service} は、ユーザー インターフェースを持たず、バックグラウンドで操作を実行するコンポーネントです。 +サービスを開始して 1 回限りの操作を実行する(ファイルのダウンロードなど)には、{@link android.content.Intent} を {@link android.content.Context#startService startService()} に渡します。 + +{@link android.content.Intent} は、開始するサービスを記述し、必要なデータすべてを含んでいます。 +
+ +クライアントサーバーのインターフェースでサービスがデザインされている場合、{@link android.content.Intent} を {@link +android.content.Context#bindService bindService()} に渡して、他のコンポーネントからのサービスにバインドできます。 +詳細については、「サービス」のガイドをご覧ください。
+
+ - ブロードキャストを配信するには:
+
ブロードキャストは、アプリが受け取ることのできるメッセージです。システムは、システムの起動や端末の充電開始など、さまざまなシステム イベントを配信します。他のアプリにブロードキャストを配信するには、{@link android.content.Intent} を {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()}、{@link android.content.Context#sendOrderedBroadcast(Intent, String) +sendOrderedBroadcast()}、{@link +android.content.Context#sendStickyBroadcast sendStickyBroadcast()} のいずれかに渡します。 + + + +
+
+
インテントのタイプ
+ +インテントには 2 つのタイプがあります。
+ +-
+
- 明示的インテントは、開始するコンポーネントを名前(完全修飾クラス名)で指定します。 +通常は開始するアクティビティやサービスのクラス名がわかっているため、明示的インテントを使用してアプリ内のコンポーネントを開始します。 +たとえば、ユーザー操作に応答して新しいアクティビティを開始したり、バックグラウンドでファイルをダウンロードするサービスを開始したりします。 + + + +
- 暗黙的インテントでは、特定のコンポーネントを指定せず、代わりに実行する全般的な動作を宣言することで、他のアプリからコンポーネントを処理できるようにします。 +たとえば、マップ上にユーザーの位置を表示する場合、暗黙的インテントを使って、特定の場所をマップ上に表示できる別のアプリにその操作を要求します。 + + +
暗黙的インテントを使用してアクティビティやサービスを開始する際、システムによってただちに {@link android.content.Intent} オブジェクトで指定されたアプリ コンポーネントが開始されます。 +
+ +暗黙的インテントを作成するとき、Android システムはインテントの内容を、端末上の他のアプリの マニフェスト ファイルで定義された インテント フィルタ と比較して、開始すべきコンポーネントを見つけます。 + +インテントがインテント フィルタに一致した場合、システムがそのコンポーネントを開始して、{@link android.content.Intent} を配信します。 +複数のインテント フィルタが競合する場合、ユーザーが仕様するアプリを選択できるようシステムによってダイアログが表示されます。 +
+ +インテント フィルタは、コンポーネントが受け取りたいインテントのタイプを指定する式で、アプリのマニフェスト ファイルに含まれています。 + +たとえば、アクティビティのインテント フィルタを宣言すると、特定のインテント タイプを持つアクティビティを他のアプリから直接開始できるようになります。同様に、アクティビティでインテント フィルタを宣言しない場合は、明示的インテントでのみアクティビティを開始できます。 + + +
+ +警告: アプリの安全性を保つため、{@link android.app.Service} を開始するときは常に明示的インテントを使用し、サービスでインテント フィルタを宣言しないようにしてください。 + +暗黙的インテントを使ってサービスを開始すると、どのサービスがインテントに応答するかを把握できず、ユーザーにはどのサービスが開始するのかがわからないため、セキュリティ上の危険が伴います。 + +Android 5.0(API レベル 21)以降では、暗黙的インテントで {@link android.content.Context#bindService bindService()} を呼び出すと、システムから例外がスローされます。 + +
+ + + + + +インテントを作成する
+ +{@link android.content.Intent} オブジェクトには Android システムが開始するコンポーネントを決定する際に使用する情報(インテントを受け取るべき正確なコンポーネント名やコンポーネントのカテゴリなど)に加えて、受け取る側のコンポーネントがアクションを適切に実行するために使用する情報(実行するアクションと、実行対象のデータなど)が含まれています。 + + +
+ + +{@link android.content.Intent} に含まれる主な情報は次のとおりです。
+ +-
+
+
- コンポーネント名 +
- 開始するコンポーネントの名前です。
+
+
これは省略可能ですが、インテントを明示的にするためには不可欠な情報です。つまり、コンポーネント名で定義されたアプリ コンポーネントにのみ、インテントが配信されます + +コンポーネント名がない場合、インテントは暗黙的になり、他のインテント情報(下記で説明するアクション、データ、カテゴリなど)に基づいてインテントを受け取るべきコンポーネントをシステムが決定します + +—そのため、アプリ内の特定のコンポーネントを開始する必要がある場合は、コンポーネント名を指定する必要があります。 +
+ +注: {@link android.app.Service} を開始するときは、常にコンポーネント名を指定する必要があります。 +指定しない場合、どのサービスがインテントに応答するかを把握できず、ユーザーにはどのサービスが開始するのかがわからなくなります。 +
+ +{@link android.content.Intent} のフィールドは {@link android.content.ComponentName} オブジェクトで、アプリのパッケージ名など、ターゲットのコンポーネントの完全修飾クラス名を使用して指定できます(例: {@code com.example.ExampleActivity})。 + + +コンポーネント名は、{@link +android.content.Intent#setComponent setComponent()}、{@link android.content.Intent#setClass +setClass()}、{@link android.content.Intent#setClassName(String, String) setClassName()}、{@link android.content.Intent} コンストラクタなどを使用して設定できます。 +
+ +
+
+ - アクション +
- 実行する全体的なアクションを指定する文字列です(閲覧や選択など)。
+
+
ブロードキャスト インテントの場合、これが発生済みで報告済みのアクションになります。ほとんどのアクションは、残りのインテントがどのように構成されているか、特にデータやエクストラに含まれている内容によって決まります。 +— + + +
インテントによって自身のアプリで使用する(または他のアプリで使用して自身のアプリのコンポーネントを呼び出す)独自のアクションを指定できますが、通常は {@link android.content.Intent} クラスや他のフレームワーク クラスで定義されたアクション定数を使用します。 + +アクティビティを開始する際の一般的なアクションをいくつか次に示します。 +
+ +-
+
- {@link android.content.Intent#ACTION_VIEW} +
- ギャラリー アプリで表示する写真や、マップアプリで表示する住所など、アクティビティ内にユーザーに表示する情報がある場合は、{@link + android.content.Context#startActivity startActivity()} を使ってインテントにこのアクションを使用します。 + + + +
- {@link android.content.Intent#ACTION_SEND} +
- これは「共有」インテントとしても知られており、メールアプリやソーシャル シェアリング アプリなどの他のアプリ経由でユーザーが共有できるデータがある場合に、{@link + android.content.Context#startActivity startActivity()} でインテントに使用します。 + +
全体的なアクションを定義するその他の定数については、{@link android.content.Intent} クラスのリファレンスをご覧ください。 +システムの設定アプリで特定の画面を開くアクションの {@link android.provider.Settings} など、他のアクションは Android フレームワークの別の場所で定義されます。 + +
+ +インテントのアクションは、{@link android.content.Intent#setAction +setAction()} や {@link android.content.Intent} コンストラクタを使って指定できます。
+ +独自のアクションを定義したら、接頭辞としてアプリのパッケージ名を必ず含めます。 +次に例を示します。
+static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
+
+
+ - データ +
- アクションの実行対象であるデータや、データの MIME タイプを参照する URI({@link android.net.Uri} オブジェクト)です。
+提供されるデータタイプは、インテントのアクションによって決まります。たとえば、アクションが {@link android.content.Intent#ACTION_EDIT} の場合、データには編集するドキュメントの URI が含まれます。
+
+
+
+
インテントの作成時、URI だけでなくデータタイプ(MINE タイプ)を指定することが重要な場面が多くあります。たとえば、画像を表示できるアクティビティの場合、URI 形式は似ていてもオーディオ ファイルは再生できません。そのため、データの MIME タイプを指定することで、Android システムがインテントを受け取るのに最適なコンポーネントを見つけることができます。ただし、MIME タイプは URI から推測できることもあります。特にデータが {@code content:} URI の場合は、データが端末上にあり、{@link android.content.ContentProvider} に制御されるデータであることを示し、データの MIME タイプがシステムから見えるようになります。 + + + + + +— + +
+ +データ URI のみを設定するには、{@link android.content.Intent#setData setData()} を呼び出します。MIME タイプのみを設定するには、{@link android.content.Intent#setType setType()} を呼び出します。 +必要であれば、{@link +android.content.Intent#setDataAndType setDataAndType()} を使って両方を明示的に設定することもできます。 +
+ +警告: URI と MIME タイプの両方を設定する場合は、お互いの値を無効にしてしまわないよう、{@link android.content.Intent#setData setData()} と {@link android.content.Intent#setType setType()} を呼び出さないでください。URI と MIME タイプの両方を設定する場合は、常に {@link android.content.Intent#setDataAndType setDataAndType()} を使用してください。 + + + +
+
+
+ - カテゴリ +
- インテントを処理するコンポーネントの種類に関する追加情報が含まれた文字列です。
+カテゴリの記述は、インテントにいくつでも含めることができますが、ほとんどのインテントではカテゴリは必須ではありません。一般的なカテゴリの例を次に示します。
+
+
+
+
-
+
- {@link android.content.Intent#CATEGORY_BROWSABLE} +
- ターゲットのアクティビティは、ウェブブラウザから開始して画像やメール メッセージなど、リンクで参照されたデータを表示できます。 +— + +
- {@link android.content.Intent#CATEGORY_LAUNCHER} +
- このアクティビティはタスクの初期のアクティビティで、システムのアプリケーション ランチャーの一覧に表示されます。 + + +
カテゴリの全一覧は、{@link android.content.Intent} クラスの説明をご覧ください。 +
+ +カテゴリは、{@link android.content.Intent#addCategory addCategory()} を使って指定できます。
+
+
上記のプロパティ(コンポーネント名、アクション、データ、カテゴリ)は、インテントの特性の定義を表しています。 +これらのプロパティを読み取ることで、Android システムはどのアプリ コンポーネントを開始すべきかを解決できます。 +
+ +ただし、インテントにはアプリ コンポーネントの解決に影響を与えない追加情報を含めることもできます。 +インテントに含めることのできる情報は次のとおりです。
+ +-
+
- エクストラ +
- 要求されたアクションの実行に必要な追加情報のキーと値のペアです。データの URI の特定の種類を使用するアクションがあるのと同様に、特定のエクストラを使用するアクションもあります。
+
+
+
エクストラはさまざまな {@link android.content.Intent#putExtra putExtra()} を使って追加でき、それぞれがキー名と値の 2 つのパラメータを受け入れます。また、すべてのエクストラ データを使って {@link android.os.Bundle} オブジェクトを作成し、{@link +android.content.Intent#putExtras putExtras()} を使って {@link android.os.Bundle} を {@link android.content.Intent} に挿入することもできます。 + + +
+ +たとえば、{@link android.content.Intent#ACTION_SEND} を使ってメールを送信するインテントを作成するとき、{@link android.content.Intent#EXTRA_EMAIL} キーを使って「宛先」の受信者を指定したり、{@link android.content.Intent#EXTRA_SUBJECT} を使って「件名」を指定したりできます。 + + +
+ +{@link android.content.Intent} クラスは多くの標準データタイプの {@code EXTRA_*} 定数を指定できます。 +独自のエクストラ キーを宣言する必要がある場合は(アプリが受け取るインテント用に)、アプリのパッケージ名を接頭辞として必ず含めます。 + +次に例を示します。
+static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
+
+
+ - フラグ +
- {@link android.content.Intent} クラスで定義されるフラグは、インテントのメタデータとして機能します。
+フラグは、Android システムにアクティビティの起動方法(アクティビティがどのタスクに属するかなど)や、起動後の取り扱い方法(最近のアクティビティの一覧に含めるかどうかなど)を指示します。
+
+
+
+
+
詳細については、{@link android.content.Intent#setFlags setFlags()} メソッドをご覧ください。
+
+
+
明示的インテントの例
+ +明示的インテントは、アプリ内の特定のアクティビティやサービスなど、特定のアプリ コンポーネントを起動する際に使用するものです。明示的インテントを作成するには、{@link android.content.Intent} オブジェクトでコンポーネント名を定義します。他のインテント プロパティはすべて省略可能です。 + + +—
+ +たとえば、アプリでウェブからファイルをダウンロードするサービスを {@code DownloadService} という名前でビルドした場合、次のコードでそれを開始できます。 +
+ ++// Executed in an Activity, so 'this' is the {@link android.content.Context} +// The fileUrl is a string URL, such as "http://www.example.com/image.png" +Intent downloadIntent = new Intent(this, DownloadService.class); +downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl)); +startService(downloadIntent); ++ +
{@link android.content.Intent#Intent(Context,Class)} コンストラクタがアプリに {@link android.content.Context} を、コンポーネントに {@link java.lang.Class} オブジェクトを提供します。 + +このようにして、このインテントはアプリの {@code DownloadService} クラスを明示的に開始します。 +
+ +サービスのビルドと開始の詳細については、「サービス」のガイドをご覧ください。 +
+ + + + +暗黙的インテントの例
+ +暗黙的インテントは、端末上のどんなアプリでも実行できるアクションを指定します。 +暗黙的インテントは、自身のアプリではそのアクションを実行できないが、他のアプリでは実行可能であり、どのアプリを使うかをユーザーに選ばせたい場合に便利です。 +
+ +たとえば、他のユーザーと共有できるようにするコンテンツがある場合は、{@link android.content.Intent#ACTION_SEND} アクションを使ってインテントを作成し、共有するコンテンツを指定するエクストラを追加します。 + +そのインテントで {@link android.content.Context#startActivity startActivity()} を呼び出すと、ユーザーはどのアプリでコンテンツを共有するかを選択できます。 + +
+ +警告: {@link android.content.Context#startActivity +startActivity()} に送る暗黙的インテントを処理できるアプリがユーザーが持っていない場合もあります。 +その場合、呼び出しは失敗し、アプリはクラッシュします。アクティビティが必ずインテントを受け取るようにするには、{@link android.content.Intent} オブジェクトで {@link android.content.Intent#resolveActivity +resolveActivity()} を呼び出します。 +結果が null 以外の場合は、インテントを処理できるアプリが少なくとも 1 つはあることを意味し、{@link android.content.Context#startActivity startActivity()} を安全に呼び出すことができます。 + +結果が null の場合は、そのインテントは使用せず、可能であればそのインテントを発行する機能を無効にする必要があります。 + +
+ + ++// Create the text message with a string +Intent sendIntent = new Intent(); +sendIntent.setAction(Intent.ACTION_SEND); +sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); +sendIntent.setType("text/plain"); + +// Verify that the intent will resolve to an activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(sendIntent); +} ++ +
注: この場合、URI は使用されませんが、エクストラに含まれるコンテンツを指定するためインテントのデータタイプは宣言されます。 +
+ + +{@link android.content.Context#startActivity startActivity()} が呼び出されたとき、システムによってすべてのインストール済みアプリの中にこのタイプのインテント({@link android.content.Intent#ACTION_SEND} アクションとテキスト/プレーン データが含まれるインテント)を処理できるものがあるかどうかが確認されます + + +インテントを処理できるアプリが 1 つしかない場合は、そのアプリがすぐに開いてインテントを受け取ります。 +インテントを処理できるアクティビティが複数ある場合、ユーザーが使用するアプリを選択できるダイアログが表示されます。 +
+ + +アプリチューザを表示する
+ +暗黙的インテントに応答するアプリが 2 つ以上ある場合、ユーザーは使用するアプリを選択でき、そのアプリをアクションに対するデフォルトの選択肢にすることができます。 + +これは、ウェブ ページを開いたり、(1 つのカメラを選ぶ傾向にあるユーザーが) +写真を撮影したりといったアクションの実行時に、ユーザーが今後同じアプリの使用を希望するような場合に便利です(ユーザーは常に同じウェブブラウザを使用する傾向があります)。 +
+ +ただし、インテントに応答するアプリが複数あって、ユーザーが毎回別のアプリを使用する可能性がある場合は、チューザのダイアログを明示的に表示する必要があります。 +チューザのダイアログでは、 +アクションのたびに使用するアプリをユーザーに選択させます(ユーザーはアクションのデフォルトのアプリを選択できません)。 +たとえば、アプリが {@link +android.content.Intent#ACTION_SEND} アクションを使って「共有」を実行するとき、 ユーザーが現在の状況によって別のアプリを使用して共有する場合もあるため、図 2 のようにチューザのダイアログは常に表示する必要があります。 +
+ + + + +チューザを表示するには、{@link +android.content.Intent#createChooser createChooser()} を使用して {@link android.content.Intent} を作成し、{@link +android.app.Activity#startActivity startActivity()} に渡します。次に例を示します。
+ ++Intent sendIntent = new Intent(Intent.ACTION_SEND); +... + +// Always use string resources for UI text. +// This says something like "Share this photo with" +String title = getResources().getString(R.string.chooser_title); +// Create intent to show the chooser dialog +Intent chooser = Intent.createChooser(sendIntent, title); + +// Verify the original intent will resolve to at least one activity +if (sendIntent.resolveActivity(getPackageManager()) != null) { + startActivity(chooser); +} ++ +
これにより、{@link +android.content.Intent#createChooser createChooser()} メソッドに渡されたインテントに応答するアプリのリストを示すダイアログが表示され、 +指定されたテキストがダイアログのタイトルになります。
+ + + + + + + + + +暗黙的インテントを受け取る
+ +アプリが受け取ることのできる暗黙的インテントを通知するには、マニフェスト ファイルで {@code <intent-filter>} 要素を使ってアプリのコンポーネントごとに 1 つ以上のインテント フィルタを宣言します。各インテント フィルタは、インテントのアクション、データ、カテゴリに基づいて受け入れるインテントのタイプを指定します。 + + + +インテントがいずれかのインテント フィルタを通過した場合のみ、システムが暗黙的インテントをアプリのコンポーネントに配信します。 +
+ +注: 明示的インテントは、コンポーネントが宣言しているインテント フィルタに関係なく、常にターゲットに配信されます。 +
+ +アプリのコンポーネントは固有のジョブそれぞれに対して個別のフィルタを宣言する必要があります。たとえば、画像キャラリーのアプリの 1 つのアクティビティには、画像を表示するフィルタと、画像を編集するフィルタの 2 つがあります。 + +アクティビティが開始すると、{@link android.content.Intent} を調べて {@link android.content.Intent} にある情報に基づいてどのように動作するかを決定します(編集コントロールを表示するかどうかなど)。 + +
+ +各インテント フィルタは、アプリのマニフェスト ファイルの {@code <intent-filter>} 要素で定義され、これは対応するアプリのコンポーネント({@code <activity>} 要素など)にネストされます。 + + +{@code <intent-filter>} 内で、次の 3 つの要素のなかで 1 つ以上を使用して、受け入れるインテントのタイプを指定できます。 + +
+ +-
+
- {@code <action>} +
- {@code name} 属性で、受け入れるインテントのアクションを宣言します。値は、クラス定数ではなく、アクションのリテラル文字列値である必要があります。 + +
- {@code <data>} +
- データ URI (
scheme
、host
、port
、path
など) や MIME タイプのさまざまな側面を指定する 1 つ以上の属性を使用して、受け入れるデータのタイプを宣言します。 + +
+ - {@code <category>} +
- {@code name} 属性で、受け入れるインテントのカテゴリを宣言します。値は、クラス定数ではなく、アクションのリテラル文字列値である必要があります。
+
+
+
注: 暗黙的インテントを受け取るには、インテント フィルタに {@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを含める必要があります。 + +{@link android.app.Activity#startActivity startActivity()} メソッドと {@link android.app.Activity#startActivityForResult startActivityForResult()}メソッドはすべてのインテントを、{@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを宣言しているものとして処理します。 + + + + インテント フィルタでカテゴリを宣言していない場合、暗黙的インテントはアクティビティに紐付けされません。 +
+
+
次に、データ タイプがテキストの場合に、{@link android.content.Intent#ACTION_SEND} インテントを受け取るインテント フィルタを使用したアクティビティ宣言の例を示します。 +
+ ++<activity android:name="ShareActivity"> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + </intent-filter> +</activity> ++ +
{@code <action>}、{@code <data>}、{@code <category>} のなかで 2 つ以上のインスタンスを含むフィルタを作成することもできます。その場合、コンポーネントがそれらのフィルタ要素のすべての組み合わせを処理できることを確認しておきます。 + + + + +
+ +複数のタイプのインテントに対応しながら、アクション、データ、カテゴリタイプの特定の組み合わせのみを処理する場合は、複数のインテント フィルタを作成する必要があります。 +
+ + +コンポーネントへのアクセスを制限する
+インテント フィルタを使用して他のアプリでコンポーネントを開始できないようにする方法は安全ではありません。 +インテント フィルタでは暗黙的インテントの特定の種類にのみ応答するようコンポーネントを制限しますが、開発者がコンポーネントを決定する場合は、明示的インテントを使用して別のアプリからアプリのコンポーネントを開始できるようになります。アプリのコンポーネントを自身のアプリでのみ開始できるようにする必要がある場合は、そのコンポーネントの {@code +exported} 属性を{@code "false"} に設定します。 + + + + +
+暗黙的インテントは、3 つの要素それぞれへのインテントを比較して、フィルタでテストされます。 +コンポーネントに配信されるには、インテントが 3 つのテストすべてを通過する必要があります。一致しないものが 1 つでも場合、Android システムはインテントをコンポーネントに配信しません。 + +ただし、コンポーネントは複数のインテント フィルタを保持していることもあるため、1 つのインテント フィルタを通過できなかったインテントでも、別のフィルタを通過できる場合があります。システムによるインテント解決の詳細は、次のセクションのインテントの解決で説明します。 + + +
+ +警告: 他のアプリの {@link android.app.Service} で誤って実行されないように、自身のサービスは常に明示的インテントを使用して開始し、サービスではインテント フィルタは宣言しないでください。 + +
+ +注: すべてのアクティビティにおいて、インテント フィルタはマニフェスト ファイルで宣言する必要があります。ただし、ブロードキャスト レシーバーのフィルタは、{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String, +Handler) registerReceiver()} を呼び出すことで動的に登録できます。 + + +その後、レシーバーの登録を解除するには、{@link +android.content.Context#unregisterReceiver unregisterReceiver()} を使用します。これにより、アプリが実行中の特定の期間だけ、アプリが特定のブロードキャストをリッスンできるようになります。 + +
+ + + + + + + +フィルタの例
+ +インテント フィルタの動作をより深く理解するため、ソーシャル シェアリング アプリのマニフェスト ファイルからの次のスニペットをご覧ください。 +
+ ++<activity android:name="MainActivity"> + <!-- This activity is the main entry, should appear in app launcher --> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> + +<activity android:name="ShareActivity"> + <!-- This activity handles "SEND" actions with text data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="text/plain"/> + </intent-filter> + <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> + <intent-filter> + <action android:name="android.intent.action.SEND"/> + <action android:name="android.intent.action.SEND_MULTIPLE"/> + <category android:name="android.intent.category.DEFAULT"/> + <data android:mimeType="application/vnd.google.panorama360+jpg"/> + <data android:mimeType="image/*"/> + <data android:mimeType="video/*"/> + </intent-filter> +</activity> ++ +
1 つ目のアクティビティである {@code MainActivity} は、アプリのメイン エントリ ポイントで、ユーザーがランチャー アイコンから初めてアプリを起動したときに開くアクティビティです。— +
+-
+
- {@link android.content.Intent#ACTION_MAIN} アクションが、これがメインのエントリ ポイントで、インテント データはないことを示しています。 + +
- {@link android.content.Intent#CATEGORY_LAUNCHER} カテゴリが、このアクティビティのアイコンをシステムのアプリ ランチャーに配置する必要があることを示しています。 +{@code <activity>} 要素が {@code icon} を使ってアイコンを指定しない場合、システムは {@code <application>} 要素からのアイコンを使用します。 + + +
アクティビティをアプリ ランチャーに表示するには、この 2 つをペアリングする必要があります。
+ +2 つ目のアクティビティである {@code ShareActivity} が、テキストやメディア コンテンツの共有を促します。 +ユーザーは {@code MainActivity} に移動することでこのアクティビティに入ることもありますが、2 つのインテント フィルタのいずれかに一致する暗黙的インテントを発行する別のアプリから直接 {@code ShareActivity} に入ることもできます。 + +
+ +注: MIME タイプ({@code +application/vnd.google.panorama360+jpg})は、パノラマ写真を指定する特別なデータタイプで、Google +panorama API を使って処理できます。 + +
+ + + + + + + + + + + + + +ペンディング インテントを使用する
+ +{@link android.app.PendingIntent} オブジェクトは、{@link +android.content.Intent} オブジェクトのラッパーです。{@link android.app.PendingIntent} の主な目的は、別のアプリケーションに {@link android.content.Intent} をアプリ自身のプロセスから実行したように使用できるパーミッションを付与することです。 + + +
+ +ペンディング インテントの主な使用例には、次のようなものがあります。
+-
+
- 通知 を使ってユーザーがアクションを実行するときに実施するインテントを宣言する(Android システムの {@link android.app.NotificationManager} が {@link android.content.Intent} を実行します)。 + + +
- +アプリのウィジェット を使ってユーザーがアクションを実行するときに実施するインテントを宣言する(ホーム画面のアプリが {@link android.content.Intent} を実行します)。 + +
- 今後の指定された時間に実施するインテントを宣言する(Android システムの {@link android.app.AlarmManager} が {@link android.content.Intent} を実行します)。 + +
各 {@link android.content.Intent} オブジェクトはアプリの特定のタイプのコンポーネント({@link android.app.Activity}、{@link android.app.Service}、{@link android.content.BroadcastReceiver} のいずれか)で処理されることを前提としているため、{@link android.app.PendingIntent} も同様の前提で作成する必要があります。 + + +ペンディング インテントを使用する場合、アプリはインテントの実行時に {@link android.content.Context#startActivity +startActivity()} などの呼び出しを行いません。 +代わりに、{@link android.app.PendingIntent} の作成時にそれぞれのクリエーター メソッドを呼び出して目的のコンポーネント タイプを宣言する必要があります。 +
+ +-
+
- {@link android.app.Activity} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()}。 + +
- {@link android.app.Service} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getService PendingIntent.getService()}。 + +
- {@link android.content.BroadcastReceiver} を開始する {@link android.content.Intent} の場合は、{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()}。 + +
アプリが他のアプリからペンディング インテントを受け取る場合を除いて、{@link android.app.PendingIntent} の作成時に必要となる {@link android.app.PendingIntent} メソッドはほぼ上記の 3 つのみです。 + +
+ +各メソッドが現在のアプリの {@link android.content.Context}、ラップする {@link android.content.Intent}、インテントの使用方法を指定する 1 つ以上のフラグ(インテントを 2 回以上できるかどうかなど)を受け取ります。 + +
+ +ペンディング インテントの使用に関する詳細については、 +「通知」や「App Widgets」など、それぞれの使用例の API ガイドをご覧ください。 +
+ + + + + + + +インテント解決
+ + +システムがアクティビティを開始する暗黙的インテントを受け取ると、次の 3 つの側面に基づいてインテントをインテント フィルタと比較し、そのインテントに最適なアクティビティを検索します。 +
+ +-
+
- インテントのアクション +
- インテントのデータ(URI とデータタイプの両方) +
- インテントのカテゴリ +
次のセクションでは、インテント フィルタがアプリのマニフェスト ファイルでどのように宣言されているかという観点から、インテントが適切なコンポーネントに紐付けられる方法について説明します。 +
+ + +アクションのテスト
+ +受け入れるインテントのアクションを指定するには、インテント フィルタでゼロ個以上の {@code +<action>} 要素を宣言します。 +次に例を示します。
+ ++<intent-filter> + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.VIEW" /> + ... +</intent-filter> ++ +
このフィルタを通過するには、{@link android.content.Intent} で指定されたアクションが、フィルタにリストされたアクションのいずれかに一致する必要があります。 +
+ +フィルタのリストにアクションが 1 つもない場合は、インテントに一致するものがないため、すべてのインテントがテストに失敗します。 +ただし、{@link android.content.Intent} がアクションを指定していない場合は、テストに合格します(フィルタに少なくとも 1 つのアクションが含まれている必要があります)。 + +
+ + + +カテゴリのテスト
+ +受け入れるインテントのカテゴリを指定するには、インテント フィルタでゼロ個以上の {@code +<category>} 要素を宣言します。 +次に例を示します。
+ ++<intent-filter> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + ... +</intent-filter> ++ +
インテントがカテゴリのテストに合格するには、{@link android.content.Intent} 内のすべてのカテゴリが、フィルタ内のカテゴリに一致する必要があります。 +インテント フィルタでは、{@link android.content.Intent} で指定されたカテゴリよりも多くのカテゴリが宣言されている場合もあるため、すべてが {@link android.content.Intent} に一致しなくてもテストには合格します。— + +そのため、カテゴリのないインテントは、フィルタで宣言されているカテゴリに関係なく、常にこのテストに合格することになります。 +
+ +注: Androidは自動的に、{@link +android.content.Context#startActivity startActivity()} と {@link +android.app.Activity#startActivityForResult startActivityForResult()} に渡されるすべての暗黙的インテントに {@link android.content.Intent#CATEGORY_DEFAULT} カテゴリを自動的に適用します。そのため、アクティビティで暗黙的インテントを受け取りたい場合は、前出の {@code <intent-filter>} の例のように、アクティビティのインテント フィルタに {@code "android.intent.category.DEFAULT"} のカテゴリを含める必要があります。 + + + + +
+ + + +データのテスト
+ +受け入れるインテント データを指定するには、インテント フィルタでゼロ個以上の {@code +<data>} 要素を宣言します。 +次に例を示します。
+ ++<intent-filter> + <data android:mimeType="video/mpeg" android:scheme="http" ... /> + <data android:mimeType="audio/mpeg" android:scheme="http" ... /> + ... +</intent-filter> ++ +
各 <data>
要素では、URI 構造とデータタイプ(MIME メディア タイプ)を指定できます。
+URI の各パートには、{@code scheme}、{@code host}、{@code port}、{@code path} の個別の属性があります。—
+—
+
+
{@code <scheme>://<host>:<port>/<path>}
+ ++次に例を示します。 +
+ +{@code content://com.example.project:200/folder/subfolder/etc}
+ +この URI では、スキームが {@code content}、ホストが {@code com.example.project}、ポートが {@code 200}、パスが {@code folder/subfolder/etc} です。 + +
+ +これらの各属性は {@code <data>} 要素では省略可能ですが、一次従属があります。 +
+-
+
- スキームが指定されていない場合、ホストは無視されます。 +
- ホストが指定されていない場合、ポートは無視されます。 +
- スキームとホストの両方が指定されていない場合、パスは無視されます。 +
インテントの URI をフィルタの URI 仕様に比較するときは、フィルタに含まれる URI の一部でのみ比較されます。 +次に例を示します。
+-
+
- フィルタでスキームのみが指定されている場合、そのスキームを持つすべての URI がフィルタに一致します。 + +
- フィルタでスキームと認証局が指定されていて、パスが指定されていない場合、パスにかかわらず同じスキームと認証局を持つすべての URI がフィルタを通過します。 + +
- フィルタでスキーム、認証局、パスが指定されている場合、同じスキーム、認証局、パスを持つ URI のみがフィルタを通過します。 + +
注: パスの指定では、ワイルドカードのアスタリスク(*)を使ってパス名の部分一致のみを要求することもできます。 +
+ +データのテストでは、インテントの URI と MIME タイプの両方を、フィルタで指定された URI と MIME タイプと比較します。 +規則は次のとおりです。 +
+ +-
+
- URI も MIME タイプも含まないインテントは、フィルタで URI や MIME タイプが指定されていない場合のみテストをパスします。 + + +
- URI を含んでいて MIME タイプを含んでいないインテント(明示的にも含まれておらず、URI からも推測できない)場合は、URI がフィルタの URI 形式に一致し、フィルタが MIME タイプを指定していない場合のみテストをパスします。 + + + +
- MIME タイプを含んでいて、URI を含んでいないインテントは、フィルタのリストに同じ MIME タイプがあり、URI 形式が指定されていない場合のみテストをパスします。 + + +
- URI と MINE タイプの両方を含む(明示的か、URI からの推測)インテントは、MIME タイプがフィルタのリストにあるタイプに一致した場合のみ、テストの MIME タイプのパートをパスします。 + +テストの URI のパートは、URI がフィルタの URI に一致するか、{@code content:} URI か {@code file:} URI があって URI が指定されていない場合にパスできます。つまり、フィルタにリストに MIME タイプのみがある場合、コンポーネントは {@code content:} データと {@code file:} データをサポートすると推定されます。 + + + + +
+この最後の規則(d)は、コンポーネントがファイルやコンテンツ プロバイダからのローカル データを取得できるという予測を反映しています。そのため、フィルタにはデータタイプのみをリストして、{@code content:} スキームや {@code file:} スキームを明示的に指定する必要はありません。これは一般的なケースです。 + + + +たとえば、次の {@code <data>} 要素は、コンポーネントがコンテンツ プロバイダからの画像データを取得し、それを表示できることを Android に伝えています。 + + +
+ ++<intent-filter> + <data android:mimeType="image/*" /> + ... +</intent-filter>+ +
+利用可能なデータはほとんどコンテンツプロバイダによって投入されることから、データタイプが指定されていて URI 指定されていないデータが最も一般的です + +
+ ++もうひとつ一般的な設定として、スキームと データタイプを使ったフィルタがあります。たとえば、次の {@code <data>} 要素は、アクションを実行するためにコンポーネントがネットワークから動画データを取得できることを Android に伝えています。 + + + +
+ ++<intent-filter> + <data android:scheme="http" android:type="video/*" /> + ... +</intent-filter>+ + + +
インテントのマッチング
+ +インテントをインテント フィルタにマッチングする目的には、アクティベートするターゲットを発見するということだけでなく、端末上のコンポーネントのセットに関連する何かを発見するという目的があります。 + +たとえば、ホーム アプリは {@link android.content.Intent#ACTION_MAIN} アクションと {@link android.content.Intent#CATEGORY_LAUNCHER} カテゴリを指定するインテント フィルタを持つすべてのアクティビティを見つけることで、アプリ ランチャーを設定します。 + + +
+ +アプリケーションでも、同様の方法でインテントのマッチングを使用できます。{@link android.content.pm.PackageManager} には特定のインテントを受け入れることのできるすべてのコンポーネントを返す一連の {@code query...()} メソッドと、インテントに応答できる最適なコンポーネントを返す同様のシリーズの {@code resolve...()} メソッドがあります。 + + + +たとえば、{@link android.content.pm.PackageManager#queryIntentActivities +queryIntentActivities()} は引数として渡されたインテントを実行できるすべてのアクティビティの一覧を返し、{@link +android.content.pm.PackageManager#queryIntentServices +queryIntentServices()} は同様のサービスの一覧を返します。いずれのメソッドでもコンポーネントのアクティベートは行われず、応答できるものを列挙するだけです。 + + + +ブロードキャスト レシーバー用にも、同様のメソッド {@link android.content.pm.PackageManager#queryBroadcastReceivers +queryBroadcastReceivers()} があります。 + +
+ + + + diff --git a/docs/html-intl/intl/ja/guide/components/loaders.jd b/docs/html-intl/intl/ja/guide/components/loaders.jd new file mode 100644 index 0000000000000000000000000000000000000000..bc936774f721ba6af82085ea3ab9b33b768e106e --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/loaders.jd @@ -0,0 +1,494 @@ +page.title=ローダ +parent.title=アクティビティ +parent.link=activities.html +@jd:body +本書の内容
+-
+
- Loader API の概要 +
- アプリケーションでローダを使用する
+
-
+
- +
- ローダを開始する +
- ローダを再開する +
- LoaderManager コールバックを使用する +
+ - 例
+
-
+
- その他の例 +
+
キークラス
+-
+
- {@link android.app.LoaderManager} +
- {@link android.content.Loader} + +
関連サンプル
+-
+
- +LoaderCursor +
- +LoaderThrottle +
Android 3.0 で導入されたローダによって、アクティビティやフラグメントでのデータの非同期ロードが簡単になりました。 +ローダには、次の 3 つの特徴があります。
+-
+
- すべての {@link android.app.Activity} と {@link +android.app.Fragment} で使用できる。 +
- 非同期のデータロードを提供する。 +
- データのソースを監視し、コンテンツが変更されたときに新しい結果を配信する。 + +
- 設定の変更後に再作成されると、自動的に最後のローダのカーソルに再接続するため、 +再度データを問い合わせる必要がない。 + +
Loader API の概要
+ +アプリケーションでローダを使用するのに必要になりそうなクラスやインターフェースは複数あります。 +次の表で、それらの概要をまとめました。
+ +クラス/インターフェース | +説明 | +
---|---|
{@link android.app.LoaderManager} | +1 つ以上の {@link
+android.content.Loader} インスタンスを管理するための、{@link android.app.Activity} や {@link android.app.Fragment} に関連した抽象クラスです。
+これにより、アプリケーションは {@link android.app.Activity} や {@link android.app.Fragment} のライフサイクルと連動して長時間の操作を管理できるようになります。最も一般的なのは、{@link android.content.CursorLoader} で使用する方法ですが、アプリケーションでは他のタイプのデータのロード用に、独自のローダを自由に作成することもできます。
+
+
+
+
+ + + 1 つのアクティビティやフラグメントごとに、{@link android.app.LoaderManager} は 1 つだけ存在しますが、{@link android.app.LoaderManager} は複数のローダを持つことができます。 + |
+
{@link android.app.LoaderManager.LoaderCallbacks} | +クライアントが {@link +android.app.LoaderManager} とやり取りするためのコールバック インターフェースです。たとえば、{@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} コールバック メソッドを使用してと新しいローダを作成します。 + | +
{@link android.content.Loader} | +非同期のデータロードを実行する抽象クラスです。これは、ローダの基本クラスです。 +通常は {@link +android.content.CursorLoader} を使用しますが、独自のサブクラスを実装することもできます。ローダがアクティブな間は、データのソースを管理し、コンテンツが変更されたときに新しい結果を配信します。 + + | +
{@link android.content.AsyncTaskLoader} | +処理を行うための {@link android.os.AsyncTask} を提供する抽象的なローダです。 | +
{@link android.content.CursorLoader} | +{@link android.content.ContentResolver} に問い合わせて {@link +android.database.Cursor} を返す{@link android.content.AsyncTaskLoader} のサブクラスです。 +これは、カーソルのクエリ用に標準的な方法で {@link +android.content.Loader} プロトコルを実装するクラスで、アプリケーションの UI をブロックせずにバックグラウンドでカーソルのクエリを実行するように、{@link android.content.AsyncTaskLoader} を基に構築されています。{@link +android.content.ContentProvider} からデータを非同期的にロードする際は、フラグメントの API やアクティビティの API 経由でマネージド クエリを実行するのではなく、このローダを使用するのが最適です。 + + + + | +
上の表のクラスとインターフェースは、アプリケーションでローダを実装する際に使用する必須コンポーネントです。 +作成するローダごとにこれらすべてが必要になるわけではありませんが、{@link +android.app.LoaderManager} への参照は、ローダを初期化したり {@link +android.content.CursorLoader} などの {@link android.content.Loader} を実装したりするには {@link +android.app.LoaderManager} への参照が常に必要になります。 +次のセクションでは、アプリケーションでのこれらのクラスとインターフェースの使用方法を説明します。 +
+ +アプリケーションでローダを使用する
+このセクションでは、Android アプリケーションのローダの使用方法について説明します。通常、ローダを使用するアプリケーションには次の内容が含まれます。 +
+-
+
- {@link android.app.Activity} または {@link android.app.Fragment}。 +
- {@link android.app.LoaderManager} のインスタンス。 +
- {@link +android.content.ContentProvider} でサポートされているデータをロードする {@link android.content.CursorLoader}。あるいは、{@link android.content.Loader} や{@link android.content.AsyncTaskLoader} の独自のサブクラスを実装して他のソースからデータをロードすることもできます。 + + +
- {@link android.app.LoaderManager.LoaderCallbacks} の実装。ここで、新しいローダを作成して既存のローダへの参照を管理します。 + + +
- {@link +android.widget.SimpleCursorAdapter} などのローダのデータを表示する方法。 +
- {@link android.content.CursorLoader} を使用するときの、{@link android.content.ContentProvider} などのデータ ソース。 + +
ローダを開始する
+ +{@link android.app.LoaderManager} は 1 つ以上の {@link +android.content.Loader} インスタンスを {@link android.app.Activity} や {@link android.app.Fragment} 内で管理します。 +1 つのアクティビティやフラグメントごとに、{@link +android.app.LoaderManager} は 1 つだけ存在します。
+ +通常は、アクティビティの {@link +android.app.Activity#onCreate onCreate()} メソッドか、フラグメントの {@link android.app.Fragment#onActivityCreated onActivityCreated()} メソッド内で {@link android.content.Loader} を初期化します。 + +その方法は次のとおりです。 +
+ +// Prepare the loader. Either re-connect with an existing one, +// or start a new one. +getLoaderManager().initLoader(0, null, this);+ +
{@link android.app.LoaderManager#initLoader initLoader()} メソッドが次のパラメータを受け取ります。 +
+-
+
- ローダを識別する一意の ID。この例では、ID は 0 です。 +
- ローダの構築時に提供する任意の引数(この例では
null
)。 +
+
+ - {@link android.app.LoaderManager} がローダのイベントを報告する際に呼び出す {@link android.app.LoaderManager.LoaderCallbacks} の実装。 +この例では、ローカルクラスが {@link +android.app.LoaderManager.LoaderCallbacks} インターフェースを実装するため、自身の {@code this} に参照を渡します。 + + +
{@link android.app.LoaderManager#initLoader initLoader()} の呼び出しによって、ローダが初期化され、アクティブになります。 +結果には次の 2 つの可能性があります。
+-
+
- ID で指定されたローダが既に存在する場合は、最後に作成されたローダが再利用されます。 + +
- ID で指定したローダが存在しない場合、{@link android.app.LoaderManager#initLoader initLoader()} が {@link android.app.LoaderManager.LoaderCallbacks} メソッドの {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} をトリガーします。ここで、インスタンスを作成して新しいローダを返すコードを実装します。詳細については、onCreateLoader のセクションをご覧ください。 + + + + +
いずれの場合でも、その {@link android.app.LoaderManager.LoaderCallbacks} の実装はローダに関連付けられ、ローダの状態が変化したときに呼び出されます。 + +この呼び出しの時点で、呼び出し側が開始された状態にあり、要求されたローダが既に存在し、データを生成済みの場合は、システムはただちに {@link +android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} を呼び出す({@link android.app.LoaderManager#initLoader initLoader()} の間に)ため、それに備えておく必要があります。 + + + +このコールバックの詳細については、 +onLoadFinished をご覧ください。
+ +{@link android.app.LoaderManager#initLoader initLoader()} メソッドは作成された {@link android.content.Loader} を返しますが、そこへの参照はキャプチャしないことに注意してください。 + +{@link android.app.LoaderManager} は自動的にローダの生存状態を管理します。 +{@link android.app.LoaderManager} は必要に応じて開始と停止を行いし、ローダとそれに関連付けられたコンテンツの状態を管理します。 + +このことからもわかるように、ローダと直接やり取りすることはほとんどありません(ローダの動作を微調整するローダ メソッドの使用例については、 LoaderThrottle のサンプルをご覧ください)。 + +特定のイベントが発生したときにローディングの処理に干渉することを目的に、{@link +android.app.LoaderManager.LoaderCallbacks} を使用することがよくあります。 + +このトピックの詳細については、LoadManager コールバックを使用するをご覧ください。
+ +ローダを再開する
+ +上記のように {@link android.app.LoaderManager#initLoader initLoader()} を使用する場合、指定した ID があれば既存のローダを使用し、なければ新たに作成します。 + +ただし、古いデータを破棄して最初からやり直したいこともあります。 +
+ +古いデータを破棄するには、{@link +android.app.LoaderManager#restartLoader restartLoader()} を使用します。たとえば、この {@link android.widget.SearchView.OnQueryTextListener} を実装すると、ユーザーのクエリが変化したときにローダが再開されます。 + +新しい検索フィルタを使用して新しいクエリを実行できるように、ローダは再開される必要があります。 +
+ ++public boolean onQueryTextChanged(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; +}+ +
LoaderManager コールバックを使用する
+ +{@link android.app.LoaderManager.LoaderCallbacks} はクライアントが {@link android.app.LoaderManager} とやり取りできるようにするコールバック インターフェースです。 +
+特に、{@link android.content.CursorLoader} のローダでは、停止後もデータを保持しておくことが望まれます。 +これにより、アプリケーションがアクティビティやフラグメントの {@link android.app.Activity#onStop +onStop()} メソッドや {@link android.app.Activity#onStart onStart()} メソッド全体でデータを維持することができるので、ユーザーがアプリケーションに戻ったときにデータの再ロードを待つ必要がありません。 + + +新しいローダを作成するタイミングを知りたいときや、ローダのデータの使用を停止するタイミングをアプリケーションに伝えるときは、{@link android.app.LoaderManager.LoaderCallbacks} メソッドを使用します。 + +
+ +{@link android.app.LoaderManager.LoaderCallbacks} には次のメソッドが含まれています。 +
+-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — 指定された ID の新しい {@link android.content.Loader} をインスタンス化して返します。 + +
-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}— 前に作成されたローダがロードを完了した時に呼び出されます。 + +
-
+
- {@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} — 前に作成されたローダがリセットされ、データが利用不可になったときに呼び出されます。 + + + +
これらのメソッドについては、次のセクションで詳しく説明します。
+ +onCreateLoader
+ +ローダにアクセスしようとしたとき(たとえば、{@link +android.app.LoaderManager#initLoader initLoader()} 経由など)、ID で指定したローダが存在するかどうかを確認されます。 +存在しない場合は、{@link +android.app.LoaderManager.LoaderCallbacks} メソッドの {@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} をトリガーします。ここで、新しいローダを作成します。 +通常は、{@link +android.content.CursorLoader} になりますが、独自の {@link +android.content.Loader} サブクラスを実装することもできます。
+ +この例では、{@link +android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} +コールバック メソッドが {@link android.content.CursorLoader} を作成します。{@link android.content.CursorLoader}は、そのコンストラクタ メソッドを使用して構築する必要があり、{@link +android.content.ContentProvider} へのクエリを実行するのに必要なすべての情報が必要になります。 + +具体的に必要な情報は次のとおりです。
+-
+
- uri — 取得するコンテンツの URI。 +
- projection — 返す列のリスト。
null
を渡すとすべての列が返されるため、効率的ではありません。 +
+ - selection — SQL WHERE 句の書式で返す行を宣言するフィルタ(WHERE 自体は除く)。
+
null
を渡すと指定した URI のすべての行が返されます。 +
+ - selectionArgs — selection に ? を含めると、selection に表示される順序で selectionArgs の値に置き換えられます。 + +この値は、Strings 配列でバインドされます。 +
- sortOrder — SQL
+ORDER BY 句(ORDER 自体は除く)の形式で行を順序付けします。
null
を渡すとデフォルトのソート順序が使用されるため、順序が付けられない場合があります。 +
+
次に例を示します。
++ // If non-null, this is the current filter the user has provided. +String mCurFilter; +... +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); +}+
onLoadFinished
+ +このメソッドは、前に作成したローダがロードを完了したときに呼び出されます。このメソッドは、このローダが提供した最後のデータが解放される前に呼び出されることが保証されています。 + +この時点で、すべての古いデータを削除する必要がありますが(まもなく解放されるため)、データの所有者はローダでありローダが処理するため、自身でデータを解放しないようにしてください。 + +
+ + +アプリケーションがもうデータを使用していないことを検知すると、ローダがデータを解放します。 +たとえば、データが {@link +android.content.CursorLoader} からのカーソルの場合は、自身で {@link +android.database.Cursor#close close()} を呼び出さないようにしてください。カーソルが {@link android.widget.CursorAdapter} に置かれている場合は、古い {@link android.database.Cursor} がクローズされないように {@link +android.widget.SimpleCursorAdapter#swapCursor swapCursor()} メソッドを使用する必要があります。 + +次に例を示します。
+ ++// This is the Adapter being used to display the list's data.+ +
SimpleCursorAdapter mAdapter; +... + +public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); +}
onLoaderReset
+ +このメソッドは、前に作成されたローダがリセットされ、データが利用できなくなったときに呼び出されます。 +このコールバックにより、データが解放されるタイミングがわかり、そのデータへの参照を削除できます。 +
+この実装では、null
の値を使用して {@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} を呼び出します。
+
+
+// This is the Adapter being used to display the list's data. +SimpleCursorAdapter mAdapter; +... + +public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); +}+ + +
例
+ +以下は、連絡先のコンテンツ プロバイダに対するクエリの結果が含まれた {@link android.widget.ListView} を表示する {@link +android.app.Fragment} の完全な実装の例です。 +{@link +android.content.CursorLoader} を使用してプロバイダへのクエリを管理しています。
+ +この例にあるように、アプリケーションがユーザーの連絡先にアクセスするには、マニフェストに {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} の許可を含める必要があります。 + +
+ ++public static class CursorLoaderListFragment extends ListFragment + implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { + + // This is the Adapter being used to display the list's data. + SimpleCursorAdapter mAdapter; + + // If non-null, this is the current filter the user has provided. + String mCurFilter; + + @Override public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Give some text to display if there is no data. In a real + // application this would come from a resource. + setEmptyText("No phone numbers"); + + // We have a menu item to show in action bar. + setHasOptionsMenu(true); + + // Create an empty adapter we will use to display the loaded data. + mAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_list_item_2, null, + new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, + new int[] { android.R.id.text1, android.R.id.text2 }, 0); + setListAdapter(mAdapter); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // Place an action bar item for searching. + MenuItem item = menu.add("Search"); + item.setIcon(android.R.drawable.ic_menu_search); + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + SearchView sv = new SearchView(getActivity()); + sv.setOnQueryTextListener(this); + item.setActionView(sv); + } + + public boolean onQueryTextChange(String newText) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; + getLoaderManager().restartLoader(0, null, this); + return true; + } + + @Override public boolean onQueryTextSubmit(String query) { + // Don't care about this. + return true; + } + + @Override public void onListItemClick(ListView l, View v, int position, long id) { + // Insert desired behavior here. + Log.i("FragmentComplexList", "Item clicked: " + id); + } + + // These are the Contacts rows that we will retrieve. + static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { + Contacts._ID, + Contacts.DISPLAY_NAME, + Contacts.CONTACT_STATUS, + Contacts.CONTACT_PRESENCE, + Contacts.PHOTO_ID, + Contacts.LOOKUP_KEY, + }; + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + // First, pick the base URI to use depending on whether we are + // currently filtering. + Uri baseUri; + if (mCurFilter != null) { + baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, + Uri.encode(mCurFilter)); + } else { + baseUri = Contacts.CONTENT_URI; + } + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + + Contacts.DISPLAY_NAME + " != '' ))"; + return new CursorLoader(getActivity(), baseUri, + CONTACTS_SUMMARY_PROJECTION, select, null, + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); + } + + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + } + + public void onLoaderReset(Loader<Cursor> loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } +}+
その他の例
+ +ApiDemos には、ローダの使用方法を示す他のサンプルがいくつか用意されています。 +
+-
+
- +LoaderCursor — 上記のスニペットの完全バージョン。 + +
- LoaderThrottle — スロットリングを使用して、データの変更時にコンテンツ プロバイダのクエリ数を軽減する方法の例です。 + +
SDK サンプルのダウンロードとインストールの詳細については、Getting the Samples をご覧ください。 +
+ diff --git a/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd b/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd new file mode 100644 index 0000000000000000000000000000000000000000..691a5f4718801cce755f073b570a3fd273cf6cfb --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/processes-and-threads.jd @@ -0,0 +1,411 @@ +page.title=プロセスとスレッド +page.tags=lifecycle,background + +@jd:body + +本書の内容
+-
+
- プロセス
+
-
+
- プロセスのライフサイクル +
+ - スレッド
+
-
+
- ワーカー スレッド +
- スレッド セーフのメソッド +
+ - プロセス間通信(IPC) +
アプリケーション コンポーネントが開始し、アプリケーションに他に実行中のコンポーネントがない場合、Android システムは実行用のシングル スレッドを持つアプリケーション用の新しい Linux プロセスを開始します。 + +デフォルトでは、同じアプリケーションのすべてのコンポーネントは同じプロセスとスレッド(「メイン」 スレッドと呼ばれます)で実行します。 +アプリケーション コンポーネントが開始したときに、既にそのアプリケーションのプロセスが存在する場合(アプリケーションからの他のコンポーネントが存在するため)、コンポーネントはそのプロセス内で開始し、同じ実行用のスレッドを使用します。 + +ただし、アプリケーション内の別のコンポーネントを別のプロセスで実行するよう調整でき、あらゆるプロセスに対して追加のスレッドを作成できます。 + +
+ +このドキュメントでは、Android アプリケーションでプロセスとスレッドがどのように動作するかについて説明します。
+ + +プロセス
+ +デフォルトでは、同じアプリケーションのすべてのコンポーネントは同じプロセスで実行し、ほとんどのアプリケーションでこの動作を変更する必要はありません。 +ただし、特定のコンポーネントが属するプロセスを管理する必要がある場合は、マニフェスト ファイルでそれを行うことができます。 +
+ +コンポーネント要素の各タイプのマニフェスト エントリ({@code +<activity>}、{@code +<service>}、{@code +<receiver>}、{@code +<provider>})は、コンポーネントを実行するプロセスを指定できる {@code android:process} 属性をサポートしています。— +—この属性を設定して、各コンポーネントが独自のプロセスで実行するようにしたり、一部のコンポーネントで同じプロセスを共有し、残りのコンポーネントでは別のプロセスを使用するようにしたりできます。 +また、{@code android:process} を設定すると、異なるアプリケーションのコンポーネントを同じプロセスで実行させることもできます。この場合、アプリケーションが同じ Linux ユーザー ID を共有していて、同じ証明書で署名されている必要があります。 +— + +
+ +{@code +<application>} 要素も {@code android:process} 属性をサポートしており、すべてのコンポーネントに適用されるデフォルトの値を設定します。 +
+ +メモリの空きが少なくなり、早急にユーザーに提供する必要のあるプロセスが必要とする場合は、Android がプロセスをどこかの時点でシャットダウンするよう決定する場合があります。 +破棄されたプロセスで実行しているアプリケーション コンポーネントは、結果的に破棄されます。 +プロセスは、それらのコンポーネントの処理が再度発生したときに再開されます。 +
+ +破棄するプロセスを決定する際、Android システムはユーザーへの相対的な重要度を測ります。 +たとえば、画面に見えているアクティビティをホストするプロセスよりも、もう画面に見えていないアクティビティをホストするプロセスの方が先にシャットダウンされることになります。 +そのため、プロセスを停止するかどうかは、そのプロセスで実行しているコンポーネントの状態によって決まります。 +ここから、停止するプロセスを決定する規則について詳しく説明していきます。 +
+ + +プロセスのライフサイクル
+ +Android システムは、可能な限り長期間アプリケーション プロセスを維持しようとしますが、新たに重要なプロセスが発生した際には、メモリを回収するために古いプロセスをいずれは削除する必要が生じます。 +どのプロセスを維持して、どのプロセスを強制終了するかを決定するため、システムはプロセスで実行しているコンポーネントとコンポーネントの状態に基づいて、各プロセスを「重要度の階層」に位置付けします。 + + +まず、重要度の最も低いプロセスが除去され、その後システム リソースを回復できるまで重要度の低い順に除去していきます。 + +
+ +重要度の階層には 5 つのレベルがあります。次の一覧では、さまざまなプロセスのタイプを重要度の高い順に表しています(1 つ目のプロセスが最も重要度が高く、最後に強制終了されます)。 + +
+ +-
+
- フォアグラウンド プロセス
+
ユーザーが現在行っている操作に必要なプロセスです。次の条件のいずれかにあてはまる場合、そのプロセスはフォアグラウンドにあるとみなされます。 +
+ +-
+
- ユーザーが操作している {@link android.app.Activity} のホストになっている({@link +android.app.Activity} の{@link android.app.Activity#onResume onResume()} メソッドが呼び出された)。 + + +
- ユーザーが操作しているアクティビティにバインドされている {@link android.app.Service} のホストになっている。 + + +
- 「フォアグラウンド」 で実行中の {@link android.app.Service} のホストになっている(サービスが {@link android.app.Service#startForeground startForeground()} を呼び出した)。— + + +
- {@link android.app.Service#onCreate onCreate()}、{@link android.app.Service#onStart +onStart()}、{@link android.app.Service#onDestroy onDestroy()} のいずれかのライフサイクル コールバックを実行している {@link android.app.Service} のホストになっている。 + + +
- {@link + android.content.BroadcastReceiver#onReceive onReceive()} メソッドを実行している {@link android.content.BroadcastReceiver} のホストになっている。 +
通常は、2~3 個のフォアグラウンド プロセスが存在します。フォアグラウンド プロセスは、それらすべてを実行できなくなるほどメモリが少なくなると、最終手段として強制終了されます。 +—通常はその時点で、端末がメモリのページング状態に達しているため、ユーザー インターフェースのレスポンシブを維持するには一部のフォアグラウンド プロセスを強制終了する必要があります。 + +
+
+ - 可視プロセス
+
フォアグラウンド コンポーネントはないものの、ユーザーに対して画面上に表示される内容に影響を与える可能性のあるプロセスです。 +次の条件のいずれかにあてはまる場合、そのプロセスは可視プロセスであるとみなされます。 +
+ +-
+
- フォアグラウンドにないが、ユーザーに表示されている {@link android.app.Activity} のホストになっている({@link android.app.Activity#onPause onPause()} メソッドが呼び出された)。 +たとえば、フォアグラウンドのアクティビティがダイアログを開始したときに、前のアクティビティがその背後に見えている場合などがあります。 + + + +
- 可視(またはフォアグラウンドの)アクティビティにバインドされている {@link android.app.Service} のホストになっている。 + +
可視プロセスは非常に重要度が高いため、フォアグラウンド プロセスの実行を維持するのに必要な場合のみ、強制終了されます。 +
+
+
+ - サービス プロセス
+
{@link +android.content.Context#startService startService()} メソッドで開始されたサービスを実行するプロセスで、上の 2 つのカテゴリに分類されないものです。 +サービス プロセスは、ユーザーに表示される内容には直接関係ありませんが、ユーザーにとって必要な操作を実行している場合が多いため(バックグラウンドで音楽を再生したり、ネットワーク経由でデータをダウンロードしたりなど)、フォアグラウンド プロセスと可視プロセスのすべてと合わせて、それらを継続するのにメモリが不足した場合のみ強制終了されます。 + + +
+
+
+ - バックグラウンド プロセス
+
現在ユーザーに表示されていないアクティビティを有するプロセスです(アクティビティの {@link android.app.Activity#onStop onStop()} メソッドが呼び出された)。 +ユーザーの操作性に直接影響を与えるものではなく、フォアグラウンド プロセス、可視プロセス、サービス プロセス用にメモリを回収する必要があればいつでも強制終了されます。 + + +通常はバックグラウンドで実行するプロセスは多数あるため、最近ユーザーに表示されたアクティビティのあるプロセスを最後に強制終了するよう、LRU(最小使用頻度)リストに入れられます。 + +アクティビティがライフサイクル メソッドを正確に実装し、現在の状態を保存する場合は、そのプロセスを強制終了しても、ユーザーがそのアクティビティに戻ったときに、アクティビティがすべての視覚的状態を復元するため、ユーザーの操作性に視覚的な影響はありません + + +。状態の保存と復元の詳細については、「Activities」のドキュメントをご覧ください。 +
+
+
+ - 空のプロセス
+
アクティブなアプリケーション コンポーネントが 1 つも含まれていないプロセスです。このようなプロセスは、プロセスをキャッシュしておくことのみを目的として保持され、次回コンポーネントを実行する際の起動時間を向上させることができます。 + +システムは、プロセスのキャッシュと下層のカーネル キャッシュとの間の全体的なシステム リソースのバランスを整える目的でこれらのシステムを頻繁に強制終了します。 +
+
+
Android では、プロセスで現在アクティブなコンポーネントの重要度に基づいて、あてはまるランクのなかで最も高いランクにプロセスを位置付けます。 +たとえば、サービス アクティビティと可視アクティビティの両方のホストとなっているプロセスは、サービス プロセスではなく、可視プロセスとして位置付けられます。 +
+ +さらに、他のプロセスから依存されているプロセスの位置付けが上がる場合があります。他のプロセスのために動作しているプロセスは、その対象プロセスよりも下に位置付けられることはありません。 +— +たとえば、プロセス A のコンテンツ プロバイダが、プロセス B のクライアントのために動作している場合や、プロセス A のサービスがプロセス B のコンポーネントにバインドされている場合、プロセス A の重要度は常にプロセス B 以上であるとみなされます。 + +
+ +サービスを実行するプロセスは、バックグラウンドのアクティビティを持つプロセスよりも上に位置付けされるため、長時間の操作を開始するアクティビティでは、特に、操作がアクティビティよりも長く続く場合、ワーカー スレッドを作成するよりもその操作のサービスを開始する方がよいと考えられます。たとえば、ウェブサイトに写真をアップロードするアクティビティでは、ユーザーがアクティビティから離れた後もアップロードをバックグラウンドで続行できるよう、アップロードを実行するサービスを開始することをお勧めします。サービスを使用することで、アクティビティの状況に変わらず、その操作に「サービス プロセス」以上の優先度が保証されることになります。 + + + + + +同じ理由から、ブロードキャスト レシーバーでもスレッドに長時間の処理を置くのではなく、サービスを採用するようお勧めします。 +
+ + + + +スレッド
+ +アプリケーション起動の際、システムは アプリケーション実行用のスレッドを作成します。これは、「メイン スレッド」と呼ばれます。 +このスレッドは、イベント(描画イベントを含む)を適切なユーザー インターフェース ウィジェットに送信する役割を担うため非常に重要です。 +また、これはアプリケーションが Android UI ツールキット({@link +android.widget} と {@link android.view} パッケージからのコンポーネント)からのコンポーネントとやり取りをするスレッドでもあります。 +そのため、メイン スレッドは UI スレッドと呼ばれることもあります。 +
+ +コンポーネントのインスタンスごとに別のスレッドが作成されることはありません。同じプロセスで実行するすべてのコンポーネントは UI スレッドでインスタンス化され、スレッドから送られた各コンポーネントをシステムが呼び出します。 + +結果的に、システムのコールバック(ユーザー操作を報告する {@link android.view.View#onKeyDown onKeyDown()} やライフサイクル コールバック メソッドなど)に応答するメソッドは常にプロセスの UI スレッドで実行することになります。 + +
+ +たとえば、ユーザーが画面上のボタンをタッチすると、アプリの UI スレッドがタッチ イベントをウィジェットに送信し、ウィジェットがそのタッチされた状態を設定してイベント キューに無効化の要求を投稿します。 + +UI スレッドが要求をキューから取り出し、ウィジェットに自身を描画するよう通知します。 +
+ +アプリがユーザー操作に応答して集中的な動作を実行する場合、アプリケーションを正しく実装していない限りこのシングル スレッド モデルではパフォーマンスの低下につながる可能性があります。 +具体的には、すべてが UI スレッドで行われている場合、長ネットワークへのアクセスやデータベースへの問い合わせといった時間のかかる操作を実行すると UI 全体をブロックしてしまいます。スレッドがブロックされると、描画イベントを含むすべてのイベントを送信できなくなります。 + + +ユーザー側には、アプリケーションがハングしたように見えます。 +さらには、UI スレッドが数秒以上(現時点では 5 秒以上)ブロックされると、ユーザーに「アプリケーションが応答していません」のダイアログが表示されます。 + +ユーザーはアプリケーションを停止するか、不快な場合はアンインストールしてしまう可能性があります。 +
+ +また、Android UI ツールキットはスレッド セーフではありません。そのため、ワーカー スレッドから UI を操作できません。すべての操作は、UI スレッドから行う必要があります。 +— +そのため、Android のシングル スレッド モデルには 2 つの明快なルールがあります。
+ +-
+
- UI スレッドをブロックしない +
- UI スレッド以外から Android UI ツールキットにアクセスしない +
ワーカー スレッド
+ +上記で説明したシングル スレッド モデルにより、アプリケーションの UI の応答性のためにも UI スレッドをブロックしないことが不可欠です。 +即座に実行する必要のない操作の場合は、別のスレッド(「バックグラウンド」スレッドや「ワーカー」スレッド)で実行するようにする必要があります。 + +
+ +例として、別のスレッドから画像をダウンロードして {@link android.widget.ImageView} に表示するクリック リスナのコードの一部を次に示します。 +
+ ++public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + Bitmap b = loadImageFromNetwork("http://example.com/image.png"); + mImageView.setImageBitmap(b); + } + }).start(); +} ++ +
ここでは、ネットワークの操作を処理する新しいスレッドを作成しているため、一見問題ないように見えます。 +ただし、これはUI スレッド以外から Android UI ツールキットにアクセスしないというシングルスレッド モデルの 2 つ目のルールに違反しています。このサンプルは、UI スレッドではなくワーカー スレッドから {@link +android.widget.ImageView} を変更しています。— +結果として、未定義かつ予想外の動作を引き起こし、追跡が難しく時間のかかる作業になってしまいます。 +
+ +この問題を修正するため、Android には UI スレッド以外からのアクセス方法がいくつか用意されています。 +使用できるメソッドは次のとおりです。
+ +-
+
- {@link android.app.Activity#runOnUiThread(java.lang.Runnable) +Activity.runOnUiThread(Runnable)} +
- {@link android.view.View#post(java.lang.Runnable) View.post(Runnable)} +
- {@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable, +long)} +
たとえば、上記のコードは {@link +android.view.View#post(java.lang.Runnable) View.post(Runnable)} メソッドを使用して修正できます。
+ ++public void onClick(View v) { + new Thread(new Runnable() { + public void run() { + final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); + mImageView.post(new Runnable() { + public void run() { + mImageView.setImageBitmap(bitmap); + } + }); + } + }).start(); +} ++ +
これで、この実装がスレッドセーフになりました。ネットワーク操作は別のスレッドから実行され、{@link android.widget.ImageView} は UI スレッドから操作されます。 +
+ +ただし、操作が複雑になるにつれて、この種のコードも複雑化してメンテナンスも難しくなります。 +ワーカー スレッドとのより複雑なやり取りを処理するため、ワーカー スレッドで {@link android.os.Handler} を使うと、UI スレッドから配信されたメッセージを処理できます。 + +ただし、最善なのは{@link android.os.AsyncTask} クラスを拡張することであり、これにより UI を操作する必要のあるワーカー スレッドのタスクの実行を簡素化できます。 +
+ + +AsyncTask を使用する
+ +{@link android.os.AsyncTask} では、ユーザー インターフェースに非同期の処理を実行できます。 +スレッドやハンドラを自身で処理する必要なく、ワーカー スレッドの操作をブロックし、結果を UI スレッドに発行します。 +
+ +これを使用するには、{@link android.os.AsyncTask} をサブクラス化し、バックグラウンド スレッドのプール内で実行する {@link +android.os.AsyncTask#doInBackground doInBackground()} コールバック メソッドを実装する必要があります。 +UI を更新するには、{@link +android.os.AsyncTask#onPostExecute onPostExecute()} を実装します。これは {@link +android.os.AsyncTask#doInBackground doInBackground()} からの結果を配信し、UI スレッド内で実行されるため、UI を安全に更新できます。その後、UI スレッドから {@link android.os.AsyncTask#execute execute()} を呼び出してタスクを実行できます。 + +
+ +たとえば、次のように {@link android.os.AsyncTask} を使って前出の例を実装できます。 +
+ ++public void onClick(View v) { + new DownloadImageTask().execute("http://example.com/image.png"); +} + +private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { + /** The system calls this to perform work in a worker thread and + * delivers it the parameters given to AsyncTask.execute() */ + protected Bitmap doInBackground(String... urls) { + return loadImageFromNetwork(urls[0]); + } + + /** The system calls this to perform work in the UI thread and delivers + * the result from doInBackground() */ + protected void onPostExecute(Bitmap result) { + mImageView.setImageBitmap(result); + } +} ++ +
ワーカー スレッドで処理される作業と、UI スレッドで処理される作業が分けられたため、UI は安全に、コードはシンプルになりました。 +
+ +このクラスの使用方法をより深く理解するには {@link android.os.AsyncTask} に目を通す必要がありますが、ここに、その仕組みについて簡単に挙げておきます。 +
+ +-
+
- ジェネリックを使ってパラメータのタイプ、進捗の値、タスクの最終値を指定できます + +
- {@link android.os.AsyncTask#doInBackground doInBackground()} メソッドがワーカー スレッド上で自動的に実行されます + +
- {@link android.os.AsyncTask#onPreExecute onPreExecute()}、{@link +android.os.AsyncTask#onPostExecute onPostExecute()}、{@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()}はすべて UI スレッドで呼び出されます +
- {@link android.os.AsyncTask#doInBackground doInBackground()} から返される値は、{@link android.os.AsyncTask#onPostExecute onPostExecute()} に送られます + +
- {@link android.os.AsyncTask#publishProgress publishProgress()} は、{@link +android.os.AsyncTask#doInBackground doInBackground()} でいつでも呼び出すことができます。UI スレッドで {@link +android.os.AsyncTask#onProgressUpdate onProgressUpdate()} を実行できます +
- いつでも、どのスレッドからでもタスクをキャンセルできます +
警告: ワーカー スレッドの使用時に発生する可能性のあるもう 1 つの問題として、実行時の設定が変更された(ユーザーが画面の向きを変えた場合など)ことによってアクティビティが予期せず再起動され、ワーカー スレッドが破棄されてしまうことがあります。 + +このような再起動の間タスクを維持する方法、アクティビティが破棄されたときの正しいタスクのキャンセル方法については、Shelves のサンプル アプリケーションのソース コードをご覧ください。 + +
+ + +スレッド セーフのメソッド
+ +状況によっては、実装したメソッドが複数のスレッドから呼び出されることがあり、その場合はメソッドがスレッドセーフになるよう作成する必要があります。 +
+ +主に、バインドされたサービスのメソッドなど、リモートで呼び出されるメソッドなどがこれに該当します。—{@link android.os.IBinder} に実装されたメソッドへの呼び出しが、{@link android.os.IBinder IBinder} を実行しているプロセスと同じプロセスで発生した場合、メソッドは呼び出し側のスレッドで実行されます。ただし、呼び出しが別のプロセスで起こった場合は、メソッドはシステムが {@link android.os.IBinder +IBinder} と同じプロセスに保持するスレッドのプールから選ばれたスレッドで実行されます(プロセスの UI スレッドでは実行されません)。 + + + +たとえば、サービスの {@link android.app.Service#onBind onBind()} メソッドがサービスのプロセスの UI スレッドから呼び出されるのに対して、{@link android.app.Service#onBind +onBind()} が返すオブジェクトで実装されたメソッド(RPC メソッドを実装するサブクラスなど)は、プール内のスレッドから呼び出されます。 + + +サービスは複数のクライアントを持てるため、複数のプール スレッドが同じ {@link android.os.IBinder IBinder} メソッドを同時に動かすことができます。このため、{@link android.os.IBinder +IBinder} メソッドはスレッドセーフになるよう実装する必要があります。 +
+ +同様に、コンテンツ プロバイダは他のプロセスから送られたデータ要求を受け取ることができます。{@link android.content.ContentResolver} クラスと {@link android.content.ContentProvider} クラスによってプロセス間通信がどのように管理されているかが見えなくなりますが、それらの要求に応答する {@link +android.content.ContentProvider} メソッド({@link +android.content.ContentProvider#query query()}、 {@link android.content.ContentProvider#insert +insert()}、{@link android.content.ContentProvider#delete delete()}、{@link +android.content.ContentProvider#update update()}、{@link android.content.ContentProvider#getType +getType()})は、プロセスの UI スレッドではなく、コンテンツ プロバイダのプロセスにあるスレッドのプールから呼び出されます。 + + +——これらのメソッドは同時に複数のスレッドから呼び出される可能性があるため、先ほどと同様にスレッドセーフになるよう実装する必要があります。 +
+ + +プロセス間通信(IPC)
+ +Android では、リモート プロシージャ コール(RPC)を使ったプロセス間通信のメカニズムを備えており、メソッドはアクティビティや他のアプリケーション コンポーネントから呼び出された後に、リモート(別のプロセス)で実行され、結果を呼び出し側に返します。 + + +これにより、メソッドの呼び出しとそのデータをオペレーティング システムが理解できるレベルまで分解し、ローカル プロセスとアドレス空間からリモート プロセスとアドレス空間にそれを送信して、そこで呼び出しが再度組み立てて、再現します。 + +その後、戻り値が逆方向に伝達されます。 +Android ではこれらの IPC トランザクションを実行するためのすべてのコードが用意されているため、開発者は RPC のプログラミング インターフェースの定義と実装に集中できます。 +
+ +IPC を実行するには、アプリケーションが {@link +android.content.Context#bindService bindService()} を使ってサービスにバインドされている必要があります。詳細については、デベロッパー ガイドの「サービス」をご覧ください。
+ + + diff --git a/docs/html-intl/intl/ja/guide/components/recents.jd b/docs/html-intl/intl/ja/guide/components/recents.jd new file mode 100644 index 0000000000000000000000000000000000000000..81626e1f2925adb3ce0c6c8a436da4cf5203a200 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/recents.jd @@ -0,0 +1,256 @@ +page.title=オーバービュー画面 +page.tags="recents","overview" + +@jd:body + +本書の内容
+-
+
- オーバービュー画面にタスクを追加する + + +
- タスクを削除する + + +
キークラス
+-
+
- {@link android.app.ActivityManager.AppTask} +
- {@link android.content.Intent} +
サンプル コード
+-
+
- ドキュメント中心のアプリ +
オーバービュー画面(別名、最近使った画面、最近使ったタスクリスト、最近使ったアプリ)は、最近アクセスしたアクティビティやタスクの一覧を示すシステムレベルの UI です。 + +ユーザーはリスト内をナビゲートして再開するタスクを選択したり、スワイプしてタスクをリストから削除したりできます。 + +Android 5.0(API レベル 21)のリリースでは、異なるドキュメントを持つ同一アクティビティ内の複数のインスタンスが、1 つのタスクとしてオーバービュー画面に表示される場合があります。 +たとえば、Google ドライブには複数の Google ドキュメントごとのタスクが表示される場合があります。 +オーバービュー画面には、各ドキュメントが 1 つのタスクとして表示されます。 +
+ + + + +通常、オーバービュー画面にタスクとアクティビティを提示する方法はシステムが定義できるよう許可し、この動作を変更する必要はありません。
+ただし、アクティビティをいつ、どのようにオーバービュー画面に表示するかをアプリで決定することもできます。
+{@link android.app.ActivityManager.AppTask} クラスを使ってタスクを管理でき、{@link android.content.Intent} クラスのアクティビティ フラグを使うとアプリをオーバービュー画面に追加、削除するタイミングを指定できます。
+
+
+また、
+<activity>
属性を使ってマニフェストで動作を設定することもできます。
オーバービュー画面にタスクを追加する
+ +{@link android.content.Intent} クラスのフラグを使用してタスクを追加すると、ドキュメントをいつ、どのようにオーバービュー画面で開いたり、再度開いたりできるかを細かく制御できます。
+<activity>
属性を使用すると、常に新しいタスクでドキュメントを開くか、ドキュメントの既存のタスクを再利用するかを選択できます。
+
+
+
インテント フラグを使用してタスクを追加する
+ +アクティビティの新しいドキュメントを作成するときは、{@link android.app.ActivityManager.AppTask} クラスの {@link android.app.ActivityManager.AppTask#startActivity(android.content.Context, android.content.Intent, android.os.Bundle) startActivity()} メソッドを呼び出し、アクティビティを起動するインテントを渡します。 + + +論理的な改行を挿入して、システムがアクティビティをオーバービュー画面の新しいタスクとして扱えるようにするには、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグを、アクティビティを起動する {@link android.content.Intent} の {@link android.content.Intent#addFlags(int) addFlags()} メソッドに渡します。 + + +
+ +注: {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグは、Android 5.1(API レベル 21)で廃止された {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET} を置き換えるものです。 + +
+ +新しいドキュメントの作成時に {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグを設定すると、システムは常にターゲット アクティビティの新しいタスクをルートとして作成するようになります。この設定によって、同じドキュメントを複数のタスクで開くことが可能になります。 + +これをメインのアクティビティが行う方法を、次のコードで示し舞うs。 +
+ + ++public void createNewDocument(View view) { + final Intent newDocumentIntent = newDocumentIntent(); + if (useMultipleTasks) { + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + } + startActivity(newDocumentIntent); + } + + private Intent newDocumentIntent() { + boolean useMultipleTasks = mCheckbox.isChecked(); + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; + } + + private static int incrementAndGet() { + Log.d(TAG, "incrementAndGet(): " + mDocumentCounter); + return mDocumentCounter++; + } +} ++ +
注: {@code FLAG_ACTIVITY_NEW_DOCUMENT} フラグを使って起動されたアクティビティには、マニフェスト ファイルで {@code android:launchMode="standard"} 属性の値(デフォルト)が設定されている必要があります。 + +
+ +メイン アクティビティが新しいアクティビティを起動するとき、システムはアクティビティのインテント コンポーネント名とインテント データに一致するインテントを持つ既存のタスクを検索します。 +タスクが見つからない場合や、インテントに {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグに含まれている場合は、新しいタスクがアクティビティのルートとして作成されます。 + +タスク見つかった場合は、そのタスクをフロントに移動して、新しいインテントを {@link android.app.Activity#onNewIntent onNewIntent()} に渡します。新しいアクティビティがインテントを受け取り、次の例のようにオーバービュー画面に新しいドキュメントを作成します。 + + +
+ + ++@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_new_document); + mDocumentCount = getIntent() + .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0); + mDocumentCounterTextView = (TextView) findViewById( + R.id.hello_new_document_text_view); + setDocumentCounterText(R.string.hello_new_document_counter); +} + +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity + is reused to create a new document. + */ + setDocumentCounterText(R.string.reusing_document_counter); +} ++ + +
アクティビティの属性を使用してタスクを追加する
+ +アクティビティのマニフェストで、<activity>
の属性の{@code android:documentLaunchMode} を使ってアクティビティを常に新しいタスクで起動するよう指定することもできます。
+
+
+この属性には 4 つの値があり、ユーザーがアプリケーションでドキュメントを開くときに次のような効果を生みます。
+
-
+
- 「{@code intoExisting}」 +
- アクティビティがそのドキュメントの既存のタスクを再利用します。これは、インテント フラグを使用してタスクを追加するで説明したように、{@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグを設定せずに、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグを設定した場合と同じです。 + + + + +
- 「{@code always}」 +
- ドキュメントが既に開いている場合でも、アクティビティがドキュメントの新しいタスクを作成します。これは、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグと {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグの両方を設定した場合と同じです。 + + + +
- 「{@code none”}」 +
- アクティビティはドキュメントの新しいタスクを作成しません。オーバービュー画面はデフォルトでアクティビティがタスクを作成したかのように処理し、アプリの 1 つのタスクを表示して、ユーザーが最後に呼び出したアクティビティから再開します。 + + + +
- 「{@code never}」 +
- アクティビティはドキュメントの新しいタスクを作成しません。この値を設定すると、{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} フラグと {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK} フラグのいずれかが設定されている場合にその動作をオーバーライドし、オーバービュー画面にはアプリの 1 つのタスクが表示され、ユーザーが最後に呼び出したアクティビティから再開します。 + + + + +
注: {@code none} と {@code never} の値以外の場合、アクティビティを {@code launchMode="standard"} を使って定義する必要があります。 +属性が指定されていない場合は、{@code documentLaunchMode="none"} が使用されます。 +
+ +タスクを削除する
+ +デフォルトで、アクティビティの完了時にドキュメントのタスクはオーバービュー画面から自動的に削除されます。
+この動作は、{@link android.app.ActivityManager.AppTask} クラスで {@link android.content.Intent} フラグを使うか、
+<activity>
属性を使ってオーバーライドできます。
+
<activity>
属性の {@code android:excludeFromRecents} を {@code true} に設定すると、タスクを常にオーバービュー画面から完全に除外することができます。
+
+
+
アプリがオーバービュー画面に表示できるタスクの最大数を設定するには、<activity>
属性の {@code android:maxRecents} に整数値を設定します。
+
+
+デフォルトでは 16 に設定されています。タスクの最大数に達すると、最も古いタスクがオーバービュー画面から削除されます。
+{@code android:maxRecents} の最大値は 50(低メモリの端末では 25)で、1 未満の値は無効です。
+
AppTask クラスを使用してタスクを削除する
+ +オーバービュー画面に新しいタスクを作成するアクティビティで {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()} を呼び出すと、タスクを削除して関連アクティビティのすべてを終了させるタイミングを指定できます。 + +
+ + ++public void onRemoveFromRecents(View view) { + // The document is no longer needed; remove its task. + finishAndRemoveTask(); +} ++ +
注: {@link android.app.ActivityManager.AppTask#finishAndRemoveTask() finishAndRemoveTask()} メソッドを使用すると、次のセクションで説明する {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} タグの使用がオーバーライドされます。 + + +
+ +完了したタスクを保持する
+ +アクティビティの終了後もオーバービュー画面にタスクを保持する場合は、{@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} フラグを、アクティビティを起動するインテントの {@link android.content.Intent#addFlags(int) addFlags()} メソッドに渡します。 + +
+ + ++private Intent newDocumentIntent() { + final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class); + newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | + android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); + newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet()); + return newDocumentIntent; +} ++ +
<activity>
属性の {@code android:autoRemoveFromRecents} を {@code false} に設定することでも同じ効果を得られます。
+
+
+ドキュメントのアクティビティのデフォルト値は {@code true}、通常のアクティビティでは {@code false} になります。
+この属性を使用すると、前のセクションで説明した {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS} フラグがオーバーライドされます。
+
-
+
- 基本 +
- マニフェストでサービスを宣言する +
- 開始されたサービスを作成する + + +
- バインドされたサービスを作成する +
- ユーザーに通知を送信する +
- サービスをフォアグラウンドで実行する +
- サービスのライフサイクルを管理する + + +
- {@link android.app.Service} +
- {@link android.app.IntentService} +
- バインドされたサービス +
本書の内容
+-
+
-
+
キークラス
+-
+
サンプル
+ + +関連ドキュメント
+-
+
{@link android.app.Service} は、バックグラウンドで長時間動作して作業を行い、ユーザー インターフェースを表示しないアプリケーション コンポーネントです。 +別のアプリケーション コンポーネントがサービスを開始し、ユーザーが他のアプリケーションに切り替えた場合でも、サービスはバックグラウンドで実行し続けることができます。 + +さらに、コンポーネントをサービスにバインドして操作したり、プロセス間通信(IPC)を実行したりすることも可能です。 +たとえば、サービスはネットワーク トランザクションの処理、音楽の再生、ファイルの I/O の実行、コンテンツ プロバイダとのやり取りなどのすべてをバックグラウンドで行うことができます。 + +
+ +サービスには、基本的に次の 2 つの形式があります。
+ +-
+
- 開始されたサービス +
- アプリケーション コンポーネント(アクティビティなど)が {@link android.content.Context#startService startService()} を呼び出して開始したときに、サービスが「開始された」状態になります。 +一旦開始されると、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 +通常、開始されたサービスは 1 つの操作を実行するだけで、呼び出し元に結果を返すことはありません。たとえば、サービスはネットワーク上でファイルのダウンロードやアップロードを行います。 + +操作が完了すると、サービスは自身で停止する必要があります。 + +
- バインドされたサービス +
- アプリケーション コンポーネントが {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドすると、サービスは「バインドされた」状態になります。バインドされたサービスは、コンポーネントがサービスを操作したり、要求を送信したり、結果を取得したり、さらにはプロセス間通信(IPC)でもそれを行えるクライアントサーバー型インターフェースを提供します。 + +バインドされたサービスは、他のアプリケーション コンポーネントがそれにバインドしている限り実行し続けます。 +サービスには同時に複数のコンポーネントがバインドできますが、すべてがアンバインドされると、サービスは破棄されます。 + +
このドキュメントではこの 2 種類のサービスそれぞれの概要について説明しますが、サービスは開始された状態(無期限に実行)、バインドされた状態のどちらの方法でも動作できます。これは、2 つのコールバック メソッドを実装するかどうかの問題で、{@link +android.app.Service#onStartCommand onStartCommand()} ではコンポーネントにサービスの開始を許可し、{@link +android.app.Service#onBind onBind()} ではバインドを許可することになります。 + +
+ +アプリケーションが開始された、バインドされた、またはその両方かであるかどうかにかかわらず、どんなコンポーネントでもアクティビティを使用できるのと同じように、{@link android.content.Intent} を使って開始することで、どんなアプリケーション コンポーネントでもサービスを使用できます。 + +—ただし、マニフェスト ファイルでサービスを非公開として宣言して、他のアプリケーションからのアクセスをブロックすることもできます。 +詳細については、マニフェストでサービスを宣言するで説明します。 + +
+ +警告: サービスは、そのホスト プロセスのメインスレッドで実行します。サービスが自身のスレッドを作成することはなく、別のプロセスで実行されることもありません(別の方法を指定しない限り)。 +— +つまり、サービスが CPU を集中的に使ったり、ブロック操作を行ったりするような場合(MP3 の再生やネットワーク作業)は、サービス内に新しいスレッドを作成してその作業を行う必要があります。 + +別のスレッドを使うことで、「アプリケーションが応答していません (ANR)」のエラーが発生するリスクを軽減でき、アプリケーションのメインスレッドをアクティビティのユーザー操作専用にすることができます。 + +
+ + +基本
+ +サービスとスレッド、どちらを使用すべきか。
+サービスは、ユーザーがアプリケーションを操作していない間もバックグラウンドで実行できるコンポーネントにすぎません。 +そのような必要性がある場合に限り、サービスを作成します。 +
+ユーザーがアプリケーションを操作している間だけ、メインスレッド外で作業を行う必要がある場合は、サービスではなくスレッドを作成することをお勧めします。 +たとえば、アクティビティを実行している間だけ音楽を再生する場合は、{@link android.app.Activity#onCreate onCreate()} にスレッドを作成し、{@link +android.app.Activity#onStart onStart()} で実行を開始して、{@link android.app.Activity#onStop +onStop()} で停止します。 + +また、従来の {@link java.lang.Thread} クラスの代わりに {@link android.os.AsyncTask} や {@link android.os.HandlerThread} を使用する方法もあります。 +スレッドの詳細については、「プロセスとスレッド」のドキュメントをご覧ください。 +
+サービスを使用する際は、デフォルトではアプリケーションのメインスレッドで実行されるため、集中的な作業やブロック操作を行う場合はサービス内に新しいスレッドを作成する必要があることに注意してください。 + +
+サービスを作成するには、{@link android.app.Service} のサブクラス(またはその既存のサブクラス)を作成する必要があります。 +実装時には、サービスのライフサイクルの重要側面を扱うコールバック メソッドをオーバーライドして、必要に応じてサービスにバインドするためのメカニズムをコンポーネントに提供する必要があります。 + +オーバーライドする必要のある、最も重要なコールバック メソッドは次の 2 つです。
+ +-
+
- {@link android.app.Service#onStartCommand onStartCommand()} +
- アクティビティなどの他のコンポーネントが、{@link android.content.Context#startService +startService()} を呼び出してサービスの開始を要求したときに、システムがこのメソッドを呼び出します。 +このメソッドが実行されるとサービスは開始され、バックグラウンドで無期限に実行します。 +これを実装すると、作業完了時に {@link android.app.Service#stopSelf stopSelf()} か {@link +android.content.Context#stopService stopService()} を呼び出して自身でサービスを停止する必要があります +(バインドのみを提供する場合は、このメソッドを実装する必要はありません)。 + +
- {@link android.app.Service#onBind onBind()} +
- {@link android.content.Context#bindService +bindService()} を呼び出して他のコンポーネントをサービスにバインドさせるとき(RPC 実行時など)に、システムがこのメソッドを呼び出します。 +このメソッドの実装時には、{@link android.os.IBinder} を返してクライアントがサービスとの通信に使うインターフェースを提供する必要があります。 +このメソッドの実装は常に必要ですが、バインドを許可しない場合は、null を返す必要があります。 + +
- {@link android.app.Service#onCreate()} +
- サービスが始めて作成されたときに、1 回限りのセットアップ処理を実行するためにシステムがこのメソッドを呼び出します({@link android.app.Service#onStartCommand onStartCommand()} か {@link android.app.Service#onBind onBind()} のいずれかを呼び出す前)。 + +サービスが既に実行中の場合、このメソッドは呼び出されません。 + +
- {@link android.app.Service#onDestroy()} +
- サービスがもう使用されておらず破棄されたときに、システムがこのメソッドを呼び出します。これは、スレッドや登録されたリスナ、レシーバーなどをクリーンアップするためにサービスに実装する必要があります。 + +これが、サービスが受け取る最後の呼び出しになります。 +
コンポーネントが {@link +android.content.Context#startService startService()} を呼び出してサービスを開始すると(結果的に {@link +android.app.Service#onStartCommand onStartCommand()} が呼び出される)、{@link android.app.Service#stopSelf()} を使ってサービス自身が停止するか、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止するまで、サービスは実行し続けます。 + +
+ +コンポーネントが {@link android.content.Context#bindService bindService()} を呼び出してサービスを作成した(そして {@link +android.app.Service#onStartCommand onStartCommand()} が呼び出されていない)場合、サービスはコンポーネントにバインドされている間のみ実行します。 + +すべてのクライアントからアンバインドされると、サービスはシステムによって破棄されます。 +
+ +Android システムは メモリが少なくなって、ユーザーが使用しているアクティビティ用のシステムリソースを回復させる必要が生じた場合のみ、サービスを強制的に停止させます。 +サービスがユーザーが使用しているアクティビティにバインドされている場合は、それが強制終了される可能性は低く、フォアグラウンドで実行(後で説明)するように宣言されている場合は、強制終了されることはほとんどありません。一方で、サービスが開始されてから長時間実行している場合は、システムはバックグラウンド タスクのリストにおけるその位置付けを徐々に低くし、そのサービスが強制終了される確率が高くなります。開始されたサービスを作成する際は、システムによる再起動を円滑に処理するようデザインする必要があります。 + + + +— +システムがサービスを強制終了すると、リソースが回復次第そのサービスが再起動します(後述の {@link +android.app.Service#onStartCommand onStartCommand()} から返される値にもよります)。 +システムがサービスを破棄するタイミングについては、「Processes and Threading」のドキュメントをご覧ください。 + +
+ +次のセクションでは、それぞれのタイプのサービスの作成方法と、他のアプリケーション コンポーネントからの使用方法について説明します。 +
+ + + +マニフェストでサービスを宣言する
+ +アクティビティ(や他のコンポーネント)と同様に、すべてのサービスをアプリケーションのマニフェスト ファイルで宣言する必要があります。 +
+ +サービスを宣言するには、{@code <service>} 要素を {@code <application>} の子要素として追加します。 + +次に例を示します。
+ ++<manifest ... > + ... + <application ... > + <service android:name=".ExampleService" /> + ... + </application> +</manifest> ++ +
マニフェストでのサービスの宣言に関する詳細については、{@code <service>} 要素のリファレンスをご覧ください。 +
+ +{@code <service>} に含めることで、サービスやサービスを実行するプロセスの開始に必要なパーミッションなどのプロパティを定義できる他の属性がいくつかあります。 + +{@code android:name} 属性は唯一の必須属性で、サービスのクラス名を指定します。 +—アプリケーションを発行したら、この名前は変更できません。変更すると、サービスを開始したりバインドしたりする明示的インテントの依存関係によってコードを破損する可能性があります(ブログの投稿「Things That Cannot Change」をご覧ください)。 + + + + +
アプリの安全性を保つため、{@link android.app.Service}を開始したりバインドしたりするときは、常に明示的インテントを使用し、サービスでインテント フィルタを宣言しないようにしてください。 +どのサービスを開始するかについて、ある程度のあいまい静を残しておく必要がある場合は、サービスにインテント フィルタを定義でき、{@link +android.content.Intent} からコンポーネント名を除外して、その後ターゲットのサービスのあいまい性を十分に解消する {@link +android.content.Intent#setPackage setPackage()} でインテントのパッケージを設定する必要があります。 + + +
+ +さらに、{@code android:exported} 属性を含めて {@code "false"} に設定すると、サービスを自身のアプリでしか利用できないようにできます。 + +これにより、他のアプリによるサービスの開始を効果的に回避でき、たとえ明示的インテントを使用したとしても開始できなくなります。 +
+ + + + +開始されたサービスを作成する
+ +開始されたサービスは、他のコンポーネントが {@link +android.content.Context#startService startService()} を呼び出すことで結果的にサービスの {@link android.app.Service#onStartCommand onStartCommand()} メソッドを呼び出して開始されたサービスです。 +
+ +サービスが開始されると、サービスはそれを開始したコンポーネントから独立したライフサイクルを持ち、たとえ開始したコンポーネントが破棄されても、サービスは無期限に実行できます。 + +そのため、サービスはジョブが完了したら {@link android.app.Service#stopSelf stopSelf()} を呼び出して自身で停止する必要があり、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止することもできます。 + +
+ +アクティビティなどのアプリケーション コンポーネントは、{@link +android.content.Context#startService startService()} を呼び出して、サービスを指定し、サービスが使用するデータを含めた {@link android.content.Intent} を渡してサービスを開始できます。 +サービスはこの {@link android.content.Intent} を、{@link android.app.Service#onStartCommand +onStartCommand()} メソッドで受け取ります。 +
+ +たとえば、オンライン データベースにデータを保存する必要のあるアクティビティがあるとします。アクティビティでサービスを開始し、{@link +android.content.Context#startService startService()} にインテントを渡して、保存するデータをサービスに配信します。 +サービスはインテントを {@link +android.app.Service#onStartCommand onStartCommand()} で受け取り、インターネットに接続してデータベースのトランザクションを実行します。 +トランザクションが完了したら、サービスは自身で停止し、破棄されます。 +
+ +警告: デフォルトでは、アプリケーションで宣言されたサービスは、アプリケーションと同じプロセスで、そのアプリケーションのメインスレッドで実行します。 +そのため、ユーザーが同じアプリケーションのアクティビティを操作している間に、サービスが集中的な処理やブロック操作を実行すると、アクティビティのパフォーマンスが低下します。 + +アプリケーションのパフォーマンスへの影響を回避するには、サービス内で新しいスレッドを開始する必要があります。 +
+ +従来どおり、開始されたサービスを作成するために拡張できるクラスが 2 つあります。
+-
+
- {@link android.app.Service} +
- これは、すべてのサービスの基本クラスです。サービスはデフォルトでアプリケーションのメインスレッドを使用し、アプリケーションが実行しているアクティビティのパフォーマンスを低下させることがあるため、このクラスを拡張するときは、サービスのすべての作業を行うための新しいスレッドを作成することが重要です。 + + + +
- {@link android.app.IntentService} +
- すべての開始要求を一件ずつ処理するワーカー スレッドを使用した {@link android.app.Service} のサブクラスです。 +サービスで同時に複数の要求を処理する必要がない場合は、これが最適です。 +{@link +android.app.IntentService#onHandleIntent onHandleIntent()} を実装するだけで、それぞれの開始要求のインテントを受け取り、バックグラウンドでの処理が可能になります。 + +
次のセクションでは、これらいずれかのクラスを使用してサービスを実装する方法について説明します。 +
+ + +IntentService クラスを拡張する
+ +開始されたサービスで同時に複数の要求を処理する必要があることはほとんどないため(実際には危険なマルチスレッド シナリオになります)、{@link android.app.IntentService} クラスを使用してサービスを実装するのが最適だと考えられます。 + +
+ +{@link android.app.IntentService} は、次の操作を行います。
+ +-
+
- アプリケーションのメインスレッドとは別の {@link +android.app.Service#onStartCommand onStartCommand()} に配信されるすべてのインテントを実行する、デフォルトのワーカー スレッドを作成します。 + +
- マルチスレッドの懸念を排除するため、一度に 1 つのインテントを {@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装に渡すワークキューを作成します。 + +
- {@link android.app.Service#stopSelf} を呼び出す必要がないよう、すべての開始要求の処理後にサービスを停止します。 + +
- Null を返す {@link android.app.IntentService#onBind onBind()} のデフォルト実装を提供します。 + +
- インテントをワークキュー、{@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装の順に送信する {@link android.app.IntentService#onStartCommand +onStartCommand()} のデフォルト実装を提供します。 +
上記すべての操作が行われることで、開発者が行う必要があるのは、クライアントから指示された内容を処理する {@link +android.app.IntentService#onHandleIntent onHandleIntent()} を実装するだけになります +(ただし、サービスの小さいコンストラクタを提供する必要はあります)。
+ +{@link android.app.IntentService} の実装例を次に示します。
+ ++public class HelloIntentService extends IntentService { + + /** + * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} + * constructor with a name for the worker thread. + */ + public HelloIntentService() { + super("HelloIntentService"); + } + + /** + * The IntentService calls this method from the default worker thread with + * the intent that started the service. When this method returns, IntentService + * stops the service, as appropriate. + */ + @Override + protected void onHandleIntent(Intent intent) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + } +} ++ +
コンストラクタと {@link +android.app.IntentService#onHandleIntent onHandleIntent()} の実装、必要なのはこれだけです。
+ +{@link +android.app.IntentService#onCreate onCreate()}、{@link +android.app.IntentService#onStartCommand onStartCommand()}、{@link +android.app.IntentService#onDestroy onDestroy()} などの他のコールバック メソッドもオーバーライドする場合は、{@link android.app.IntentService} がワーカー スレッドの生存状態を正しく処理できるよう、必ず super を実装するようにします。 +
+ +たとえば、{@link android.app.IntentService#onStartCommand onStartCommand()} はデフォルト実装を返す必要があります(これによりインテントが {@link +android.app.IntentService#onHandleIntent onHandleIntent()} に配信されます)。 +
+ ++@Override +public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + return super.onStartCommand(intent,flags,startId); +} ++ +
{@link android.app.IntentService#onHandleIntent onHandleIntent()} 以外で、super クラスを呼び出す必要のないメソッドは、{@link android.app.IntentService#onBind +onBind()} です(ただし、サービスでバインドを許可している場合のみ実装が必要です)。 +
+ +次のセクションでは、この種のサービスが、基本の {@link android.app.Service} クラスを拡張したときにどのように実装されるかを説明します。 +これにはさらに多くのコードがありますが、開始要求の同時処理が必要な場合には適しています。 +
+ + +Service クラスを拡張する
+ +前のセクションで説明したように、{@link android.app.IntentService} を使用すると開始されたサービスの実装が非常に簡単になります。 +ただし、サービスでマルチスレッドを実行する必要がある場合(開始要求をワークキュー経由で処理するのではなく)、{@link android.app.Service} クラスを拡張して、それぞれのインテントを処理できます。 + +
+ +比較のために、{@link +android.app.IntentService} を使用した上記の例とまったく同じ処理を実行する {@link +android.app.Service} クラスの実装の例が次のコードです。つまり、それぞれの開始要求に対し、ワーカー スレッドを使用してジョブとプロセスを実行し、一度に 1 つの要求のみを処理します。 +
+ ++public class HelloService extends Service { + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + // Normally we would do some work here, like download a file. + // For our sample, we just sleep for 5 seconds. + long endTime = System.currentTimeMillis() + 5*1000; + while (System.currentTimeMillis() < endTime) { + synchronized (this) { + try { + wait(endTime - System.currentTimeMillis()); + } catch (Exception e) { + } + } + } + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); + + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, restart + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + } +} ++ +
このように、{@link android.app.IntentService} を使う場合よりもかなり面倒です。
+ +ただし、{@link android.app.Service#onStartCommand +onStartCommand()} への各呼び出しを自身で処理するため、同時に複数の要求を実行することも可能です。この例にはあてはまりませんが、自身の状況に合う場合は、要求ごとに新しいスレッドを作成し、すぐに実行することもできます(前の要求が完了するのを待つ必要がありません)。 + +
+ +{@link android.app.Service#onStartCommand onStartCommand()} メソッドは整数を返す必要があることに注意してください。 +整数は、システムがサービスを強制終了した場合に、サービスをどのように続行させるかを記述する値です(前述したように、{@link +android.app.IntentService} のデフォルト実装が代わりにこれを処理しますが、自身で修正することもできます)。 +{@link android.app.Service#onStartCommand onStartCommand()} から返される値は、次のいずれかの定数である必要があります。 + +
+ +-
+
- {@link android.app.Service#START_NOT_STICKY} +
- {@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、配信が保留中のインテントがない限りシステムはサービスを再作成しません。 +これは、サービスが不必要で、アプリケーションが未完了のジョブを再開できる場合にサービスを実行してしまうのを回避できる最も安全な選択肢です。 + +
- {@link android.app.Service#START_STICKY} +
- {@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、{@link +android.app.Service#onStartCommand onStartCommand()} を呼び出しますが、最後のインテントは再配信しません。代わりに、サービスを開始するインテントが保留になっている場合を除いて、システムは {@link android.app.Service#onStartCommand onStartCommand()} を null インテントを使って呼び出します。保留中のインテントがある場合、そのインテントは配信されます。 + + +これは、コマンドは実行しないが、無期限に実行し、ジョブを待機するメディア プレーヤー(や同様のサービス)に適しています。 + +
- {@link android.app.Service#START_REDELIVER_INTENT} +
- {@link android.app.Service#onStartCommand +onStartCommand()} から戻った後でシステムがサービスを強制終了した場合は、サービスを再作成し、サービスに最後に配信されたインテントで {@link +android.app.Service#onStartCommand onStartCommand()} を呼び出します。 +すべてのペンディング インテントが順に配信されます。これは、ファイルのダウンロードのような、活発にジョブを実行し、ただちに再開する必要のあるサービスに適しています。 + +
これらの戻り値の詳細については、リンクされた各定数のリファレンス ドキュメントをご覧ください。 +
+ + + +サービスを開始する
+ +アクティビティや他のアプリケーション コンポーネントから {@link android.content.Intent}(開始するサービスを指定する)を {@link android.content.Context#startService startService()} に渡すことで、サービスを開始できます。 + +Android システムが、サービスの {@link +android.app.Service#onStartCommand onStartCommand()} メソッドを呼び出して、{@link +android.content.Intent} を渡します(絶対に、{@link android.app.Service#onStartCommand +onStartCommand()} を直接呼び出さないでください)。
+ +アクティビティが前のセクションで例に挙げたサービス({@code +HelloSevice})を、{@link android.content.Context#startService +startService()} で明示的インテントを使って開始する例を次に示します。
+ ++Intent intent = new Intent(this, HelloService.class); +startService(intent); ++ +
{@link android.content.Context#startService startService()} メソッドがすぐに戻り、Android システムがサービスの {@link android.app.Service#onStartCommand +onStartCommand()} メソッドを呼び出します。 +サービスがまだ実行されていない場合、システムはまず {@link +android.app.Service#onCreate onCreate()} を呼び出してから、{@link android.app.Service#onStartCommand +onStartCommand()} を呼び出します。
+ +サービスでバインドが提供されない場合は、{@link +android.content.Context#startService startService()} で配信されたインテントが、アプリケーション コンポーネントとサービス間の唯一の通信モードになります。 +ただし、サービスから結果を送り返す場合は、サービスを開始するクライアントがブロードキャスト用に {@link android.app.PendingIntent} を作成でき({@link android.app.PendingIntent#getBroadcast getBroadcast()} で)、それをサービスを開始する {@link android.content.Intent} のサービスに配信できます。 + + +その後、サービスはブロードキャストを使って結果を配信できます。 +
+ +サービスを開始する要求が複数ある場合は、それに対応する複数の呼び出しがサービスの {@link android.app.Service#onStartCommand onStartCommand()} に対して発生することになります。 +ただし、サービスを停止するために必要な要求({@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} を使用)は、1 つのみです。 +
+ + +サービスを停止する
+ +開始されたサービスは、自身でライフサイクルを管理する必要があります。つまり、システムメモリを復元する必要がある場合を除き、システムがサービスを停止したり破棄したりすることはなく、サービスは {@link android.app.Service#onStartCommand onStartCommand()} から戻った後も実行し続けます。 + +そのため、サービスは {@link android.app.Service#stopSelf stopSelf()} を呼び出して自身で停止する必要があり、他のコンポーネントが {@link android.content.Context#stopService stopService()} を呼び出して停止することもできます。 + +
+ +{@link android.app.Service#stopSelf stopSelf()} や {@link +android.content.Context#stopService stopService()} で停止が要求されたら、システムは可能な限りすぐにサービスを破棄します。 +
+ +ただし、サービスが {@link
+android.app.Service#onStartCommand onStartCommand()} への複数の要求を同時に処理している場合は、その後に新しい開始要求を受け取る可能性があることから、開始要求の処理後もサービスを停止しないでください(1 つ目の要求の最後に停止すると、2 つ目が停止されてしまいます)。
+
+この問題を回避するには、{@link android.app.Service#stopSelf(int)} を使って、常に最新の開始要求に基づいてサービスの停止要求を行うようにできます。
+
+具体的には、{@link
+android.app.Service#stopSelf(int)} を呼び出すとき、停止要求に対応する開始要求の ID({@link android.app.Service#onStartCommand onStartCommand()} に配信された startId
)を渡します。
+
+その後、{@link
+android.app.Service#stopSelf(int)} を呼び出す前にサービスが新しい開始要求を受け取ったとしても、結果的に ID が一致せずサービスが停止されなくなります。
警告: アプリケーションはサービスの処理が完了したら、システムリソースやバッテリ電力の節約のため、サービスを停止することが重要です。 +必要であれば、他のコンポーネントから {@link +android.content.Context#stopService stopService()} を呼び出してサービスを停止することもできます。 +サービスのバインドを有効にしている場合でも、{@link +android.app.Service#onStartCommand onStartCommand()} を受け取ったときには常に自身でサービスを停止する必要があります。 +
+ +サービスのライフサイクルの詳細については、後半のセクションのサービスのライフサイクルを管理するをご覧ください。
+ + + +バインドされたサービスを作成する
+ +バインドされたサービスとは、アプリケーション コンポーネントが長時間の接続を作成するために {@link +android.content.Context#bindService bindService()} を呼び出してサービスにバインドできるようにするサービスです(通常はコンポーネントが {@link +android.content.Context#startService startService()} を呼び出すことではサービスは開始できません)。 +
+ +バインドされたサービスは、アプリケーションのアクティビティや他のコンポーネントからのサービスとやり取りしたり、アプリケーションの一部の機能をプロセス間通信(IPC)を用いて他のアプリケーションが利用できるようにしたりする場合に作成します。 + +
+ +バインドされたサービスを作成するには、{@link +android.app.Service#onBind onBind()} コールバック メソッドを実装して、サービスとの通信用のインターフェースを定義する {@link android.os.IBinder} を返す必要があります。 +その後、他のアプリケーション コンポーネントが {@link android.content.Context#bindService bindService()} を呼び出してインターフェースを取得し、サービスのメソッドの呼び出しを開始できます。 + +サービスは、バインドされているアプリケーション コンポーネントのためだけに存在するため、バインドされているコンポーネントがなくなると、サービスにシステムによって破棄されます(バインドされたサービスは、{@link android.app.Service#onStartCommand onStartCommand()} でサービスが開始されたときと同じ方法で停止する必要はありません)。 + + +
+ +バインドされたサービスを作成するには、まずクライアントからサービスへの通信方法を指定するインターフェースを定義します。 +サービスとクライアント間のこのインターフェースは {@link android.os.IBinder} の実装である必要があり、サービスはこれを {@link android.app.Service#onBind +onBind()} コールバック メソッドから返す必要があります。 + +クライアントが {@link android.os.IBinder} を受け取ると、そのインターフェースを介してサービスとのやり取りを開始できます。 +
+ +複数のクライアントが同時にサービスにバインドできます。クライアントとサービスのやり取りが終わったら、{@link android.content.Context#unbindService unbindService()} を呼び出してアンバインドします。 +サービスにバインドされているクライアントがなくなったら、システムがサービスを破棄します。 +
+ +バインドされたサービスの実装方法はいくつかあり、その実装は開始されたサービスよりも複雑であるため、バインドされたサービスの詳細については、バインドされたサービス のドキュメントで別途説明しています。 + +
+ + + +ユーザーに通知を送信する
+ +一旦サービスが実行されると、トースト通知やステータスバー通知を使ってユーザーにイベントを通知できます。
+ +トースト通知は、現在のウィンドウに表示されるメッセージで、少しの間表示され、すぐに消えます。一方、ステータスバー通知では、ステータスバーにメッセージの付いたアイコンが表示され、ユーザーはそれを選択して何らかの操作(アクティビティの開始など)を行うことができます。 + +
+ +通常は、バックグラウンド ワークが完了して、ユーザーが実行できる操作がある場合(ファイルのダウンロードが完了した場合など)は、ステータスバーの通知が最適なテクニックです。 + +展開したビューでユーザーが通知を選択すると、通知がアクティビティ(ダウンロードしたファイルを表示するなど)を開始できるようになります。 +
+ +詳細については、デベロッパー ガイドの「トースト通知」や「ステータスバーの通知」をご覧ください。 +
+ + + +サービスをフォアグラウンドで実行する
+ +フォアグラウンド サービスは、ユーザーがその存在を認識しているものであるとみなされるため、メモリ残量が少なくなった場合でも、システムによる強制終了の現候補にはなりません。 +フォアグラウンド サービスではステータスバーに通知を表示する必要があり、通知は「継続中」という見出しの下に表示されるため、サービスが停止するか、フォアグラウンドから除去しない限り通知を消すことはできないということになります。 + + +
+ +たとえば、サービスから音楽を再生する音楽プレーヤーは、ユーザーがその操作を認識しているのは明らかであるため、フォアグラウンドで実行する必要があります。 + +ステータスバーの通知には現在再生中の曲名を表示でき、ユーザーが音楽プレーヤーを操作するためのアクティビティを起動できるようにできます。 +
+ +サービスをフォアグラウンドで実行するよう要求するには、{@link +android.app.Service#startForeground startForeground()} を呼び出します。このメソッドは、通知を一意に識別する整数と、ステータスバーの {@link +android.app.Notification} の 2 つのパラメータを受け付けます。 +次に例を示します。
+ ++Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), + System.currentTimeMillis()); +Intent notificationIntent = new Intent(this, ExampleActivity.class); +PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); +notification.setLatestEventInfo(this, getText(R.string.notification_title), + getText(R.string.notification_message), pendingIntent); +startForeground(ONGOING_NOTIFICATION_ID, notification); ++ +
警告: {@link +android.app.Service#startForeground startForeground()} に渡す整数 ID には、0 は使用できません。
+ + +サービスをフォアグラウンドから除去するには、{@link +android.app.Service#stopForeground stopForeground()} を呼び出します。このメソッドでは、同時にステータスバーの通知も除去するかどうかを示すブール値を受け付けます。 +このメソッドでは、サービスは停止されません。 +ただし、サービスがまだフォアグラウンドで実行中に停止した場合は、通知も除去されます。 +
+ +通知の詳細については、「Creating Status Bar Notifications」をご覧ください。 +
+ + + +サービスのライフサイクルを管理する
+ +サービスのライフサイクルは、アクティビティのライフサイクルよりもはるかにシンプルです。ただし、サービスはバックグラウンドでサイレントに実行されるため、サービスがどのように作成され、破棄されるかについては、より一層の注意を払っておく必要があります。 + +
+ +作成されてから破棄されるまでのサービスのライフサイクルには、2 つの経路があります。—— +
+ +-
+
- 開始されたサービスの場合
+
他のコンポーネントが {@link +android.content.Context#startService startService()} を呼び出したときにサービスが作成されます。その後サービスは無期限に実行し、{@link +android.app.Service#stopSelf() stopSelf()} を呼び出して自身で停止する必要があります。 +また、他のコンポーネントから {@link android.content.Context#stopService stopService()} を呼び出してサービスを停止することもできます。 + +サービスが停止すると、システムがそれを破棄します。
+
+ - バインドされたサービス
+
他のコンポーネント(クライアント)が {@link +android.content.Context#bindService bindService()} を呼び出したときにサービスが作成されます。その後、クライアントが {@link android.os.IBinder} インターフェースを介してサービスとやり取りします。 +クライアントは、{@link android.content.Context#unbindService unbindService()} を呼び出して接続を終了できます。 +サービスには同時に複数のクライアントがバインドでき、すべてがアンバインドされると、サービスはシステムによって破棄されます +(サービスを自身で停止する必要はありません)。 +
+
この 2 つの経路は、完全に分離しているわけではありません。つまり、{@link android.content.Context#startService startService()} で既に開始されたサービスにバインドすることも可能です。 +たとえば、{@link android.content.Context#startService +startService()} を呼び出してバックグラウンドの音楽サービスを開始し、{@link android.content.Intent} を使って再生する音楽を指定できます。 +その後、ユーザーがプレーヤーを操作したり、現在の曲に関する情報を入手したりする場合は、{@link +android.content.Context#bindService bindService()} を呼び出すことでアクティビティをサービスにバインドできます。 + +このような場合は、すべてのクライアントがアンバインドされるまで、{@link +android.content.Context#stopService stopService()} や {@link android.app.Service#stopSelf +stopSelf()} ではサービスは停止されません。
+ + +ライフサイクル コールバックを実装する
+ +アクティビティと同様に、サービスにもコールバック メソッドがあり、それを実装することでサービスの状態の変化を監視したり、適切なタイミングで処理を実行したりできます。 +次のスケルトン サービスは、それぞれのライフサイクル メソッドを表しています。 +
+ ++public class ExampleService extends Service { + int mStartMode; // indicates how to behave if the service is killed + IBinder mBinder; // interface for clients that bind + boolean mAllowRebind; // indicates whether onRebind should be used + + @Override + public void {@link android.app.Service#onCreate onCreate}() { + // The service is being created + } + @Override + public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { + // The service is starting, due to a call to {@link android.content.Context#startService startService()} + return mStartMode; + } + @Override + public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()} + return mBinder; + } + @Override + public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { + // All clients have unbound with {@link android.content.Context#unbindService unbindService()} + return mAllowRebind; + } + @Override + public void {@link android.app.Service#onRebind onRebind}(Intent intent) { + // A client is binding to the service with {@link android.content.Context#bindService bindService()}, + // after onUnbind() has already been called + } + @Override + public void {@link android.app.Service#onDestroy onDestroy}() { + // The service is no longer used and is being destroyed + } +} ++ +
注: アクティビティのライフサイクル コールバック メソッドの場合とは異なり、これらのコールバック メソッドのスーパークラスの実装を呼び出す必要はありません。 +
+ + + + +これらのメソッドを実装すると、サービスのライフサイクル内の次の 2 つのネストされたループを監視できます。
+ +-
+
- サービスの全体の生存期間は、{@link
+android.app.Service#onCreate onCreate()} が呼び出されてから、{@link
+android.app.Service#onDestroy} から戻るまでの間です。アクティビティと同様に、サービスが {@link android.app.Service#onCreate onCreate()} で初期設定を行い、{@link
+android.app.Service#onDestroy onDestroy()} で残りのすべてのリソースを解放します。
+たとえば、音楽再生サービスでは、音楽を再生するスレッドを {@link
+android.app.Service#onCreate onCreate()} に作成して、停止するスレッドを {@link
+android.app.Service#onDestroy onDestroy()} に作成します。
+
+
+
{@link android.app.Service#onCreate onCreate()} メソッドと {@link android.app.Service#onDestroy +onDestroy()} メソッドは、それが{@link android.content.Context#startService startService()} か {@link +android.content.Context#bindService bindService()} のどちらで作成された場合でも、すべてのサービスに対して呼び出されます。 +
+
+ - サービスのアクティブな生存期間 {@link
+android.app.Service#onStartCommand onStartCommand()} か {@link android.app.Service#onBind onBind()} のいずれかへの呼び出しから開始します。各メソッドには、{@link android.content.Context#startService
+startService()} か {@link android.content.Context#bindService bindService()} のいずれかに渡された {@link
+android.content.Intent} が渡されます。
+
+
サービスが開始された場合、アクティブな生存期間の完了は、全体の生存期間の完了と同じタイミングとなります({@link android.app.Service#onStartCommand +onStartCommand()} から戻った後もサービスはまだアクティブです)。 +サービスがバインドされた場合、アクティブな生存期間は {@link +android.app.Service#onUnbind onUnbind()} から戻った時点で完了します。
+
+
注: 開始されたサービスは、{@link android.app.Service#stopSelf stopSelf()} か {@link +android.content.Context#stopService stopService()} への呼び出しで停止されますが、サービスには同様のコールバックはありません({@code onStop()} コールバックがありません)。 + +そのため、サービスがクライアントにバインドされていない限り、サービスが停止するとシステムがそれを破棄します。受け取るコールバックは {@link +android.app.Service#onDestroy onDestroy()} のみです。 +—
+ +図 2 は、サービスの典型的なコールバック メソッドを表しています。この図では、{@link android.content.Context#startService startService()} で作成されたサービスと {@link android.content.Context#bindService bindService()} で作成されたサービスを分けていますが、開始方法にかかわらず、すべてのサービスがクライアントからバインドされる可能性があることに注意してください。つまり、当初は {@link android.app.Service#onStartCommand +onStartCommand()} で(クライアントが {@link android.content.Context#startService startService()} を呼び出した際)開始されたサービスも、{@link android.app.Service#onBind onBind()} への呼び出し(クライアントが {@link android.content.Context#bindService bindService()} を呼び出した際)を受け取ることができます。 + + + + + +
+ +バインドを提供するサービスの作成に関する詳細は、「バインドされたサービス」のドキュメントをご覧ください。このドキュメントのバインドされたサービスのライフサイクルを管理するでは、{@link android.app.Service#onRebind onRebind()} コールバックの詳細についても説明しています。 + + +
+ + + diff --git a/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd b/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd new file mode 100644 index 0000000000000000000000000000000000000000..12f5911da22e94b98a235199ec76d902f887d58c --- /dev/null +++ b/docs/html-intl/intl/ja/guide/components/tasks-and-back-stack.jd @@ -0,0 +1,578 @@ +page.title=タスクとバックスタック +parent.title=アクティビティ +parent.link=activities.html +@jd:body + +本書の内容
+-
+
- アクティビティの状態を保存する +
- タスクを管理する
+
-
+
- 起動モードを定義する +
- アフィニティを処理する +
- バックスタックをクリアする +
- タスクを開始する +
+
記事
+ + +関連ドキュメント
+ +通常、アプリケーションには複数のアクティビティが含まれています。それぞれのアクティビティは、ユーザーが実行して、他のアクティビティを開始するといった特定のアクションを中心に設計されています。 + +たとえば、メール アプリケーションに新規メッセージ一覧を表示する 1 つのアクティビティがあるとします。ユーザーがメッセージを選択すると、そのメッセージを表示するための新しいアクティビティが開きます。 +
+ +アクティビティでは、端末上の他のアプリケーションに存在するアクティビティを開始することもできます。たとえば、アプリケーションがメールの送信を求める場合は、「送信」アクションを実行し、メールアドレスや本文などのデータを含めるインテントを定義できます。 + +その結果、この種のインテントの処理を宣言している別のアプリケーションのアクティビティが開きます。 +この場合、インテントはメールを送信することであるため、メール アプリケーションの「作成」アクティビティが開始されます(複数のアクティビティが同じインテントに対応している場合、システムはユーザーに選択を求めます)。 + +メールが送信されると、元のアクティビティが再開され、まるでメール アクティビティがそのアプリケーションの一部であるように見えます。 +アクティビティは異なるアプリケーションのものでも、Android は両方のアクティビティを同じタスク内に保つことによって、このシームレスな操作性を維持しています。 + +
+ +タスクとは、ユーザーが特定の作業を行う時に情報のやり取りを行うアクティビティの集まりです。 +アクティビティは、各アクティビティが開かれた順にスタック(バックスタック)形式で配置されます。 +
+ + + +ほとんどのタスクは、端末のホーム画面から開始されます。ユーザーがアプリケーション ランチャーでアイコン(またはホーム画面のショートカット)にタッチすると、アプリケーションのタスクがフォアグラウンドに移動します。 + +アプリケーションにタスクが存在しない(アプリケーションが最近使われていない)場合は、新しいタスクが作成され、そのアプリケーションの「メイン」アクティビティがスタック内のルート アクティビティとして開きます。 + +
+ +現在のアクティビティが別のアクティビティを開始すると、新しいアクティビティがスタックの一番上にプッシュされ、アクティブになります。 +前のアクティビティはスタックに残りますが、停止されます。アクティビティが停止すると、システムはそのユーザー インターフェースの状態を維持します。 +ユーザーが [戻る] ボタンを押すと、現在のアクティビティがスタックの一番上から消え(アクティビティは破棄され)、前のアクティビティが再開します(UI は前の状態で復元されます)。 + + +スタック内のアクティビティが並べ替えられることはなく、スタック上にプッシュされるかスタックから消されるかのみです — 現在のアクティビティにより開始されるとスタック上にプッシュされ、ユーザーが [戻る] ボタンを押すと破棄されます。 + +このように、バックスタックは「後入れ先出し」オブジェクト構造となっています。 + +図 1 は、この動作を時系列に視覚化し、アクティビティとそれに伴うその時点でのバックスタックの状態を示したものです。 + +
+ + + + + +ユーザーが続けて [戻る] ボタンを押すと、スタック内のアクティビティは消えていき、前のアクティビティが表示されます。最終的に、ユーザーはホーム画面(またはタスクの開始時に実行されていたアクティビティ)に戻ります。 + + +すべてのアクティビティがスタックから削除されると、タスクはなくなります。
+ +図 2. 2 つのタスク: タスク B がフォアグラウンドでユーザー操作を受け入れます。タスク A は再開されるまでバックグラウンドで待機します。 +
+図 3. 1 つのアクティビティが複数回インスタンス化されます。
+タスクは結束した構成単位で、ユーザーが新しいタスクを開始したり [ホーム] ボタンを使ってホーム画面に移動したりすると「バックグラウンド」に移動できます。 +バックグラウンドでは、タスク内のすべてのアクティビティが停止されますが、タスクのバックスタックは元の状態を保ちます — 図 2 に示すように、別のタスクが行われている間、タスクはフォーカスを失った状態になります。 + + +タスクはその後「フォアグラウンド」に戻り、ユーザーは操作の続きを行うことができます。 +たとえば、現在のタスク(タスク A)のスタックに 3 つのアクティビティがあるとします。現在のアクティビティの下に 2 つのアクティビティがある状態です。 +ユーザーが [ホーム] ボタンを押し、アプリケーション ランチャーから新しいアプリケーションを起動します。 + +ホーム画面が表示されると、タスク A はバックグラウンドに移動します。 +新しいアプリケーションが起動すると、システムはそのアプリケーションのタスク(タスク B)を開始します。タスク B には独自のアクティビティ スタックがあります。 +アプリケーションの操作が終了すると、ユーザーはホームに戻り、タスク A を開始した元のアプリケーションを選択します。ここでタスク A はフォアグラウンドに移動します — 3 つのアクティビティはすべて元のままで、スタックの一番上にあるアクティビティが再開します。 + + + +この時点で、ユーザーはホームに移動してタスク B を開始したアプリケーションを選択して(またはオーバービュー画面でアプリのタスクを選択して)タスク B に切り替えることもできます。これは、Android のマルチタスク操作の一例です。 + + + +
+ +注: バックグラウンドには複数のタスクを一度に置くことができます。しかし、ユーザーが多数のバックグラウンド タスクを同時に実行すると、システムがメモリを回復するためにバックグラウンド アクティビティを破棄する場合があります。その結果、アクティビティの状態は失われます。アクティビティの状態セクションをご覧ください。 + + +
+ +バックスタック内のアクティビティが並べ替えられることはないため、アプリケーションが複数のアクティビティからの特定のアクティビティ開始を許可すると、(アクティビティの前のインスタンスを一番上に移動させるのではなく)そのアクティビティの新しいインスタンスが作成されてスタック上にプッシュされます。 + + +これによって、図 3 に示すように、アプリケーションの 1 つのアクティビティが(別のタスクからも)複数回インスタンス化される場合があります。 +この場合は、ユーザーが [戻る] ボタンを使って移動すると、アクティビティの各インスタンスが(UI の状態はそれぞれそのままで)開いた順に表示されます。 + + +しかし、1 つのアクティビティを何度もインスタンス化したくない場合は、この動作を修正できます。 +その方法については、後述のセクションタスクを管理するで説明します。
+ + +以下は、アクティビティとタスクのデフォルトの動作をまとめたものです。
+ +-
+
- アクティビティ A がアクティビティ B を開始すると、アクティビティ A は停止しますが、システムはその状態(スクロールの位置やフォームに入力されたテキストなど)を保持します。アクティビティ B が開いた状態でユーザーが [戻る] ボタンを押すと、アクティビティ A が再開し、その状態が復元されます。 + + + +
- ユーザーが [ホーム] ボタンを押してタスクを離れると、現在のアクティビティは停止し、そのタスクはバックグラウンドに移動します。 + +システムはタスク内のすべてのアクティビティの状態を保持します。後にユーザーがタスクを開始したランチャー アイコンを選択してタスクを再開すると、タスクはフォアグラウンドに移動し、スタックの一番上にあるアクティビティを開始します。 + + +
- ユーザーが [戻る] ボタンを押すと、現在のアクティビティはスタックから消え、破棄されます。 + +スタック内にある前のアクティビティが再開します。アクティビティが破棄された場合、システムはその状態を保持しません。 + +
- アクティビティは、別のタスクからでも複数回インスタンス化できます。 +
ナビゲーション デザイン
+Android 上でのアプリ ナビゲーションの仕組みの詳細については、Android Design の「Navigation」ガイドをご覧ください。
+アクティビティの状態を保存する
+ +上述のように、デフォルト動作では、システムはアクティビティが停止するとその状態を保持します。 +この方法では、ユーザーが前のアクティビティに戻ると、ユーザー インターフェースが前の状態のままで表示されます。 +しかし、コールバック メソッドを使って積極的にアクティビティの状態を保持することもできます。破棄されたアクティビティを再作成しなければならないことを考えると、アクティビティの状態は積極的に保持すべきです。 + +
+ +システムが(新しいアクティビティの開始時やバックグラウンドへのタスクの移動時などに)アクティビティの 1 つを停止している時にシステム メモリの回復が必要になると、システムはそのアクティビティを完全に破棄する可能性があります。 + +これにより、アクティビティの状態に関する情報が失われてしまいます。システムは、アクティビティがバックスタックに留まっていることは認識していますが、アクティビティがスタックの一番上に置かれるとアクティビティを(再開ではなく)再作成しなければなりません。 + + +ユーザーの作業内容が失われるのを回避するには、{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} コールバック メソッドをアクティビティに実装することによって、作業状態を積極的に保持する必要があります。 + + +
+ +アクティビティの状態の保存方法の詳細については、「Activities」ドキュメントをご覧ください。 +
+ + + +タスクを管理する
+ +上記のように、Android は、連続して開始されたすべてのアクティビティを同じタスクの「後入れ先出し」式スタックに置くことによって、タスクやバックスタックを管理します。この方法は、ほとんどのアプリケーションでうまく動作し、アクティビティがどのようにタスクに関連付けられ、どのようにバックスタックに置かれているのかを心配する必要はありません。 + + +しかし、通常の動作に割り込みたい場合もあります。 +アプリケーション内のアクティビティが開始された時に(現在のタスク内に置かれる代わりに)新しいタスクを開始させたり、アクティビティの開始時に(新しいインスタンスをバックスタックの一番上に作成する代わりに)アクティビティの既存インスタンスを前に持ってきたり、ユーザーがタスクを離れる時にルート アクティビティ以外のすべてのアクティビティをバックスタックからクリアする場合などが考えられます。 + + + +
+ +{@code <activity>} マニフェスト エレメントの属性と {@link android.app.Activity#startActivity startActivity()} に渡すインテント内のフラグを使って、これらの、さらに他の動作を実現できます。 + + +
+ +この件に関して、使用できる主な {@code <activity>} 属性には以下のものがあります。 +
+ +-
+
- {@code taskAffinity} + +
- {@code launchMode} + +
- {@code allowTaskReparenting} + +
- {@code clearTaskOnLaunch} + +
- {@code alwaysRetainTaskState} + +
- {@code finishOnTaskLaunch} + +
使用できる主なインテント フラグには以下のものがあります。
+ +-
+
- {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} +
- {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} +
- {@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP} +
以下のセクションでは、これらのマニフェスト属性とインテント フラグを使ってアクティビティをタスクに関連付ける方法とバックスタック内での動作を定義する方法を説明します。 +
+ +また、タスクとアクティビティの提示方法やオーバービュー画面での管理方法に関する考慮点について別途記載しています。 +詳細については、「オーバービュー画面」をご覧ください。 +通常、オーバービュー画面にタスクとアクティビティを提示する方法はシステムが定義できるよう許可し、この動作を変更する必要はありません。 +
+ +警告: ほとんどのアプリケーションはアクティビティとタスクに対するデフォルトの動作に割り込むべきではありません。 +アクティビティがデフォルトの動作を変更する必要があると判断した場合は、起動時と他のアクティビティやタスクからの [戻る] ボタンによる移動時のアクティビティのユーザビリティを慎重にテストする必要があります。ユーザーが想定する動作と競合する恐れのあるナビゲーション時の動作については必ずテストを行ってください。 + + +
+ + +起動モードを定義する
+ +起動モードでは、アクティビティの新しいインスタンスを現在のタスクに関連付ける方法を定義できます。 +次の 2 つの方法を使ってさまざまな起動モードを定義できます。
+-
+
- マニフェスト ファイルを使用する
+
マニフェスト ファイルにアクティビティを宣言する際に、開始時にアクティビティをタスクに関連付ける方法を指定できます。 +
+ - インテント フラグを使用する
+
{@link android.app.Activity#startActivity startActivity()} を呼び出す際に、新しいアクティビティを現在のタスクに関連付ける方法(または関連付けるかどうか)を宣言する {@link android.content.Intent} にフラグを置くことができます。 + +
+
アクティビティ A がアクティビティ B を開始する場合、アクティビティ B は自身を現在のタスクに関連付ける方法(もしあれば)をマニフェストに定義し、アクティビティ A はアクティビティ B を現在のタスクに関連付ける方法を要求できます。 + +両方のアクティビティがアクティビティ B をタスクに関連付ける方法を定義している場合は、アクティビティ B の要求よりも(インテントに定義される)アクティビティ A の要求が優先されます。 + +
+ +注: マニフェスト ファイルで使用できる起動モードの中にはインテントのフラグとして使用できないものもあります。同様に、インテントのフラグとして使用できる起動モードの中には、マニフェストで定義できないものもあります。 + +
+ + +マニフェスト ファイルを使用する
+ +マニフェスト ファイルでアクティビティを宣言する際に、{@code <activity>} エレメントの {@code launchMode} 属性を使ってアクティビティをタスクに関連付ける方法を定義できます。 + + +
+ +{@code launchMode} 属性は、アクティビティをタスク内で起動する方法についての指示を定めます。
+
+launchMode
属性には、次の 4 つの起動モードを割り当てることができます。
+
+
-
+
- {@code "standard"}(デフォルトのモード) +
- デフォルトの設定です。システムは、開始されたタスクからアクティビティの新しいインスタンスをタスク内に作成し、インテントを渡します。 +アクティビティは複数回インスタンス化できます。各インスタンスは異なるタスクに所属でき、1 つのタスクは複数のインスタンスを持つことができます。 + +
- {@code "singleTop"} +
- アクティビティのインスタンスが現在のタスクの一番上に既に存在する場合は、システムはアクティビティの新しいインスタンスを作成せずに、{@link android.app.Activity#onNewIntent onNewIntent()} メソッドを呼び出して、インテントをそのインスタンスに渡します。
+
+
+アクティビティは複数回インスタンス化できます。各インスタンスは異なるタスクに所属でき、1 つのタスクは複数のインスタンスを持つことができます(バックスタックの一番上にあるアクティビティがそのアクティビティの既存のインスタンスでない場合のみ)。
+
+
+
たとえば、タスクのバックスタックがアクティビティ B、C、そしてアクティビティ D を一番上に持つルート アクティビティ A で構成されているとします(スタックは A-B-C-D で D が一番上)。 +D タイプのアクティビティにインテントが届きます。もし D の起動モードがデフォルトの {@code "standard"} である場合は、そのクラスの新しいインスタンスが起動し、スタックは A-B-C-D-D となります。しかし、D の起動モードが {@code "singleTop"} である場合は、スタックの一番上にある D の既存のインスタンスが {@link android.app.Activity#onNewIntent onNewIntent()} を介してインテントを受け取ります — この場合、スタックは A-B-C-D のままとなります。ただし、B タイプのアクティビティのインテントが届くと、その起動モードが {@code "singleTop"} であっても、B の新しいインスタンスがスタックに追加されます。 + + + + + +
+注: アクティビティの新しいインスタンスが作成されると、ユーザーは [戻る] ボタンを押して前のアクティビティに戻ることができます。 +しかし、アクティビティの既存のインスタンスが新しいインテントに対応すると、ユーザーは、新しいインテントが {@link android.app.Activity#onNewIntent onNewIntent()} で届く前の状態に [戻る] ボタンを押して戻ることはできません。 + + + + +
+
+
+ - {@code "singleTask"} +
- システムは新しいタスクを作成し、新しいタスクのルートにアクティビティをインスタンス化します。しかし、そのアクティビティのインスタンスが別のタスクに既に存在する場合は、システムは新しいインスタンスを作成せずに、{@link android.app.Activity#onNewIntent onNewIntent()} メソッドを呼び出して、インテントを既存のインスタンスに渡します。
+
+
+同時に存在できるアクティビティのインスタンスは 1 つだけです。
+
+
注: アクティビティは新しいタスク内で開始されますが、ユーザーは [戻る] ボタンを押して前のアクティビティに戻ることができます。 +
+ - {@code "singleInstance"} +
- システムが、他のアクティビティをインスタンスを保持しているタスクで起動しないことを除いて {@code "singleTask"} と同じです。 +アクティビティは、常にタスクの唯一の構成要素となります。このアクティビティによって開始されたアクティビティは別のタスクで開きます。 + +
たとえば、Android Browser アプリケーションは、{@code <activity>} エレメントの {@code singleTask} 起動モードを指定することによって、ウェブブラウザ アクティビティを常に自身のタスクで開くことを宣言しています。これは、開発されたアプリケーションが Android Browser を開くインテントを発行すると、そのアクティビティがアプリケーションのタスクには配置されないことを意味します。 + + + +代わりに、Android Browser の新しいタスクが開始されるか、Android Browser に既に実行中のバックグラウンド タスクがある場合は、そのタスクがフォアグラウンドに移動し、新しいインテントに対応します。 + +
+ +アクティビティを新しいタスク内で開始するかアクティビティを起動したアクティビティと同じタスクで開始するかにかかわらず、ユーザーは [戻る] ボタンを押して前のアクティビティに戻ることができます。 +ただし、{@code singleTask} 起動モードを設定したアクティビティを開始し、そのアクティビティのインスタンスがバックグラウンド タスクに存在する場合は、そのタスク全体がフォアグラウンドに移動します。 + +この時点で、バックスタックの一番上に、フォアグラウンドに移動したタスクのすべてのアクティビティが含まれてます。 + +図 4 は、このタイプのシナリオを示しています。
+ + + + +マニフェスト ファイルでの起動モードの使用の詳細については、<activity>
エレメントのドキュメントをご覧ください。{@code launchMode} 属性と利用できる値について詳しく説明しています。
+
+
+
注: 次のセクションで説明しますが、{@code launchMode} 属性を使ってアクティビティに指定する動作は、アクティビティを開始するインテントに含まれるフラグによって上書きされる場合があります。 + +
+ + + +インテント フラグを使用する
+ +アクティビティの開始時に、{@link android.app.Activity#startActivity startActivity()} に渡すインテントにフラグを含めることによってアクティビティとタスクのデフォルトの関連付けを変更できます。 + +以下は、デフォルトの動作を変更するために使用できるフラグです。 +
+ ++
この手順は、上述のセクションで説明した {@code "singleTask"} {@code launchMode} の値の動作と同じものです。 +
この手順は、上述のセクションで説明した {@code "singleTop"} {@code launchMode} の値の動作と同じものです。 +
この動作を起こす {@code launchMode} 属性には値はありません。 +
+ほとんどのケースで {@code FLAG_ACTIVITY_CLEAR_TOP} は {@code FLAG_ACTIVITY_NEW_TASK} と併用されます。同時に使用することで、これらのフラグは、別のタスクにある既存のアクティビティを捜し出し、インテントに対応できる位置に置く手段を提供します。 + + +
+注: 指定されたアクティビティの起動モードが {@code "standard"} である場合は、やはりスタックから削除されます。その場所に、渡されるインテントに対応する新しいインスタンスが開始されます。 + + +これは、起動モードが {@code "standard"} である場合は、新しいインテントに対して常に新しいインスタンスが作成されるためです。 +
+アフィニティを処理する
+ +アフィニティは、アクティビティの所属が望ましいタスクを示します。 デフォルトでは、同じアプリケーションのすべてアクティビティに相互のアフィニティが設定されています。 +このため、同じアプリケーションのすべてのアクティビティは、デフォルトで同じタスクに属します。 +しかし、アクティビティのデフォルトのアフィニティは変更できます。 +異なるアプリケーションに定義されているアクティビティがアフィニティを共有したり、同じアプリケーションに定義されたアクティビティに別のタスクのアフィニティを割り当てたりすることができます。 + +
+ +{@code <activity>} エレメントの {@code taskAffinity} 属性を使って、任意のアクティビティのアフィニティを変更できます。 + +
+ +{@code taskAffinity} 属性には文字列を指定します。これは、{@code <manifest>} エレメントに宣言されたデフォルトのパッケージ名とは異なる一意のものでなければなりません。理由は、システムがアプリケーションに対するデフォルトのタスク アフィニティを識別するためにこの名前を使用するためです。 + + + + +
+ +アフィニティは、以下の 2 つの状況で役立ちます。
+-
+
- アクティビティを開始するインテントが {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグを含んでいる場合
+
+
+
+
新しいアクティビティは、デフォルトで、{@link android.app.Activity#startActivity startActivity()} を呼び出したアクティビティのタスクで開始されます。 +呼び出し元と同じバックスタックにプッシュされます。 +しかし、{@link android.app.Activity#startActivity startActivity()} に渡されたインテントに {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグが含まれると、システムは新しいアクティビティを収容する別のタスクを捜します。 + + +これは、通常新しいタスクですが、新しいタスクである必要はありません。 +新しいアクティビティとして同じアフィニティを持つ既存のタスクが存在する場合は、アクティビティはそのタスクで開始されます。 +存在しない場合は、新しいタスクを開始します。
+ +このフラグによってアクティビティが新しいタスクを開始し、ユーザーが [ホーム] ボタンを押してタスクを離れる場合には、ユーザーがそのタスクに戻るための手段が必要です。 + +エンティティの中には(通知マネージャーなど)、自身の一部としてではなく、常に外部タスクでアクティビティを開始するものがあります。そのために、これらのエンティティが {@link android.app.Activity#startActivity startActivity()} に渡すインテントには常に {@code FLAG_ACTIVITY_NEW_TASK} が含まれます。このフラグを使った外部エンティティにより起動される可能性があるアクティビティがある場合は、起動アイコンなどを使って、アクティビティが開始したタスクにユーザーが戻れるよう独立した手段を確保します。(タスクのルート アクティビティには {@link android.content.Intent#CATEGORY_LAUNCHER} インテント フィルタがあります。後述のタスクを開始するセクションをご覧ください)。 + + + + + + +
+
+
+ - アクティビティの {@code allowTaskReparenting} 属性が {@code "true"} に設定されている場合。
+
+
この場合は、タスクがフォアグラウンドに移動した時に、アクティビティは自身が開始したタスクから、アフィニティがあるタスクへと移動できます。 +
+たとえば、選ばれた都市の天気を予報するアクティビティが旅行アプリケーションの一部として定義されているケースを考えてみましょう。 +このアクティビティは、アプリケーション内のその他のアクティビティと同じアフィニティ(デフォルトのアプリケーション アフィニティ)を持ち、この属性による親への再割り当てが許可されています。いずれかのアクティビティにより開始された天気予報アクティビティは、最初はそのアクティビティと同じタスクに属しています。 + + +しかし、旅行アプリケーションのタスクがフォアグラウンドに移動すると、天気予報アクティビティはそのタスクに再度割り当てられ、タスク内に表示されます。 +
+
+
ヒント: {@code .apk} ファイルがユーザーの視点で 1 つ以上の「アプリケーション」を含んでいる場合は、各「アプリケーション」に関連付けられたアクティビティに {@code taskAffinity} 属性を使って異なるアフィニティを割り当てることをお勧めします。 + +
+ + + +バックスタックをクリアする
+ +ユーザーがタスクを長時間離れると、システムはルート アクティビティを除くすべてのアクティビティをタスクからクリアします。 +ユーザーが再びタスクに戻ると、ルート アクティビティのみが復元されます。システムがこの動作を行うのは、しばらく時間が経過した後は、ユーザーが前に行っていた作業を放棄した可能性が高く、新しいことを始めるためにタスクに戻ったとみなされるためです。 + +
+ +この動作を変更するために、以下のアクティビティ属性を使用できます。
+ +-
+
alwaysRetainTaskState
+
+- タスクのルート アクティビティでこの属性が {@code "true"} に設定されていると、上記のデフォルトの動作は発生しません。長時間が経過しても、タスクはすべてのアクティビティをスタックに保持します。 + + + +
clearTaskOnLaunch
+- タスクのルート アクティビティでこの属性が {@code "true"} に設定されている場合、ユーザーがタスクを離れて戻るたびに、スタックがルート アクティビティまでクリアされます。 + +つまり、{@code alwaysRetainTaskState} の逆の動作となります。 + +ユーザーがタスクをほんの少しの間離れた場合でも、タスクは常に初期状態に戻ります。 + + +
finishOnTaskLaunch
+
+- この属性は、{@code clearTaskOnLaunch} に似ていますが、タスク全体ではなく 1 つのアクティビティに作用します。 + +ルート アクティビティを含むあらゆるアクティビティを消すことができます。 +この属性が {@code "true"} に設定されていると、アクティビティは現在のセッションが開かれている間のみタスクの一部として留まります。 +ユーザーがタスクから離れて戻ると、アクティビティは消えています。 + +
タスクを開始する
+ +指定するアクションとして {@code "android.intent.action.MAIN"}、指定するカテゴリとして {@code "android.intent.category.LAUNCHER"} を持つインテント フィルタを付加することによって、アクティビティをタスクのエントリ ポイントとして設定できます。 + + +次に例を示します。
+ ++<activity ... > + <intent-filter ... > + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + ... +</activity> ++ +
この種類のインテント フィルタを使うことによって、アクティビティのアイコンとラベルがアプリケーション ランチャーに表示されるようになります。これにより、ユーザーは、アクティビティを起動し、アクティビティの起動後は、作成されたタスクにいつでも戻ることができるようになります。 + + +
+ +ユーザーがタスクを離れた後に、このアクティビティ ランチャーを使って戻ってくることが可能でなければならないため、2 番目の機能が重要になります。 +アクティビティが {@link android.content.Intent#ACTION_MAIN} と {@link android.content.Intent#CATEGORY_LAUNCHER} フィルタを持つ場合のみに、アクティビティが常にタスクを開始することを示す {@code "singleTask"} と {@code "singleInstance"} の 2 つの起動モードを使用すべきなのはこのためです。 + + + +たとえば、フィルタがない場合にどうなるのかを想像してみてください。 +インテントが {@code "singleTask"} アクティビティを起動し、新しいタスクを開始し、ユーザーがそのタスクでしばらくの間作業を行います。 +その後、ユーザーは [ホーム] ボタンを押します。 +タスクはバックグラウンドに移動し、見えなくなります。タスクはアプリケーション ランチャーに表示されていないため、この状態ではユーザーがタスクに戻る手段がありません。 +
+ +ユーザーがアクティビティに戻るのを防ぐには、<activity>
エレメントの {@code finishOnTaskLaunch} を {@code "true"} に設定します(スタックをクリアするをご覧ください)。
+
+
+
+
オーバービュー画面でのタスクとアクティビティの表示方法と管理方法の詳細については、「オーバービュー画面」をご覧ください。 + +
+ + diff --git a/docs/html-intl/intl/ja/guide/index.jd b/docs/html-intl/intl/ja/guide/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..07688b63ec208288380bfb6a1e1652c3d15f5323 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/index.jd @@ -0,0 +1,74 @@ +page.title=Android 入門 + +@jd:body + + +アプリの動作方法について学ぶには、「App Fundamentals」をご覧ください。 +
+今すぐコーディングを始める場合は、「Building Your First App」をご覧ください。
+Android は、モバイル端末用の画期的なアプリやゲームを Java 言語環境でビルドできる、充実したアプリケーション フレームワークを提供します。 +左側のナビゲーションに表示されているドキュメントには、さまざまな Android API を使ってアプリをビルドする詳しい方法が記載されています。 +
+ +Android 開発の経験がない場合は、Android アプリのフレームワークについて次の基本的な概念を理解していることが重要になります。 +
+ + +アプリには複数のエントリ ポイントがある
+ +Android のアプリは、個別に呼び出し可能な異なるコンポーネントを組み合わせてビルドされます。 +たとえば、1 つのアクティビティが 1 つの画面でユーザー インターフェースを提供し、サービスがバックグラウンドで個別に処理を実行します。 + +
+ +インテントを使って、1 つのコンポーネントから別のコンポーネントを開始できます。地図アプリで住所を表示するアクティビティなどのように、別のアプリでコンポーネントを開始することもできます。 +このモデルでは、1 つのアプリに複数のエントリ ポイントを提供し、あらゆるアプリを他のアプリが呼び出すアクションの「デフォルト」として動作させることができます。 + +
+ + +詳細を見る
+ + +さまざまな端末に対応するアプリ
+ +Android は、さまざまな端末の構成に独自のリソースを提供できる柔軟なアプリ フレームワークを提供します。 +たとえば、画面サイズごとに個別の XML レイアウト ファイルを作成し、システムが使用中の端末の画面サイズに基づいて適用するレイアウトを決定します。 + +
+ +アプリの機能に特定のハードウェア(カメラなど)が必要な場合は、実行時に端末機能の使用可能状況をクエリできます。 +必要に応じて、アプリに必要な機能を宣言することもできます。これによって、Google Play ストアなどのアプリ マーケットでは、宣言した機能に対応していない端末へのインストールが許可されません。 + +
+ + +詳細を見る
+ + +本書の内容
+-
+
- マニフェスト ファイルの構造 +
- ファイルの規則 +
- ファイルの特徴
+
-
+
- インテント フィルタ +
- アイコンとラベル +
- パーミッション +
- ライブラリ +
+
+ すべてのアプリケーションには、そのルート ディレクトリに AndroidManifest.xml ファイル(名前はこのまま)が必要です。 + マニフェスト ファイルはアプリに関する重要な情報を Android システムに提示します。これは、システムがアプリのコードを実行する前に必要な情報です。 + + + その他、マニフェスト ファイルでは次のことを行います。 +
+ +-
+
- アプリケーションの Java パッケージ名を指定します。パッケージ名は、アプリケーションの一意の識別子としての機能を果たします。 + + +
- アプリケーションのコンポーネント(アプリケーションを構成するアクティビティ、サービス、ブロードキャスト レシーバー、コンテンツ プロバイダ)を記述します。 + +各コンポーネントを実装するクラスの名前を指定し、その機能(対応可能な {@link android.content.Intent Intent} メッセージなど)を公開します。 + +これらの宣言によって、Android システムは、どんなコンポーネントがあり、それらのコンポーネントがどのような条件で起動されるのかを把握できます。 + + +
- アプリケーション コンポーネントをホストするプロセスを決定します。 + +
- アプリケーションが API の保護された部分にアクセスしたり他のアプリケーションとやり取りしたりする際に必要となるパーミッションを宣言します。 + + +
- 他のアプリケーションがアプリケーションのコンポーネントとやり取りするために必要なパーミッションを宣言します。 + + +
- アプリケーションの実行時にプロファイリングやその他の情報を提供する {@link android.app.Instrumentation} クラスを記載します。 +これらの宣言は、アプリケーションの開発時やテスト時にのみマニフェストに含まれ、アプリケーションの公開前に削除されます。 + + + +
- アプリケーションに必要な Android API の最小限のレベルを宣言します。 + + +
- アプリケーションにリンクする必要があるライブラリを記載します。 +
マニフェスト ファイルの構造
+ ++次の図は、マニフェスト ファイルの一般的な構造とファイルに含むことができるすべてのエレメントを示します。 +各エレメントとそれぞれの属性はすべて別のファイルに記述されます。 +エレメントの詳細を見るには、図中、図の下にあるアルファベット順のエレメント一覧、またはその他の説明文に表示されているエレメント名をクリックしてください。 + + + +
+ ++<?xml version="1.0" encoding="utf-8"?> + +<manifest> + + <uses-permission /> + <permission /> + <permission-tree /> + <permission-group /> + <instrumentation /> + <uses-sdk /> + <uses-configuration /> + <uses-feature /> + <supports-screens /> + <compatible-screens /> + <supports-gl-texture /> + + <application> + + <activity> + <intent-filter> + <action /> + <category /> + <data /> + </intent-filter> + <meta-data /> + </activity> + + <activity-alias> + <intent-filter> . . . </intent-filter> + <meta-data /> + </activity-alias> + + <service> + <intent-filter> . . . </intent-filter> + <meta-data/> + </service> + + <receiver> + <intent-filter> . . . </intent-filter> + <meta-data /> + </receiver> + + <provider> + <grant-uri-permission /> + <meta-data /> + <path-permission /> + </provider> + + <uses-library /> + + </application> + +</manifest> ++ +
+以下は、マニフェスト ファイルに含むことができるすべてのエレメントをアルファベット順に並べたものです。 +使用が許可されているのはこれらのエレメントのみです。独自のエレメントや属性は追加できません。 + +
+ +
+<action>
+<activity>
+<activity-alias>
+<application>
+<category>
+<data>
+<grant-uri-permission>
+<instrumentation>
+<intent-filter>
+<manifest>
+<meta-data>
+<permission>
+<permission-group>
+<permission-tree>
+<provider>
+<receiver>
+<service>
+<supports-screens>
+<uses-configuration>
+<uses-feature>
+<uses-library>
+<uses-permission>
+<uses-sdk>
+
ファイルの規則
+ ++マニフェスト ファイルに含まれるエレメントと属性には、通常、次の規則とルールが適用されます。 + +
+ +-
+
- エレメント +
- 必須のエレメントは
<manifest>
と<application>
のみです。両方のエレメントを提示する必要があり、使用できるのはそれぞれ 1 回のみです。 + + +その他のほとんどのエレメントは、複数回使ってもまったく使わなくてもかまいませんが、意味のあるマニフェストを行うにはいくつかのエレメントが必要です。 + + + + ++内容のあるエレメントには他のエレメントが含まれているためです。すべての値は属性によって設定され、エレメント内に文字データが設定されることはありません。 + +
+ ++同じレベルにあるエレメントに順番はありません。たとえば、
<activity>
や<provider>
、<service>
エレメントは、どのような順で並べてもかまいません。 + + + +(<activity-alias>
エレメントは例外となります。 + +エイリアスとなっている<activity>
のすぐ後に記述する必要があります)。 + + +
+
+ - 属性 +
- 正式には、すべての属性はオプションです。しかし、エレメントが目的を達成するために設定しなければならない属性もあります。
+このドキュメントはガイドとしてお使いください。
+真の意味でオプションの属性には、デフォルト値または指定がない場合の動作が記述されています。
+
+
+
ルートの
<manifest>
エレメントの属性の一部を除き、すべての属性名は {@code android:} 接頭辞で始まります(例: {@code android:alwaysRetainTaskState})。 + + +この接頭辞は共通であるため、ドキュメントで属性が名前で参照されている場合は通常省略されます。 + +
+
+ - クラス名の宣言 +
- 多くのエレメントは Java オブジェクトと一致しています。これらのエレメントには、アプリケーション自体(
<application>
エレメント)とその主要なコンポーネントであるアクティビティ(<activity>
)、サービス(<service>
)、ブロードキャスト レシーバー(<receiver>
)やコンテンツ プロバイダ(<provider>
)が含まれます。 + + + + + + + + + + + ++サブクラスを定義する場合は、コンポーネント クラス({@link android.app.Activity}、{@link android.app.Service}、{@link android.content.BroadcastReceiver}、{@link android.content.ContentProvider})でいつも行うように、サブクラスは {@code name} 属性で宣言されます。 + + +この名前には、完全なパッケージ名を含む必要があります。 +たとえば、{@link android.app.Service} サブクラスの宣言は以下のようになります。 + +
+ +<manifest . . . > + <application . . . > + <service android:name="com.example.project.SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest>
+ ++ただし、簡素化する方法として、文字列の最初の文字がピリオドの場合、文字列はアプリケーションのパッケージ名に付加されます(
+ +<manifest>
エレメントのpackage
属性によって指定されるため)。 + + + + +以下は、上記のものと同じ内容です。 +<manifest package="com.example.project" . . . > + <application . . . > + <service android:name=".SecretService" . . . > + . . . + </service> + . . . + </application> +</manifest>
+ ++コンポーネントの開始時に、Android は名前が指定されたサブクラスのインスタンスを作成します。サブクラスが指定されていない場合は、基底クラスのインスタンスを作成します。 + +
+
+ - 複数の値 +
- 1 つ以上の値が指定されている場合は、1 つのエレメントに複数の値が記載されているのではなく、エレメントが繰り返されているケースがほとんどです。
+たとえば、インテント フィルタには複数のアクションが記載されている場合があります。
+
+
+
<intent-filter . . . > + <action android:name="android.intent.action.EDIT" /> + <action android:name="android.intent.action.INSERT" /> + <action android:name="android.intent.action.DELETE" /> + . . . +</intent-filter>
+
+ - リソースの値 +
- 属性には、ユーザーに対して表示する値を含むものもあります。たとえば、アクティビティのラベルやアイコンです。
+これらの属性の値は、ローカライズされていなければならないため、リソースまたはテーマから設定する必要があります。
+リソースの値は、以下の形式で記述されます。
+
+
+
{@code @[package:]type:name}
+ ++リソースがアプリケーションと同じパッケージ内にある場合は package 名を省略できます。type はリソースのタイプ(「string」や「drawable」など)、name は特定のリソースの名前です。 + +次に例を示します。 + +
+ +<activity android:icon="@drawable/smallPic" . . . >
+ ++テーマからの値も同様の方法で表記されますが、冒頭は '{@code @}' ではなく '{@code ?}' となります。 + +
+ +{@code ?[package:]type:name} +
+
+ - 文字列の値 +
- 属性値が文字列で文字をエスケープする場合はダブル バックスラッシュ('{@code \\}')を使う必要があります。たとえば、改行は '{@code \\n}'、Unicode の文字は '{@code \\uxxxx}' となります。 + + +
ファイルの特徴
+ ++以下のセクションでは、Android の機能がどのようにマニフェスト ファイルに反映されるのかを説明します。 + +
+ + +インテント フィルタ
+ ++アプリケーションのコア コンポーネント(アクティビティ、サービス、ブロードキャスト レシーバー)はインテントによって開始されます。 +インテントとは、目的とするアクションを記述している情報の束({@link android.content.Intent} オブジェクト)で、使用されるデータやアクションを実行するコンポーネントのカテゴリ、その他の関連する指示を含みます。 + + +Android は、インテントに対応する適切なコンポーネントを捜し出し、必要に応じて新しいインスタンスを起動し、それにインテント オブジェクトを渡します。 + + + +
+ +
+コンポーネントはインテント フィルタを使ってその機能(対応できるインテントの種類)を通知します。
+Android システムはコンポーネントを起動する前にコンポーネントが対応できるインテントを知っておく必要があるため、インテント フィルタはマニフェスト ファイルの <intent-filter>
エレメントで指定されます。
+
+
+
+コンポーネントは、それぞれが異なる機能を記述しているフィルタをいくつでも持つことができます。
+
+
+対象となるコンポーネントの名前を明示的に指定しているインテントは、コンポーネントを起動します。この場合、フィルタは適用されません。 +対象の名前が指定されていない場合は、コンポーネントのフィルタを通過したインテントのみがコンポーネントを起動できます。 + + +
+ ++インテント フィルタに対してインテント オブジェクトをテストする方法については、「インテントとインテント フィルタ」ドキュメントをご覧ください。 + + + +
+ + +アイコンとラベル
+ +
+エレメントは、小さなアイコンやテキスト ラベルをユーザーに表示するために、{@code icon} と {@code label} 属性を持つ場合があります。
+画面に長い説明文を表示するための {@code description} 属性を持つエレメントもあります。
+
+たとえば、<permission>
エレメントはこれらすべての属性を持っています。これによって、アプリケーションがユーザーにパーミッションを付与するかどうかを尋ねる際に、ユーザーに対して、パーミッションを示すアイコン、パーミッションの名前、パーミッションについての説明文を提示できます。
+
+
+
+
+
+
+どの場合においても、属性を含むエレメントに設定されたアイコンとラベルが、そのすべてのサブエレメントの {@code icon} と {@code label} のデフォルト設定となります。
+そのため、<application>
エレメントに設定されたアイコンとラベルは、アプリケーションの各コンポーネントのデフォルトのアイコンとラベルとなります。
+
+
+同様に、コンポーネントに設定されたアイコンとラベルは、— <activity>
エレメントのように — それぞれのコンポーネントの <intent-filter>
エレメントのデフォルト設定となります。
+
+
+
+
+<application>
エレメントにラベルを設定し、アクティビティとそのインテント フィルタに設定しない場合は、アプリケーション ラベルはアクティビティとインテント フィルタの両方のラベルとして取り扱われます。
+
+
+
+
+
+インテント フィルタに設定されるアイコンとラベルは、コンポーネントがユーザーに対して提示されるときはいつでも、そのフィルタにより通知されている機能を提供するコンポーネントを示すために使用されます。 + +たとえば、「{@code android.intent.action.MAIN}」と「{@code android.intent.category.LAUNCHER}」が設定されているフィルタは、アプリケーションを起動するアクティビティを通知しています — つまり、アプリケーション ランチャーに表示されるということです。 + + + +そのため、このフィルタに設定されているアイコンとラベルがランチャーに表示されるものとなります。 + +
+ + +パーミッション
+ ++パーミッションは、コードの一部や端末上のデータへのアクセスを制限する機能を提供します。 + 誤用や悪用によってユーザーの利用を妨げたり有害な作用をもたらす恐れのある重要なデータやコードを保護したりするための制限を設定します。 + +
+ ++それぞれのパーミッションは一意のラベルで識別されています。通常、ラベルは制限されるアクションを示します。 +以下は、Android により定義されているパーミッションの例です。 + +
+ +{@code android.permission.CALL_EMERGENCY_NUMBERS}
+
{@code android.permission.READ_OWNER_DATA}
+
{@code android.permission.SET_WALLPAPER}
+
{@code android.permission.DEVICE_POWER}
+1 つの機能は、1 つのパーミッションでのみ保護できます。 +
+ +
+アプリケーションがパーミッションにより保護されている機能へのアクセスを必要としている場合は、<uses-permission>
エレメントをマニフェスト ファイルに記述し、そのパーミッションが必要であることを宣言する必要があります。
+
+
+これによって、アプリケーションが端末にインストールされた際に、インストーラーは、アプリケーションの証明書に署名した関係機関を確認し、場合によってはユーザーに尋ねることで、要求されたパーミッションを付与するかどうかを決定します。
+
+
+パーミッションが付与されると、アプリケーションは保護された機能を使用できるようになります。
+
+パーミッションが付与されなかった場合は、アプリケーションは機能にアクセスできず、ユーザーに通知が表示されることもありません。
+
+
+アプリケーションは、パーミッションを使って自身のコンポーネント(アクティビティ、サービス、ブロードキャスト レシーバー、コンテンツ プロバイダ)を保護することもできます。
+Android により定義されているパーミッション({@link android.Manifest.permission android.Manifest.permission} に記載)や他のアプリケーションにより宣言されたパーミッションであればどれでも使用できます。
+
+
+独自のパーミッションを定義することもできます。新しいパーミッションは、<permission>
エレメントを使って宣言します。
+
+
+たとえば、次のようにアクティビティを保護できます。
+
+<manifest . . . > + <permission android:name="com.example.project.DEBIT_ACCT" . . . /> + <uses-permission android:name="com.example.project.DEBIT_ACCT" /> + . . . + <application . . .> + <activity android:name="com.example.project.FreneticActivity" + android:permission="com.example.project.DEBIT_ACCT" + . . . > + . . . + </activity> + </application> +</manifest> ++ +
+この例では、{@code DEBIT_ACCT} パーミッションは <permission>
エレメントで宣言されているだけではなく、その使用が <uses-permission>
エレメントで要求されている点に注意してください。
+
+
+
+
+アプリケーション自身によって保護が設定されている場合でも、アプリケーションの他のコンポーネントが保護されたアクティビティを起動するために、その使用を要求する必要があります。
+
+
+
+同じ例で、別の場所で宣言されたパーミッションに {@code permission} 属性が設定されている場合({@code android.permission.CALL_EMERGENCY_NUMBERS} など)は、<permission>
エレメントを使って再度宣言する必要があります。
+
+
+
+
+その場合も <uses-permission>
でその使用を要求する必要があります。
+
+
+<permission-tree>
エレメントは、コードに定義されるパーミッションの集まりに対するネームスペースを宣言します。
+
+
+<permission-group>
エレメントは、パーミッションのセットに対するラベル(マニフェスト ファイルに <permission>
エレメントを使って宣言されたもの、その他の場所で宣言されたものの両方)を定義します。
+
+
+
+これは、ユーザーに提示される際のパーミッションのグループ分けのみに影響します。
+<permission-group>
エレメントでは、パーミッションのグループへの所属は指定されません。グループ名のみが指定されます。
+
+
+パーミッションは、<permission>
エレメントの permissionGroup
属性にグループ名を割り当てることによって、グループに配置されます。
+
+
+
+
+
+
ライブラリ
+ ++すべてのアプリケーションはデフォルトの Android ライブラリにリンクされています。このライブラリには、Activity、Service、Intent、View、Button、Application、ContentProvider などの共通クラスを含む、アプリケーションをビルドするための基本パッケージが含まれています。 + + + +
+ +
+しかし、独自のライブラリに含まれているパッケージもあります。開発中のアプリケーションがこれらのパッケージのコードを使用している場合は、該当するライブラリにリンクするよう明示的に求める必要があります。
+
+この場合は、マニフェスト ファイルに各ライブラリを指定する <uses-library>
エレメントが別途含まれている必要があります。
+
+(ライブラリ名は該当するパッケージのドキュメントに記載されています)。
+
+
本書の内容
+-
+
- 基本 +
- ユーザー パーミッション +
- Calendars テーブル
+
-
+
- カレンダーへのクエリ +
- カレンダーの変更 +
- カレンダーの挿入 +
+ - Events テーブル
+
-
+
- イベントの追加 +
- イベントのアップデート +
- イベントの削除 +
+ - Attendees テーブル
+
-
+
- 参加者の追加 +
+ - Reminders テーブル
+
-
+
- リマインダーの追加 +
+ - Instances テーブル + +
- カレンダーのインテント + + + +
- 同期アダプタ +
キークラス
+-
+
- {@link android.provider.CalendarContract.Calendars} +
- {@link android.provider.CalendarContract.Events} +
- {@link android.provider.CalendarContract.Attendees} +
- {@link android.provider.CalendarContract.Reminders} +
カレンダー プロバイダは、ユーザーのカレンダー イベントのためのリポジトリです。カレンダー プロバイダ API を使用すると、カレンダー、イベント、参加者、リマインダーなどに対するクエリ、挿入、アップデート、削除の操作を実行できます。 + +
+ + +カレンダー プロバイダ API は、アプリケーションや同期アダプタで使用できます。ルールは、呼び出しを実行しているプログラムのタイプによって異なります。 +本書では主に、カレンダー プロバイダ API のアプリケーションとしての使用について説明します。 +同期アダプタの場合の違いについては、同期アダプタをご覧ください。 + +
+ + +通常、カレンダー データを読み取ったり書き込んだりするためには、アプリケーションのマニフェストにユーザー パーミッションで説明している適切なパーミッションが含まれている必要があります。 + +一般的な操作を簡単に実行できるようにするため、カレンダー プロバイダには、いくつかのインテントが用意されています。これらについては、カレンダーのインテントで説明しています。 + +これらのインテントは、ユーザーをカレンダー アプリケーションに誘導して、イベントを挿入、参照、編集できるようにします。 +ユーザーは、カレンダー アプリケーションを操作した後、元のアプリケーションに戻ります。 +これにより、アプリケーションがパーミッションを要求したり、イベントの参照や作成のためのインターフェースを提供したりする必要がなくなります。 +
+ +基本
+ +コンテンツ プロバイダは、データを保存してアプリケーションからアクセスできるようにします。 +Android プラットフォームによって提供されるコンテンツ プロバイダ(カレンダー プロバイダを含む)は、一般にリレーショナル データベース モデルに基づくテーブルのセットとしてデータを公開します。このモデルにおいて、各行はレコード、各列は特定のタイプと意味のデータになっています。 + +アプリケーションと同期アダプタは、ユーザーのカレンダー データを保持するデータベース テーブルの読み取りおよび書き込みアクセスを、カレンダー プロバイダ API を使用して取得できます。 + +
+ +各コンテンツ プロバイダは、データセットを一意に指定するパブリック URI({@link android.net.Uri} オブジェクトとしてラップされています)を公開します。
+
+複数のデータセット(複数のテーブル)を制御するコンテンツ プロバイダは、データセットごとに個別の URI を公開します。
+プロバイダの URI はすべて、文字列「content://」で始まります。
+これは、コンテンツ プロバイダによって管理されているデータであることを示します。
+カレンダー プロバイダは、クラス(テーブル)それぞれの URI のための定数を定義します。
+URI の形式は <class>.CONTENT_URI
です。
+たとえば、{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} のようになります。
+
図 1 に、カレンダー プロバイダのデータモデルを図示します。メイン テーブルとそれらを相互にリンクしているフィールドが示されています。 +
+ + + + +ユーザーは複数のカレンダーを持つことができ、カレンダーをそれぞれ異なるタイプのアカウント(Google カレンダー、Exchange など)と関連付けることができます。
+ +{@link android.provider.CalendarContract} は、カレンダーのデータモデルとイベント関連の情報を定義します。データは、次に示すいくつかのテーブルに保存されます。
+ +テーブル(クラス) | +説明 | +
---|---|
{@link android.provider.CalendarContract.Calendars} |
+
+ このテーブルは、該当するカレンダー固有の情報を保持します。 +各行には、名前、色、同期情報など、1 つのカレンダーに関する詳細が格納されます。 + | +
{@link android.provider.CalendarContract.Events} | + +このテーブルは、該当するイベント固有の情報を保持します。 +各行には、1 つのイベントに関する情報が格納されます—イベントのタイトル、場所、開始時刻、終了時刻などが該当します。 + +イベントは、単発だったり繰り返し発生したりすることが考えられます。参加者、リマインダー、拡張プロパティは、個別のテーブルに格納されます。 +これらのテーブルにはそれぞれ、Events テーブルの {@link android.provider.BaseColumns#_ID} を参照する {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} があります。 + + | + +
{@link android.provider.CalendarContract.Instances} | + +このテーブルは、あるイベントの発生ごとの開始時刻と終了時刻を保持します。 +各行は、イベントの発生 1 回を表します。 +単発イベントには、イベントのインスタンスが 1 対 1 で対応します。 +繰り返しのイベントには、そのイベントの複数回の発生それぞれに対応する複数の行が自動生成されます。 + | +
{@link android.provider.CalendarContract.Attendees} | + +このテーブルは、イベントの参加者(ゲスト)の情報を保持します。 +各行は、1 回のイベントの 1 人のゲストを表します。 +ゲストのタイプと、ゲストのイベントへの出欠の回答を指定します。 + | +
{@link android.provider.CalendarContract.Reminders} | + +このテーブルは、アラートや通知のデータを保持します。 +各行は、1 回のイベントの 1 つのアラートを表します。1 つのイベントが複数のリマインダーを持つことができます。 +1 イベントあたりの最大リマインダー数は {@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS} で指定され、指定されたカレンダーを所有する同期アダプタによって設定されます。 + + + +リマインダーは、イベント開始前の分単位で指定され、ユーザーに注意喚起する手段を示す情報を保持します。 + | +
カレンダー プロバイダ API は、柔軟で効果的な設計になっています。ですが同時に、エンドユーザーにとって使いやすくすることや、カレンダーとそのデータの整合性を保護することが重要です。 + +次に、そのために API の使用に際して留意すべきことを示します。 +
+ +-
+
+
- カレンダー イベントの挿入、アップデート、参照カレンダー プロバイダからイベントの挿入、変更、読み取りを直接実行するためには、適切なパーミッションが必要です。ただし、作成しているのが本格的なカレンダー アプリケーションや同期アダプタではない場合は、そうしたパーミッションを要求する必要はありません。その代わりに、Android のカレンダー アプリケーションがサポートしているインテントを使用し、読み取りと書き込みの操作をそのアプリケーションに引き渡すことができます。インテントを使用すると、アプリケーションがユーザーをカレンダー アプリケーションに誘導し、自動入力されたフォームで目的の操作を実行するようになります。 +操作を完了したユーザーは、アプリケーションに戻されます。一般的な操作をカレンダーを介して実行するようにアプリケーションを設計することで、ユーザーに一貫性のある堅牢なユーザー インターフェースが提供できます。 + +これが推奨アプローチです。 +詳細については、カレンダーのインテントをご覧ください。 + + + +
- 同期アダプタ。同期アダプタは、ユーザーの端末上にあるカレンダー データを別のサーバーやデータソースと同期します。 +{@link android.provider.CalendarContract.Calendars} テーブルと {@link android.provider.CalendarContract.Events} テーブルには、同期アダプタ用に予約された列があります。プロバイダやアプリケーションがそれらを変更しないようにする必要があります。 + + + +実際には、同期アダプタとしてアクセスしない限り、それらの列は参照できません。 +同期アダプタの詳細については、同期アダプタをご覧ください。 + + +
ユーザー パーミッション
+ +カレンダー データを読み込むためには、アプリケーションはマニフェスト ファイルに {@link android.Manifest.permission#READ_CALENDAR} パーミッションを含める必要があります。 +カレンダー データを削除、挿入、アップデートするためには、{@link android.Manifest.permission#WRITE_CALENDAR} パーミッションを含める必要があります。 + +
+ ++<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"...> + <uses-sdk android:minSdkVersion="14" /> + <uses-permission android:name="android.permission.READ_CALENDAR" /> + <uses-permission android:name="android.permission.WRITE_CALENDAR" /> + ... +</manifest> ++ + +
Calendars テーブル
+ +{@link android.provider.CalendarContract.Calendars} テーブルには、個々のカレンダーの詳細情報が格納されます。 +次に示す Calendars の列は、アプリケーションと同期アダプタのどちらからも書き込み可能です。 +サポートされているすべてのフィールドの一覧については、{@link android.provider.CalendarContract.Calendars} のリファレンスをご覧ください。 + +
+定数 | +説明 | +
---|---|
{@link android.provider.CalendarContract.Calendars#NAME} | +カレンダーの名前。 | +
{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME} | +ユーザーに表示されるこのカレンダーの名前。 | +
{@link android.provider.CalendarContract.Calendars#VISIBLE} | + +カレンダーが表示対象として選択されているかどうかを示すブール値。値 0 は、このカレンダーに関連付けられているイベントを表示しないことを示します。 + +値 1 は、このカレンダーに関連付けられているイベントを表示することを示します。 +この値は、{@link android.provider.CalendarContract.Instances} テーブルの行の生成に影響を与えます。 + | + + +
{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS} | + +カレンダーを同期してそのイベントを端末に格納するかどうかを示すブール値。 +値 0 は、このカレンダーを同期せず、イベントを端末に格納しないことを指定します。 +値 1 は、このカレンダーのイベントを同期し、イベントを端末に格納することを指定します。 + | +
カレンダーへのクエリ
+ +次の例は、特定のユーザーが所有するカレンダーを取得する方法を示しています。 +簡潔にするため、この例のクエリ操作はユーザー インターフェース スレッド(「メインスレッド」)内に示されています。 +実際には、メインスレッドではなく非同期スレッドで実行してください。 +詳細については、「ローダ」をご覧ください。 +データを読み込むだけでなく変更する場合は、{@link android.content.AsyncQueryHandler} をご覧ください。 + +
+ + ++// Projection array. Creating indices for this array instead of doing +// dynamic lookups improves performance. +public static final String[] EVENT_PROJECTION = new String[] { + Calendars._ID, // 0 + Calendars.ACCOUNT_NAME, // 1 + Calendars.CALENDAR_DISPLAY_NAME, // 2 + Calendars.OWNER_ACCOUNT // 3 +}; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1; +private static final int PROJECTION_DISPLAY_NAME_INDEX = 2; +private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;+ + +
ACCOUNT_TYPE を含める必要がある理由 +
{@link android.provider.CalendarContract.Calendars#ACCOUNT_NAME Calendars.ACCOUNT_NAME} にクエリする場合は、このセクションに {@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE} も含める必要があります。
+
+
+
+これは、指定されたアカウントは ACCOUNT_NAME
とその ACCOUNT_TYPE
がどちらも与えられることで一意とみなされるからです。
+
+ACCOUNT_TYPE
は、そのアカウントが {@link android.accounts.AccountManager} で登録されたときに使用されたアカウント認証システムです。
+
+また、端末アカウントに関連付けられていないカレンダー用に、{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} という特殊なタイプのアカウントがあります。{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} アカウントは同期されません。
+
+
+
+
この例の次の部分では、クエリを作成します。クエリの条件は selection に指定しています。
+この例のクエリは、ACCOUNT_NAME
が「sampleuser@google.com」で、ACCOUNT_TYPE
が「com.google」で、OWNER_ACCOUNT
が「sampleuser@google.com」であるカレンダーを検索します。
+
+
+
+ユーザーが所有しているだけでなく参照したことのあるすべてのカレンダーを確認するには、OWNER_ACCOUNT
を省略します。このクエリは、データベース クエリが返した結果セットをトラバースするのに使用できる {@link android.database.Cursor} オブジェクトを返します。
+
+
+
+コンテンツ プロバイダでのクエリの使用については、「コンテンツ プロバイダ」をご覧ください。
+
// Run query +Cursor cur = null; +ContentResolver cr = getContentResolver(); +Uri uri = Calendars.CONTENT_URI; +String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND (" + + Calendars.ACCOUNT_TYPE + " = ?) AND (" + + Calendars.OWNER_ACCOUNT + " = ?))"; +String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google", + "sampleuser@gmail.com"}; +// Submit the query and get a Cursor object back. +cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);+ +
次のセクションでは、カーソルを使用して結果セットをステップ単位で移動します。例の冒頭で設定した定数を使用して各フィールドの値を返します。 + +
+ +// Use the cursor to step through the returned records +while (cur.moveToNext()) { + long calID = 0; + String displayName = null; + String accountName = null; + String ownerName = null; + + // Get the field values + calID = cur.getLong(PROJECTION_ID_INDEX); + displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX); + accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX); + ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX); + + // Do something with the values... + + ... +} ++ +
カレンダーの変更
+ +カレンダーのアップデートを実行する場合、カレンダーの {@link android.provider.BaseColumns#_ID} を、URI({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})の末尾に追加された ID として、または最初の selection 項目として指定できます。
+
+
+
+
+先ほどの selection を "_id=?"
で始め、最初の selectionArg
をカレンダーの {@link android.provider.BaseColumns#_ID} にする必要があります。
+
+
+URL に含まれる ID をエンコードすることでも、アップデートを実行できます。この例では、カレンダーの表示名をこの({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()} を使用する)アプローチで変更しています。
+
+
+
+
private static final String DEBUG_TAG = "MyActivity"; +... +long calID = 2; +ContentValues values = new ContentValues(); +// The new display name for the calendar +values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar"); +Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows);+ +
カレンダーの挿入 + +
カレンダーは主に同期アダプタで管理するように設計されているため、新しいカレンダーは必ず同期アダプタとして挿入してください。 +ほとんどの場合、アプリケーションはカレンダーに対し、表示名の変更のような表面的な変更しかできません。 +アプリケーションがローカル カレンダーを作成する必要がある場合は、{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} として {@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} を使用し、カレンダーの挿入を同期アダプタとして実行することで作成できます。{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} は、端末アカウントと関連付けられていないカレンダー用の特殊なアカウント タイプです。 + + + + + + +このタイプのカレンダーは、サーバーと同期されません。同期アダプタの詳細については、同期アダプタをご覧ください。 +
+ +Events テーブル
+ +{@link android.provider.CalendarContract.Events} テーブルには、個々のイベントの詳細情報が格納されます。 + +イベントを追加、アップデート、削除するためには、アプリケーションはマニフェスト ファイルに {@link android.Manifest.permission#WRITE_CALENDAR} パーミッションを含める必要があります。 +
+ +次に示す Events の列は、アプリケーションと同期アダプタのどちらからも書き込み可能です。 +サポートされているすべてのフィールドの一覧については、{@link android.provider.CalendarContract.Events} のリファレンスをご覧ください。 +
+ +定数 | +説明 | +
---|---|
{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID} | +イベントが属するカレンダーの {@link android.provider.BaseColumns#_ID}。 | +
{@link android.provider.CalendarContract.EventsColumns#ORGANIZER} | +イベントの主催者(所有者)のメールアドレス。 | +
{@link android.provider.CalendarContract.EventsColumns#TITLE} | +イベントのタイトル。 | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION} | +イベントが開催される場所。 | +
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION} | +イベントの説明。 | +
{@link android.provider.CalendarContract.EventsColumns#DTSTART} | +エポックからの UTC ミリ秒単位で表現されたイベント開始時刻。 | +
{@link android.provider.CalendarContract.EventsColumns#DTEND} | +エポックからの UTC ミリ秒単位で表現されたイベント終了時刻。 | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE} | +イベントのタイムゾーン。 | +
{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE} | +イベントの終了時刻のタイムゾーン。 | +
{@link android.provider.CalendarContract.EventsColumns#DURATION} | + +RFC5545 形式でのイベントの期間。たとえば、"PT1H" という値はイベントが 1 時間であること、"P2W" という値は期間が 2 週間であることを示します。
+
+
+ |
+
+
+
{@link android.provider.CalendarContract.EventsColumns#ALL_DAY} | + +値 1 は、そのイベントがローカルのタイムゾーンで定義された終日を占めることを示します。 +値 0 は、1 日のどこかで始まって終わる定例のイベントであることを示します。 + | + + +
{@link android.provider.CalendarContract.EventsColumns#RRULE} | + +イベント形式の繰り返し発生ルール。たとえば、"FREQ=WEEKLY;COUNT=10;WKST=SU" のようになります。
+その他の例については、こちらをご覧ください。
+ |
+
+
{@link android.provider.CalendarContract.EventsColumns#RDATE} | +イベントの繰り返し発生日。通常、{@link android.provider.CalendarContract.EventsColumns#RDATE} は {@link android.provider.CalendarContract.EventsColumns#RRULE} と組み合わせて、繰り返し発生全体を定義するのに使用します。 + + + +詳細については、RFC5545 の仕様をご覧ください。 | +
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY} | + +このイベントを埋まっている時間に数えるか、それともスケジュールのやり直しが利く空き時間とみなすか。 + | + +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY} | +ゲストがイベントを変更できるかどうか。 | +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS} | +ゲストが他のゲストを招待できるかどうか。 | +
{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS} | +ゲストが他の参加者のリストを参照できるかどうか。 | +
イベントの追加
+ +アプリケーションが新しいイベントを挿入する場合は、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用することをお勧めします。詳細については、インテントを使用したイベントの挿入をご覧ください。 +ただし、必要があればイベントを直接挿入できます。 +ここではその方法について説明します。 +
+ + +新しいイベントを挿入するためのルールは次のとおりです。
+-
+
+
- {@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID} と {@link android.provider.CalendarContract.EventsColumns#DTSTART} を含める必要があります。 + + + +
- {@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE} を含める必要があります。 +システムにインストールされているタイムゾーン ID のリストを取得するには、{@link java.util.TimeZone#getAvailableIDs()} を使用します。 + +インテントを使用したイベントの挿入で説明しているように、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用してイベントを挿入している場合、このルールは該当しません—その場合はデフォルトのタイムゾーンが指定されます。 + + + + +
- 繰り返されないイベントには、{@link android.provider.CalendarContract.EventsColumns#DTEND} を含める必要があります。 + + + +
- 繰り返されるイベントには、{@link android.provider.CalendarContract.EventsColumns#RRULE} と {@link android.provider.CalendarContract.EventsColumns#RDATE} に加えて {@link android.provider.CalendarContract.EventsColumns#DURATION} を含める必要があります。 + + +インテントを使用したイベントの挿入で説明しているように、{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用してイベントを挿入している場合、このルールは該当しません—その場合は、{@link android.provider.CalendarContract.EventsColumns#RRULE} を {@link android.provider.CalendarContract.EventsColumns#DTEND} と {@link android.provider.CalendarContract.EventsColumns#DTSTART} と組み合わせて使用でき、カレンダー アプリケーションはこれを自動で期間に変換します。 + + + + + + +
イベントの挿入の例を次に示します。簡潔にするため、この例は UI スレッドで実行されています。 +実際には、挿入やアップデートは非同期スレッドで実行して、アクションをバックグラウンド スレッドに移してください。 +詳細については、{@link android.content.AsyncQueryHandler} をご覧ください。 +
+ + ++long calID = 3; +long startMillis = 0; +long endMillis = 0; +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 9, 14, 7, 30); +startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 9, 14, 8, 45); +endMillis = endTime.getTimeInMillis(); +... + +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Events.DTSTART, startMillis); +values.put(Events.DTEND, endMillis); +values.put(Events.TITLE, "Jazzercise"); +values.put(Events.DESCRIPTION, "Group workout"); +values.put(Events.CALENDAR_ID, calID); +values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles"); +Uri uri = cr.insert(Events.CONTENT_URI, values); + +// get the event ID that is the last element in the Uri +long eventID = Long.parseLong(uri.getLastPathSegment()); +// +// ... do something with event ID +// +//+ +
注: イベントの作成後にイベント ID を取得していることに注目してください。 +これがイベント ID を取得する最も簡単な方法です。他のカレンダー操作を実行するためにイベント ID が必要になることはよくあります—イベントに対する参加者やリマインダーの追加などが該当します。 + +
+ + +イベントのアップデート
+ +アプリケーションでユーザーによるイベントの編集を許可する場合は、{@link android.content.Intent#ACTION_EDIT EDIT} インテントを使用することをお勧めします。詳細については、インテントを使用したイベントの挿入をご覧ください。ただし、イベントは必要に応じて直接編集できます。
+
+
+イベントのアップデートを実行する場合は、イベントの _ID
を、URI({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})の末尾に追加された ID として、または前出の selection の最初の項目として指定できます。
+
+
+
+前出の selection を "_id=?"
で始め、最初の selectionArg
をカレンダーの _ID
にする必要があります。
+
+ID なしの selection を使用してアップデートすることもできます。次に、イベントのアップデートの例を示します。
+
+ここでは、{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()} を使用するアプローチでイベントのタイトルを変更しています。
+
+
private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 188; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri updateUri = null; +// The new title for the event +values.put(Events.TITLE, "Kickboxing"); +updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().update(updateUri, values, null, null); +Log.i(DEBUG_TAG, "Rows updated: " + rows);+ +
イベントの削除
+ +イベントは、目的のイベントの {@link android.provider.BaseColumns#_ID} を URI の末尾に追加する ID として使用するか、標準的な選択を使用して削除できます。 + +ID の追加で削除を実行する場合、選択はできません。削除には、アプリケーションとして実行する方法と同期アダプタとして実行する方法の 2 種類があります。 +アプリケーションとしての削除では、削除される列が 1 に設定されます。 +このフラグは同期アダプタに対して、その行が削除されたことを通知し、この削除をサーバーに通知するよう指示します。 + +同期アダプタとしての削除では、すべての関連データとともにデータベースからイベントが削除されます。 +次の例では、アプリケーションがイベントをその {@link android.provider.BaseColumns#_ID} を使用して削除しています。 +
+ + +private static final String DEBUG_TAG = "MyActivity"; +... +long eventID = 201; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +Uri deleteUri = null; +deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +int rows = getContentResolver().delete(deleteUri, null, null); +Log.i(DEBUG_TAG, "Rows deleted: " + rows); ++ +
Attendees テーブル
+ +{@link android.provider.CalendarContract.Attendees} テーブルの各行は、あるイベントの 1 人の参加者ないしゲストを表します。 +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} を呼び出すと、指定された {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} を持つイベントの参加者リストが返されます。 + + +この {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} は特定のイベントの {@link android.provider.BaseColumns#_ID} と一致している必要があります。 + + +
+ +次の表に、書き込み可能なフィールドを示します。
+新しい参加者を挿入する際には、ATTENDEE_NAME
を除くすべてを含める必要があります。
+
+
定数 | +説明 | +
---|---|
{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} | +イベントの ID。 | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME} | +参加者の名前。 | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL} | +参加者のメールアドレス。 | +
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP} | +参加者のイベントに対する関係。次のどれかです。 +
|
+
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE} | +参加者のタイプ。次のどれかです。 +
|
+
{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS} | +参加者の出席ステータス。次のどれかです。 +
|
+
参加者の追加
+ +次の例では、あるイベントに 1 人の参加者を挿入しています。{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} は必須です。 + +
+ ++long eventID = 202; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Attendees.ATTENDEE_NAME, "Trevor"); +values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com"); +values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); +values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL); +values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); +values.put(Attendees.EVENT_ID, eventID); +Uri uri = cr.insert(Attendees.CONTENT_URI, values); ++ +
Reminders テーブル
+ +{@link android.provider.CalendarContract.Reminders} テーブルの各行は、あるイベントの 1 つのリマインダーを表します。 +{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} を呼び出すと、指定された {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID} を持つイベントのリマインダー リストが返されます。 + + +
+ + +次の表に、リマインダーに関する書き込み可能なフィールドを示します。新しいリマインダーを挿入する際には、これらをすべて含める必要があります。 +同期アダプタは、サポートするリマインダーのタイプを {@link android.provider.CalendarContract.Calendars} テーブルで指定しています。 + +詳細については、{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS} をご覧ください。 + +
+ + +定数 | +説明 | +
---|---|
{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID} | +イベントの ID。 | +
{@link android.provider.CalendarContract.RemindersColumns#MINUTES} | +リマインダーが通知されるまでの分単位の時間。 | +
{@link android.provider.CalendarContract.RemindersColumns#METHOD} | +アラーム手段。サーバーに設定されます。次のどれかです。 +
|
+
リマインダーの追加
+ +この例では、イベントにリマインダーを追加します。このリマインダーは、イベントの 15 分前に通知されます。 +
++long eventID = 221; +... +ContentResolver cr = getContentResolver(); +ContentValues values = new ContentValues(); +values.put(Reminders.MINUTES, 15); +values.put(Reminders.EVENT_ID, eventID); +values.put(Reminders.METHOD, Reminders.METHOD_ALERT); +Uri uri = cr.insert(Reminders.CONTENT_URI, values);+ +
Instances テーブル
+ +{@link android.provider.CalendarContract.Instances} テーブルは、あるイベントの発生の開始時刻と終了時刻を保持します。 + +各行は、イベントの発生 1 回を表します。 +Instances テーブルは書き込みできません。イベントの発生をクエリする手段を提供するためだけのものです。 +
+ +次の表に、インスタンスに関してクエリできるフィールドの一部を示します。タイムゾーンは {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE} と {@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES} で定義されます。 + + + +
+ + +定数 | +説明 | +
---|---|
{@link android.provider.CalendarContract.Instances#BEGIN} | +インスタンスの開始時刻(UTC ミリ秒単位)。 | +
{@link android.provider.CalendarContract.Instances#END} | +インスタンスの終了時刻(UTC ミリ秒単位)。 | +
{@link android.provider.CalendarContract.Instances#END_DAY} | + +インスタンスの、カレンダーのタイムゾーンにおけるユリウス暦での終了日。 + + + | +
{@link android.provider.CalendarContract.Instances#END_MINUTE} | + +カレンダーのタイムゾーンにおける午前零時を基準にしたインスタンスの終了分。 + | + +
{@link android.provider.CalendarContract.Instances#EVENT_ID} | +このインスタンスのイベントの _ID 。 |
+
{@link android.provider.CalendarContract.Instances#START_DAY} | +インスタンスの、カレンダーのタイムゾーンにおけるユリウス暦での開始日。 + | +
{@link android.provider.CalendarContract.Instances#START_MINUTE} | + +カレンダーのタイムゾーンにおける午前零時を基準にしたインスタンスの開始分。 + + | + +
Instances テーブルへのクエリ
+ +Instances テーブルにクエリするには、クエリの範囲を示す時刻を URI に指定する必要があります。この例で、{@link android.provider.CalendarContract.Instances} は {@link android.provider.CalendarContract.EventsColumns} インターフェースの実装を介して {@link android.provider.CalendarContract.EventsColumns#TITLE} フィールドへのアクセスを取得します。 + + + +言い換えると、{@link android.provider.CalendarContract.EventsColumns#TITLE} はデータベースの参照に対して返されているのであって、{@link android.provider.CalendarContract.Instances} テーブルそのものへのクエリに対して返されているのではありません。 + + + +
+ ++private static final String DEBUG_TAG = "MyActivity"; +public static final String[] INSTANCE_PROJECTION = new String[] { + Instances.EVENT_ID, // 0 + Instances.BEGIN, // 1 + Instances.TITLE // 2 + }; + +// The indices for the projection array above. +private static final int PROJECTION_ID_INDEX = 0; +private static final int PROJECTION_BEGIN_INDEX = 1; +private static final int PROJECTION_TITLE_INDEX = 2; +... + +// Specify the date range you want to search for recurring +// event instances +Calendar beginTime = Calendar.getInstance(); +beginTime.set(2011, 9, 23, 8, 0); +long startMillis = beginTime.getTimeInMillis(); +Calendar endTime = Calendar.getInstance(); +endTime.set(2011, 10, 24, 8, 0); +long endMillis = endTime.getTimeInMillis(); + +Cursor cur = null; +ContentResolver cr = getContentResolver(); + +// The ID of the recurring event whose instances you are searching +// for in the Instances table +String selection = Instances.EVENT_ID + " = ?"; +String[] selectionArgs = new String[] {"207"}; + +// Construct the query with the desired date range. +Uri.Builder builder = Instances.CONTENT_URI.buildUpon(); +ContentUris.appendId(builder, startMillis); +ContentUris.appendId(builder, endMillis); + +// Submit the query +cur = cr.query(builder.build(), + INSTANCE_PROJECTION, + selection, + selectionArgs, + null); + +while (cur.moveToNext()) { + String title = null; + long eventID = 0; + long beginVal = 0; + + // Get the field values + eventID = cur.getLong(PROJECTION_ID_INDEX); + beginVal = cur.getLong(PROJECTION_BEGIN_INDEX); + title = cur.getString(PROJECTION_TITLE_INDEX); + + // Do something with the values. + Log.i(DEBUG_TAG, "Event: " + title); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(beginVal); + DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime())); + } + }+ +
カレンダーのインテント
+アプリケーションがカレンダー データの読み取りや書き込みを実行するのにパーミッションは要りません。その代わり、Android のカレンダー アプリケーションがサポートするインテントを使用し、読み取りと書き込みの操作をそのアプリケーションに引き渡します。次の表に、カレンダー プロバイダによってサポートされているインテントを示します。
+アクション | +URI | + +説明 | +エクストラ | +
---|---|---|---|
+ {@link android.content.Intent#ACTION_VIEW VIEW} |
+
|
+ <ms_since_epoch> に指定された時刻でカレンダーを開きます。 |
+ なし | +
{@link android.content.Intent#ACTION_VIEW VIEW} + + |
+
|
+ <event_id> で指定されたイベントを参照します。 |
+
+ {@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} + + + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
+
{@link android.content.Intent#ACTION_EDIT EDIT} | +
|
+ <event_id> で指定されたイベントを編集します。 |
+
+ {@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} + + + {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} |
+
{@link android.content.Intent#ACTION_EDIT EDIT} + + {@link android.content.Intent#ACTION_INSERT INSERT} |
+
|
+
+ イベントを作成します。 | +次の表に示された任意のエクストラ。 | +
次の表に、カレンダー プロバイダによってサポートされているインテント エクストラを示します。 +
+インテント エクストラ | +説明 | +
---|---|
{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE} | +イベントの名前。 | +
{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} + | +イベントの開始時刻(エポックからのミリ秒単位)。 | +
{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} + | + +イベントの終了時刻(エポックからのミリ秒単位)。 | +
{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY CalendarContract.EXTRA_EVENT_ALL_DAY} + | + +イベントが終日かどうかを示すブール値。使用できる値は true または false です。
+ |
{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION Events.EVENT_LOCATION} + | + +イベントの場所。 | +
{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION Events.DESCRIPTION} + | + +イベントの説明。 | +
+ {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} | +招待者のメールアドレス(コンマ区切りリスト形式)。 | +
+ {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE} | +イベントの反復ルール。 | +
+ {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL Events.ACCESS_LEVEL} + | + +イベントが公開か非公開か。 | +
{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY Events.AVAILABILITY} + | + +このイベントを埋まっている時間に数えるか、それともスケジュールのやり直しが利く空き時間とみなすか。 | + +
次のセクションでは、これらのインテント使用方法を説明します。
+ + +インテントを使用したイベントの挿入
+ +{@link android.content.Intent#ACTION_INSERT INSERT} インテントを使用すると、アプリケーションはイベント挿入タスクをカレンダーそのものに引き渡すことができます。このアプローチでは、アプリケーションは {@link android.Manifest.permission#WRITE_CALENDAR} パーミッションをマニフェスト ファイルに含める必要さえなくなります。 + + +
+ + +このアプローチのアプリケーションをユーザーが実行すると、アプリケーションによってユーザーがカレンダーに誘導されイベントを追加できるようになります。 +{@link android.content.Intent#ACTION_INSERT INSERT} インテントは、追加フィールドを使用して、カレンダーに格納されている詳細情報をフォームに自動入力します。 + +それに対して、ユーザーはイベントのキャンセル、必要に応じたイベントの編集、イベントのカレンダーへの保存ができます。 + +
+ + + +次に示すのは、2012 年 1 月 19 日の午前 7:30 から 午前 8:30 までのイベントをスケジュールするコード スニペットです。 +このコード スニペットの以下の点に注目してください。
+ +-
+
- URI として {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI} を指定しています。 + + +
- {@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME} と {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME} の各エクストラ フィールドを使用して、イベントの時間をフォームに自動入力しています。 + + + + +これらの値は、エポックからの UTC ミリ秒単位であることが必要です。 + + +
- {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL} エクストラ フィールドを使用して、参加者をメールアドレスで示したコンマ区切りリストを指定しています。 + + +
+Calendar beginTime = Calendar.getInstance(); +beginTime.set(2012, 0, 19, 7, 30); +Calendar endTime = Calendar.getInstance(); +endTime.set(2012, 0, 19, 8, 30); +Intent intent = new Intent(Intent.ACTION_INSERT) + .setData(Events.CONTENT_URI) + .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()) + .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()) + .putExtra(Events.TITLE, "Yoga") + .putExtra(Events.DESCRIPTION, "Group class") + .putExtra(Events.EVENT_LOCATION, "The gym") + .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY) + .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com"); +startActivity(intent); ++ +
インテントを使用したイベントの編集
+ +イベントは、イベントのアップデートで説明したように、直接アップデートできます。ただし、{@link android.content.Intent#ACTION_EDIT EDIT} インテントを使用すれば、パーミッションのないアプリケーションが、カレンダー アプリケーションにイベント編集を引き渡すことができます。カレンダーでのイベント編集を終えたユーザーは、元のアプリケーションに戻ります。 + + + +
次の例のインテントは、指定されたイベントの新しいタイトルを設定して、ユーザーがそのイベントをカレンダーで編集できるようにしています。 +
+ + +long eventID = 208; +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_EDIT) + .setData(uri) + .putExtra(Events.TITLE, "My New Title"); +startActivity(intent);+ +
インテントを使用したカレンダー データの参照
+カレンダー プロバイダには、{@link android.content.Intent#ACTION_VIEW VIEW} インテントを使用する次の 2 つの方法が用意されています。
+-
+
- 特定の日付のカレンダーを開く方法。 +
- イベントを参照する方法。 + +
次の例は、特定の日付のカレンダーを開く方法を示しています。
+// A date-time specified in milliseconds since the epoch. +long startMillis; +... +Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); +builder.appendPath("time"); +ContentUris.appendId(builder, startMillis); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(builder.build()); +startActivity(intent);+ +
次の例は、参照するためにイベントを開く方法を示しています。
+long eventID = 208; +... +Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); +Intent intent = new Intent(Intent.ACTION_VIEW) + .setData(uri); +startActivity(intent); ++ + +
同期アダプタ
+ + +アプリケーションと同期アダプタとの間で、カレンダー プロバイダにアクセスする方法の違いは、次のいくつかだけです。 +
+ +-
+
- 同期アダプタは、{@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} を
true
に設定して、それが同期アダプタであることを示す必要があります。
+
+
+ - 同期アダプタは、{@link android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} と {@link android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} をクエリ パラメータとして URI に指定する必要があります。 + + + +
- 同期アダプタは、アプリケーションやウィジェットより多くの列に書き込みアクセスできます。
+ たとえば、アプリケーションで変更できるのは、名前、表示名、可視性の設定、カレンダーが同期対象かどうかなど、カレンダーの特性の一部のみです。
+
+それに対し、同期アダプタはこれらの列の他に、カレンダーの色、タイムゾーン、アクセスレベル、場所など、数多くにアクセスできます。ただし、
ACCOUNT_NAME
とACCOUNT_TYPE
で指定されるものだけに限定されます。 + + +
次に示すヘルパー メソッドを使用すると、同期アダプタで使用するための URI が返されます。
+static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } ++
同期アダプタの実装例(カレンダーに特化されたものではありません)については、SampleSyncAdapter をご覧ください。 + diff --git a/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd b/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd new file mode 100644 index 0000000000000000000000000000000000000000..e12b62f222c535c2c9cb4b0aecd4d6c7999eafda --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/contacts-provider.jd @@ -0,0 +1,2356 @@ +page.title=連絡先プロバイダ +@jd:body +
クイックビュー
+-
+
- 人の情報に関する Android のリポジトリ。 +
- + ウェブとの同期。 + +
- + ソーシャル ストリーム データの統合。 + +
本書の内容
+-
+
- + 連絡先プロバイダの構成 + +
- + 未加工連絡先 + +
- + データ + +
- + 連絡先 + +
- + 同期アダプタからのデータ + +
- + 必要なパーミッション + +
- + ユーザー プロファイル + +
- + 連絡先プロバイダのメタデータ + +
- + 連絡先プロバイダへのアクセス +
- + +
- + 連絡先プロバイダの同期アダプタ + +
- + ソーシャル ストリーム データ + +
- + 連絡先プロバイダの追加機能 + +
キークラス
+-
+
- {@link android.provider.ContactsContract.Contacts} +
- {@link android.provider.ContactsContract.RawContacts} +
- {@link android.provider.ContactsContract.Data} +
- {@code android.provider.ContactsContract.StreamItems} +
関連サンプル
+-
+
- + Contact Manager + + + +
- + サンプル同期アダプタ + + +
関連ドキュメント
+-
+
- + コンテンツ プロバイダの基本 + + + +
+ 連絡先プロバイダは、人のデータに関する端末の中央リポジトリを管理する、柔軟で効果的な Android コンポーネントです。 +連絡先プロバイダは、端末の連絡先アプリケーションに表示されるデータのソースであり、さらに独自アプリケーションで連絡先プロバイダのデータにアクセスし、端末とオンライン サービスとの間でデータを転送することもできます。 + +このプロバイダは幅広いデータソースに対応しており、各人に関してできるだけ多くのデータを管理しようとするため、複雑な構造をしています。 + +そのため、連絡先プロバイダの API には、データの取得と変更をどちらもやりやすくするクラスやインターフェースが多数用意されています。 + + +
++ このガイドでは、以下について説明します。 +
+-
+
- + プロバイダの基本構造。 + +
- + プロバイダからのデータの取得方法。 + +
- + プロバイダでのデータの変更方法。 + +
- + サーバーから連絡先プロバイダとデータを同期する同期アダプタの作成方法。 + + +
+ このガイドは、Android のコンテンツ プロバイダの基礎知識がある読者を対象としています。Android のコンテンツ プロバイダについて詳しくは、「コンテンツ プロバイダの基本」をご覧ください。 + + +サンプル同期アダプタ サンプルアプリは、同期アダプタを使用して連絡先プロバイダと Google ウェブ サービスでホストされているサンプル アプリケーションとの間でデータを転送する例です。 + + + +
+連絡先プロバイダの構成
++ 連絡先プロバイダは、Android のコンテンツ プロバイダ コンポーネントです。人に関する 3 種類のデータを保持しており、それぞれがコンテンツ プロバイダによって提供される 1 つのテーブルに対応しています。この構成を図 1 に示します。 + + +
+ + ++ この 3 つのテーブルは、一般にそれぞれのコントラクト クラス名で呼ばれます。各クラスは、テーブルによって使用されるコンテンツ URI、列名、列の値のための定数を定義しています。 + +
+-
+
- + {@link android.provider.ContactsContract.Contacts} テーブル + +
- + 各行は、未加工連絡先の行の集約に基づいて異なる人を表します。 + +
- + {@link android.provider.ContactsContract.RawContacts} テーブル + +
- + 各行には、ユーザーのアカウントとタイプに固有の、人に関するデータの概要が格納されています。 + +
- + {@link android.provider.ContactsContract.Data} テーブル + +
- + 各行には、メールアドレスや電話番号など、未加工連絡先の詳細情報が格納されています。 + +
+ {@link android.provider.ContactsContract} に含まれるコントラクト クラスによって表現される他のテーブルは補助テーブルであり、連絡先プロバイダがその操作を管理したり、端末の連絡先アプリや電話アプリの特定機能をサポートしたりするために使用します。 + + +
+未加工連絡先
++ 未加工連絡先は、アカウント タイプとアカウント名の 1 つのペアを使用して得られる人に関するデータです。 +連絡先プロバイダでは、1 人に関するデータのソースとして複数のオンライン サーバーを使用できるため、同じ個人に対して複数の未加工連絡先が許されます。 + + 未加工連絡先が複数ある場合、ユーザーは同じアカウント タイプの複数のアカウントから取得したその人のデータを組み合わせることができます。 + +
++ 未加工連絡先データの大半は、{@link android.provider.ContactsContract.RawContacts} テーブルには格納されません。 +その代わり、{@link android.provider.ContactsContract.Data} テーブルの 1 つまたは複数の行に格納されています。 +各データ行には列 {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} があり、親 {@link android.provider.ContactsContract.RawContacts} 行の {@code android.provider.BaseColumns#_ID RawContacts._ID} 値が格納されています。 + + + +
+重要な未加工連絡先列
++ 表 1 に、{@link android.provider.ContactsContract.RawContacts} の重要な列を示します。 +表の後の注もお読みください。 +
+ +列名 | +用途 | +注 | +
---|---|---|
+ {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME} + | ++ この未加工連絡先のソースであるアカウント タイプにおけるアカウント名。 + たとえば、Google アカウントのアカウント名は、デバイス オーナーの Gmail アドレスのどれかです。 +詳しくは、次の {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} の項目をご覧ください。 + + + | ++ この名前の形式は、アカウント タイプによって異なります。必ずしもメールアドレスとは限りません。 + + | +
+ {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} + | +
+ この未加工連絡先のソースであるアカウント タイプ。たとえば、Google アカウントのアカウント タイプは com.google です。
+アカウント タイプは必ず、所有または管理しているドメインのドメイン ID で修飾してください。
+そうすることで、アカウント タイプが確実に一意になります。
+
+ |
+ + 連絡先データを提供するアカウント タイプには、通常、連絡先プロバイダと同期する関連同期アダプタが用意されています。 + + |
+ {@link android.provider.ContactsContract.RawContactsColumns#DELETED} + | ++ 未加工連絡先の「削除済み」フラグ。 + | ++ 連絡先プロバイダは、同期アダプタが該当行をサーバーから削除し、最終的にリポジトリから削除するまで、このフラグを基に行を内部的に管理します。 + + + | +
注
++ 次に、{@link android.provider.ContactsContract.RawContacts} テーブルに関する重要な注を示します。 + +
+-
+
- + 未加工連絡先の名前は、{@link android.provider.ContactsContract.RawContacts} の行には格納されません。 +その代わり、{@link android.provider.ContactsContract.Data} テーブルの {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行に格納されます。 + +未加工連絡先は、このタイプの行を {@link android.provider.ContactsContract.Data} テーブルに 1 行だけ持ちます。 + + +
-
+ 警告: 未加工連絡先の行で独自のアカウント データを使用する場合は、まずそれを {@link android.accounts.AccountManager} に登録する必要があります。
+登録するには、ユーザーに対し、アカウントのリストにアカウント タイプとアカウント名を追加するよう求めます。
+そうしないと、連絡先プロバイダによって未加工連絡先の行が自動的に削除されてしまいます。
+
+
+ たとえば、ドメインが {@code com.example.dataservice} であるウェブベースのサービス用に連絡先データをアプリで管理する場合、そのサービス用のユーザー アカウントが {@code becky.sharp@dataservice.example.com} であれば、そのユーザーが先にそのアカウントの「タイプ」({@code com.example.dataservice})と「名前」({@code becky.smart@dataservice.example.com})を追加しておくことで、アプリが未加工連絡先の行を追加できるようになります。 + + + + + この要件については、文書で説明するか、ユーザーにタイプと名前を追加するよう求めるか、あるいはその両方を実施してください。 +アカウントのタイプと名前については、次のセクションで詳しく説明します。 + +
+
未加工連絡先データのソース
++ 未加工連絡先の働きを理解するために、「Emily Dickinson」というユーザーについて考えてみましょう。彼女は自分の端末に次の 3 つのアカウントを定義しています。 + +
+-
+
emily.dickinson@gmail.com
+ emilyd@gmail.com
+ - Twitter アカウント「belle_of_amherst」 +
+ このユーザーは、[アカウント] の設定でこの 3 つのアカウントすべてについて [連絡先を同期] を有効にしています。 + +
+
+ Emily Dickinson がブラウザのウィンドウを開き、Gmail に emily.dickinson@gmail.com
としてログインし、[連絡先] を開いて「Thomas Higginson」を追加したとしましょう。
+
+後日、彼女が Gmail に emilyd@gmail.com
としてログインし、メールを「Thomas Higginson」宛てに送信すると、彼は自動的に連絡先として追加されます。
+
+彼女はまた、Twitter で「colonel_tom」(Thomas Higginson の Twitter ID)をフォローしています。
+
+
+ 連絡先プロバイダは、この操作の結果として次の 3 行の未加工連絡先を作成します。 +
+-
+
-
+ 「Thomas Higginson」の、
emily.dickinson@gmail.com
に関連付けられた未加工連絡先。 + ユーザー アカウントのタイプは Google です。 +
+ -
+ 「Thomas Higginson」の、
emilyd@gmail.com
に関連付けられた新たな未加工連絡先。 + ユーザー アカウントのタイプはやはり Google です。名前が前の行とまったく同じなのに新たな未加工連絡先が作成されたのは、この個人が異なるユーザー アカウントに追加されたからです。 + + +
+ - + 「Thomas Higginson」の、「belle_of_amherst」に関連付けられた未加工連絡先。ユーザー アカウントのタイプは Twitter です。 + + +
データ
+
+ 前にも説明したように、未加工連絡先のデータは未加工連絡先の _ID
値にリンクされている {@link android.provider.ContactsContract.Data} 行に格納されます。
+
+これにより、1 つの未加工連絡先が同じタイプのデータ(メールアドレスや電話番号など)のインスタンスを複数持つことができます。
+たとえば、{@code emilyd@gmail.com} に対する「Thomas Higginson」(Google アカウント emilyd@gmail.com
に関連付けられた、Thomas Higginson の未加工連絡先の行)には、thigg@gmail.com
という個人用アドレスと thomas.higginson@gmail.com
という仕事用アドレスがあり、連絡先プロバイダはこの 2 つのメールアドレスの行を格納し、両方とも同じ未加工連絡先にリンクします。
+
+
+
+
+
+
+ 異なるタイプのデータが同じテーブルに格納されることに注目してください。表示名、電話番号、メール、住所、写真、ウェブサイトに関する詳細行はすべて、{@link android.provider.ContactsContract.Data} テーブルにあります。 + +これを管理しやすくするため、{@link android.provider.ContactsContract.Data} テーブルの一部の行には説明的な名前が、それ以外には一般的な名前がそれぞれ付いています。 + +説明的な名前が付いた列の内容は、行データのタイプによらず意味が同じなのに対し、一般的な名前が付いた列の内容は、データのタイプによって意味が異なります。 + + +
+説明的な名前の列
++ 説明的な名前が付いた列の例をいくつか示します。 +
+-
+
- + {@link android.provider.ContactsContract.Data#RAW_CONTACT_ID} + +
-
+ このデータの、未加工連絡先の
_ID
列の値。 +
+ - + {@link android.provider.ContactsContract.Data#MIMETYPE} + +
- + カスタム MIME タイプで表現した、この行に格納されているデータのタイプ。連絡先プロバイダは、{@link android.provider.ContactsContract.CommonDataKinds} のサブクラスに定義されている MIME タイプを使用します。 + +これらの MIME タイプはオープンソースで、連絡先プロバイダと連携する任意のアプリケーションまたは同期アダプタで使用できます。 + + +
- + {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} + +
- + このタイプのデータ行が 1 つの未加工連絡先に対して複数発生する場合、{@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} 列はそのタイプに対するプライマリ データを含むデータ行を示します。 + +たとえば、ユーザーがある連絡先の電話番号を長押しし、[デフォルトに設定] を選択すると、その番号を含む {@link android.provider.ContactsContract.Data} 行の {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} 列にゼロでない値が設定されます。 + + + + + +
汎用名の列
+
+ 自由に使用できる DATA1
~ DATA15
という 15 個の汎用列の他に、同期アダプタしか使用してはいけない SYNC1
~ SYNC4
という 4 個の列があります。
+
+
+汎用名列の定数は、行に指定されているデータのタイプによらず、常に機能します。
+
+
+ DATA1
列はインデックス付きです。連絡先プロバイダは常に、この列を、最も頻繁にクエリの対象となるとプロバイダが予想するデータ用の列として使用します。
+たとえば、メールの行では、この列には実際のメールアドレスが格納されます。
+
+
+ DATA15
は慣例として、写真サムネイルのようなバイナリ ラージ オブジェクト(BLOB)データ用に予約されています。
+
+
タイプ固有の列名
++ 特定タイプの行に含まれる列に対する作業をやりやすくするため、連絡先プロバイダではタイプ固有の列名定数もあり、たとえば {@link android.provider.ContactsContract.CommonDataKinds} のサブクラスに定義されています。 + +こうした定数は、同じ列名に異なる定数名を充てて、特定タイプの行に含まれるデータにアクセスしやすくしているだけのものです。 + + +
++ たとえば、{@link android.provider.ContactsContract.CommonDataKinds.Email} クラスには、MIME タイプが {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE Email.CONTENT_ITEM_TYPE} である{@link android.provider.ContactsContract.Data} 行向けにタイプ固有の列名定数が定義されています。 + + + +このクラスには、メールアドレス 列用に {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} という定数が含まれています。 + +{@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} の実際の値は「data1」で、これはこの列の汎用名と同じです。 + + +
+
+ 警告: 連絡先プロバイダにあらかじめ定義されている MIME タイプのどれかである行を使用している {@link android.provider.ContactsContract.Data} テーブルには、独自のカスタムデータを追加しないでください。
+
+追加すると、データが失われたり、連絡先プロバイダが誤動作したりすることがあります。
+たとえば、メールアドレスではなくユーザー名が格納されている MIME タイプ {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE Email.CONTENT_ITEM_TYPE} の行は、列 DATA1
には追加しないでください。
+
+
+一方、行に独自のカスタム MIME タイプを使用している場合は、独自のタイプ固有名を定義して列を自由に使用してかまいません。
+
+
+ 図 2 に、説明的な名前の列とデータ列で {@link android.provider.ContactsContract.Data} 行がどう見えるか、そしてタイプ固有の列名が汎用列名をどう「オーバーレイ」するかを示します。 + + +
+ + +タイプ固有列名が使用されるクラス
++ 表 2 に、最もよく用いられるタイプ固有列名クラスを示します。 +
+ +対応クラス | +データのタイプ | +注 | +
---|---|---|
{@link android.provider.ContactsContract.CommonDataKinds.StructuredName} | +このデータ行に関連付けられている未加工連絡先の名前データ。 | +1 つの未加工連絡先は、この行を 1 行だけ持ちます。 | +
{@link android.provider.ContactsContract.CommonDataKinds.Photo} | +このデータ行に関連付けられている未加工連絡先のメインの写真。 | +1 つの未加工連絡先は、この行を 1 行だけ持ちます。 | +
{@link android.provider.ContactsContract.CommonDataKinds.Email} | +このデータ行に関連付けられている未加工連絡先のメールレアドレス。 | +1 つの未加工連絡先は複数のメールアドレスを持つことができます。 | +
{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal} | +このデータ行に関連付けられている未加工連絡先の住所。 | +1 つの未加工連絡先は複数の住所を持つことができます。 | +
{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} | +その未加工連絡先を連絡先プロバイダのグループのどれかにリンクする識別子。 | ++ グループは、アカウント タイプとアカウント名のオプション機能です。詳しくは、連絡先グループをご覧ください。 + + | +
連絡先
++ 連絡先プロバイダは、すべてのアカウント タイプとアカウント名にわたって未加工連絡先の行を結び付けて 1 つの連絡先を形成します。 +これにより、1 人の人についてユーザーが集めた全データを表示したり変更したりしやすくなります。 +連絡先プロバイダは、新しい連絡先の行の作成と、既存の連絡先の行を使用した未加工連絡先の集約とを管理します。 +アプリケーションと同期アダプタは連絡先の追加はできず、連絡先の行の一部の列は読み取り専用です。 + +
++ 注: 連絡先を連絡先プロバイダに {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()} を使用して追加しようとすると、{@link java.lang.UnsupportedOperationException} 例外が発生します。 + +「読み取り専用」になっている列をアップデートしようとしても、そのアップデートは無視されます。 + +
++ 連絡先プロバイダは、既存の連絡先と一致しない新しい未加工連絡先が追加されると、それに対して新しい連絡先を作成します。 +また、既存の未加工連絡先のデータが変更され、それまで関連付けられていた連絡先と一致しなくなった場合にも、同じ処理がなされます。 + +アプリケーションまたは同期アダプタが、既存の連絡先と一致する新しい未加工連絡先を作成すると、その新しい未加工連絡先は既存の連絡先に集約されます。 + + +
+
+ 連絡先プロバイダは、連絡先の行を未加工連絡先とリンクするのに、{@link android.provider.ContactsContract.Contacts Contacts} テーブルの _ID
列を使用します。
+
+未加工連絡先テーブル {@link android.provider.ContactsContract.RawContacts} の CONTACT_ID
列には、未加工連絡先の各行に関連付けられている連絡先の行の _ID
値が格納されます。
+
+
+
+ {@link android.provider.ContactsContract.Contacts} テーブルには列 {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} もあり、こちらは連絡先の行への「永久」リンクです。 + +連絡先プロバイダは連絡先を自動的に管理するため、集約や同期が行われると、それに応じて連絡先の行の {@code android.provider.BaseColumns#_ID} 値が変更される場合があります。 + +この処理が行われても、コンテンツ URI {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} と連絡先の {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} の組み合わせは、引き続きその連絡先の行を指すため、{@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} を使用して「お気に入り」の連絡先へのリンクを管理するなどができます。 + + + + +この列には、{@code android.provider.BaseColumns#_ID} 列の形式と関係のない独自の形式があります。 + +
++ 図 3 に、3 つのテーブルの相互関係を示します。 +
+ + +同期アダプタからのデータ
++ ユーザーは端末に連絡先データを直接入力しますが、データはウェブサービスから同期アダプタを経由して連絡先プロバイダにも流れます。同期アダプタは、端末とサービスの間のデータ転送を自動化します。 + +同期アダフタはシステムの管理下でバックグラウンドで実行され、{@link android.content.ContentResolver} のメソッドを呼び出してデータを管理します。 + + +
++ Android では、同期アダプタと連携するウェブサービスをアカウント タイプで識別します。 + 各同期アダプタが扱うアカウント タイプは 1 つですが、そのタイプのアカウント名を複数サポートできます。 +アカウント名とアカウント タイプについては、未加工連絡先データのソースで簡単に説明しています。 +次に、アカウント タイプとアカウント名が同期アダプタやサービスとどのような関係にあるかを詳しく説明します。 + +
+-
+
- + アカウント タイプ + +
-
+ ユーザーがデータを格納しているサービスを示します。ほとんどの場合、ユーザーにはサービスに対する認証が求められます。
+たとえば、Google Contacts はアカウント タイプの 1 つで、コード
google.com
で識別されます。 +この値は、{@link android.accounts.AccountManager} によって使用されるアカウント タイプに対応します。 + +
+ - + アカウント名 + +
- + あるアカウント タイプで使用する特定のアカウントまたはログインを示します。Google Contacts アカウントは Google アカウントと同じで、アカウント名としてメールアドレスを使用します。 + + 他のサービスでは、1 語のユーザー名や数字の ID が使われていることもあります。 + +
+ アカウント タイプは、一意である必要はありません。1 人のユーザーが複数の Google Contacts アカウントを設定し、それぞれのデータを連絡先プロバイダにダウンロードする、ということが可能です。このような使い方は、そのユーザーが個人用のアカウント名で私用の連絡先を、仕事用のアカウント名で仕事用の連絡先を管理している場合にありえます。 + +アカウント名は、普通は一意です。 +この 2 つを組み合わせて、連絡先プロバイダと外部サービスとの間のある決まったデータフローを識別します。 + +
++ 独自サービスのデータを連絡先プロバイダに転送する場合は、独自の同期アダプタを作成する必要があります。 +詳しくは、連絡先プロバイダの同期アダプタをご覧ください。 + +
++ 図 4 に、人に関するデータの流れにおける連絡先プロバイダの位置付けを示します。 +右から 2 列目の各ボックス内のアダプタには、そのアダプタのアカウント タイプが示されています。 +
+ + +必要なパーミッション
++ 連絡先プロバイダにアクセスするアプリケーションは、次のパーミッションを要求する必要があります。 + +
+-
+
- 1 つ以上のテーブルに対する読み取りアクセス +
-
+ {@link android.Manifest.permission#READ_CONTACTS}。
AndroidManifest.xml
に+ <uses-permission>
要素を使用して<uses-permission android:name="android.permission.READ_CONTACTS">
のように指定します。 + + + +
+ - 1 つ以上のテーブルに対する書き込みアクセス +
-
+ {@link android.Manifest.permission#WRITE_CONTACTS}。
AndroidManifest.xml
に+ <uses-permission>
要素を使用して<uses-permission android:name="android.permission.WRITE_CONTACTS">
のように指定します。 + + + +
+
+ これらのパーミッションは、ユーザー プロファイル データにまでは拡張されません。ユーザー プロファイルとそれに必要なパーミッションについては、次のセクションであるユーザー プロファイルで説明しています。 + + +
++ ユーザーの連絡先データは個人的で秘密性の高い情報であることを再度ご確認ください。ユーザーはプライバシーに敏感であり、アプリケーションが自分や自分の連絡先に関するデータを集めることを望みません。 + + 連絡先データにアクセスするためのパーミッションが必要な理由が明らかでないと、ユーザーがアプリケーションを低く評価したりインストールを拒否したりすることがあります。 + +
+ユーザー プロファイル
+
+ {@link android.provider.ContactsContract.Contacts} テーブルには、その端末のユーザーのプロファイル データを格納している行が 1 行あります。
+このデータが記述しているのは端末の user
であって、そのユーザーの連絡先ではありません。
+プロファイルの連絡先の行は、プロファイルを使用する各システムの未加工連絡先の行にリンクされています。
+
+ プロファイルの未加工連絡先の各行は、複数のデータ行を持つことができます。ユーザー プロファイルにアクセスするための定数は、{@link android.provider.ContactsContract.Profile} クラスに用意されています。
+
+
+ ユーザー プロファイルにアクセスするには、特別なパーミッションが必要です。読み取りと書き込みに必要な {@link android.Manifest.permission#READ_CONTACTS} パーミッションと {@link android.Manifest.permission#WRITE_CONTACTS} パーミッションの他に、ユーザー プロファイルに対する読み取りと書き込みのために {@code android.Manifest.permission#READ_PROFILE} パーミッションと {@code android.Manifest.permission#WRITE_PROFILE} パーミッションがそれぞれ必要です。 + + + + + +
++ ユーザーのプロファイルは秘密性の高い情報であることを再度ご確認ください。パーミッション {@code android.Manifest.permission#READ_PROFILE} を使用すると、端末ユーザーの個人識別データにアクセスできます。 + +アプリケーションの説明には、ユーザー プロファイルへのアクセス パーミッションが必要な理由を必ず記載してください。 + +
++ ユーザーのプロファイルが格納された連絡先の行を取得するには、{@link android.content.ContentResolver#query(Uri,String[], String, String[], String) ContentResolver.query()} を呼び出します。 + +コンテンツ URI を {@link android.provider.ContactsContract.Profile#CONTENT_URI} に設定し、選択条件は何も指定しません。 + +このコンテンツ URI は、そのプロファイルの未加工連絡先やデータを取得するためのベース URI としても使用できます。 +たとえば、次のスニペットは指定されたプロファイルのデータを取得します。 +
++// Sets the columns to retrieve for the user profile +mProjection = new String[] + { + Profile._ID, + Profile.DISPLAY_NAME_PRIMARY, + Profile.LOOKUP_KEY, + Profile.PHOTO_THUMBNAIL_URI + }; + +// Retrieves the profile from the Contacts Provider +mProfileCursor = + getContentResolver().query( + Profile.CONTENT_URI, + mProjection , + null, + null, + null); ++
+ 注: 連絡先の行を複数取得する場合、そのなかの 1 つがユーザー プロファイルかどうかを確認するには、行の {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} 列をテストします。 + +その連絡先がユーザー プロファイルであれば、この列は「1」に設定されています。 + +
+連絡先プロバイダのメタデータ
++ 連絡先プロバイダは、連絡先データの状態を継続的に追跡するためのデータをリポジトリで管理します。 +リポジトリに関するこのメタデータは、RawContacts、Data、Contacts の各テーブルの行、{@link android.provider.ContactsContract.Settings} テーブル、{@link android.provider.ContactsContract.SyncState} テーブルなど、さまざまな場所に格納されています。 + + +次の表に、各メタデータの効果を示します。 + +
+ +テーブル | +列 | +値 | +意味 | +
---|---|---|---|
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#DIRTY} | +「0」 - 前回の同期以降、変更はありません。 | +
+ 端末上で変更があり、サーバーと同期する必要がある未加工連絡先をマークします。
+Android アプリケーションが行をアップデートすると、連絡先プロバイダによって値が自動的に設定されます。
+
+ + 未加工連絡先やデータのテーブルを変更する同期アダプタは、使用するコンテンツ URI の末尾に文字列 {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} を必ず追加してください。 + +これにより、プロバイダが行をダーティとマークするのを防ぐことができます。 + こうしないと、同期アダプタによる変更がローカルな変更と認識され、変更のソースがサーバーであるにもかかわらず、その変更がサーバーに送信されます。 + + + |
+
「1」 - 前回の同期以降に変更があり、サーバーへの同期が必要です。 | +|||
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#VERSION} | +この行のバージョン番号。 | ++ この行またはその関連データが変更されるたび、連絡先プロバイダがこの値を自動的にインクリメントします。 + + | +
{@link android.provider.ContactsContract.Data} | +{@link android.provider.ContactsContract.DataColumns#DATA_VERSION} | +この行のバージョン番号。 | ++ このデータ行が変更されるたび、連絡先プロバイダがこの値を自動的にインクリメントします。 + + | +
{@link android.provider.ContactsContract.RawContacts} | +{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID} | ++ この未加工連絡先をそれが作成されたアカウントと一意に結び付ける文字列値。 + + | +
+ 同期アダプタが新しい未加工連絡先を作成するたび、この列はその未加工連絡先に対するサーバーの一意の ID に設定される必要があります。
+Android アプリケーションが新しい未加工連絡先を作成した場合、そのアプリケーションはこの列を空欄のままにする必要があります。
+同期アダプタはこれを確認して、サーバー上に新しい未加工連絡先を作成し、{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID} の値を取得します。
+
+
+ + 特に、ソース ID はアカウント タイプごとに一意で、同期中に安定している必要があります。 + + +
|
+
{@link android.provider.ContactsContract.Groups} | +{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE} | +「0」 - このグループに属する連絡先が Android アプリケーションの UI に表示されなくなります。 | ++ この列は、ユーザーが特定のグループに属する連絡先を非表示にすることを許可するサーバーに対して互換性を確保するために用意されています。 + + | +
「1」 - このグループに属する連絡先を Android アプリケーションの UI に表示できます。 | +|||
{@link android.provider.ContactsContract.Settings} | ++ {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE} | ++ 「0」 - このアカウントとアカウント タイプについて、グループに属さない連絡先は Android アプリケーションの UI に表示されなくなります。 + + | ++ デフォルトでは、グループに属する未加工連絡先がないなら連絡先は表示されません(未加工連絡先のグループ メンバーシップは、{@link android.provider.ContactsContract.Data} テーブルの 1 つないし複数の {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} 行によって示されます)。 + + + + あるアカウントとアカウント タイプについて、{@link android.provider.ContactsContract.Settings} テーブルの行でこのフラグを設定すると、グループのない連絡先を強制的に表示できます。 + + このフラグの用途の 1 つとして、グループを使用しないサーバーから連絡先を取得して表示することが考えられます。 + | +
+ 「0」 - このアカウントとアカウント タイプについて、グループに属さない連絡先が Android アプリケーションの UI に表示されます。 + + | + +|||
{@link android.provider.ContactsContract.SyncState} | +(すべて) | ++ このテーブルを使用して、同期アダプタのメタデータを格納します。 + | ++ このテーブルを使用すると、同期状態などの同期関連データを永続的に端末上に格納できます。 + + | +
連絡先プロバイダへのアクセス
++ このセクションでは、連絡先プロバイダからのデータにアクセスするためのガイドラインについて、以下に注目して説明します。 + +
+-
+
- + エンティティ クエリ。 + +
- + バッチ変更。 + +
- + インテントを使用した取得と変更。 + +
- + データ整合性。 + +
+ 同期アダプタからの変更については、連絡先プロバイダの同期アダプタでも詳しく説明しています。 + +
+エンティティのクエリ
++ 連絡先プロバイダのテーブルは階層構造になっており、ある行とその「子」の行すべてを取得すると便利なことがよくあります。 +たとえば、ある人に関するすべての情報を表示するために、{@link android.provider.ContactsContract.Contacts} 行 1 行に対するすべての {@link android.provider.ContactsContract.RawContacts} 行や、{@link android.provider.ContactsContract.RawContacts} 行 1 行に対するすべての {@link android.provider.ContactsContract.CommonDataKinds.Email} 行を取得することが考えられます。 + + + + +こうした処理をやりやすくするため、連絡先プロバイダにはエンティティ構造が用意されています。これは、テーブル間でのデータベースの和集合のように機能します。 + + +
++ 1 つのエンティティは、ある親テーブルとその子テーブルから選ばれた列からなるテーブルのようなものです。 + エンティティをクエリする場合は、そのエンティティで使用できる列に基づいてプロジェクションと検索の条件を指定します。 +その結果が {@link android.database.Cursor} で、取得された各子テーブル行につき 1 行を含みます。 +たとえば、ある連絡先名と、その名前のすべての未加工連絡先の {@link android.provider.ContactsContract.CommonDataKinds.Email} 行について、{@link android.provider.ContactsContract.Contacts.Entity} をクエリすると、各 {@link android.provider.ContactsContract.CommonDataKinds.Email} 行につき 1 行を含む {@link android.database.Cursor} が得られます。 + + + + +
++ エンティティにより、クエリが簡素化されます。エンティティを使用することで、ある連絡先または未加工連絡先の連絡先データをすべて取得できるため、まず親テーブルにクエリして ID を取得し、次にその ID 使用して子テーブルにクエリする必要がありません。また、連絡先プロバイダは、エンティティに対するクエリを 1 回のトランザクションで処理することから、取得されたデータの内部的な整合性が保証されます。 + + + + +
++ 注: エンティティには通常、親テーブルと子テーブルのすべての列が含まれるわけではありません。 +そのエンティティの列名定数のリストにない列名に対して作業しようとすると、{@link java.lang.Exception} が発生します。 + +
++ 次のスニペットは、ある連絡先のすべての未加工連絡先を取得する方法を示しています。このスニペットは、「メイン」と「詳細」という 2 つのアクティビティを持つ、もっと大きなアプリケーションの一部です。 +メイン アクティビティは、連絡先の行の一覧を示します。ユーザーが 1 つを選択すると、このアクティビティはその ID を詳細アクティビティに送ります。 + +詳細アクティビティは {@link android.provider.ContactsContract.Contacts.Entity} を使用して、選択した連絡先と関連付けられているすべての未加工連絡先から取得したすべてのデータ行を示します。 + + +
++ このスニペットは「詳細」アクティビティからの抜粋です。 +
++... + /* + * Appends the entity path to the URI. In the case of the Contacts Provider, the + * expected URI is content://com.google.contacts/#/entity (# is the ID value). + */ + mContactUri = Uri.withAppendedPath( + mContactUri, + ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); + + // Initializes the loader identified by LOADER_ID. + getLoaderManager().initLoader( + LOADER_ID, // The identifier of the loader to initialize + null, // Arguments for the loader (in this case, none) + this); // The context of the activity + + // Creates a new cursor adapter to attach to the list view + mCursorAdapter = new SimpleCursorAdapter( + this, // the context of the activity + R.layout.detail_list_item, // the view item containing the detail widgets + mCursor, // the backing cursor + mFromColumns, // the columns in the cursor that provide the data + mToViews, // the views in the view item that display the data + 0); // flags + + // Sets the ListView's backing adapter. + mRawContactList.setAdapter(mCursorAdapter); +... +@Override +public Loader<Cursor> onCreateLoader(int id, Bundle args) { + + /* + * Sets the columns to retrieve. + * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. + * DATA1 contains the first column in the data row (usually the most important one). + * MIMETYPE indicates the type of data in the data row. + */ + String[] projection = + { + ContactsContract.Contacts.Entity.RAW_CONTACT_ID, + ContactsContract.Contacts.Entity.DATA1, + ContactsContract.Contacts.Entity.MIMETYPE + }; + + /* + * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw + * contact collated together. + */ + String sortOrder = + ContactsContract.Contacts.Entity.RAW_CONTACT_ID + + " ASC"; + + /* + * Returns a new CursorLoader. The arguments are similar to + * ContentResolver.query(), except for the Context argument, which supplies the location of + * the ContentResolver to use. + */ + return new CursorLoader( + getApplicationContext(), // The activity's context + mContactUri, // The entity content URI for a single contact + projection, // The columns to retrieve + null, // Retrieve all the raw contacts and their data rows. + null, // + sortOrder); // Sort by the raw contact ID. +} ++
+ 読み込みが完了すると、{@link android.app.LoaderManager} は {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D) onLoadFinished()} に対するコールバックを起動します。 + +このメソッドへの入力引数の 1 つは、クエリの結果を含む {@link android.database.Cursor} です。 +独自アプリでは、データをこの {@link android.database.Cursor} から取得して表示したりさらに処理したりできます。 + +
+バッチ変更
++ 可能であれば必ず、連絡先プロバイダのデータを「バッチモード」で挿入、アップデート、削除してください。そのためには、{@link android.content.ContentProviderOperation} オブジェクトの {@link java.util.ArrayList} を作成し、{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を呼び出します。 + + +連絡先プロバイダはすべての操作を 1 つのトランザクションの 1 つの {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} で行うため、変更内容が連絡先リポジトリで不整合のままになることは決してありません。 + + + +また、バッチ変更では、未加工連絡先とその詳細データを同時に挿入しやすくなっています。 + +
++ 注: 1 つの未加工連絡先を変更する場合は、変更を独自アプリ内で処理するのではなく、インテントを端末の連絡先アプリケーションに送信することを検討してください。この方法については、インテントを使用した取得と変更で詳しく説明しています。 + + + +
+明け渡し点
+
+ 多数の操作を伴うバッチ変更は、他のプロセスをブロックしてユーザーにとっての全体的な使用感を悪化させかねません。
+意図したすべての変更をできるだけ少ない個別リストに整理するとともに、それらがシステムをブロックしないようにするために、1 つまたは複数の操作に明け渡し点を設定してください。
+
+
+ 明け渡し点の実体は、{@link android.content.ContentProviderOperation#isYieldAllowed()} の値が true
に設定された {@link android.content.ContentProviderOperation} オブジェクトです。
+
+連絡先プロバイダが明け渡し点に遭遇すると、作業を一時中断して他のプロセスを実行させ、現在のトランザクションをクローズします。
+作業を再開した連絡先プロバイダは、{@link java.util.ArrayList} に含まれている次の操作を行い、新しいトランザクションを始めます。
+
+
+
+ 明け渡し点により、{@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} の呼び出し 1 回につき複数のトランザクションが発生します。 +そのため、明け渡し点は 1 組の関連する行への最後の操作に設定してください。 + + たとえば、未加工連絡先の行とその関連データ行を追加する一連の操作の最後に、あるいは 1 人の連絡先に関連する 1 組の行に対する最後の操作に、明け渡し点を設定します。 + + +
++ 明け渡し点は、アトミック操作の単位でもあります。2 つの明け渡し点間のすべてのアクセスは、1 つのまとまりとして成功または失敗します。 +明け渡し点を設定しない場合、最小のアトミック操作は操作のバッチ全体になります。 +明け渡し点を使用すると、操作がシステムのパフォーマンスを低下させるのを防ぐと同時に、操作の一部分が確実にアトミックになります。 + + +
+変更の後方参照
++ 新しい未加工連絡先の行とその関連データの行を 1 組の {@link android.content.ContentProviderOperation} オブジェクトとして挿入している場合は、データの行を未加工連絡先の行にリンクする必要があります。そのためには、未加工連絡先の {@code android.provider.BaseColumns#_ID} 値を {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} 値として挿入します。 + + + +ただし、この値は、データの行のために{@link android.content.ContentProviderOperation} を作成している間は使用できません。未加工連絡先に {@link android.content.ContentProviderOperation} 操作がまだ適用されていないからです。 + + +これを回避するため、{@link android.content.ContentProviderOperation.Builder} クラスにはメソッド {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} が用意されています。 + + + このメソッドを使用すると、前の操作の結果を使用して列を挿入または変更できます。 + +
++ {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} メソッドには引数が 2 つあります。 + +
+-
+
-
+
key
+
+ - + キーと値のペアのキーです。この引数の値は、変更中のテーブルに含まれる列であることが必要です。 + + +
-
+
previousResult
+
+ -
+ {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} から取得した {@link android.content.ContentProviderResult} オブジェクトの配列に含まれる値の、0 ベースのインデックスです。
+
+バッチ操作が適用されると、各操作の結果は結果用の中間配列に格納されます。
+
+
previousResult
値はそうした結果の 1 つのインデックスで、key
値を使用して取得され、格納されます。 + +これにより、新しい未加工連絡先レコードを挿入してその {@code android.provider.BaseColumns#_ID} 値に戻り、次に {@link android.provider.ContactsContract.Data} 行を追加するときにその値を「後方参照」できます。 + + ++ {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を初めて呼び出すと、指定した {@link android.content.ContentProviderOperation} オブジェクトの {@link java.util.ArrayList} と同じサイズを使用して、結果配列全体が作成されます。 + + +ただし、結果配列に含まれるすべての要素は
+null
に設定され、そのためまだ適用されていない操作から結果を後方参照しようとすると {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} が {@link java.lang.Exception} をスローします。 + + + + + +
+
+ 次のスニペットは、新しい未加工連絡先とデータをバッチで挿入する方法を示しています。その中には、明け渡し点を指定し、後方参照を使用するコードが含まれています。
+これらのスニペットは、
+ Contact Manager
サンプル アプリケーションの ContactAdder
クラスの一部である createContacEntry()
メソッドの拡張版です。
+
+
+
+
+ 最初のスニペットは、連絡先データを UI から取得します。この時点で、ユーザーは新しい未加工連絡先の追加先となるアカウントを既に選択してあります。 + +
++// Creates a contact entry from the current UI values, using the currently-selected account. +protected void createContactEntry() { + /* + * Gets values from the UI + */ + String name = mContactNameEditText.getText().toString(); + String phone = mContactPhoneEditText.getText().toString(); + String email = mContactEmailEditText.getText().toString(); + + int phoneType = mContactPhoneTypes.get( + mContactPhoneTypeSpinner.getSelectedItemPosition()); + + int emailType = mContactEmailTypes.get( + mContactEmailTypeSpinner.getSelectedItemPosition()); ++
+ 次のスニペットは、未加工連絡先の行を {@link android.provider.ContactsContract.RawContacts} テーブルに挿入する操作を作成します。 + +
++ /* + * Prepares the batch operation for inserting a new raw contact and its data. Even if + * the Contacts Provider does not have any data for this person, you can't add a Contact, + * only a raw contact. The Contacts Provider will then add a Contact automatically. + */ + + // Creates a new array of ContentProviderOperation objects. + ArrayList<ContentProviderOperation> ops = + new ArrayList<ContentProviderOperation>(); + + /* + * Creates a new raw contact with its account type (server type) and account name + * (user's account). Remember that the display name is not stored in this row, but in a + * StructuredName data row. No other data is required. + */ + ContentProviderOperation.Builder op = + ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); ++
+ 次に、表示名、電話、メールのデータ行を作成します。 +
++ 操作の各ビルダー オブジェクトは、{@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} を使用して {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} を取得します。 + + +この参照が最初の操作からの {@link android.content.ContentProviderResult} オブジェクトを後方参照しており、それが未加工連絡先の行を追加し、新しい {@code android.provider.BaseColumns#_ID} 値を返します。 + + +その結果、各データ行はその {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} によって、属する新しい {@link android.provider.ContactsContract.RawContacts} 行に自動的にリンクされます。 + + +
++ メール行を追加する {@link android.content.ContentProviderOperation.Builder} オブジェクトは、明け渡し点を設定する {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean) withYieldAllowed()} でフラグ付けされます。 + + +
++ // Creates the display name for the new raw contact, as a StructuredName data row. + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * withValueBackReference sets the value of the first argument to the value of + * the ContentProviderResult indexed by the second argument. In this particular + * call, the raw contact ID column of the StructuredName data row is set to the + * value of the result returned by the first operation, which is the one that + * actually adds the raw contact row. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to StructuredName + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + + // Sets the data row's display name to the name in the UI. + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified phone number and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Phone + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + + // Sets the phone number and type + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); + + // Inserts the specified email and type as a Phone data row + op = + ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + /* + * Sets the value of the raw contact id column to the new raw contact ID returned + * by the first operation in the batch. + */ + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + + // Sets the data row's MIME type to Email + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) + + // Sets the email address and type + .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) + .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); + + /* + * Demonstrates a yield point. At the end of this insert, the batch operation's thread + * will yield priority to other threads. Use after every set of operations that affect a + * single contact, to avoid degrading performance. + */ + op.withYieldAllowed(true); + + // Builds the operation and adds it to the array of operations + ops.add(op.build()); ++
+ 最後のスニペットは、新しい未加工連絡先とデータ行を挿入する {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} を呼び出しています。 + + +
++ // Ask the Contacts Provider to create a new contact + Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" + + mSelectedAccount.getType() + ")"); + Log.d(TAG,"Creating contact: " + name); + + /* + * Applies the array of ContentProviderOperation objects in batch. The results are + * discarded. + */ + try { + + getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + } catch (Exception e) { + + // Display a warning + Context ctx = getApplicationContext(); + + CharSequence txt = getString(R.string.contactCreationFailure); + int duration = Toast.LENGTH_SHORT; + Toast toast = Toast.makeText(ctx, txt, duration); + toast.show(); + + // Log exception + Log.e(TAG, "Exception encountered while inserting contact: " + e); + } +} ++
+ バッチ処理を使用すると、楽観的並行性制御を実装できます。これは、背後のリポジトリをロックする必要なく変更トランザクションを適用する手法です。 + + この手法を使用するには、トランザクションを適用してから、同時に行うことのできる可能性のある他の変更をチェックします。 +一貫性のない変更が発生していることがわかった場合は、トランザクションをロールバックしてやり直します。 + +
++ 楽観的並行性制御は、一度に使用するユーザーが 1 人でデータリポジトリへの同時アクセスがまれなモバイル端末に便利です。 +ロックが使用されないため、ロックの設定や他のトランザクションによるロックの解放待ちで時間を無駄にしません。 + +
++ {@link android.provider.ContactsContract.RawContacts} 行を 1 行更新している間に楽観的並行性制御を使用する方法は次のとおりです。 + +
+-
+
- + 取得する他のデータとともに、未加工連絡先の {@link android.provider.ContactsContract.SyncColumns#VERSION} 列を取得します。 + + +
- + 制約を強制するのに適した {@link android.content.ContentProviderOperation.Builder} オブジェクトを、メソッド {@link android.content.ContentProviderOperation#newAssertQuery(Uri)} を使用して作成します。 + +コンテンツ URI に、未加工連絡先の {@code android.provider.BaseColumns#_ID} が末尾に追加された {@link android.provider.ContactsContract.RawContacts#CONTENT_URI RawContacts.CONTENT_URI} を使用します。 + + + + +
- + {@link android.content.ContentProviderOperation.Builder} オブジェクトに対し、{@link android.content.ContentProviderOperation.Builder#withValue(String, Object) withValue()} を呼び出して、{@link android.provider.ContactsContract.SyncColumns#VERSION} 列と取得したばかりのバージョン番号を比較します。 + + + + +
- + 同じ {@link android.content.ContentProviderOperation.Builder} に対し、{@link android.content.ContentProviderOperation.Builder#withExpectedCount(int) withExpectedCount()} を呼び出して、このアサーションで 1 行だけがテストされるようにします。 + + + +
- + {@link android.content.ContentProviderOperation.Builder#build()} を呼び出して {@link android.content.ContentProviderOperation} オブジェクトを作成し、次のこのオブジェクトを {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} に渡す {@link java.util.ArrayList} に先頭オブジェクトとして追加します。 + + + + +
- + バッチトランザクションを適用します。 + +
+ 目的の未加工連絡先の行が、行の読み込みからその変更の試行までの間に別の操作によってアップデートされた場合、{@link android.content.ContentProviderOperation} の「アサート」が失敗し、操作のバッチ全体がバックアウトされます。 + +バックアウトが終わったら、バッチをやり直すこと、または他のアクションを行うことができます。 + +
++ 次のスニペットは、{@link android.content.CursorLoader} を使用して未加工連絡先を 1 つクエリした後に、{@link android.content.ContentProviderOperation} を「アサート」します。 + + +
++/* + * The application uses CursorLoader to query the raw contacts table. The system calls this method + * when the load is finished. + */ +public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { + + // Gets the raw contact's _ID and VERSION values + mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); + mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); +} + +... + +// Sets up a Uri for the assert operation +Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID); + +// Creates a builder for the assert operation +ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri); + +// Adds the assertions to the assert operation: checks the version and count of rows tested +assertOp.withValue(SyncColumns.VERSION, mVersion); +assertOp.withExpectedCount(1); + +// Creates an ArrayList to hold the ContentProviderOperation objects +ArrayList ops = new ArrayList<ContentProviderOperationg>; + +ops.add(assertOp.build()); + +// You would add the rest of your batch operations to "ops" here + +... + +// Applies the batch. If the assert fails, an Exception is thrown +try + { + ContentProviderResult[] results = + getContentResolver().applyBatch(AUTHORITY, ops); + + } catch (OperationApplicationException e) { + + // Actions you want to take if the assert operation fails go here + } ++
インテントを使用した取得と変更
++ インテントを端末の連絡先アプリケーションに送信すると、連絡先プロバイダに間接的にアクセスできます。 +インテントが端末の連絡先アプリケーション UI を起動し、ユーザーはそこで連絡先関連の作業を行えます。 +このタイプのアクセスで、ユーザーは次の作業ができます。 +
-
+
- 連絡先をリストから選び、アプリケーションに返してさらに作業する。 +
- 既存の連絡先データを編集する。 +
- 任意のアカウントに新しい未加工連絡先を挿入する。 +
- 連絡先または連絡先データを削除する。 +
+ ユーザーがデータを挿入またはアップデートしている場合は、まずデータを収集し、次にそれをインテントの一部として送信できます。 + +
++ インテントを使用して端末の連絡先アプリケーション経由で連絡先プロバイダにアクセスする場合、連絡先プロバイダにアクセスするための独自の UI やコードを作成する必要はありません。 +また、連絡先プロバイダに対する読み取りや書き込みのパーミッションを要求する必要もありません。 +端末の連絡先アプリケーションは、連絡先に対する読み取りパーミッションをデリゲートできます。また、連絡先プロバイダへの変更を他のアプリケーション経由で行っていることから、書き込みパーミッションは不要です。 + + +
++ プロバイダにアクセスするためのインテントを送信する汎用プロセスについては、コンテンツ プロバイダの基本のセクション「インテント経由のデータアクセス」で詳しく説明しています。 + +表 4 に、利用可能なタスクで使用できるアクション、MIME タイプ、データ値をまとめます。{@link android.content.Intent#putExtra(String, String) putExtra()} で使用できるエクストラ値については、{@link android.provider.ContactsContract.Intents.Insert} のリファレンス ドキュメントに一覧があります。 + + + + +
+ +タスク | +アクション | +データ | +MIME タイプ | +注 | +
---|---|---|---|---|
連絡先をリストから選ぶ | +{@link android.content.Intent#ACTION_PICK} | +
+ 次のどれかです。
+
|
+ + 使用せず + | +
+ 指定したコンテンツ URI のタイプに応じて、未加工連絡先のリストか、未加工連絡先から取得されたデータのリストを表示します。
+
+
+ {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()} を呼び出してください。それにより、選択した行のコンテンツ URI が返されます。
+
+URI の形式は、テーブルのコンテンツ URI の末尾にその行の |
+
新しい未加工連絡先を挿入する | +{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION} | +該当せず | ++ {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE RawContacts.CONTENT_TYPE}。未加工連絡先のセットに対する MIME タイプです。 + + | ++ 端末の連絡先アプリケーションの [連絡先の追加] 画面を表示します。インテントに追加したエクストラ値が表示されます。 +{@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()} を使用して送信すると、新たに追加された未加工連絡先の URI が、アクティビティの {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} コールバック メソッドの {@link android.content.Intent} 引数の「data」フィールドに格納されて戻ってきます。 + + + + +この値を取得するには、{@link android.content.Intent#getData()} を呼び出します。 + | +
連絡先を編集する | +{@link android.content.Intent#ACTION_EDIT} | ++ 連絡先の {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}。 +エディタ アクティビティを使用すると、ユーザーがその連絡先に関連付けられている任意のデータを編集できます。 + + | ++ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE Contacts.CONTENT_ITEM_TYPE}。1 つの連絡先です。 + | ++ 連絡先アプリケーションに連絡先の編集画面を表示します。インテントに追加したエクストラ値が表示されます。 +ユーザーが [完了] をタップして編集内容を保存すると、アクティビティがフォアグラウンドに戻ります。 + + | +
ピッカー(やはりデータを追加できる)を表示する。 | +{@link android.content.Intent#ACTION_INSERT_OR_EDIT} | ++ 該当せず + | ++ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE} + | +
+ このインテントは、連絡先アプリのピッカー画面を常に表示します。ユーザーは、編集する連絡先を選ぶか、新しい連絡先を追加できます。
+ユーザーの選択に応じて編集画面か追加画面が開き、インテントに含めて渡したエクストラ データが表示されます。
+
+メールアドレスや電話番号などの連絡先データを独自アプリに表示する場合は、このインテントを使用すると、ユーザーが既存の連絡先にデータを追加できます。
+
+
+ + 注: このインテントのエクストラで名前の値を送信する必要はありません。ユーザーは必ず既存の名前を選ぶか新しい名前を追加するからです。 +そのうえ、アプリが名前を送信し、ユーザーが編集することを選んだ場合、連絡先アプリは送信した名前を表示し、以前の値を上書きします。 + +ユーザーがこのことに気付かず、編集内容を保存すると、以前の値が失われます。 + + + |
+
+ 端末の連絡先アプリは、インテントを使用して未加工連絡先や任意のデータを削除することを許可しません。 +そのため、未加工連絡先を削除するには {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()} または {@link android.content.ContentProviderOperation#newDelete(Uri) ContentProviderOperation.newDelete()} を使用してください。 + + + +
++ 次のスニペットは、新しい未加工連絡先とデータをバッチで挿入するインテントをコンストラクトして送信する方法を示しています。 + +
++// Gets values from the UI +String name = mContactNameEditText.getText().toString(); +String phone = mContactPhoneEditText.getText().toString(); +String email = mContactEmailEditText.getText().toString(); + +String company = mCompanyName.getText().toString(); +String jobtitle = mJobTitle.getText().toString(); + +// Creates a new intent for sending to the device's contacts application +Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); + +// Sets the MIME type to the one expected by the insertion activity +insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); + +// Sets the new contact name +insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); + +// Sets the new company and job title +insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); +insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); + +/* + * Demonstrates adding data rows as an array list associated with the DATA key + */ + +// Defines an array list to contain the ContentValues objects for each row +ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); + + +/* + * Defines the raw contact row + */ + +// Sets up the row as a ContentValues object +ContentValues rawContactRow = new ContentValues(); + +// Adds the account type and name to the row +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()); +rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); + +// Adds the row to the array +contactData.add(rawContactRow); + +/* + * Sets up the phone number data row + */ + +// Sets up the row as a ContentValues object +ContentValues phoneRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +phoneRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE +); + +// Adds the phone number and its type to the row +phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); + +// Adds the row to the array +contactData.add(phoneRow); + +/* + * Sets up the email data row + */ + +// Sets up the row as a ContentValues object +ContentValues emailRow = new ContentValues(); + +// Specifies the MIME type for this data row (all data rows must be marked by their type) +emailRow.put( + ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE +); + +// Adds the email address and its type to the row +emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); + +// Adds the row to the array +contactData.add(emailRow); + +/* + * Adds the array to the intent's extras. It must be a parcelable object in order to + * travel between processes. The device's contacts app expects its key to be + * Intents.Insert.DATA + */ +insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); + +// Send out the intent to start the device's contacts app in its add contact activity. +startActivity(insertIntent); ++
データの整合性
++ 連絡先リポジトリにはユーザーによる修正や更新が予想される重要で秘密性の高いデータが格納されるため、連絡先プロバイダにはデータの整合性に関して明確に定義されたルールがあります。 +連絡先データを変更する際にこれらのルールを守ることは、開発側の責任です。 +ここでは、重要なルールを示します。 + +
+-
+
- + {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行を、追加する {@link android.provider.ContactsContract.RawContacts} 行ごとに必ず追加してください。 + + +
- + {@link android.provider.ContactsContract.Data} テーブルに {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} 行のない {@link android.provider.ContactsContract.RawContacts} 行は、集約中に問題を引き起こすことがあります。 + + + + +
- + 新しい {@link android.provider.ContactsContract.Data} 行を、その親 {@link android.provider.ContactsContract.RawContacts} 行に必ずリンクしてください。 + + +
- + {@link android.provider.ContactsContract.RawContacts} にリンクされていない {@link android.provider.ContactsContract.Data} 行は端末の連絡先アプリケーションで可視にならず、同期アダプタで問題になることがあります。 + + + +
- + 変更するのは、所有する未加工連絡先のデータに限ってください。 + +
- + 通常、連絡先プロバイダは複数の異なるアカウント タイプやオンライン サービスから取得したデータを管理しています。 +そのため、アプリケーションが所有しているデータのみ変更または削除されるようにし、アプリケーションが管理しているアカウント タイプとアカウント名のデータのみ挿入するようにすることが必要です。 + + + +
- + 権限、コンテンツ URI、URI パス、列名、MIME タイプ、{@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} 値については、{@link android.provider.ContactsContract} とそのサブクラスに定義されている定数を必ず使用してください。 + + + +
- + そのような定数を使用することがエラーの予防に役立ちます。また、使われなくなった定数があれば、コンパイラーから警告として通知されます。 + + +
カスタムデータ行
++ 独自のカスタム MIME タイプを作成して使用すると、{@link android.provider.ContactsContract.Data} テーブルで独自データ行を挿入、編集、削除、取得できます。 +独自行で使用できるのは {@link android.provider.ContactsContract.DataColumns} に定義された列だけですが、独自タイプに固有の列名をデフォルトの列名にマッピングできます。 + + +端末の連絡先アプリケーションで、独自行のデータは表示されますが、編集または削除はできず、ユーザーはデータの追加ができません。 + +ユーザーがカスタムデータ行を変更できるようにするには、独自のアプリケーションでエディタ アクティビティを提供する必要があります。 + +
+
+ カスタムデータを表示するには、1 つの <ContactsAccountType>
要素と 1 つまたは複数の <ContactsDataKind>
子要素を含む contacts.xml
ファイルを提供します。
+
+詳しくは、<ContactsDataKind> element
に関するセクションで説明しています。
+
+
+ カスタム MIME タイプについて詳しくは、「コンテンツ プロバイダの作成」をご覧ください。 + + +
+連絡先プロバイダの同期アダプタ
++ 連絡先プロバイダは、特に端末とオンライン サービスとの間における連絡先データの同期を処理するために設計されています。 +これを使用することで、ユーザーは既存のデータを新しい端末にダウンロードしたり、既存のデータを新しいアカウントにアップロードしたりできています。 + + また、同期によって、追加や変更のソースに関係なく、ユーザーは最新データを入手できます。 +同期の利点としては他にも、端末がネットワークに接続されていなくても連絡先データを使用できるようになることが挙げられます。 + +
++ 同期はさまざまな手法で実装できますが、Android システムでは次のタスクを自動化するプラグイン同期フレームワークを提供しています。 + +
-
+
+
- + ネットワークの可用性のチェック。 + +
- + ユーザーのプリファレンスに基づく同期のスケジュールと実施。 + +
- + 停止された同期の再開。 + +
+ このフレームワークを使用するには、同期アダプタ プラグインを提供する必要があります。各同期アダプタはサービスと連絡先プロバイダに対して一意ですが、同じサービスに対して複数のアカウント名を処理できます。 +また、このフレームワークでは同じサービスとプロバイダに対して複数の同期アダプタが可能です。 + +
+同期アダプタのクラスとファイル
++ 同期アダプタは、{@link android.content.AbstractThreadedSyncAdapter} のサブクラスとして実装し、Android アプリケーションの一部としてインストールします。 + +システムは同期アダプタに関する知識を、アプリケーション マニフェストの要素からと、マニフェストが指す専用の XML ファイルから取得します。 +この XML ファイルは、オンライン サービスのアカウント タイプと連絡先プロバイダに絡む権限を定義しており、この組み合わせでアダプタを一意に識別します。 + +同期アダプタは、ユーザーが同期アダプタのアカウント タイプに対してアカウントを追加し、同期アダプタの同期対象である連絡先プロバイダで同期を有効にすることで、アクティブになります。 + +この時点で、システムはアダプタの管理を開始し、連絡先プロバイダとサーバーとの同期が必要になるとそれを呼び出します。 + +
+
+ 注: アカウント タイプを同期アダプタの識別の一環として使用することにより、システムは同じ組織から異なるサービスにアクセスする同期アダプタを検出してグループ化できます。
+
+たとえば、Google オンライン サービス用の同期アダプタでは、すべて同じアカウント タイプ com.google
です。
+ユーザーが Google アカウントを端末に追加すると、Google サービス用にインストールされているすべての同期アダプタがひとまとめにリストされ、リストされている各同期アダプタは端末上の異なる連絡先プロバイダと同期します。
+
+
+
+ データにアクセスするたび、ほとんどのサービスがユーザーに ID の確認を要求するため、Android システムでは、同期アダプタ フレームワークと類似した認証フレームワークを提供しており、往々にして同期アダプタ フレームワークと組み合わせて使用します。 + +この認証フレームワークでは、{@link android.accounts.AbstractAccountAuthenticator} のサブクラスであるプラグイン認証システムを使用します。 + +認証システムは、次の手順でユーザーの身元を検証します。 + +
-
+
- + ユーザー名とパスワードか、それに準ずる情報(ユーザーの資格情報)を収集します。 + + +
- + 収集した資格情報をサービスに送信します。 + +
- + サービスの返答を検証します。 + +
+ サービスが資格情報を受け入れた場合、認証システムはその資格情報を後での使用のために格納します。 +{@link android.accounts.AccountManager} はプラグイン認証フレームワークのおかげで、OAuth2 認証トークンなど、認証システムがサポートして公開することを選択している任意の認証トークンへのアクセスを提供できます。 + + +
++ 認証は必須ではありませんが、たいていの連絡先サービスが使用しています。 + ただし、認証に Android 認証フレームワークを使用する必要はありません。 +
+同期アダプタの実装
++ 連絡先プロバイダ用の同期アダプタを実装するには、まず以下を備えた Android アプリケーションを作成します。 + +
+-
+
- + システムからの同期アダプタとのバインド要求に対処する {@link android.app.Service} コンポーネント。 + + +
-
+ システムは、同期しようとするとき、サービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドを呼び出して、同期アダプタの {@link android.os.IBinder} を取得します。
+
+これにより、システムはアダプタのメソッドに対するプロセス間呼び出しを実行できます。
+
+
+ サンプル同期アダプタのサンプルアプリで、このサービスのクラス名は
+com.example.android.samplesync.syncadapter.SyncService
です。 + + +
+ - + {@link android.content.AbstractThreadedSyncAdapter} の具象サブクラスとして実装された、実際の同期アダプタ。 + + +
-
+ このクラスが、サーバーからのデータのダウンロード、端末からのデータのアップロード、競合の解消といった作業を実施します。
+アダフタの主な作業は、メソッド {@link android.content.AbstractThreadedSyncAdapter#onPerformSync( Account, Bundle, String, ContentProviderClient, SyncResult) onPerformSync()} で実行されます。
+
+
+このクラスは、シングルトンとしてインスタンス化する必要があります。
+
+ サンプル同期アダプタのサンプルアプリで、同期アダプタはクラス
+com.example.android.samplesync.syncadapter.SyncAdapter
に定義されています。 + + +
+ - + {@link android.app.Application} のサブクラス。 + +
- + このクラスは同期アダプタ シングルトンのファクトリとして機能します。同期アダプタのインスタンス化には {@link android.app.Application#onCreate()} メソッドを使用し、同期アダプタ シングルトンを同期アダプタのサービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドに返すための静的な「getter」メソッドを提供します。 + + + + + +
- + 省略可能: システムからのユーザー認証要求に対処する {@link android.app.Service} コンポーネント。 + + +
-
+ {@link android.accounts.AccountManager} は、このサービスを開始することによって認証プロセスを始めます。
+サービスの {@link android.app.Service#onCreate()} メソッドは、認証システム オブジェクトをインスタンス化します。
+システムは、アプリケーションの同期アダプタのためにユーザー アカウントを認証しようとするとき、サービスの {@link android.app.Service#onBind(Intent) onBind()} メソッドを呼び出して、認証システムの {@link android.os.IBinder} を取得します。
+
+
+これにより、システムは認証システムのメソッドに対するプロセス間呼び出しを実行できます。
+
+
+ サンプル同期アダプタのサンプルアプリで、このサービスのクラス名は
+com.example.android.samplesync.authenticator.AuthenticationService
です。 + + +
+ - + 省略可能: 認証の要求を処理する {@link android.accounts.AbstractAccountAuthenticator} の具象サブクラス。 + + + +
-
+ このクラスは、ユーザーの資格情報をサーバーに対して認証するために {@link android.accounts.AccountManager} が呼び出すメソッドを提供します。認証プロセスの詳細は、使用されているサーバー技術に応じて多岐にわたります。
+
+認証について詳しくは、使用するサーバー ソフトウェアのドキュメントをご覧ください。
+
+
+ サンプル同期アダプタのサンプルアプリで、認証はクラス
+com.example.android.samplesync.authenticator.Authenticator
に定義されています。 + + +
+ - + システムに対する同期アダプタと認証システムを定義する XML ファイル。 + +
-
+ 前述の同期アダプタと認証システム サービスのコンポーネントは、アプリケーション マニフェストの
<service>
要素に定義されます。 + + +これらの要素には、特定のデータをシステムに提供する次のような<meta-data>
子要素が含まれます。 + + + + +-
+
-
+ 同期アダプタ サービス用の
<meta-data>
要素は、XML ファイルres/xml/syncadapter.xml
を指します。 + + +このファイルが、連絡先プロバイダと同期されるウェブサービスの URI と、そのウェブサービスで使用するアカウント タイプを指定します。 + + +
+ -
+ 省略可能: 認証システム用の
<meta-data>
要素は、XML ファイルres/xml/authenticator.xml
を指します。 + + +このファイルが、この認証システムがサポートするアカウント タイプと、認証プロセスの最中に表示される UI リソースを指定します。 + +この要素に指定されるアカウント タイプは、同期アダプタ用に指定されるアカウント タイプと同じであることが必要です。 + + +
+
+ -
+ 同期アダプタ サービス用の
ソーシャル ストリーム データ
++ {@code android.provider.ContactsContract.StreamItems} テーブルと {@code android.provider.ContactsContract.StreamItemPhotos} テーブルは、ソーシャル ネットワークからの受信データを管理します。 + +独自ネットワークからのストリーム データをこれらのテーブルに追加する同期アダプタを作成したり、ストリーム データをこれらのテーブルから読み込んで独自アプリケーションに表示したり、この両方を行ったりできます。 + +このような機能があると、ソーシャル ネットワーキングのサービスやアプリケーションを Android のソーシャル ネットワーキング機能に統合できます。 + +
+ソーシャル ストリーム テキスト
+
+ ストリーム アイテムは、必ず未加工連絡先に関連付けられます。{@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID} は、未加工連絡先の _ID
値にリンクされます。
+
+未加工連絡先のアカウント タイプとアカウント名は、ストリーム アイテム行にも格納されます。
+
+
+ ストリームからのデータを次の列に格納します。 +
+-
+
- + {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE} + +
- + 必須。このストリーム アイテムに関連付けられている未加工連絡先の、ユーザーのアカウント タイプ。 +ストリーム アイテムを挿入する際には、この値を忘れずに設定してください。 + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME} + +
- + 必須。このストリーム アイテムに関連付けられている未加工連絡先の、ユーザーのアカウント名。 +ストリーム アイテムを挿入する際には、この値を忘れずに設定してください。 + +
- + 識別用列 + +
-
+ 必須。ストリーム アイテムを挿入する際には、次の識別用列を挿入する必要があります。
+
+
-
+
- + {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}:このストリーム アイテムが関連付けられている連絡先の {@code android.provider.BaseColumns#_ID} 値。 + + + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: このストリーム アイテムが関連付けられている連絡先の {@code android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} 値。 + + + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}:このストリーム アイテムが関連付けられている未加工連絡先の {@code android.provider.BaseColumns#_ID} 値。 + + + +
+ - + {@code android.provider.ContactsContract.StreamItemsColumns#COMMENTS} + +
- + 省略可能。ストリーム アイテムの冒頭に表示できる概要情報を格納します。 + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#TEXT} + +
- + ストリーム アイテムのテキスト。アイテムのソースによって投稿されたコンテンツか、そのストリーム アイテムを生成した何らかのアクションに関する説明です。 +この列には、{@link android.text.Html#fromHtml(String) fromHtml()} でレンダリングできる任意の書式や埋め込みリソース画像を含めることができます。 + +プロバイダは、長いコンテンツを切り捨てたり省いたりすることがありますが、タグは壊さないようにします。 + + +
- + {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} + +
- + ストリーム アイテムが挿入またはアップデートされた時刻を含むテキスト。エポックからのミリ秒の形式です。 +ストリーム アイテムを挿入またはアップデートするアプリケーションは、この列の管理を担当します。この列は、連絡先プロバイダによって自動的に管理されるわけではありません。 + + + +
+ ストリーム アイテムの識別情報を表示するには、{@code android.provider.ContactsContract.StreamItemsColumns#RES_ICON}、{@code android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}、{@code android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} を使用してアプリケーション内のリソースにリンクします。 + + + + +
++ {@code android.provider.ContactsContract.StreamItems} テーブルには、同期アダプタ専用に列 {@code android.provider.ContactsContract.StreamItemsColumns#SYNC1} ~ {@code android.provider.ContactsContract.StreamItemsColumns#SYNC4} も格納されます。 + + + +
+ソーシャル ストリーム フォト
++ {@code android.provider.ContactsContract.StreamItemPhotos} テーブルには、ストリーム アイテムに関連付けられた写真が格納されます。 +このテーブルの {@code android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} 列は、{@code android.provider.ContactsContract.StreamItems} テーブルの {@code android.provider.BaseColumns#_ID} 列の値にリンクされます。 + + +写真の参照は、テーブルの次の列に格納されます。 + +
+-
+
- + {@code android.provider.ContactsContract.StreamItemPhotos#PHOTO} 列(BLOB)。 + +
- + 写真のバイナリ表現。格納や表示のためにプロバイダによってサイズが変更されます。 + この列は、写真を格納するために使用されていた連絡先プロバイダの従来のバージョンとの下方互換性のために用意されています。 +ただし、現在のバージョンでは、写真の格納にこの列を使用しないでください。 +代わりに、{@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} または {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI}(どちらについても次の項目で説明します)を使用して、写真をファイルに保存します。 + + +現状では、この列には写真のサムネイルが格納されており、読み出し可能です。 + + +
- + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} + +
- + 未加工連絡先の写真の数値 ID。この値を定数 {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI} の末尾に追加して、1 つの写真ファイルを指すコンテンツ URI を取得し、{@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) openAssetFileDescriptor()} を呼び出して、その写真ファイルのハンドルを取得します。 + + + + + +
- + {@code android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI} + +
- + この行によって表されている写真の写真ファイルを直接指すコンテンツ URI。 + この URI を使用して {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) openAssetFileDescriptor()} を呼び出して、写真ファイルのハンドルを取得します。 + + +
ソーシャル ストリーム テーブルの使用
++ これらのテーブルは、連絡先プロバイダの他の主なテーブルと同じように機能しますが、次のような例外があります。 +
+-
+
- + これらのテーブルには、追加のアクセス パーミッションが必要です。これらからの読み出しには、アプリケーションにパーミッション {@code android.Manifest.permission#READ_SOCIAL_STREAM} が必要です。 +これらの変更には、アプリケーションにパーミッション {@code android.Manifest.permission#WRITE_SOCIAL_STREAM} が必要です。 + + + +
-
+ {@code android.provider.ContactsContract.StreamItems} テーブルについては、各未加工連絡先に格納できる行数に上限があります。
+上限に達すると、連絡先プロバイダは最も古い {@code android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP} を持つ行を自動的に削除して、新しいストリーム アイテムのための領域を作ります。
+
+
+この上限を取得するには、コンテンツ URI {@code android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI} にクエリを発行します。
+
+コンテンツ URI を除くすべての引数は、
null
のままでかまいません。 +このクエリは、列 {@code android.provider.ContactsContract.StreamItems#MAX_ITEMS} だけの 1 行を含む Cursor を返します。 + + +
+
+ クラス {@code android.provider.ContactsContract.StreamItems.StreamItemPhotos} は、1 つのストリーム アイテムの写真行を含む {@code android.provider.ContactsContract.StreamItemPhotos} のサブテーブルを定義します。 + + +
+ソーシャル ストリーム操作
++ 連絡先プロバイダによって端末の連絡先アプリケーションと連携して管理されるソーシャル ストリーム データは、ソーシャル ネットワーキング システムと既存の連絡先を接続するためのとても便利な手段を用意しています。 + +利用できる機能は次のとおりです。 +
+-
+
- + ソーシャル ネットワーキング サービスを連絡先プロバイダに同期アダプタを使用して同期することで、ユーザーの連絡先による最近のアクティビティを取得し、それを {@code android.provider.ContactsContract.StreamItems} テーブルや {@code android.provider.ContactsContract.StreamItemPhotos} テーブルに格納して後で使えるようにできます。 + + + + +
- + ユーザーが連絡先を選択して表示したときには、定期的な同期とは別に同期アダプタを起動して追加データを取得できます。 +この機能により、同期アダプタは連絡先の高解像度の写真や直近のストリーム アイテムを取得できます。 + + +
- + 端末の連絡先アプリケーションと連絡先プロバイダに関する通知を登録すると、連絡先が表示された場合にインテントを受信し、その時点で連絡先のステータスをサービスからアップデートできます。 + +このアプローチは、同期アダプタを使用してフル同期を実施するより、処理が速く、帯域幅が節約されます。 + + +
- + ユーザーが端末の連絡先アプリケーションで連絡先を見ている間に、その連絡先をソーシャル ネットワーキング サービスに追加できます。 +この機能は「連絡先の招待」機能を使用して実現できます。連絡先の招待は、既存の連絡先をネットワークに追加するアクティビティと、端末の連絡先アプリケーションと連絡先プロバイダにアプリケーションの詳細を提供する XML ファイルとを組み合わせて実現できます。 + + + + +
+ 連絡先プロバイダを使用したストリーム アイテムの定期的な同期は、他の同期と同じです。 +同期について詳しくは、連絡先プロバイダの同期アダプタをご覧ください。 +通知の登録と連絡先の招待については、次の 2 つのセクションで説明します。 + +
+ソーシャル ネットワーキング表示を処理するための登録
++ 同期アダプタを登録し、同期アダプタによって管理されている連絡先をユーザーが表示したときに通知されるようにする方法は、次のとおりです。 + +
+-
+
-
+
contacts.xml
という名前のファイルをプロジェクトのres/xml/
ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 +
+ -
+ このファイルに要素
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 +
+ -
+ ユーザーが端末の連絡先アプリケーションで連絡先の詳細ページを開いたときに通知されるサービスを登録するには、属性
viewContactNotifyService="serviceclass"
を要素に追加します。serviceclass
は、端末の連絡先アプリケーションからインテントを受け取ることになるサービスの完全修飾クラス名です。 + + + +通知側サービスのために、{@link android.app.IntentService} を機能拡張したクラスを使用して、そのサービスがインテントを受け取れるようにします。 + +受け取るインテントに含まれるデータには、ユーザーがクリックした未加工連絡先のコンテンツ URI が格納されます。 +通知側サービスから、同期アダプタをバインドして呼び出し、未加工連絡先のデータをアップデートできます。 + +
+
+ ユーザーがストリーム アイテムかストリーム フォトかその両方をクリックしたときに呼び出されるアクティビティを登録する方法は次のとおりです。 +
+-
+
-
+
contacts.xml
という名前のファイルをプロジェクトのres/xml/
ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 +
+ -
+ このファイルに要素
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 +
+ -
+ アクティビティのどれかを登録して、ユーザーが端末の連絡先アプリケーションでストリーム アイテムをタップしたことに対処するには、属性
viewStreamItemActivity="activityclass"
を要素に追加します。activityclass
は、端末の連絡先アプリケーションからインテントを受け取ることになるアクティビティの完全修飾クラス名です。 + + + + +
+ -
+ アクティビティのどれかを登録して、ユーザーが端末の連絡先アプリケーションでストリーム フォトをタップしたことに対処するには、属性
viewStreamItemPhotoActivity="activityclass"
を要素に追加します。activityclass
は、端末の連絡先アプリケーションからインテントを受け取ることになるアクティビティの完全修飾クラス名です。 + + + + +
+
+ <ContactsAccountType>
要素については、<ContactsAccountType> 要素で詳しく説明しています。
+
+
+ 受け取るインテントには、ユーザーがクリックしたアイテムまたは写真のコンテンツ URI が格納されます。 + テキスト アイテムと写真とで異なるアクティビティを使用するには、同じファイルで両方の属性を使用します。 +
+ソーシャル ネットワーキング サービスの操作
++ ユーザーは、連絡先をソーシャル ネットワーキング サービスに招待するのに、端末の連絡先アプリケーションを離れる必要はありません。 +その代わりとして、連絡先をアクティビティのどれかに招待するインテントを端末の連絡先アプリケーションに送信させることができます。 +これをセットアップする方法は次のとおりです。 +
+-
+
-
+
contacts.xml
という名前のファイルをプロジェクトのres/xml/
ディレクトリに作成します。 +このファイルが既に存在する場合は、この手順を省略できます。 +
+ -
+ このファイルに要素
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
を追加します。 + + この要素が既に存在する場合は、この手順を省略できます。 +
+ -
+ 次の属性を追加します。
+
-
+
inviteContactActivity="activityclass"
+ -
+
inviteContactActionLabel="@string/invite_action_label"
+
+
activityclass
値は、インテントを受信するアクティビティの完全修飾クラス名です。 +invite_action_label
値は、端末の連絡先アプリケーションの [Add Connection] メニューに表示される文字列です。 + + +
+
+ 注: ContactsSource
は廃止されたタグ名で、ContactsAccountType
に置き換わっています。
+
+
contacts.xml リファレンス
+
+ ファイル contacts.xml
には、同期アダプタやアプリケーションと連絡先アプリケーションや連絡先プロバイダとのやり取りを管理する XML 要素が含まれています。
+これらの要素について、以降のセクションで説明します。
+
+
<ContactsAccountType> 要素
+
+ <ContactsAccountType>
要素は、アプリケーションと連絡先アプリケーションとのやり取りを管理します。
+構文は次のとおりです。
+
+<ContactsAccountType + xmlns:android="http://schemas.android.com/apk/res/android" + inviteContactActivity="activity_name" + inviteContactActionLabel="invite_command_text" + viewContactNotifyService="view_notify_service" + viewGroupActivity="group_view_activity" + viewGroupActionLabel="group_action_text" + viewStreamItemActivity="viewstream_activity_name" + viewStreamItemPhotoActivity="viewphotostream_activity_name"> ++
+ 含まれているファイル: +
+
+ res/xml/contacts.xml
+
+ 含めることのできる要素: +
+
+ <ContactsDataKind>
+
+ 説明: +
++ ユーザーが連絡先の 1 人をソーシャル ネットワーキングに招待できるようにしたり、ソーシャル ネットワーキング ストリームのどれかがアップデートされたらユーザーに通知したりするための、Android コンポーネントや UI ラベルを宣言します。 + + +
+
+ 属性プレフィックス android:
は、<ContactsAccountType>
の属性に必須ではないことに注目してください。
+
+
+ 属性: +
+-
+
- {@code inviteContactActivity} +
- + ユーザーが端末の連絡先アプリケーションで [Add Connection] を選択したときに起動する、アプリケーション内のアクティビティの完全修飾クラス名。 + + + +
- {@code inviteContactActionLabel} +
- + [Add Connection] メニューで、{@code inviteContactActivity} に指定されたアクティビティ用に表示されるテキスト。 + + たとえば、文字列「Follow in my network」を指定できます。このラベルには文字列リソース ID を使用できます。 + + +
- {@code viewContactNotifyService} +
-
+ ユーザーが連絡先を表示したときに通知を受け取ることになる、独自アプリケーション内のサービスの完全修飾クラス名。
+この通知は端末の連絡先アプリケーションによって送信されます。これを使用することで、アプリケーションはデータ処理の多い操作を必要になるまで延期できます。
+
+たとえば、アプリケーションはこの通知への対応として、連絡先の高解像度写真と直近のソーシャル ストリーム アイテムを読み込んで表示できます。
+
+この機能について詳しくは、ソーシャル ストリーム操作で説明しています。
+
NotifierService.java
ファイルに指定された通知サービスの例は、SampleSyncAdapter サンプル アプリケーションにあります。 + + + +
+ - {@code viewGroupActivity} +
- + グループ情報を表示できる、独自アプリケーション内のアクティビティの完全修飾クラス名。 +ユーザーが端末の連絡先アプリケーションでグループラベルをタップすると、このアクティビティの UI が表示されます。 + + +
- {@code viewGroupActionLabel} +
-
+ ユーザーがアプリケーションでグループを表示できるようにする UI コントロールに対し、連絡先アプリケーションが表示するラベル。
+
+
+ たとえば、端末に Google+ アプリケーションをインストールし、Google+ を連絡先アプリケーションと同期すると、Google+ のサークルが連絡先アプリケーションの [グループ] タブにグループとして表示されます。 + +Google+ サークルのどれかをクリックすると、そのサークルに所属する人が「グループ」として表示されます。 +表示の最上部に、Google+ アイコンが表示されます。それをクリックすると、制御が Google+ アプリに移ります。連絡先アプリケーションはこれを {@code viewGroupActivity} を使用して行い、Google+ アイコンを {@code viewGroupActionLabel} の値として使用します。 + + + + +
++ この属性には、文字列リソース ID を使用できます。 +
+
+ - {@code viewStreamItemActivity} +
- + ユーザーが未加工連絡先のストリーム アイテムをタップしたときに端末の連絡先アプリケーションが起動する、独自アプリケーション内のアクティビティの完全修飾クラス名。 + + +
- {@code viewStreamItemPhotoActivity} +
- + ユーザーが未加工連絡先のストリーム アイテムで写真をタップしたときに端末の連絡先アプリケーションが起動する、独自アプリケーション内のアクティビティの完全修飾クラス名。 + + + +
<ContactsDataKind> 要素
+
+ <ContactsDataKind>
要素は、連絡先アプリケーションにおける独自アプリケーションのカスタムデータ行の表示を管理します。構文は次のとおりです。
+
+
+<ContactsDataKind + android:mimeType="MIMEtype" + android:icon="icon_resources" + android:summaryColumn="column_name" + android:detailColumn="column_name"> ++
+ 含まれているファイル: +
+<ContactsAccountType>
++ 説明: +
+
+ この要素は、カスタムデータ行のコンテンツを未加工連絡先の詳細の一部として連絡先アプリケーションに表示させるために使用します。
+<ContactsAccountType>
の各 <ContactsDataKind>
子要素は、同期アダプタが {@link android.provider.ContactsContract.Data} テーブルに追加するカスタムデータ行のタイプを表します。
+
+使用するカスタム MIME タイプごとに <ContactsDataKind>
要素を 1 つ追加します。
+データを表示しないカスタムデータ行がある場合は、この要素を追加する必要はありません。
+
+
+ 属性: +
+-
+
- {@code android:mimeType} +
-
+ {@link android.provider.ContactsContract.Data} テーブルに含まれるカスタムデータ行のどれかに定義したカスタム MIME タイプ。
+たとえば、値
vnd.android.cursor.item/vnd.example.locationstatus
は、連絡先の最新の場所情報を記録するデータ行のためのカスタム MIME タイプということが考えられます。 + + +
+ - {@code android:icon} +
- + 連絡先アプリケーションがデータの隣に表示する Android ドローアブル リソース。 + +そのデータが独自サービスからのものであることを示すのに使用します。 + + +
- {@code android:summaryColumn} +
- + データ行から取得された 2 つの値で最初の列名。この値は、このデータ行のエントリの先頭行として表示されます。 +この先頭行は、データの要約として使われることを狙ったものですが、省略可能です。 +android:detailColumn もご覧ください。 + + +
- {@code android:detailColumn} +
- + データ行から取得された 2 つの値で 2 番目の列名。この値は、このデータ行のエントリの 2 行目として表示されます。 +{@code android:summaryColumn} もご覧ください。 + + +
連絡先プロバイダの追加機能
++ ここまでのセクションで説明した主な機能の他に、連絡先プロバイダには連絡先データの作業用として次のような便利な機能が用意されています。 + +
+-
+
- 連絡先グループ +
- 写真機能 +
連絡先グループ
++ 連絡先プロバイダでは、オプションで、関連連絡先のコレクションをグループ データでラベル付けできます。 +あるユーザー アカウントに関連付けられているサーバーがグループを管理する場合、そのアカウントのアカウント タイプ用の同期アダプタが、連絡先プロバイダとサーバーとの間でグループデータを転送する必要があります。 + +ユーザーが新しい連絡先をサーバーに追加し、その連絡先を新しいグループに入れた場合、同期アダプタはその新しいグループを {@link android.provider.ContactsContract.Groups} テーブルに追加する必要があります。 + +ある未加工連絡先が属するグループ(複数の場合あり)は、{@link android.provider.ContactsContract.Data} テーブルに、{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} MIME タイプを使用して格納されます。 + + +
++ サーバーからの未加工連絡先データを連絡先プロバイダに追加する同期アダプタを設計している場合、グループを使用しないのであれば、連絡先プロバイダに対してデータが可視であることを通知する必要があります。 + +ユーザーがアカウントを端末に追加したときに実行されるコード内で、連絡先プロバイダがそのアカウントに対して追加する {@link android.provider.ContactsContract.Settings} 行をアップデートします。 + +この行で、{@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE Settings.UNGROUPED_VISIBLE} 列の値を 1 に設定します。 + +こうすると、連絡先プロバイダは、グループを使用していない場合でも、独自の連絡先データを可視にします。 + +
+連絡先の写真
++ {@link android.provider.ContactsContract.Data} テーブルは、写真を MIME タイプ {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE Photo.CONTENT_ITEM_TYPE} の行として格納します。 + +この行の {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} 列は、それが属する未加工連絡先の {@code android.provider.BaseColumns#_ID} 列にリンクされます。 + + + クラス {@link android.provider.ContactsContract.Contacts.Photo} は、連絡先のプライマリ フォトの写真情報を格納する {@link android.provider.ContactsContract.Contacts} のサブテーブルを定義します。ここでプライマリ フォトとは、連絡先のプライマリ未加工連絡先のプライマリ フォトのことを示します。 + +同様に、クラス {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} は、未加工連絡先のプライマリ フォトに関する情報を含む {@link android.provider.ContactsContract.RawContacts} のサブテーブルを定義します。 + + + +
++ {@link android.provider.ContactsContract.Contacts.Photo} と {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} の参照ドキュメントには、写真情報の取得例が含まれています。 + +未加工連絡先のプライマリ サムネイルを取得するための便利なクラスはありませんが、{@link android.provider.ContactsContract.Data} テーブルにクエリを送信して、未加工連絡先の {@code android.provider.BaseColumns#_ID}、{@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE Photo.CONTENT_ITEM_TYPE}、{@link android.provider.ContactsContract.Data#IS_PRIMARY} 列を選んでその未加工連絡先のプライマリ フォト行を探すことができます。 + + + + + + +
++ 人のソーシャル ストリーム データにも写真が含まれていることがあります。その場合は {@code android.provider.ContactsContract.StreamItemPhotos} テーブルに格納されています。このテーブルについては、ソーシャル ストリーム フォトで詳しく説明しています + + +
diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd new file mode 100644 index 0000000000000000000000000000000000000000..9eef5d6eed4604e5a3f9d334bda93ee23dc8ecdb --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-basics.jd @@ -0,0 +1,1196 @@ +page.title=コンテンツ プロバイダの基本 +@jd:body +本書の内容
+-
+
-
+ 概要
+
-
+
- + プロバイダにアクセスする + +
- + コンテンツ URI + +
+ -
+ プロバイダからデータを取得する
+
-
+
- + 読み取りアクセス パーミッションを要求する + +
- + クエリを作成する + +
- + クエリ結果を表示する + +
- + クエリ結果を取得する + +
+ - + コンテンツ プロバイダ パーミッション + +
- + データを挿入、更新、削除する + + +
- + プロバイダ データタイプ + +
-
+ プロバイダ アクセスの別の形式
+
-
+
- + バッチアクセス + +
- + インテント経由のデータアクセス + +
+ - + コントラクト クラス + +
- + MIME タイプ リファレンス + +
キークラス
+-
+
- + {@link android.content.ContentProvider} + +
- + {@link android.content.ContentResolver} + +
- + {@link android.database.Cursor} + +
- + {@link android.net.Uri} + +
関連サンプル
+-
+
- + + Cursor (People) + +
- + + Cursor (Phones) + +
関連ドキュメント
+-
+
- + + コンテンツ プロバイダの作成 + +
- + + カレンダー プロバイダ + +
+ コンテンツ プロバイダは、データの中央リポジトリへのアクセスを管理します。プロバイダは Android アプリケーションの一部であり、通常、データを処理するための独自の UI を備えています。 + +ただし、コンテンツ プロバイダは主に他のアプリケーションでの使用を意図したものです。アプリケーションはプロバイダ クライアント オブジェクトを使用してプロバイダにアクセスします。 +さらに、プロバイダとプロバイダ クライアントにはデータを扱うための一貫性のある標準のインターフェースが備わっており、プロセス間の通信や安全なデータ アクセスを処理します。 + + +
++ このトピックでは、次の項目に関する基本的な内容を説明します。 +
+-
+
- コンテンツ プロバイダの仕組み。 +
- コンテンツ プロバイダからのデータの取得に使用する API。 +
- コンテンツ プロバイダへのデータの挿入、データの更新や削除に使用する API。 +
- プロバイダでの作業に役立つその他の API 機能。 +
概要
++ 外部アプリケーションでは、コンテンツ プロバイダのデータは、リレーショナル データベースで使用する表と同様に、1 つ以上の表として表示されます。 +行はプロバイダが収集するデータの何らかのタイプのインスタンスを表しており、行内のそれぞれの列はインスタンスに対して収集した個々のデータを表しています。 + + +
++ たとえば、Android プラットフォームに組み込まれているプロバイダの 1 つに単語リストがありますが、ここにはユーザーが保存しておく標準以外の単語のスペリングが格納されます +表 1 は、このプロバイダの表にデータがどのように格納されているのかを表しています。 + +
+ +word | +app id | +frequency | +locale | +_ID | +
---|---|---|---|---|
mapreduce | +user1 | +100 | +en_US | +1 | +
precompiler | +user14 | +200 | +fr_FR | +2 | +
applet | +user2 | +225 | +fr_CA | +3 | +
const | +user1 | +255 | +pt_BR | +4 | +
int | +user5 | +100 | +en_UK | +5 | +
+ 表 1 の各行は、標準の辞書には含まれていない単語のインスタンスを表しています。
+各列は、該当する単語のデータの一部(その単語が最初に見つかったロケールなど)を表しています。
+列の見出しは、プロバイダに格納される列の名前です。
+行のロケールを調べるには、locale
列を参照します。このプロバイダの場合、_ID
列が「プライマリキー」の列の役割を果たし、プロバイダはこの列を自動的に保持します。
+
+
+
+ 注: プロバイダはプライマリキーを持つ必要がなく、プライマリキーがある場合は _ID
をプライマリキーの列名として使用する必要はありません。
+ただし、プロバイダのデータを {@link android.widget.ListView} にバインドする場合は、いずれかの列の名前を _ID
とする必要があります。
+
+この要件についての詳細は、クエリ結果を表示するセクションをご覧ください。
+
+
プロバイダにアクセスする
++ アプリケーションは、{@link android.content.ContentResolver} クライアント オブジェクトを使用して、コンテンツ プロバイダのデータにアクセスします。 +このオブジェクトには、プロバイダ オブジェクトの同名のメソッドを呼び出すメソッドが備わっています。これは、{@link android.content.ContentProvider} の具体的なサブクラスのインスタンスのいずれかになります。 + +{@link android.content.ContentResolver} メソッドには、永続ストレージの基本的な「CRUD」(作成、取得、更新、削除)機能が備わっています。 + + +
++ クライアント アプリケーションのプロセスにおける {@link android.content.ContentResolver} オブジェクトと、プロバイダを所有するアプリケーションの {@link android.content.ContentProvider} オブジェクトが、プロセス間の通信を自動的に処理します。さらに、{@link android.content.ContentProvider} は、データのリポジトリと、外部に表形式で表示されるデータの間の抽象化レイヤーとして機能します。 + + + + +
++ 注: 通常、アプリケーションがプロバイダにアクセスする場合、そのマニフェスト ファイルで特定のパーミッションを要求する必要があります。 +詳細は、コンテンツ プロバイダ パーミッションセクションをご覧ください。 + +
++ たとえば、単語リスト プロバイダから単語とそのロケールの一覧を取得するには、{@link android.content.ContentResolver#query ContentResolver.query()} を呼び出します。 + + {@link android.content.ContentResolver#query query()} メソッドによって、単語リスト プロバイダが定義する{@link android.content.ContentProvider#query ContentProvider.query()} メソッドが呼び出されます。 + +コードの次の行は、{@link android.content.ContentResolver#query ContentResolver.query()} 呼び出しを表しています。 + +
+
+// Queries the user dictionary and returns results +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Selection criteria + mSelectionArgs, // Selection criteria + mSortOrder); // The sort order for the returned rows ++
+ 表 2 は、query(Uri,projection,selection,selectionArgs,sortOrder)} の引数が SQL SELECT 文にどのように一致しているかを示しています。 + + +
+ +query() 引数 | +SELECT キーワード / パラメータ | +注 | +
---|---|---|
Uri |
+ FROM table_name |
+ Uri は、table_name という名前のプロバイダの表にマッピングされます。 |
+
projection |
+ col,col,col,... |
+
+ projection は、取得するそれぞれの行に含まれる列の配列です。
+
+ |
+
selection |
+ WHERE col = value |
+ selection は、行を選択する際の基準を指定します。 |
+
selectionArgs |
+
+ (正確に一致するものはありません。選択句では、? プレースホルダーが選択引数に置き換わります)
+
+ |
+ |
sortOrder |
+ ORDER BY col,col,... |
+
+ sortOrder は、返される {@link android.database.Cursor} 内で行が表示される順番を指定します。
+
+ |
+
コンテンツ URI
++ コンテンツ URI は、プロバイダのデータを特定する URI です。コンテンツ URI には、プロバイダ全体の識別名(認証局)と表をポイントする名前(パス)が含まれます。 + +プロバイダの表にアクセスするためのクライアント メソッドを呼び出す場合、その引数の 1 つがコンテンツ URI になります。 + + +
++ コードの前半の行では、定数 {@link android.provider.UserDictionary.Words#CONTENT_URI} に、単語リストの「words」表のコンテンツ URI が入ります。 + +{@link android.content.ContentResolver} オブジェクトは URI の認証局をパースし、認証局を既知のプロバイダのシステム表と比較して、プロバイダを「解決」します。 + +その後、{@link android.content.ContentResolver} は、クエリ引数を正しいプロバイダに送信できます。 + + +
++ {@link android.content.ContentProvider} は、アクセスする表を選択するのに、コンテンツ URI のパス部分を使用します。 +通常、プロバイダは公開する各表のパスを持ちます。 +
++ コードの前半の行では、「words」表の完全な URI は次のようになります。 +
++content://user_dictionary/words ++
+ ここで、user_dictionary
文字列はプロバイダの認証局になり、words
文字列は表のパスになります。
+文字列 content://
(スキーム)は常に存在し、これがコンテンツ URI であることを示します。
+
+
+
+ 多くのプログラムでは、URI の末尾に ID 値を付加することで、表内の 1 つの行にアクセスできます。たとえば、_ID
が 4
の行を単語リストから取得するには、次のコンテンツ URI を使用します。
+
+
+
+Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); ++
+ 通常は、一連の行を取得してからいずれかの行を更新、削除するような場合に ID 値を使用します。 + +
++ 注: {@link android.net.Uri} クラスと {@link android.net.Uri.Builder} クラスには、正しい形式の URI オブジェクトを文字列から作成するための、便利なメソッドが用意されています。 +{@link android.content.ContentUris} には、URI に ID 値を付加するための便利なメソッドが用意されています。前述のスニペットは {@link android.content.ContentUris#withAppendedId + withAppendedId()} を使用して、UserDictionary コンテンツ URI に ID を付加しています。 + + +
+ + + +プロバイダからデータを取得する
++ このセクションでは、単語リスト プロバイダの例を使い、プロバイダからデータを取得する方法を説明します。 + +
++ わかりやすくするために、このセクションのコード スニペットは「UI スレッド」の {@link android.content.ContentResolver#query ContentResolver.query()} を呼び出しています。 +ただし、実際のコードでは、個別のスレッドで非同期にクエリを実行する必要があります。 +この操作は、{@link android.content.CursorLoader} クラスを使用して行うこともできます。このクラスについての詳細は、「ローダ」に関するガイドをご覧ください。 + + +さらに、コードの行はスニペットのみであり、完全なアプリケーションにはなっていません。 + +
++ プロバイダからデータを取得するには、次の基本的な手順に従います。 +
+-
+
- + プロバイダの読み取りアクセスを要求します。 + +
- + プロバイダにクエリを送信するコードを定義します。 + +
読み取りアクセス パーミッションを要求する
+
+ プロバイダからデータを取得するには、アプリケーションからプロバイダの読み取りアクセスを要求します。
+実行時にはこのパーミッションを要求できません。その代わりに、<uses-permission>
要素とプロバイダで定義した正確なパーミッション名を使用して、このパーミッションを必要としていることをマニフェストで指定する必要があります。
+
+
+
+この要素をマニフェストで指定すると、実際に、このパーミッションをアプリケーションに「要求」することになります。
+ユーザーがアプリケーションをインストールすると、この要求が暗黙的に付与されることになります。
+
+
+ 使用する読み取りアクセス パーミッションの正確な名前と、プロバイダが使用するその他のアクセス パーミッションの名前については、プロバイダのドキュメントをご覧ください。 + + +
++ プロバイダにアクセスする際のパーミッションのロールの詳細は、コンテンツ プロバイダ パーミッションセクションをご覧ください。 + +
+
+ 単語リスト プロバイダはパーミッション android.permission.READ_USER_DICTIONARY
をマニフェスト ファイルで定義するため、プロバイダからの読み取りを行うアプリケーションはこのパーミッションを要求する必要があります。
+
+
+
クエリを作成する
++ プロバイダからのデータの取得の次の手順では、クエリを作成します。最初のスニペットで、単語リスト プロバイダにアクセスするための変数をいくつか定義します。 + +
++ +// A "projection" defines the columns that will be returned for each row +String[] mProjection = +{ + UserDictionary.Words._ID, // Contract class constant for the _ID column name + UserDictionary.Words.WORD, // Contract class constant for the word column name + UserDictionary.Words.LOCALE // Contract class constant for the locale column name +}; + +// Defines a string to contain the selection clause +String mSelectionClause = null; + +// Initializes an array to contain selection arguments +String[] mSelectionArgs = {""}; + ++
+ 次のスニペットでは、単語リスト プロバイダの例を使って、{@link android.content.ContentResolver#query ContentResolver.query()} を使用する方法を示しています。 + +プロバイダ クライアント クエリは SQL クエリに似たものであり、戻り値となる一連の列、一連の選択基準、並べ替えの順番を含みます。 + +
+
+ クエリの戻り値となる一連の列は、投影(変数 mProjection
)と呼ばれます。
+
+
+ 取得する行を指定する式は、選択句と選択引数に分割されます。
+選択句は論理式やブール式、列名、値(変数 mSelectionClause
)の組み合わせになります。
+値の代わりに置き換え可能パラメータ ?
を指定すると、クエリ メソッドによって、選択引数の配列(変数 mSelectionArgs
)から値が取得されます。
+
+
+
+ 次のスニペットでは、ユーザーが単語を入力しない場合、選択句が null
に設定され、クエリによってプロバイダのすべての単語が返されます。
+ユーザーが単語を入力すると、選択句が UserDictionary.Words.WORD + " = ?"
に設定され、選択引数の配列の最初の要素が、ユーザーが入力した単語に設定されます。
+
+
+
+/* + * This defines a one-element String array to contain the selection argument. + */ +String[] mSelectionArgs = {""}; + +// Gets a word from the UI +mSearchString = mSearchWord.getText().toString(); + +// Remember to insert code here to check for invalid or malicious input. + +// If the word is the empty string, gets everything +if (TextUtils.isEmpty(mSearchString)) { + // Setting the selection clause to null will return all words + mSelectionClause = null; + mSelectionArgs[0] = ""; + +} else { + // Constructs a selection clause that matches the word that the user entered. + mSelectionClause = UserDictionary.Words.WORD + " = ?"; + + // Moves the user's input string to the selection arguments. + mSelectionArgs[0] = mSearchString; + +} + +// Does a query against the table and returns a Cursor object +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Either null, or the word the user entered + mSelectionArgs, // Either empty, or the string the user entered + mSortOrder); // The sort order for the returned rows + +// Some providers return null if an error occurs, others throw an exception +if (null == mCursor) { + /* + * Insert code here to handle the error. Be sure not to use the cursor! You may want to + * call android.util.Log.e() to log this error. + * + */ +// If the Cursor is empty, the provider found no matches +} else if (mCursor.getCount() < 1) { + + /* + * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily + * an error. You may want to offer the user the option to insert a new row, or re-type the + * search term. + */ + +} else { + // Insert code here to do something with the results + +} ++
+ このクエリは、 SQL 文に似ています。 +
++SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; ++
+ この SQL 文では、コントラクト クラスの定数ではなく、実際の列の名前が使用されます。 +
+悪意のある入力から保護する
++ コンテンツ プロバイダが管理するデータが SQL データベース内にある場合、外部の信頼されていないデータを未処理の SQL 文に含めると SQL インジェクションが発生することがあります。 + +
++ 次のような選択句を考えてみます。 +
++// Constructs a selection clause by concatenating the user's input to the column name +String mSelectionClause = "var = " + mUserInput; ++
+ このようにすれば、ユーザーが悪意のある SQL を SQL 文に連結できるようになります。
+ たとえば、ユーザーが mUserInput
に「nothing; DROP TABLE *;」と入力すると、選択句は var = nothing; DROP TABLE *;
となります。
+選択句は SQL 文として処理されるため、この場合、基本的な SQLite データベースのすべての表が消去されることがあります(プロバイダに SQL インジェクションの試みの検出が設定されていない場合)。
+
+
+
+
+ この問題を回避するには、?
を置き換え可能パラメータとして使う選択句と、選択引数の個別の配列を使用します。
+そうすることで、ユーザー入力は、SQL 文の一部として解釈されずに、クエリに直接バインドされます。
+
+ SQL として扱われないため、ユーザー入力によって悪意のある SQL が挿入されることはありません。ユーザー入力を含める際に連結を使用しないで、次の選択句を使用します。
+
+
+// Constructs a selection clause with a replaceable parameter +String mSelectionClause = "var = ?"; ++
+ 選択引数の配列を次のように設定します。 +
++// Defines an array to contain the selection arguments +String[] selectionArgs = {""}; ++
+ 選択引数の配列に次のように値を格納します。 +
++// Sets the selection argument to the user's input +selectionArgs[0] = mUserInput; ++
+ プロバイダが SQL データベースに基づいたものではない場合でも、選択内容を指定する場合は、?
を置き換え可能パラメータとして使う選択句と、選択引数の配列を使用することをお勧めします。
+
+
+
クエリ結果を表示する
++ {@link android.content.ContentResolver#query ContentResolver.query()} クライアント メソッドは、常に {@link android.database.Cursor} を返します。これには、クエリの選択基準に一致する、行へのクエリの投影によって指定される列が含まれます。 + +{@link android.database.Cursor} オブジェクトは、含まれる行と列へのランダム読み取りアクセスを提供します。 + +{@link android.database.Cursor} メソッドを使用すると、結果の行の繰り返し、各列のデータタイプの識別、列からのデータの取得、結果のその他のプロパティの確認といった操作が可能となります。 + +一部の {@link android.database.Cursor} を実装すると、プロバイダのデータが変更された場合にオブジェクトが自動的に送信されたり、{@link android.database.Cursor} が変更された場合にオブザーバ オブジェクトのメソッドがトリガーされたり、その両方が実行されたりします。 + + +
++ 注: クエリを作成するオブジェクトの特性に基づいて、プロバイダによって列へのアクセスが制限されることがあります。 +たとえば、連絡先プロバイダにより同期アダプタは一部の列へのアクセスが制限されるため、その場合はアクティビティやサービスを返しません。 + +
++ 選択基準に一致する行がない場合は、{@link android.database.Cursor#getCount Cursor.getCount()} が 0(空のカーソル)の {@link android.database.Cursor} オブジェクトを返します。 + + +
+
+ 内部エラーが発生した場合、クエリの結果はプロバイダによって異なります。null
が返されることもあれば、{@link java.lang.Exception} がスローされることもあります。
+
+
+ {@link android.database.Cursor} は行の「一覧」であることから、{@link android.database.Cursor} のコンテンツを表示する場合は、{@link android.widget.SimpleCursorAdapter} 経由で {@link android.widget.ListView} にリンクすることをお勧めします。 + + +
++ 次のスニペットは前のスニペットのコードの続きです。クエリによって取得する {@link android.database.Cursor} を含む {@link android.widget.SimpleCursorAdapter} オブジェクトを作成し、このオブジェクトを {@link android.widget.ListView} のアダプタに設定します。 + + + +
++// Defines a list of columns to retrieve from the Cursor and load into an output row +String[] mWordListColumns = +{ + UserDictionary.Words.WORD, // Contract class constant containing the word column name + UserDictionary.Words.LOCALE // Contract class constant containing the locale column name +}; + +// Defines a list of View IDs that will receive the Cursor columns for each row +int[] mWordListItems = { R.id.dictWord, R.id.locale}; + +// Creates a new SimpleCursorAdapter +mCursorAdapter = new SimpleCursorAdapter( + getApplicationContext(), // The application's Context object + R.layout.wordlistrow, // A layout in XML for one row in the ListView + mCursor, // The result from the query + mWordListColumns, // A string array of column names in the cursor + mWordListItems, // An integer array of view IDs in the row layout + 0); // Flags (usually none are needed) + +// Sets the adapter for the ListView +mWordList.setAdapter(mCursorAdapter); ++
+ 注: {@link android.database.Cursor} によって {@link android.widget.ListView} を戻すには、カーソルに _ID
という名前の列を含める必要があります。
+
+ そのため、{@link android.widget.ListView} には表示されまませんが、前述のクエリは「words」表に _ID
列を取得します。
+
+ また、このような制限があることから、大部分のプロバイダがそれぞれの表に _ID
列を持ちます。
+
+
クエリ結果を取得する
++ クエリ結果を単に表示するだけでなく、他のタスクに使用することもできます。たとえば、単語リストからスペリングを取得して、それを他のプロバイダで検索するといった操作も可能です。 + +そのためには、次のように {@link android.database.Cursor} の行に操作を繰り返します。 +
++ +// Determine the column index of the column named "word" +int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); + +/* + * Only executes if the cursor is valid. The User Dictionary Provider returns null if + * an internal error occurs. Other providers may throw an Exception instead of returning null. + */ + +if (mCursor != null) { + /* + * Moves to the next row in the cursor. Before the first movement in the cursor, the + * "row pointer" is -1, and if you try to retrieve data at that position you will get an + * exception. + */ + while (mCursor.moveToNext()) { + + // Gets the value from the column. + newWord = mCursor.getString(index); + + // Insert code here to process the retrieved word. + + ... + + // end of while loop + } +} else { + + // Insert code here to report an error if the cursor is null or the provider threw an exception. +} ++
+ {@link android.database.Cursor} の実装には「取得」メソッドがいくつか備わっており、オブジェクトからさまざまなタイプのデータを取得できます。 +たとえば、前述のスニペットは {@link android.database.Cursor#getString getString()} を使用しています。 +さらに、列のデータタイプを示す値を返す {@link android.database.Cursor#getType getType()} メソッドも使用しています。 + + +
+ + + +コンテンツ プロバイダ パーミッション
++ プロバイダのアプリケーションでは、他のアプリケーションがプロバイダのデータにアクセスするのに必要なパーミッションを指定できます。 +これらのパーミッションを設定しておけば、ユーザーはアプリケーションがアクセスしようとしているデータの種類を把握できます。 +他のアプリケーションは、プロバイダの要件に基づき、そのプロバイダにアクセスするのに必要なパーミッションを要求します。 +エンドユーザーがアプリケーションをインストールする際には、要求されたパーミッションを確認できます。 + +
++ プロバイダのアプリケーションでパーミッションを指定していない場合は、他のアプリケーションはプロバイダのデータにアクセスできません。 +ただし、指定したパーミッションに関係なく、プロバイダのアプリケーションのコンポーネントには完全な読み取り権限と書き込み権限を常に付与する必要があります。 + +
+
+ 前述のとおり、単語リスト プロバイダには、データを取得するための android.permission.READ_USER_DICTIONARY
パーミッションが必要です。
+
+ プロバイダには、データの挿入、更新、削除に対してそれぞれ個別の android.permission.WRITE_USER_DICTIONARY
パーミッションがあります。
+
+
+ プロバイダにアクセスするのに必要なパーミッションを取得するには、アプリケーションのマニフェスト ファイルの <uses-permission>
要素を使用してパーミッションを要求する必要があります。
+
+Android Package Manager でアプリケーションをインストールする場合は、ユーザーがアプリケーションが要求するすべてのパーミッションを承認する必要があります。
+ユーザーがすべてのパーミッションを承認すると、Package Manager がインストールを続行します。ユーザーが承認しない場合は、Package Manager がインストールを中止します。
+
+
+
+ 次の <uses-permission>
要素は、単語リスト プロバイダへの読み取りアクセスを要求します。
+
+
+
+ <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> ++
+ プロバイダ アクセスへのパーミッションの影響については、セキュリティとパーミッションに関するガイドをご覧ください。 + +
+ + + +データを挿入、更新、削除する
++ データを収集するには、プロバイダからデータを取得するのと同様に、プロバイダ クライアントとプロバイダの {@link android.content.ContentProvider} 間で操作を行います。 + + 対応する {@link android.content.ContentProvider} のメソッドに渡した引数を使用して、{@link android.content.ContentResolver} のメソッドを呼び出します。 +プロバイダとプロバイダ クライアントが、セキュリティとプロセス間の通信を自動的に処理します。 + +
+データを挿入する
++ プロバイダにデータを挿入するには、{@link android.content.ContentResolver#insert ContentResolver.insert()} メソッドを呼び出します。 + +このメソッドはプロバイダに新しい行を挿入し、その行のコンテンツ URI を返します。 + このスニペットは、単語リスト プロバイダに新しい単語を挿入する方法を示しています。 +
++// Defines a new Uri object that receives the result of the insertion +Uri mNewUri; + +... + +// Defines an object to contain the new values to insert +ContentValues mNewValues = new ContentValues(); + +/* + * Sets the values of each column and inserts the word. The arguments to the "put" + * method are "column name" and "value" + */ +mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); +mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); +mNewValues.put(UserDictionary.Words.WORD, "insert"); +mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); + +mNewUri = getContentResolver().insert( + UserDictionary.Word.CONTENT_URI, // the user dictionary content URI + mNewValues // the values to insert +); ++
+ 新しい行のデータは 1 つの {@link android.content.ContentValues} オブジェクトに入ります。これは 1 行カーソルの形式に似ています。
+このオブジェクト内の列は同じデータタイプを持つ必要はなく、値をまったく指定しない場合は、{@link android.content.ContentValues#putNull ContentValues.putNull()} を使用して列を null
に設定できます。
+
+
+
+ この列は自動的に保持されるため、スニペットは _ID
列を追加しません。
+プロバイダは、追加するそれぞれの行に、_ID
の一意の値を割り当てます。
+通常、プロバイダはこの値を表のプライマリキーとして使用します。
+
+ newUri
で返されるコンテンツ URI は、新たに追加された行を特定するものであり、次の形式となります。
+
+
+content://user_dictionary/words/<id_value> ++
+ <id_value>
は、新しい行の _ID
のコンテンツです。
+ ほとんどのプロバイダではコンテンツ URI のこの形式を自動的に検出し、特定の行で要求された操作を実行します。
+
+
+ 返された {@link android.net.Uri} から _ID
の値を取得するには、{@link android.content.ContentUris#parseId ContentUris.parseId()} を呼び出します。
+
+
データを更新する
+
+ 行を更新するには、挿入操作と同じように、値を更新した {@link android.content.ContentValues} オブジェクトと、クエリ操作のときと同じように選択基準を使用します。
+
+ 使用するクライアント メソッドは {@link android.content.ContentResolver#update ContentResolver.update()} です。
+更新する列の {@link android.content.ContentValues} オブジェクトに値を追加する操作のみが必要になります。
+列のコンテンツを消去する場合は、値を null
に設定します。
+
+
+ 次のスニペットは、ロケール言語が「en」となっているすべての行のロケールを null
に変更します。
+戻り値は、更新された行の数となります。
+
+// Defines an object to contain the updated values +ContentValues mUpdateValues = new ContentValues(); + +// Defines selection criteria for the rows you want to update +String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; +String[] mSelectionArgs = {"en_%"}; + +// Defines a variable to contain the number of updated rows +int mRowsUpdated = 0; + +... + +/* + * Sets the updated value and updates the selected words. + */ +mUpdateValues.putNull(UserDictionary.Words.LOCALE); + +mRowsUpdated = getContentResolver().update( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mUpdateValues // the columns to update + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); ++
+ また、{@link android.content.ContentResolver#update ContentResolver.update()} を呼び出すときには、ユーザー入力をサニタイズする必要があります。 +詳細は、悪意のある入力から保護するセクションをご覧ください。 + +
+データを削除する
++ 行の削除は行データの取得と似た操作になります。削除する行の選択基準を指定することで、クライアント メソッドが削除した行の数を返します。 + + 次のスニペットは appid が「user」となっている行を削除します。メソッドによって削除された行の数が返されます。 + +
++ +// Defines selection criteria for the rows you want to delete +String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; +String[] mSelectionArgs = {"user"}; + +// Defines a variable to contain the number of rows deleted +int mRowsDeleted = 0; + +... + +// Deletes the words that match the selection criteria +mRowsDeleted = getContentResolver().delete( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); ++
+ また、{@link android.content.ContentResolver#delete ContentResolver.delete()} を呼び出すときには、ユーザー入力をサニタイズする必要があります。 +詳細は、悪意のある入力から保護するセクションをご覧ください。 + +
+ +プロバイダ データタイプ
++ コンテンツ プロバイダではさまざまなデータタイプを利用できます。単語リスト プロバイダで提供できるのはテキストのみですが、次のような形式を提供できます。 + +
+-
+
- + 整数 + +
- + long 整数(long) + +
- + 浮動小数点 + +
- + long 浮動小数点(double) + +
+ それ以外にも、プロバイダでは 64KB バイト配列として実装されるバイナリ ラージ オブジェクト(BLOB)もよく使用されます。 +利用可能なデータタイプについては、{@link android.database.Cursor} クラスの「get」メソッドをご覧ください。 + +
++ プロバイダの各列のデータタイプは、通常、そのドキュメントに一覧が記載されています。 + 単語リスト プロバイダのデータタイプは、コントラクト クラス {@link android.provider.UserDictionary.Words} のリファレンスに一覧が記載されています(コントラクト クラスの詳細は、コントラクト クラスセクションをご覧ください)。 + + + さらに、{@link android.database.Cursor#getType + Cursor.getType()} を呼び出すことで、データタイプを判断することもできます。 +
++ プロバイダは、プロバイダによって定義される各コンテンツ URI の MIME データタイプも保持します。MIME タイプ情報を使用すると、プロバイダが提供するデータをアプリケーションが処理できるかを判断したり、MIME タイプに基づいて処理のタイプを選択したりできます。 + +通常は、複雑なデータ構造やファイルを持つプロバイダで作業をする際に MIME タイプが必要になります。 + +たとえば、連絡先プロバイダの {@link android.provider.ContactsContract.Data} 表は MIME タイプを使用して、それぞれの行に格納される連絡先データのタイプをラベル付けします。 + +コンテンツ URI に対応する MIME タイプを取得するには、{@link android.content.ContentResolver#getType ContentResolver.getType()} を呼び出します。 + +
++ 「MIME タイプ リファレンス」セクションでは、標準とカスタムの両方の MIME タイプについて説明しています。 + +
+ + + +プロバイダ アクセスの別の形式
++ アプリケーションの開発では、次に示すプロバイダ アクセスの別の 3 つの形式が重要になります。 +
+-
+
- + バッチアクセス: {@link android.content.ContentProviderOperation} クラスのメソッドを使用したアクセス呼び出しのバッチを作成し、{@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()} に適用できます。 + + + +
- + 非同期クエリ: クエリは個別のスレッドで実行する必要があります。この操作は、{@link android.content.CursorLoader} オブジェクトを使用して行うこともできます。 +「ローダ」のガイドには、この操作の例が記載されています。 + + + +
- + インテント経由のデータアクセス: インテントをプロバイダに直接送信できませんが、プロバイダのアプリケーションにはインテントを送信できます。通常、プロバイダのデータの修正に最適な機能を備えたアプリケーションになります。 + + + +
+ バッチアクセスとインテント経由の修正については、次のセクションで説明しています。 +
+バッチアクセス
++ 多数の行を挿入する場合や、同じメソッド呼び出しで複数の表に行を挿入する場合は、プロバイダへのバッチアクセスを使用すると便利です。また、一般的には、境界をまたいでプロセス全体にトランザクションとして一連の操作を実行する場合にもバッチアクセスが便利です。 + + +
++ 「バッチモード」でプロバイダにアクセスするには、{@link android.content.ContentProviderOperation} オブジェクトの配列を作成してから、{@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()} を使用してそれらのオブジェクトをコンテンツ プロバイダに送信します。 + + +このメソッドには、特定のコンテンツ URI ではなく、コンテンツ プロバイダの認証局を渡します。そうすることで、配列内のそれぞれの {@link android.content.ContentProviderOperation} オブジェクトを別々の表に対して機能するようになります。 + + +{@link android.content.ContentResolver#applyBatch + ContentResolver.applyBatch()} への呼び出しでは、結果の配列が返されます。 +
+
+ {@link android.provider.ContactsContract.RawContacts} コントラクト クラスの説明には、バッチ挿入を示したコード スニペットが記載されています。
+Contact Manager のサンプル アプリケーションでは、ContactAdder.java
ソースファイルでのバッチアクセスの例が紹介されています。
+
+
+
+
ヘルパーアプリでデータを表示する
++ アプリケーションにアクセス パーミッションが付与されている場合でも、インテントを使用して別のアプリケーションにデータを表示できます。 +たとえば、カレンダー アプリケーションは {@link android.content.Intent#ACTION_VIEW} インテントにアクセスしますが、このインテントは特定の日付やイベントを表示するものです。 + + これにより、独自の UI を作成しなくても、カレンダー情報を表示できます。この機能の詳細は、「カレンダー プロバイダ」のガイドをご覧ください。 + + +
++ インテントの送信先アプリケーションは、必ずしもプロバイダに関連付けられたアプリケーションである必要はありません。 +たとえば、連絡先プロバイダから連絡先を取得してから、連絡先の画像のコンテンツ URI を含む {@link android.content.Intent#ACTION_VIEW} インテントを画像ビューワに送信するといった操作が可能です。 + + +
+インテント経由のデータアクセス
++ インテントを使用すれば、コンテンツ プロバイダに間接的にアクセスできます。アプリケーションにアクセス パーミッションがない場合でも、パーミッションを持つアプリケーションから結果のインテントを取得したり、パーミッションを持つアプリケーションをアクティベートしてそのアプリケーションをユーザーに使用させたりすることで、ユーザーがプロバイダのデータにアクセスできるようになります。 + + + +
+一時的なパーミッションによりアクセスを取得する
++ 適切なアクセス パーミッションがない場合でも、パーミッションを持つアプリケーションにインテントを送信し、「URI」パーミッションを含む結果のインテントを受け取ることで、コンテンツ プロバイダのデータにアクセスできます。 + + + これらのパーミッションは特定のコンテンツ URI のパーミッションであり、パーミッションを受け取ったアクティビティが終了するまで効力を持ちます。 +永続的なパーミッションを持つアプリケーションは、次のように結果のインテントにフラグを設定し、一時的なパーミッションを付与します。 + +
+-
+
- + 読み取りパーミッション: {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} + + +
- + 書き込みパーミッション: {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} + + +
+ 注: これらのフラグは、認証局がコンテンツ URI に含まれるプロバイダへの全般的な読み取りと書き込みアクセスを付与するものではありません。アクセスは URI 自身に限定されます。 + +
+
+ プロバイダは、<provider>
要素の android:grantUriPermission
属性や、<provider>
要素の <grant-uri-permission>
子要素を使用して、コンテンツ URI の URI パーミッションを自身のマニフェストで定義します。
+
+
+
+
+
+
+
+URI パーミッションのメカニズムについての詳細は、URI パーミッション セクションのセキュリティとパーミッションに関するガイドをご覧ください。
+
+
+
+ たとえば、{@link android.Manifest.permission#READ_CONTACTS} パーミッションを持たない場合でも、連絡先プロバイダの連絡先のデータを取得できます。 +連絡先の誕生日にグリーティング カードをオンラインで送信するアプリケーションなどにこのメカニズムを利用できます。 +ユーザーのすべての連絡先やそのすべての情報へのアクセス件を付与する {@link android.Manifest.permission#READ_CONTACTS} を要求する代わりに、アプリケーションで使用する連絡先をユーザーが制御できるように設定することもできます。 + + +そのためには、次の手順を使用します。 +
+-
+
- + アプリケーションが、メソッド {@link android.app.Activity#startActivityForResult + startActivityForResult()} を使用して、アクション {@link android.content.Intent#ACTION_PICK} と「連絡先」MIME タイプ {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} を含むインテントを送信します。 + + + + +
- + このインテントは連絡帳アプリの「selection」アクティビティのインテント フィルタに一致するため、アクティビティがフォアグラウンドに移動します。 + + +
- + selection アクティビティでは、更新する連絡先をユーザーが選択します。 +この操作が行われると、selection が {@link android.app.Activity#setResult setResult(resultcode, intent)} を呼び出し、アプリケーションに戻すインテントを設定します。 + +インテントには、ユーザーが選択した連絡先のコンテンツ URI と、「エクストラ」フラグ {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} が含まれます。 + +これらのフラグがあることで、コンテンツ URI がポイントする連絡先のデータを読み取るための URI パーミッションがアプリに付与されます。その後、selection アクティビティによって、アプリケーションに制御を返すための {@link android.app.Activity#finish()} が呼び出されます。 + + + + +
- + アクティビティがフォアグラウンドに戻り、システムがアクティビティの {@link android.app.Activity#onActivityResult onActivityResult()} メソッドを呼び出します。 + +このメソッドは、連絡帳アプリの selection アクティビティによって作成された結果のインテントを受け取ります。 + + +
- + 結果のインテントのコンテンツ URI を使用すれば、マニフェストで永続的なアクセス パーミッションをプロバイダに要求していなくても、連絡先プロバイダから連絡先のデータを読み取ることができます。 + +その後、連絡先の誕生日情報やメールアドレスを取得し、グリーティング カードをオンラインで送信できます。 + + +
別のアプリケーションを使用する
++ パーミッションを持つアプリケーションをアクティベートし、そのアプリケーションをユーザーが使用すれば、アクセス パーミッションを持たないデータをユーザーが修正できるようになります。 + +
++ たとえば、アプリケーションの挿入 UI をアクティベートできる {@link android.content.Intent#ACTION_INSERT} インテントをカレンダー アプリケーションが受け入れるとします。このインテントに「エクストラ」データを渡すことで、アプリケーションがそのデータを使用して、事前に入力された UI を作成します。繰り返し発生するイベントは複雑な構文を持つため、カレンダー プロバイダにイベントを挿入する場合は、{@link android.content.Intent#ACTION_INSERT} でカレンダー アプリをアクティベートしてから、ユーザーにイベントを挿入してもらうことをお勧めします。 + + + + + +
+ +コントラクト クラス
++ コントラクト クラスは、アプリケーションがコンテンツ URI、列名、インテント アクション、コンテンツのその他の機能で作業する際に役立つ定数を定義します。 +プロバイダでコントラクト クラスが自動的に含まれることはありません。プロバイダのデベロッパーはコントラクト クラスを定義して、その他のデベロッパーが使用できるようにする必要があります。 + +Android プラットフォームに含まれる多くのプロバイダは、パッケージ {@link android.provider} 内に対応するコントラクト クラスを持ちます。 + +
++ たとえば、単語リスト プロバイダは、コンテンツ URI と列名の定数を含む、コントラクト クラス {@link android.provider.UserDictionary} を持つとします。 +「words」表のコンテンツ URI は、定数 {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI} で定義されます。 + + + さらに、{@link android.provider.UserDictionary.Words} クラスは、このガイドのサンプルのスニペットで使用される、列名の定数を持ちます。 +たとえば、クエリの投影は次のように定義できます。 + +
++String[] mProjection = +{ + UserDictionary.Words._ID, + UserDictionary.Words.WORD, + UserDictionary.Words.LOCALE +}; ++
+ もう一方のコントラクト クラスは、連絡先プロバイダのクラス {@link android.provider.ContactsContract} です。 + このクラスのリファレンスには、サンプルのコード スニペットが記載されています。サブクラスの 1 つである {@link android.provider.ContactsContract.Intents.Insert} は、インテントとインテント データの定数を含むコントラクト クラスです。 + + +
+ + + +MIME タイプ リファレンス
++ コンテンツ プロバイダは、標準の MIME メディア タイプかカスタムの MIME タイプ文字列、またはその両方を返すことができます。 +
++ MIME タイプは次の形式となります +
++type/subtype ++
+ たとえば、よく利用される MIME タイプ text/html
は、text
タイプと html
サブタイプを持ちます。
+プロバイダから URI に対してこのタイプが返される場合、その URI を使用するクエリは HTML タグを含むテキストを返すことになります。
+
+
+ 「ベンダー固有の」MIME タイプとも呼ばれるカスタムの MIME タイプ文字列には、より複雑な type と subtype の値が含まれます。 +複数行の場合、type 値は常に +
++vnd.android.cursor.dir ++
+ となり、1 つの行の場合は +
++vnd.android.cursor.item ++
+ となります。 +
++ subtype はプロバイダ固有の値になります。通常、Android 組み込みプロバイダは単純な subtype を使用します。 +たとえば、連絡先アプリケーションが電話番号の行を作成すると、行には次のように MIME タイプが設定されます。 + +
++vnd.android.cursor.item/phone_v2 ++
+ subtype の値は単純に phone_v2
となっていることがわかります。
+
+ 他のプロバイダ デベロッパーは、プロバイダの認証局と表明に基づいて独自のパターンの subtype を作成できます。
+たとえば、列車の時刻表を含むプロバイダについて考えてみます。
+ プロバイダの認証局は com.example.trains
であり、表 Line1、Line2、Line3 を持ちます。
+表 Line1 のコンテンツ URI
+
+
+content://com.example.trains/Line1 ++
+ に対しては、プロバイダは次の MIME タイプを返します +
++vnd.android.cursor.dir/vnd.example.line1 ++
+ 表 Line2 の行 5 のコンテンツ URI +
++content://com.example.trains/Line2/5 ++
+ に対しては、プロバイダは次の MIME タイプを返します +
++vnd.android.cursor.item/vnd.example.line2 ++
+ ほとんどのコンテンツ プロバイダが、使用する MIME タイプに対してコントラクト クラス定数を定義します。たとえば、連絡先プロバイダのコントラクト クラス {@link android.provider.ContactsContract.RawContacts} は、1 つの未加工連絡先行の MIME タイプに、定数 {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} を定義します。 + + + + +
++ 1 つの行のコンテンツ URI については、コンテンツ URI セクションをご覧ください。 + +
diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd new file mode 100644 index 0000000000000000000000000000000000000000..af2181482d33925bfd7bb69e0eade3525b1fee51 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-provider-creating.jd @@ -0,0 +1,1214 @@ +page.title=コンテンツ プロバイダの作成 +@jd:body +本書の内容
+-
+
- + データ ストレージを設計する + +
- + コンテンツ URI を設計する + +
-
+ ContentProvider クラスを実装する
+
-
+
- + 必須メソッド + +
- + query() メソッドを実装する + +
- + insert() メソッドを実装する + +
- + delete() メソッドを実装する + +
- + update() メソッドを実装する + +
- + onCreate() メソッドを実装する + +
+ -
+ コンテンツ プロバイダ MIME を実装する
+
-
+
- + テーブルの MIME タイプ + +
- + ファイルの MIME タイプ + +
+ - + コントラクト クラスを実装する + +
- + コンテンツ プロバイダ パーミッションを実装する + +
- + <provider> 要素 + +
- + インテントとデータアクセス + +
キークラス
+-
+
- + {@link android.content.ContentProvider} + +
- + {@link android.database.Cursor} + +
- + {@link android.net.Uri} + +
関連サンプル
+-
+
- + + Note Pad のサンプル アプリケーション + + +
関連ドキュメント
+-
+
- + + コンテンツ プロバイダの基本 + +
- + + カレンダー プロバイダ + +
+ コンテンツ プロバイダは、データの中央リポジトリへのアクセスを管理します。Android アプリケーションでは 1 つ以上のクラスとしてプロバイダを実装し、要素をマニフェスト ファイルで実装します。 + +いずれか 1 つのクラスがサブラス {@link android.content.ContentProvider} を実装します。これは、プロバイダと他のアプリケーションとの間のインターフェースになります。 + +コンテンツ プロバイダは他のアプリケーションへのデータの提供を意図したものですが、ユーザーがプロバイダに管理されるデータを照会、修正するアクティビティをアプリケーション内に設定することもできます。 + + +
++ このトピックの残りの部分では、コンテンツ プロバイダと使用する API のリストをビルドするための基本的な手順を挙げていきます。 + +
+ + + +ビルドを開始する前に
++ ビルドを開始する前に、次の操作を行います。 +
+-
+
-
+ コンテンツ プロバイダが必要かどうかを決定します。次のような機能を 1 つ以上提供する場合に、コンテンツ プロバイダをビルドする必要があります。
+
+
-
+
- 他のアプリケーションに複雑なデータやファイルを提供する。 +
- アプリから他のアプリへの複雑なデータのコピーをユーザーに許可する。 +
- 検索フレームワークを使用してカスタムの検索候補を提供する。 +
+ 完全に独自アプリケーション内だけで使用する場合は、SQLite データベースを使用するプロバイダは必要はありません。 + +
+
+ - + 必要かどうかを決定していない場合は、プロバイダの詳細については「コンテンツ プロバイダの基本」のトピックをご覧ください。 + + + +
+ 次に、以下の手順に従ってプロバイダをビルドします。 +
+-
+
-
+ データの未処理のストレージを設計します。コンテンツ プロバイダは次の 2 つの方法でデータを提供します。
+
-
+
- + ファイルデータ + +
- + 通常、写真、オーディオ、ビデオなどのファイルの形式となるデータです。 +ファイルはアプリケーションのプライベート スペースに格納します。 +ファイルに対する別のアプリケーションからの要求に応じて、プロバイダからファイルへのハンドルが提供されます。 + + +
- + 「構造化」データ + +
- + 通常、データベース、配列、類似の構造の形式となるデータです。 + テーブルの行と列に互換性を持つ形式でデータが格納されます。行は、担当者や在庫にあるアイテムなどのエンティティを表します。 +列は、担当者の名前やアイテムの価格などの、エンティティの一部のデータを表します。 +一般的にこのタイプのデータは SQLite データベースに格納しますが、任意のタイプの永続ストレージを使用できます。 + +Android システムで使用できるストレージ タイプの詳細は、データ ストレージを設計するをご覧ください。 + + + +
+ - + {@link android.content.ContentProvider} クラスの具体的な実装とそれに必要なメソッドを定義します。 +このクラスは、データと Android システムのそれ以外の部分とのインターフェースとなります。 +このクラスの詳細は、ContentProvider クラスを実装するセクションをご覧ください。 + + +
- + プロバイダの認証局の文字列、コンテンツ URI、列名を定義します。プロバイダのアプリケーションでインテントを処理する場合は、インテント アクション、エクストラ データ、フラグも定義します。 + +さらに、データにアクセスするアプリケーションに必要なパーミッションも定義します。 +これらの値はすべて定数として個別のコントラクト クラスに定義するようにします。そうしておくと、後で他のデベロッパーに対してこのクラスを公開できます。 +コンテンツ URI の詳細は、コンテンツ URI を設計するセクションをご覧ください。 + + + インテントの使用に関する詳細については、インテントとデータアクセスセクションをご覧ください。 + + +
- + サンプルデータや、プロバイダとクラウドベースのデータの間でデータを同期する {@link android.content.AbstractThreadedSyncAdapter} の実装などの、その他のオプション部分を追加します。 + + + +
データ ストレージを設計する
++ コンテンツ プロバイダは、構造化された形式で保存されているデータへのインターフェースです。インターフェースを作成する前に、データの格納方法を決定しておく必要があります。 +データは任意の形式で保存でき、必要に応じてデータの読み取りと書き込みを行うためのインターフェースを設計できます。 + +
++ Android には、次のように、いくつかのデータ格納テクノロジーがあります。 +
+-
+
-
+ Android システムには、Android の独自のプロバイダがテーブル指向のデータを格納するために使用する、SQLite データベース API があります。
+{@link android.database.sqlite.SQLiteOpenHelper} クラスを使用すると、データベースを作成できます。また、{@link android.database.sqlite.SQLiteDatabase} クラスは、データベースにアクセスするための基本クラスです。
+
+
+
+
+ リポジトリを実装するのに、データベースを使用する必要がありません。外部的には、プロバイダはリレーショナル データベースに似た一連のテーブルとして表示されますが、プロバイダの内部実装をそのような形式にする必要はありません。 + + +
+
+ - + ファイルデータを格納するために、Android にはファイル指向のさまざまな API があります。 + ファイル ストレージの詳細は、「Data Storage」トピックをご覧ください。 +音楽やビデオのようにメディア関連のデータを提供するプロバイダを設計する場合は、テーブルデータとファイルを組み合わせるプロバイダを作成できます。 + + + +
- + ネットワーク ベースのデータで作業する場合は、{@link java.net} と {@link android.net} のクラスを使用します。 +また、ネットワーク ベースをデータベースなどのローカル データストアに同期させ、データをテーブルやファイルとして提供することもできます。 + + サンプル同期アダプタのサンプル アプリケーションでは、このタイプの同期のデモを紹介しています。 + + +
+ データ設計上の考慮事項 +
++ 次に、プロバイダのデータ構造を設計する際のヒントを示します。 +
+-
+
-
+ テーブルデータには、プロバイダが各行の一意の数値として保持する「プライマリキー」列が常に必要です。
+この値を使用すると、行を他のテーブルの関連する行にリンクできます(「外部キー」として使用)。
+この列には任意の名前を設定できますが、プロバイダ クエリの結果を {@link android.widget.ListView} にリンクさせるには、取得する列のいずれかの名前が
_ID
になっている必要があるため、{@link android.provider.BaseColumns#_ID BaseColumns._ID} を使用することをお勧めします。 + + + + +
+ - + ビットマップ画像やサイズが非常に大きなその他のファイル指向のデータを提供する場合は、テーブルにデータを直接格納するのではなく、データをファイルに格納し、データを間接的に提供します。 + +その場合、データにアクセスするには、{@link android.content.ContentResolver} ファイル メソッドの使用が必要であることをプロバイダのユーザーに通知する必要があります。 + + +
-
+ サイズや構造が異なるデータを格納するには、バイナリ ラージ オブジェクト(BLOB)データタイプを使用します。
+たとえば、Protocol Buffer や JSON 構造を格納するには、BLOB 列を使用します。
+
+
+
+ さらに、BLOB を使用してスキーマに依存しないテーブルを実装できます。このタイプのテーブルでは、プライマリキー列、MIME タイプ列、1 つ以上の汎用列を BLOB として定義します。 + +BLOB 列内のデータの内容は、MIME タイプ列の値によって示されます。 +これにより、同じテーブルにさまざまな行タイプを格納できます。 +連絡先プロバイダの「データ」テーブル {@link android.provider.ContactsContract.Data} は、スキーマに依存しないテーブルの例です。 + + +
+
+
コンテンツ URI を設計する
++ コンテンツ URI は、プロバイダのデータを特定する URI です。コンテンツ URI には、プロバイダ全体の識別名(認証局)とテーブルやファイルをポイントする名前(パス)が含まれます。 + +オプションの ID 部分は、テーブル内の個々の行を指します。 +{@link android.content.ContentProvider} のそれぞれのデータアクセス メソッドは引数としてコンテンツ URI を使用します。これにより、アクセスするテーブル、行、ファイルを決定できます。 + + +
++ コンテンツ URI の基本については、「コンテンツ プロバイダの基本」トピックをご覧ください。 + + +
+認証局を設計する
+
+ 通常、プロバイダは、Android 内部の名前として使用される認証局を 1 つ持ちます。他のプロバイダとの競合を避けるためには、(逆に)プロバイダの認証局の基礎としてインターネット ドメインの所有権を使用する必要があります。
+
+この推奨事項は Android パッケージ名にもあてはまるため、プロバイダを含むパッケージの名前の拡張子として、プロバイダの認証局を定義できます。
+
+たとえば、Android パッケージ名が com.example.<appname>
の場合、プロバイダに認証局 com.example.<appname>.provider
を付与する必要があります。
+
+
+
パス構造を設計する
+
+ デベロッパーは通常、個々のテーブルを指すパスを末尾に追加して認証局からコンテンツ URI を作成します。
+たとえば、table1 と table2 の 2 つのテーブルがある場合、前の例の認証局を組み合わせてコンテンツ URI com.example.<appname>.provider/table1
と com.example.<appname>.provider/table2
を作成します。
+
+
+
+パスは 1 つのセグメントに限定されず、パスの各レベルにテーブルを作成する必要はありません。
+
+
コンテンツ URI ID を処理する
+
+ 慣例として、URI の末尾にある行の ID 値を持つコンテンツ URI を受け取ることで、プロバイダはテーブル内の 1 つの行へのアクセスを提供します。さらに、慣例として、プロバイダは ID 値をテーブルの _ID
列とマッチングし、一致する行に対して要求されたアクセスを実行します。
+
+
+
+
+ この慣例により、プロバイダにアクセスするアプリの一般的なパターンを簡単に設計できます。アプリはプロバイダにクエリを実行し、{@link android.widget.CursorAdapter} を使用して、取得した {@link android.database.Cursor} を {@link android.widget.ListView} に表示します。
+
+
+ {@link android.widget.CursorAdapter} の定義には、{@link android.database.Cursor} のいずれかの列を _ID
に設定する必要があります
+
+
+ その後、ユーザーはデータの確認や修正のために、表示された行のいずれかを UI から選択します。
+アプリは {@link android.widget.ListView} を返す {@link android.database.Cursor} から対応する行を取得し、この行の _ID
値を取得し、その値をコンテンツ URI の末尾に追加して、プロバイダにアクセス要求を送ります。
+
+その後、プロバイダは、ユーザーが選択した行にクエリや修正を実行します。
+
+
コンテンツ URI パターン
+
+ 受け取ったコンテンツ URI に対するアクションを簡単に選択できるように、プロバイダ API には {@link android.content.UriMatcher} という便利なクラスが用意されています。このクラスはコンテンツ URI 「パターン」を正数値にマッピングします。
+
+この正数値を switch
文で使用することで、特定のパターンに一致する 1 つ以上のコンテンツ URI に目的のアクションを選択できます。
+
+
+ コンテンツ URI パターンは、次のワイルドカード文字を使用するコンテンツ URI に一致します。 +
+-
+
-
+
*
: 任意の長さの任意の有効な文字で構成される文字列に一致します。 +
+ -
+
#
: 任意の長さの任意の数字で構成される文字列に一致します。 +
+
+ コンテンツ URI 処理の設計とコーディングの例として、テーブルを指す次のコンテンツ URI を認識する認証局 com.example.app.provider
を持つプロバイダを考えてみます。
+
+
+
-
+
-
+
content://com.example.app.provider/table1
:table1
という名前のテーブル。 +
+ -
+
content://com.example.app.provider/table2/dataset1
:dataset1
という名前のテーブル。 + +
+ -
+
content://com.example.app.provider/table2/dataset2
:dataset2
という名前のテーブル。 + +
+ -
+
content://com.example.app.provider/table3
:table3
という名前のテーブル。 +
+
+ さらに、行 ID が末尾に追加されていると、プロバイダではこれらのコンテンツ URI が認識されます。たとえば、table3
の 1
で特定される行は content://com.example.app.provider/table3/1
になります。
+
+
+
+ 次のようなコンテンツ URI パターンを使用できます。 +
+-
+
-
+
content://com.example.app.provider/*
+
+ - + プロバイダの任意のコンテンツ URI に一致します。 + +
-
+
content://com.example.app.provider/table2/*
: +
+ -
+ テーブル
dataset1
とdataset2
のコンテンツ URI に一致しますが、table1
やtable3
のコンテンツ URI には一致しません。 + + +
+ -
+
content://com.example.app.provider/table3/#
:table3
の 1 つの行のコンテンツ URI に一致します。6
で特定される行はcontent://com.example.app.provider/table3/6
になります。 + + + +
+
+ 次のコード スニペットでは、{@link android.content.UriMatcher} のメソッドが機能する仕組みを示します。
+ このコードでは、テーブルにコンテンツ URI パターン content://<authority>/<path>
を使用し、1 つの行に content://<authority>/<path>/<id>
を使用することで、表全体の URI と 1 つの行の URI を異なる方法で処理します。
+
+
+
+
+ メソッド {@link android.content.UriMatcher#addURI(String, String, int) addURI()} は認証局とパスを正数値にマッピングします。
+メソッド {@link android.content.UriMatcher#match(Uri)
+ match()} は URI に正数値を返します。次のように、switch
文によって、クエリをテーブル全体に実行するか、1 つのレコードに実行するかが決まります。
+
+
+public class ExampleProvider extends ContentProvider { +... + // Creates a UriMatcher object. + private static final UriMatcher sUriMatcher; +... + /* + * The calls to addURI() go here, for all of the content URI patterns that the provider + * should recognize. For this snippet, only the calls for table 3 are shown. + */ +... + /* + * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used + * in the path + */ + sUriMatcher.addURI("com.example.app.provider", "table3", 1); + + /* + * Sets the code for a single row to 2. In this case, the "#" wildcard is + * used. "content://com.example.app.provider/table3/3" matches, but + * "content://com.example.app.provider/table3 doesn't. + */ + sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); +... + // Implements ContentProvider.query() + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { +... + /* + * Choose the table to query and a sort order based on the code returned for the incoming + * URI. Here, too, only the statements for table 3 are shown. + */ + switch (sUriMatcher.match(uri)) { + + + // If the incoming URI was for all of table3 + case 1: + + if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; + break; + + // If the incoming URI was for a single row + case 2: + + /* + * Because this URI was for a single row, the _ID value part is + * present. Get the last path segment from the URI; this is the _ID value. + * Then, append the value to the WHERE clause for the query + */ + selection = selection + "_ID = " uri.getLastPathSegment(); + break; + + default: + ... + // If the URI is not recognized, you should do some error handling here. + } + // call the code to actually do the query + } ++
+ 別の {@link android.content.ContentUris} には、コンテンツ URI の一部である id
で作業するための便利なメソッドが備わっています。
+クラス {@link android.net.Uri} と {@link android.net.Uri.Builder} には、既存の {@link android.net.Uri} オブジェクトを解析して新しいオブジェクトをビルドするための便利なメソッドがあります。
+
+
+
ContentProvider クラスを実装する
++ {@link android.content.ContentProvider} インスタンスは、他のアプリケーションからの要求を処理することで、一連の構造化されたデータへのアクセスを管理します。 +どのような形式でアクセスする場合も、最終的には {@link android.content.ContentResolver} が呼び出されます。その後 {@link android.content.ContentProvider} の具象メソッドが呼び出され、アクセスを取得します。 + + +
+必須メソッド
++ 抽象クラス {@link android.content.ContentProvider} は 6 つの抽象メソッドを定義しますが、これらのメソッドは独自の具象サブクラスの一部として実装する必要があります。 +次のように、{@link android.content.ContentProvider#onCreate() onCreate()} を除くこれらのメソッドは、コンテンツ プロバイダへのアクセスを試みるクライアント アプリケーションによって呼び出されます。 + + +
+-
+
- + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + query()} + +
- + プロバイダからデータを取得します。引数を使って、クエリを実行するテーブル、返す行と列、結果の並び順を選択します。 + + データは {@link android.database.Cursor} オブジェクトとして返されます。 + +
- + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} + +
- + プロバイダに新しい行を挿入します。引数を使って、挿入先のテーブルを選択し、使用する列の値を取得します。 +新たに挿入した行のコンテンツ URI が返されます。 + + +
- + {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} + +
- + プロバイダ内の既存の行を更新します。引数を使って、更新するテーブルと行を選び、更新された列の値を取得します。 +更新された行の数が返されます。 + +
- + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} + +
- + プロバイダから行を削除します。引数を使って、削除するテーブルと行を選びます。 +削除された行の数が返されます。 + +
- + {@link android.content.ContentProvider#getType(Uri) getType()} + +
- + コンテンツ URI に対応する MIME タイプを返します。このメソッドの詳細は、コンテンツ プロバイダ MIME を実装するセクションをご覧ください。 + + +
- + {@link android.content.ContentProvider#onCreate() onCreate()} + +
- + プロバイダを初期化します。プロバイダが作成されると、Android システムがこのメソッドを即座に呼び出します。 +{@link android.content.ContentResolver} オブジェクトがアクセスを試みるまでは、プロバイダは作成されません。 + + +
+ これらのメソッドが持つ署名は、同じ名前の {@link android.content.ContentResolver} メソッドの署名と同じになります。 + +
++ これらのメソッドを実装する場合は、次の点を考慮する必要があります。 +
+-
+
- + {@link android.content.ContentProvider#onCreate() onCreate()} を除くこれらのすべてのメソッドは、複数のスレッドを使用して同時に呼び出すことができるため、スレッドに対応した設定にする必要があります。 +複数のスレッドの詳細は、プロセスとスレッドをご覧ください。 + + + + +
- + {@link android.content.ContentProvider#onCreate() + onCreate()} では冗長な操作は行わないようにします。本当に必要になるまでは、タスクの初期化は行わないようにします。 + 詳細は、onCreate() メソッドを実装するをご覧ください。 + + +
- + これのメソッドの実装は必須ですが、コードでは予測されたデータタイプを返す以外の操作は必要ありません。 +たとえば、他のアプリケーションが一部のテーブルにデータを挿入できないように設定するとします。 +その場合、{@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} への呼び出しを無視して 0 を返します。 + + + +
query() メソッドを実装する
+
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} メソッドは {@link android.database.Cursor} オブジェクトを返す必要があります。失敗した場合は、{@link java.lang.Exception} をスローします。
+
+SQLite データベースをデータストレージとして使用する場合は、{@link android.database.sqlite.SQLiteDatabase} クラスのいずれかの query()
メソッドが返す {@link android.database.Cursor} を返します。
+
+
+ クエリがどの行にも一致しない場合は、{@link android.database.Cursor#getCount()} メソッドが 0 を返す {@link android.database.Cursor} インスタンスを返す必要があります。
+
+ クエリプロセス中にエラーが発生した場合にのみ null
を返します。
+
+ SQLite データベースをデータストレージとして使用しない場合は、{@link android.database.Cursor} クラスのいずれかの具象サブクラスを使用します。 +たとえば、{@link android.database.MatrixCursor} クラスは、各行が {@link java.lang.Object} の配列となるカーソルを実装します。 +このクラスでは、{@link android.database.MatrixCursor#addRow(Object[]) addRow()} を使って新しい行を追加します。 + +
++ Android システムは、プロセスの境界をまたいで {@link java.lang.Exception} を送信できるように設定する必要があることにご注意ください。 +Android では、クエリエラーを処理するのに便利な、次の例外を送信できます。 + +
+-
+
- + {@link java.lang.IllegalArgumentException}(プロバイダが無効なコンテンツ URI を受け取った場合にこの例外をスローするように選択できます) + + +
- + {@link java.lang.NullPointerException} + +
insert() メソッドを実装する
++ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} メソッドは、{@link android.content.ContentValues} 引数の値を使用して、適切なテーブルに新しい行を追加します。 + +列名が {@link android.content.ContentValues} 引数にない場合は、プロバイダ コードがデータベース スキーマのいずれかで、デフォルト値を設定できます。 + + +
+
+ このメソッドは新しい行のコンテンツ URI を返します。作成するには、{@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()} を使用して、新しい行の _ID
(または他のプライマリキー)の値をテーブルのコンテンツ URI の末尾に追加します。
+
+
+
delete() メソッドを実装する
++ {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} メソッドでは、データストレージから行を物理的に削除する必要はありません。 +プロバイダで同期アダプタを使用する場合は、行全体を削除するのではなく、削除された行に「削除」フラグを付けるようにします。 + +同期アダプタは削除された行を探して、プロバイダから削除される前に、サーバーから行を削除できます。 + +
+update() メソッドを実装する
+
+ {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+ update()} メソッドは {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} が使用するのと同じ {@link android.content.ContentValues} 引数、{@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} と {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} が使用するのと同じ selection
と selectionArgs
引数を使用します。
+
+
+
+これにより、これらのメソッド間でコードを再利用できます。
+
onCreate() メソッドを実装する
++ Android システムはプロバイダを起動する際に {@link android.content.ContentProvider#onCreate() + onCreate()} を呼び出します。このメソッドでは迅速に実行できる初期化タスクのみを実行するようにし、プロバイダが実際にデータの要求を受け取るまでは、データベースの作成とデータロードを保留します。 + +{@link android.content.ContentProvider#onCreate() onCreate()} で冗長なタスクを行う場合は、プロバイダの起動が遅くなります。 + +同様に、プロバイダから他のアプリケーションへの応答も遅くなります。 + +
++ たとえば、SQLite データベースを使用すると、{@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} に {@link android.database.sqlite.SQLiteOpenHelper} オブジェクトを作成し、データベースを初めて開くときに SQL テーブルを作成できます。 + + +この操作を簡単にするために、{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase + getWritableDatabase()} を初めて呼び出すときには、{@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} メソッドが自動的に呼び出されます。 + + +
++ 次の 2 つのスニペットは、{@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} と {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} との間のやり取りを表しています。 + +最初のスニペットは {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} の実装です。 + +
++public class ExampleProvider extends ContentProvider + + /* + * Defines a handle to the database helper object. The MainDatabaseHelper class is defined + * in a following snippet. + */ + private MainDatabaseHelper mOpenHelper; + + // Defines the database name + private static final String DBNAME = "mydb"; + + // Holds the database object + private SQLiteDatabase db; + + public boolean onCreate() { + + /* + * Creates a new helper object. This method always returns quickly. + * Notice that the database itself isn't created or opened + * until SQLiteOpenHelper.getWritableDatabase is called + */ + mOpenHelper = new MainDatabaseHelper( + getContext(), // the application context + DBNAME, // the name of the database) + null, // uses the default SQLite cursor + 1 // the version number + ); + + return true; + } + + ... + + // Implements the provider's insert method + public Cursor insert(Uri uri, ContentValues values) { + // Insert code here to determine which table to open, handle error-checking, and so forth + + ... + + /* + * Gets a writeable database. This will trigger its creation if it doesn't already exist. + * + */ + db = mOpenHelper.getWritableDatabase(); + } +} ++
+ 次のスニペットは {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} の実装であり、ヘルパークラスを含みます。 + +
++... +// A string that defines the SQL statement for creating a table +private static final String SQL_CREATE_MAIN = "CREATE TABLE " + + "main " + // Table's name + "(" + // The columns in the table + " _ID INTEGER PRIMARY KEY, " + + " WORD TEXT" + " FREQUENCY INTEGER " + + " LOCALE TEXT )"; +... +/** + * Helper class that actually creates and manages the provider's underlying data repository. + */ +protected static final class MainDatabaseHelper extends SQLiteOpenHelper { + + /* + * Instantiates an open helper for the provider's SQLite data repository + * Do not do database creation and upgrade here. + */ + MainDatabaseHelper(Context context) { + super(context, DBNAME, null, 1); + } + + /* + * Creates the data repository. This is called when the provider attempts to open the + * repository and SQLite reports that it doesn't exist. + */ + public void onCreate(SQLiteDatabase db) { + + // Creates the main table + db.execSQL(SQL_CREATE_MAIN); + } +} ++ + + +
ContentProvider MIME タイプを実装する
++ {@link android.content.ContentProvider} クラスには、MIME タイプを返すための次の 2 つのクラスがあります。 +
+-
+
- + {@link android.content.ContentProvider#getType(Uri) getType()} + +
- + 任意のプロバイダに実装する必要がある必須メソッドの 1 つです。 + +
- + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} + +
- + ファイルを提供するプロバイダの場合に、実装が考えられるメソッドです。 + +
テーブルの MIME タイプ
++ {@link android.content.ContentProvider#getType(Uri) getType()} メソッドは、MIME 形式で {@link java.lang.String} を返します。これは、コンテンツ URI 引数によって返されるデータのタイプを表します。 + +{@link android.net.Uri} 引数には特定の URI ではなくパターンを指定することもできます。この場合、パターンに一致するコンテンツ URI に関連付けられているデータのタイプを返します。 + + +
++ テキスト、HTML、JPEG といった一般的なタイプのデータの場合、{@link android.content.ContentProvider#getType(Uri) getType()} では該当するデータの標準的な MIME タイプを返す必要があります。 + +利用できるこれらの標準的なタイプの詳細なリストは、「IANA MIME Media Types」のウェブサイトをご覧ください。 + + +
++ テーブル データの 1 つ以上の行を指すコンテンツ URI の場合、{@link android.content.ContentProvider#getType(Uri) getType()} は、Android のベンダー固有の MIME 形式で MIME タイプを返す必要があります。 + + +
+-
+
-
+ タイプ部分:
vnd
+
+ -
+ サブタイプ部分:
+
-
+
-
+ URI パターンが 1 つの行の場合:
android.cursor.item/
+
+ -
+ URI パターンが複数の行の場合:
android.cursor.dir/
+
+
+ -
+ URI パターンが 1 つの行の場合:
-
+ プロバイダ固有の部分:
vnd.<name>
.<type>
++
+ +<name>
と<type>
を指定します。 +<name>
の値はグローバルに一意の値とし、<type>
の値は対応する URI パターンに一意のものとする必要があります。 + +<name>
には、企業名や、アプリケーションの Android パッケージ名の一部を使うことをお勧めします。 +<type>
には、URI に関連付けられているテーブルを特定する文字列を使うことをお勧めします。 + + +
+
+ たとえば、プロバイダの認証局が com.example.app.provider
の場合、テーブル名は table1
となり、table1
の複数行の MIME タイプは次のようになります。
+
+
+
+vnd.android.cursor.dir/vnd.com.example.provider.table1 ++
+ table1
の 1 つの行の場合は、MIME タイプは次のようになります。
+
+vnd.android.cursor.item/vnd.com.example.provider.table1 ++
ファイルの MIME タイプ
++ ファイルを提供するプロバイダの場合は、{@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} を実装します。 + + このメソッドは、プロバイダが特定のコンテンツ URI に対して返すことができるファイルの MIME タイプの {@link java.lang.String} 配列を返します。クライアントで処理する MIME タイプのみを返すには、MIME タイプフィルタ引数によって、提供する MIME タイプをフィルタする必要があります。 + + +
+
+ たとえば、写真画像を .jpg
、.png
、.gif
形式で提供するプロバイダについて考えてみます。
+
+ アプリケーションが {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} をフィルタ文字列 image/*
(何らかの形式の「画像」)で呼び出す場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} メソッドは次のような配列を返します。
+
+
+
+{ "image/jpeg", "image/png", "image/gif"} ++
+ アプリの対象が .jpg
ファイルのみであり、アプリが {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} をフィルタ文字列 *\/jpeg
で呼び出す場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} は次の項目を返します。
+
+
+
+{"image/jpeg"} ++
+ プロバイダが、フィルタ文字列で要求した MIME タイプを提供していない場合、{@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} は null
を返します。
+
+
+
コントラクト クラスを実装する
+
+ コントラクト クラスは public final
クラスであり、URI、列名、MIME タイプ、プロバイダに関連するその他のメタデータを含みます。
+このクラスは、URI や列名などの実際の値が変更された場合にも、プロバイダに正しくアクセスできることを保証することで、プロバイダとその他のアプリケーションとの間にコントラクトを構築します。
+
+
+
+
+ さらに、通常、コントラクト クラスではその定数にニーモニック名が設定されているため、デベロッパーが列名や URI に誤った値を使用しにくいようになっています。 +クラスであるため、Javadoc ドキュメントを含めることができます。 +Eclipse などの統合型開発環境では、コントラクト クラスから定数名が自動的に設定され、定数の Javadoc が表示されます。 + + +
+
+ デベロッパーはアプリケーションからコントラクト クラスのクラスファイルにアクセスできませんが、提供する .jar
ファイルからクラスファイルをアプリケーションに静的にコンパイルできます。
+
+
+ {@link android.provider.ContactsContract} クラスとそのネストされたクラスは、コントラクト クラスの例です。 + +
+コンテンツ プロバイダ パーミッションを実装する
++ Android システムのあらゆる領域に対するパーミッションとクラスについては、「セキュリティとパーミッション」トピックをご覧ください。 + + また、トピック「Data Storage」にも、ストレージのさまざまなタイプに有効なセキュリティとパーミッションについて記載されています。 + + 重要な点をまとめると次のようになります。 +
+-
+
- + デフォルトでは、端末の内部ストレージに格納されるデータファイルは、アプリケーションとプロバイダでのみ使用できます。 + + +
- + 作成する {@link android.database.sqlite.SQLiteDatabase} データベースは、自分のアプリケーションとプロバイダにのみ公開されます。 + + +
- + デフォルトでは、外部ストレージに保存するデータファイルはパブリックとなり、誰もが読み取ることができます。 +他のアプリケーションは別の API 呼び出しを使用してファイルの読み取りと書き込みを実行できるため、コンテンツ プロバイダで外部ストレージにあるファイルへのアクセスは制限できません。 + + +
- + 端末の内部ストレージにあるファイルや SQLite データベースを開いたり作成したりするメソッド呼び出しは、他のすべてのアプリケーションに読み取りと書き込みの両方のアクセスを付与してしまう可能性があります。 +内部ファイルやデータベースをプロバイダのリポジトリとして使用する場合に、「誰でも読み取り可能」や「誰でも書き込み可能」なアクセスを付与してしまうと、マニフェストで設定したプロバイダのパーミッションでデータを保護できなくなってしまいます。 + + +内部ストレージのファイルとデータベースへのデフォルトのアクセスは「プライベート」になっているため、プロバイダのリポジトリの場合はこの設定を変更しないでください。 + + +
+ コンテンツ プロバイダ パーミッションを使用してデータへのアクセスを制御する場合は、内部ファイル、SQLite データベース、「クラウド」(リモート サーバーなど)にデータを格納し、ファイルやデータベースを自分のアプリケーションにのみ公開するように設定します。 + + +
+パーミッションを実装する
+
+ デフォルトではプロバイダにはパーミッションが設定されていないため、基礎となるデータがプライベートに設定されている場合でも、すべてのアプリケーションは自分のプロバイダからの読み取りとプロバイダへの書き込みを実行できます。
+これを変更するには、
+ <provider>
要素の属性や子要素を使用して、マニフェスト ファイルでプロバイダのパーミッションを設定します。
+
+プロバイダ全体に適用するパーミッションを設定することもできますし、特定のテーブル、特定のレコード、これら 3 つすべてに適用するパーミッションを設定することもできます。
+
+
+ マニフェスト ファイルで 1 つ以上の
+ <permission>
要素を使用して、プロバイダのパーミッションを定義します。
+自分のプロバイダに独自のパーミッションを作成するには、
+ android:name
属性に Java スタイルのスコーピングを使用します
+
+たとえば、読み取りパーミッションの名前を com.example.app.provider.permission.READ_PROVIDER
とします。
+
+
+
+ 次のリストは、プロバイダ パーミッションの範囲を示しています。プロバイダ全体に適用するパーミッションから始まり、より詳細な範囲のものになっています。 + + より広い範囲を持つパーミッションよりも、範囲が限定されるパーミッションの方が優先されます。 +
+-
+
- + プロバイダ レベルで 1 つの読み取りと書き込みのパーミッション + +
-
+ 1 つのパーミッションでプロバイダ全体の読み取りと書き込みのアクセスの両方を制御します。
+ <provider>
要素の+ android:permission
属性で指定します。 + + +
+ - + プロバイダ レベルで別々の読み取りと書き込みパーミッション + +
-
+ プロバイダ全体の読み取りパーミッションと書き込みパーミッションです。これらのパーミッションは
+ <provider>
要素の+ android:readPermission
属性と+ android:writePermission
属性で指定します。 + + +これらは、+ android:permission
で要求するパーミッションよりも優先されます。 + +
+ - + パスレベルのパーミッション + +
-
+ プロバイダのコンテンツ URI の読み取り、書き込み、読み取り / 書き込みパーミッションです。
+ <provider>
要素の+ <path-permission>
子要素を使用して、制御対象の各 URI を指定します。 + + +指定する各コンテンツ URI に対して、読み取り / 書き込みパーミッション、読み取りパーミッション、書き込みパーミッション、3 つすべてを指定できます。 +読み取りパーミッションと書き込みパーミッションは、読み取り / 書き込みパーミッションに優先します。 +また、パスレベルのパーミッションはプロバイダ レベルのパーミッションに優先します。 + +
+ - + 一時的なパーミッション + +
-
+ アプリケーションへの一時的なアクセスを付与するパーミッション レベルです。アプリケーションに通常必要とするパーミッションが付与されていない場合でも付与できます。
+一時的なアクセス機能により、アプリケーションのマニフェストに必要なパーミッションの数を減らせます。
+
+一時的なパーミッションを有効にすると、プロバイダへの「永続的な」パーミッションを必要とするアプリケーションのみが、継続的にすべてのデータにアクセスできます。
+
+
+
+ プロバイダからの写真の添付ファイルを外部の画像ビューワ アプリケーションで表示する場合に、メール プロバイダとアプリに実装するパーミッションを考えてみます。 + +パーミッションを要求しなくても、画像ビューワに必要なアクセスを付与するには、写真のコンテンツ URI に一時的なパーミッションを設定します。 +ユーザーが写真を表示しようとしたときに、アプリから写真のコンテンツ URI とパーミッション フラグを含むインテントを画像ビューワに送信するようにメール アプリを設計します。 + +ビューワにプロバイダの通常の読み取りパーミッションが付与されていない場合でも、画像ビューワはメール プロバイダにクエリを実行して写真を取得します。 + + +
++ 一時的なパーミッションを有効にするには、
++ <provider>
要素の+ android:grantUriPermissions
属性を設定するか、1 つ以上の+ <grant-uri-permission>
子要素を+ <provider>
要素に追加します。 + + + +一時的なパーミッションを使用する場合、プロバイダからのコンテンツ URI のサポートを削除したときは常に {@link android.content.Context#revokeUriPermission(Uri, int) + Context.revokeUriPermission()} を呼び出す必要があります。そうすると、コンテンツ URI が一時的なパーミッションに関連付けられます。 + + ++ 属性の値によって、プロバイダへのアクセスレベルが決まります。 + 属性を
+true
に設定すると、システムによってプロバイダ全体への一時的なパーミッションが付与されます。このパーミッションは、プロバイダ レベルやパスレベルのパーミッションで必要になるその他のパーミッションよりも優先されます。 + + ++ このフラグを
+false
に設定する場合は、+ <grant-uri-permission>
子要素を+ <provider>
要素に追加する必要があります。 + +それぞれの子要素は、一時的なアクセスが付与される 1 つ以上のコンテンツ URI を指定します。 + ++ 一時的なアクセスをアプリケーションに委任するには、インテントに {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} フラグか {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} フラグ、またはその両方を含める必要があります。 + +これらは、{@link android.content.Intent#setFlags(int) setFlags()} メソッドで設定します。 + +
++
++ android:grantUriPermissions
属性がない場合は、false
であると仮定されます。 + +
+
<provider> 要素
+
+ {@link android.app.Activity} コンポーネントや {@link android.app.Service} コンポーネントと同様に、
+ <provider>
要素を使用して {@link android.content.ContentProvider} のサブクラスをアプリケーションのマニフェスト ファイルに定義する必要があります。
+
+
+Android システムは要素から次の情報を取得します。
+
+
-
+
- + 認証局({@code + android:authorities}) + + +
- + システム内のプロバイダ全体を特定する識別名です。この属性の詳細は、コンテンツ URI を設計するセクションをご覧ください。 + + + +
-
+ プロバイダ クラス名(
+android:name +
) + +
+ - + {@link android.content.ContentProvider} を実装するクラスです。このクラスの詳細は、ContentProvider クラスを実装するセクションをご覧ください。 + + + +
- + パーミッション + +
-
+ 他のアプリケーションがプロバイダのデータにアクセスするのに必要なパーミッションを指定する属性です。
+
+
-
+
-
+
+ android:grantUriPermssions
: 一時的なパーミッションのフラグです。 +
+ -
+
+ android:permission
: 1 つのプロバイダ全体の読み取り / 書き込みパーミッションです。 +
+ -
+
+ android:readPermission
: プロバイダ全体の読み取りパーミッションです。 +
+ -
+
+ android:writePermission
: プロバイダ全体の書き込みパーミッションです。 +
+
+ パーミッションとそれに対応する属性の詳細は、コンテンツ プロバイダ パーミッションを実装するセクションをご覧ください。 + + +
+
+ -
+
- + 起動と制御の属性 + +
-
+ これらの属性は、Android システムの起動方法とそのタイミング、プロバイダのプロセスの特性、その他の実行時の設定を決定します。
+
+
-
+
-
+
+ android:enabled
: システムにプロバイダの起動を許可するフラグです。 +
+ -
+
+ android:exported
: 他のアプリケーションにこのプロバイダの使用を許可するフラグです。 +
+ -
+
+ android:initOrder
: 同じプロセス内の他のプロバイダに対して、このプロバイダを起動する順番です。 + +
+ -
+
+ android:multiProcess
: システムに呼び出しクライアントと同じプロセスでのプロバイダの開始を許可するフラグです。 + +
+ -
+
+ android:process
: プロバイダを実行するプロセスの名前です。 + +
+ -
+
+ android:syncable
: プロバイダのデータをサーバー上のデータと同期することを示すフラグです。 + +
+
+ 属性に関する詳細は、開発ガイドの
++ <provider>
要素に関するトピックに記載されています。 + + +
+ -
+
- + 情報に関する属性 + +
-
+ プロバイダのオプションのアイコンとラベルです。
+
-
+
-
+
+ android:icon
: プロバイダのアイコンを含むドローアブル リソースです。 + [設定] > [アプリ] > [すべて] にあるアプリのリストのプロバイダラベルの横に表示されるアイコンです。 + +
+ -
+
+ android:label
: プロバイダ、データ、その両方を説明する、情報ラベルです。 +[設定] > [アプリ] > [すべて] にあるアプリのリストのプロバイダラベルの横に表示されるアイコンです。 + +
+
+ 属性に関する詳細は、開発ガイドの
++ <provider>
要素に関するトピックに記載されています。 + +
+ -
+
インテントとデータアクセス
++ {@link android.content.Intent} を使用すると、アプリケーションはコンテンツ プロバイダに間接的にアクセスできます。 + アプリケーションは、{@link android.content.ContentResolver} や {@link android.content.ContentProvider} のメソッドを呼び出しません。 +その代わりに、アクティビティを起動するインテントを送信します。これは通常、プロバイダ独自のアプリケーションの一部となっています。 +対象のアクティビティは UI のデータの取得と表示を担当します。インテントのアクションに応じて、対象のアクティビティにより、ユーザーにプロバイダのデータの修正を求めるメッセージが表示されることがあります。 + + + さらに、インテントには、対象のアクティビティが UI に表示する「エクストラ」データが含まれることがあります。ユーザーは使用前に、このデータを変更してプロバイダのデータを修正することもできます。 + + +
++ +
++ インテント アクセスを使用して、データの整合性を保証できます。プロバイダのデータの挿入、更新、削除は、厳格に定義されたビジネス ロジックによって規定されることがあります。 +この場合、他のアプリケーションにデータを直接修正できるように許可すると、無効なデータが発生することがあります。 + +デベロッパーがインテント アクセスを使用する場合は、すべての操作を完全に文書化します。 + コードを使用してデータを修正するよりも、独自のアプリケーションの UI を使用したインテント アクセスの方が優れている理由を説明します。 + +
++ プロバイダのデータを修正するための受信インテントの処理は、その他のインテントの処理と同じです。 +インテントの使用についての詳細は、「インテントとインテント フィルタ」をご覧ください。 + +
diff --git a/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd b/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd new file mode 100644 index 0000000000000000000000000000000000000000..918426ad1480571da839b34520ad203ca320a0c6 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/providers/content-providers.jd @@ -0,0 +1,108 @@ +page.title=コンテンツ プロバイダ +@jd:body +トピック
+-
+
- + コンテンツ プロバイダの基本 + + +
- + コンテンツ プロバイダの作成 + + +
- + カレンダー プロバイダ + +
- + 連絡先プロバイダ + +
関連サンプル
+-
+
- + Contact Manager アプリケーション + + +
- + + "Cursor (People)" + + +
- + + "Cursor (Phones)" + +
- + サンプル同期アダプタ + + +
+ コンテンツ プロバイダは、一連の構造化されたデータへのアクセスを管理します。データをカプセル化し、データ セキュリティの定義のためのメカニズムを提供します。 +コンテンツ プロバイダは、1 つのプロセス内のデータを別のプロセスで実行されているコードにつなげるための標準的なインターフェースです。 + +
++ コンテンツ プロバイダのデータにアクセスする場合は、アプリケーションの {@link android.content.Context} の {@link android.content.ContentResolver} オブジェクトを使用し、クライアントとしてプロバイダとやり取りします。 + + + {@link android.content.ContentResolver} オブジェクトは、{@link android.content.ContentProvider} を実装するクラスのインスタンスである、プロバイダ オブジェクトとやり取りします。 +プロバイダ オブジェクトはクライアントからのデータ要求を受け取り、要求されたアクションを実行し、結果を返します。 + + +
++ データを他のアプリケーションと共有しない場合は、独自のプロバイダを開発する必要はありません。 +ただし、独自のアプリケーションでカスタムの検索候補を提供する場合は、独自のプロバイダが必要になります。 +また、自分のアプリケーションから別のアプリケーションに複雑なデータやファイルをコピーして貼り付ける場合も、独自のプロバイダが必要になります。 + +
+
+ Android 自身には、オーディオ、ビデオ、画像、個人的な連絡先情報などのデータを管理するコンテンツ プロバイダが用意されています。
+一部のプロバイダについては、android.provider
+
パッケージのリファレンスに一覧が記載されています。
+
+いくつかの制限もありますが、これらのプロバイダにはすべての Android アプリケーションからアクセスできます。
+
+
+ コンテンツ プロバイダの詳細は、次のトピックをご覧ください。 +
+-
+
- + コンテンツ プロバイダの基本 + + +
- + データが表形式にまとめられている場合の、コンテンツ プロバイダでのデータへのアクセス方法。 + +
- + コンテンツ プロバイダの作成 + + +
- + 独自のコンテンツ プロバイダの作成方法。 + +
- + カレンダー プロバイダ + + +
- + Android プラットフォームの一部であるカレンダー プロバイダへのアクセス方法。 + +
- + 連絡先プロバイダ + + +
- + Android プラットフォームの一部である連絡先プロバイダへのアクセス方法。 + +
本書の内容 + + 詳細を表示 + 詳細を非表示
+-
+
- + 概要 + +
- + コントロール フロー + +
-
+ クライアント アプリを作成する
+
-
+
- ドキュメントを検索する +
- プロセスの結果 +
- ドキュメント メタデータを確認する +
- ドキュメントを開く +
- 新しいドキュメントを作成する +
- ドキュメントを削除する +
- ドキュメントを編集する +
- パーミッションを固定する +
+ - カスタム ドキュメント プロバイダを作成する
+
-
+
- マニフェスト +
- コントラクト +
- サブクラス DocumentsProvider +
- セキュリティ +
+
+
キークラス
+-
+
- {@link android.provider.DocumentsProvider} +
- {@link android.provider.DocumentsContract} +
ビデオ
+ +-
+
- +DevBytes: Android 4.4 ストレージ アクセス フレームワーク: プロバイダ +
- +DevBytes: Android 4.4 ストレージ アクセス フレームワーク: クライアント +
コードサンプル
+ + + +関連ドキュメント
+-
+
- + コンテンツ プロバイダの基本 + + + +
Android 4.4 (API レベル 19)は、ストレージ アクセス フレームワーク(SAF)を採用しています。SAF を利用することで、ユーザーは設定したドキュメント ストレージ プロバイダ全体から簡単にドキュメント、画像、その他のファイルを参照して開くことができます。 + +標準の使いやすい UI により、アプリやプロバイダを通じて一貫性のある方法でファイルを参照したり、最近使用したファイルにアクセスしたりできます。 +
+ +サービスをカプセル化する {@link android.provider.DocumentsProvider} を実装することで、クラウドやローカル ストレージ サービスをエコシステムに参加させることができます。 +プロバイダのドキュメントへのアクセスが必要なクライアントも、数行のコードだけで SAF と統合できます。 + +
+ +SAF には次の項目が含まれます。
+ +-
+
- ドキュメント プロバイダ—ストレージ サービス(Google ドライブなど)が管理するファイルの表示を許可するコンテンツ プロバイダです。 +ドキュメント プロバイダは {@link android.provider.DocumentsProvider} クラスのサブクラスとして実装されます。document-provider スキーマは従来のファイル階層に基づくものですが、ドキュメント プロバイダが物理的にどのようにファイルを格納するかはその設定次第です。Android プラットフォームには、ダウンロード、画像、ビデオなどの組み込みのドキュメント プロバイダがいくつか用意されています。 + + + + + + +
- クライアント アプリ—{@link android.content.Intent#ACTION_OPEN_DOCUMENT} または {@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントを呼び出し、ドキュメント プロバイダが返したファイルを受け取るカスタムアプリです。 + + + + +
- ピッカー—クライアントアプリの検索条件を満たすすべてのドキュメント プロバイダのドキュメントにアクセスできるシステム UI です。 + +
SAF は次のような機能も提供します。
+-
+
- ユーザーは 1 つのアプリだけではなく、すべてのドキュメント プロバイダのコンテンツを参照できます。 +
- アプリからドキュメント プロバイダが所有するドキュメントへの、長期間の固定アクセスを可能にします。 +このアクセスにより、ユーザーはプロバイダ上でのファイルの追加、編集、保存、削除が可能になります。 + +
- 複数のユーザー アカウントと USB ストレージ プロバイダなどの一時的なルートをサポートします。一時的なルートはドライブを挿入した場合にのみ表示されます。 + +
概要
+ +SAF は、{@link android.provider.DocumentsProvider} クラスのサブクラスであるコンテンツ プロバイダを中心に展開します。 +ドキュメント プロバイダでは、データは下図のように従来のファイル階層で構造化されます。 +
+ + + +注:
+-
+
+
- 各ドキュメント プロバイダは、ドキュメントのツリーの検索の出発点である 1 つ以上の「ルート」を報告します。各ルートは一意の {@link android.provider.DocumentsContract.Root#COLUMN_ROOT_ID} を持ち、該当するルートの下のコンテンツを表すドキュメント(ディレクトリ)を指します。ルートはデザインによって動的に変化し、複数アカウント、一時的な USB ストレージ ドライブ、ユーザーのログインとログアウトなどのユースケースをサポートします。 + + + + + + + +
- 各ルートの下のドキュメントは 1 つだけになります。そのドキュメントは、1 ~ N 個のドキュメントを指し、さらにそれぞれのドキュメントも 1 ~ N 個のドキュメントを指すことができます。 + + +
- 各ストレージ バックエンドは、一意の {@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} を使って個々のファイルやディレクトリを参照して表示します。端末の再起動後も使用できる永続的な URI の付与に使用することから、ドキュメント ID は一意でなければならず、一度発行すると変更できません。 + + + + + + +
- ドキュメントには、開くことができるファイル(特定の MIME タイプを持つもの)か、追加のドキュメント({@link android.provider.DocumentsContract.Document#MIME_TYPE_DIR} MIME タイプを持つもの)を含むディレクトリのいずれかに設定できます。 + + + +
- 各ドキュメントはさまざまな機能を持つことができ、{@link android.provider.DocumentsContract.Document#COLUMN_FLAGS COLUMN_FLAGS} を使って記述します。たとえば、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE}、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE}、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_THUMBNAIL} といった機能です。同一の {@link android.provider.DocumentsContract.Document#COLUMN_DOCUMENT_ID} は複数のディレクトリに含めることができます。 + + + + + + +
コントロール フロー
+前述のように、ドキュメント プロバイダのデータモデルは従来のファイル階層を基本とします。 +ただし、{@link android.provider.DocumentsProvider} API でアクセスできるのであれば、任意の方法でデータを物理的に格納できます。たとえば、データにタグベースのクラウド ストレージを使用できます。 + +
+ +図 2 の例は、写真アプリが格納されたデータに SAF を使ってアクセスする様子を表しています。 +
+ + + + +注:
+-
+
+
- SAF では、プロバイダとクライアントは直接やり取りできません。 +クライアントが、ファイルを操作(ファイルの読み取り、編集、作成、削除)するためのパーミッションを要求します。 + + +
- アプリケーション(この例では写真アプリ)がインテント {@link android.content.Intent#ACTION_OPEN_DOCUMENT} または {@link android.content.Intent#ACTION_CREATE_DOCUMENT} を起動すると、やり取りが始まります。 +インテントには、基準を詳細に調整するためのフィルタが含まれる場合があります。—たとえば、「画像」の MIME タイプを持つ、開くことができるすべてのファイルを取得する、のように設定できます。 + + + +
- インテントが起動すると、システム ピッカーが登録済みの各プロバイダに移動し、一致するコンテンツのルートをユーザーに表示します。 + + +
- 基礎となるドキュメント プロバイダの種類に関係なく、ドキュメントにアクセスするための標準的なインターフェースがピッカーから提供されます。 +図 2 には、Google Drive プロバイダ、USB プロバイダ、クラウド プロバイダの例を示しています。 + +
図 3 は、Google Drive アカウントを選択したユーザーが画像を検索するピッカーを表しています。 +
+ + + + + +ユーザーが Google Drive を選択すると、図 4 のように画像が表示されます。 +この時点から、ユーザーはプロバイダとクライアント アプリがサポートするすべての操作方法を使って、画像を操作できるようになります。 + + +
+ + + +クライアント アプリを作成する
+ +Android 4.3 以前では、別のアプリからファイルを取得する場合、{@link android.content.Intent#ACTION_PICK} や {@link android.content.Intent#ACTION_GET_CONTENT} といったインテントを呼び出す必要があります。 + +その後ユーザーは、ファイルを選択するためのアプリを 1 つ選びます。選択されたアプリはユーザーが使用可能なファイルを参照して選択するためのユーザー インターフェースを提供する必要があります。 + +
+ +Android 4.4 以降であれば、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを使用するという選択肢もあります。このインテントではシステム制御のピッカー UI が表示され、ユーザーはそこから他のアプリで利用可能なすべてのファイル参照できます。 + + +ユーザーは、この 1 つの UI から、サポートされるすべてのアプリのファイルを選択できます。 +
+ +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} は、{@link android.content.Intent#ACTION_GET_CONTENT} との置き換えを意図したものではありません。どちらを使用するかは、アプリのニーズによって異なります。 + +
+ +-
+
- アプリでデータの読み取りとインポートのみを行う場合は、{@link android.content.Intent#ACTION_GET_CONTENT} を使用します。 +この方法を使用すると、アプリは、画像ファイルなどのデータのコピーをインポートします。 + + +
- アプリからドキュメント プロバイダが所有するドキュメントへの、長期間の固定アクセスを可能にするには、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} を使用します。 + +ドキュメント プロバイダに格納されている画像をユーザーが編集するための、写真編集アプリなどの例が挙げられます。 + + +
ここでは、{@link android.content.Intent#ACTION_OPEN_DOCUMENT} と {@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントに基づいたクライアント アプリの作成方法について説明します。 + +
+ + +ドキュメントを検索する
+ ++次のスニペットでは {@link android.content.Intent#ACTION_OPEN_DOCUMENT} を使って、画像ファイルがあるドキュメント プロバイダを検索します。 + +
+ +private static final int READ_REQUEST_CODE = 42; +... +/** + * Fires an intent to spin up the "file chooser" UI and select an image. + */ +public void performFileSearch() { + + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file + // browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones) + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only images, using the image MIME data type. + // If one wanted to search for ogg vorbis files, the type would be "audio/ogg". + // To search for all documents available via installed storage providers, + // it would be "*/*". + intent.setType("image/*"); + + startActivityForResult(intent, READ_REQUEST_CODE); +}+ +
注:
+-
+
- アプリが {@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを開始すると、ピッカーが起動し、条件に一致するすべてのドキュメント プロバイダが表示されます。 + + +
- カテゴリ {@link android.content.Intent#CATEGORY_OPENABLE} をインテントに追加すると、結果がフィルタリングされ、画像ファイルなどの開くことができるドキュメントのみが表示されます。 + + +
- {@code intent.setType("image/*")} 文は結果をさらにフィルタリングし、画像 MIME データタイプを持つドキュメントのみを表示します。 + +
プロセスの結果
+ +ユーザーがピッカーでドキュメントを選択すると、{@link android.app.Activity#onActivityResult onActivityResult()} が呼び出されます。選択したドキュメントを指す URI は {@code resultData} パラメータに含まれます。 + + +{@link android.content.Intent#getData getData()} を使って URI を抽出します。URI を抽出したら、その URI を使ってユーザーが希望するドキュメントを取得できます。 +次に例を示します。 +
+ +@Override +public void onActivityResult(int requestCode, int resultCode, + Intent resultData) { + + // The ACTION_OPEN_DOCUMENT intent was sent with the request code + // READ_REQUEST_CODE. If the request code seen here doesn't match, it's the + // response to some other intent, and the code below shouldn't run at all. + + if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + // The document selected by the user won't be returned in the intent. + // Instead, a URI to that document will be contained in the return intent + // provided to this method as a parameter. + // Pull that URI using resultData.getData(). + Uri uri = null; + if (resultData != null) { + uri = resultData.getData(); + Log.i(TAG, "Uri: " + uri.toString()); + showImage(uri); + } + } +} ++ +
ドキュメント メタデータを確認する
+ +ドキュメントのURI を取得したら、そのメタデータにアクセスできます。次のスニペットは、URI で指定したドキュメントのメタデータを取得して、ログに記録します。 +
+ +public void dumpImageMetaData(Uri uri) { + + // The query, since it only applies to a single document, will only return + // one row. There's no need to filter, sort, or select fields, since we want + // all fields for one document. + Cursor cursor = getActivity().getContentResolver() + .query(uri, null, null, null, null, null); + + try { + // moveToFirst() returns false if the cursor has 0 rows. Very handy for + // "if there's anything to look at, look at it" conditionals. + if (cursor != null && cursor.moveToFirst()) { + + // Note it's called "Display Name". This is + // provider-specific, and might not necessarily be the file name. + String displayName = cursor.getString( + cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + Log.i(TAG, "Display Name: " + displayName); + + int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); + // If the size is unknown, the value stored is null. But since an + // int can't be null in Java, the behavior is implementation-specific, + // which is just a fancy term for "unpredictable". So as + // a rule, check if it's null before assigning to an int. This will + // happen often: The storage API allows for remote files, whose + // size might not be locally known. + String size = null; + if (!cursor.isNull(sizeIndex)) { + // Technically the column stores an int, but cursor.getString() + // will do the conversion automatically. + size = cursor.getString(sizeIndex); + } else { + size = "Unknown"; + } + Log.i(TAG, "Size: " + size); + } + } finally { + cursor.close(); + } +} ++ +
ドキュメントを開く
+ +ドキュメントのURI を取得したら、そのドキュメントを開いてさまざまな操作を行うことができます。 +
+ +ビットマップ
+ +{@link android.graphics.Bitmap} を開く方法の例を次に示します。
+ +private Bitmap getBitmapFromUri(Uri uri) throws IOException { + ParcelFileDescriptor parcelFileDescriptor = + getContentResolver().openFileDescriptor(uri, "r"); + FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); + Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); + parcelFileDescriptor.close(); + return image; +} ++ +
この操作を UI スレッドで実行しないでください。{@link android.os.AsyncTask} を使ってバックグラウンドで実行します。 +ビットマップを開いたら、{@link android.widget.ImageView} で表示できます。 + +
+ +InputStream を取得する
+ +URI から {@link java.io.InputStream} を取得する方法の例を次に示します。このスニペットでは、ファイルの行が文字列に読み込まれます。 +
+ +private String readTextFromUri(Uri uri) throws IOException { + InputStream inputStream = getContentResolver().openInputStream(uri); + BufferedReader reader = new BufferedReader(new InputStreamReader( + inputStream)); + StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + fileInputStream.close(); + parcelFileDescriptor.close(); + return stringBuilder.toString(); +} ++ +
新しいドキュメントを作成する
+ +{@link android.content.Intent#ACTION_CREATE_DOCUMENT} インテントを使用すると、アプリでドキュメント プロバイダに新しいドキュメントを作成できます。 + +ファイルを作成するには、インテントに MIME タイプとファイル名を渡し、一意の要求コードを使ってインテントを起動します。 +後は自分で設定します。
+ + ++// Here are some examples of how you might call this method. +// The first parameter is the MIME type, and the second parameter is the name +// of the file you are creating: +// +// createFile("text/plain", "foobar.txt"); +// createFile("image/png", "mypicture.png"); + +// Unique request code. +private static final int WRITE_REQUEST_CODE = 43; +... +private void createFile(String mimeType, String fileName) { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + + // Filter to only show results that can be "opened", such as + // a file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Create a file with the requested MIME type. + intent.setType(mimeType); + intent.putExtra(Intent.EXTRA_TITLE, fileName); + startActivityForResult(intent, WRITE_REQUEST_CODE); +} ++ +
新しいドキュメントを作成したら、{@link android.app.Activity#onActivityResult onActivityResult()} で URI を取得して、ドキュメントに書き込み操作を実行できます。 + +
+ +ドキュメントを削除する
+ +ドキュメントの URI と、{@link android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE SUPPORTS_DELETE} を含むドキュメントの {@link android.provider.DocumentsContract.Document#COLUMN_FLAGS Document.COLUMN_FLAGS} を取得すると、ドキュメントを削除できます。 + + + +次に例を示します。
+ ++DocumentsContract.deleteDocument(getContentResolver(), uri); ++ +
ドキュメントを編集する
+ +SAF を使用するとテキスト ドキュメントを直接編集できます。このスニペットは {@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントを起動し、カテゴリ {@link android.content.Intent#CATEGORY_OPENABLE} を使って、開くことができるドキュメントのみを表示します。 + + + +次のように、テキスト ファイルのみを表示するようにフィルタリングします。
+ ++private static final int EDIT_REQUEST_CODE = 44; +/** + * Open a file for writing and append some text to it. + */ + private void editDocument() { + // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's + // file browser. + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + + // Filter to only show results that can be "opened", such as a + // file (as opposed to a list of contacts or timezones). + intent.addCategory(Intent.CATEGORY_OPENABLE); + + // Filter to show only text files. + intent.setType("text/plain"); + + startActivityForResult(intent, EDIT_REQUEST_CODE); +} ++ +
次に、{@link android.app.Activity#onActivityResult onActivityResult()}(「プロセスの結果」をご覧ください)からコードを呼び出して、編集を行います。次のスニペットは {@link android.content.ContentResolver} から {@link java.io.FileOutputStream} を取得します。 + + +デフォルトでは、「書き込み」モードを使用します。必要最小限のアクセスのみを要求することをお勧めします。書き込みのみが必要な場合に読み込みと書き込みを要求しないでください。 + +
+ +private void alterDocument(Uri uri) { + try { + ParcelFileDescriptor pfd = getActivity().getContentResolver(). + openFileDescriptor(uri, "w"); + FileOutputStream fileOutputStream = + new FileOutputStream(pfd.getFileDescriptor()); + fileOutputStream.write(("Overwritten by MyCloud at " + + System.currentTimeMillis() + "\n").getBytes()); + // Let the document provider know you're done by closing the stream. + fileOutputStream.close(); + pfd.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } +}+ +
パーミッションを固定する
+ +アプリで読み込みや書き込み用にファイルを開くと、システムからアプリに対して、該当するファイルの URI パーミッションが付与されます。 +このパーミッションはユーザーが端末を再起動するまで有効です。ただし、画像アプリでユーザーが最近編集した 5 つの画像にアプリから直接アクセスできるようにするにはどうすればいいでしょう。ユーザーの端末が再起動されたら、ファイルを検索するためにユーザーをシステム ピッカーに戻す必要がありますが、これは明らかにいい方法とは言えません。 + + + +
+ +このような状況を避けるために、システムがアプリに付与するパーミッションを固定します。実際は、システムが提供する固定可能な URI パーミッションをアプリで「取得」します。 + +これにより、端末を再起動した場合でも、ユーザーはアプリからファイルに継続的にアクセスできます。 +
+ + +final int takeFlags = intent.getFlags() + & (Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); +// Check for the freshest data. +getContentResolver().takePersistableUriPermission(uri, takeFlags);+ +
最後にもう 1 つ手順があります。アプリが最近アクセスした URI は、保存されていても既に無効になっている場合があります。—別のアプリによってドキュメントが削除されたり、修正されたりすることが考えられます。 + +そこで、最新のデータを確認するには、常に {@code getContentResolver().takePersistableUriPermission()} を呼び出す必要があります。 + +
+ +カスタム ドキュメント プロバイダを作成する
+ ++ファイル用のストレージ サービスを提供するアプリ(クラウド保存サービスなど)を開発する場合、カスタム ドキュメント プロバイダを作成すれば、SAF を介してファイルを利用可能にできます。 + +ここではその方法について説明します。 +
+ + +マニフェスト
+ +カスタム ドキュメント プロバイダを実装するには、アプリケーションのマニフェストに次のものを追加します。 +
+-
+
+
- API レベル 19 以降のターゲット。 + +
- カスタム ストレージ プロバイダを宣言する
<provider>
要素。 +
+
+ - クラス名となる、プロバイダの名前。パッケージ名を含みます。例:
com.example.android.storageprovider.MyCloudProvider
。 +
+
+ - 認証局の名前。これはパッケージ名(この例では
com.example.android.storageprovider
)とコンテンツ プロバイダのタイプを合わせたもの(documents
)。 + +たとえば、{@code com.example.android.storageprovider.documents} のようになります。
+
+ "true"
に設定された属性android:exported
。他のアプリで認識できるようにプロバイダをエクスポートする必要があります。 +
+
+"true"
に設定された属性android:grantUriPermissions
。 +この設定により、プロバイダのコンテンツにアクセスできるように、システムが他のアプリにアクセス権を付与します。 +特定のドキュメントへのアクセス権を固定する方法については、「パーミッションを固定する」をご覧ください。 +
+
+- {@code MANAGE_DOCUMENTS} パーミッション。デフォルトでは、プロバイダはすべてのユーザーが利用可能です。 +このパーミッションを追加することで、プロバイダをシステムに制限できます。セキュリティ上この制限は重要です。 + + +
- リソース ファイルで定義したブール値に設定された {@code android:enabled} 属性。
+この属性は、Android 4.3 以前を実行する端末でプロバイダを無効にすることを目的としています。たとえば、{@code android:enabled="@bool/atLeastKitKat"} のようになります。
+マニフェストのこの属性に加え、次の操作を実行する必要があります。
+
+
-
+
- {@code res/values/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。
+
<bool name="atLeastKitKat">false</bool>
+
+ - {@code res/values-v19/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。
+
<bool name="atLeastKitKat">true</bool>
+
+
+ - {@code res/values/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。
+
- {@code android.content.action.DOCUMENTS_PROVIDER} アクションを含むインテント フィルタ。システムがプロバイダを検索したときに、プロバイダがピッカーに表示されます。 + + + +
プロバイダを含むサンプル マニフェストの抜粋を次に示します。
+ +<manifest... > + ... + <uses-sdk + android:minSdkVersion="19" + android:targetSdkVersion="19" /> + .... + <provider + android:name="com.example.android.storageprovider.MyCloudProvider" + android:authorities="com.example.android.storageprovider.documents" + android:grantUriPermissions="true" + android:exported="true" + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="@bool/atLeastKitKat"> + <intent-filter> + <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> + </intent-filter> + </provider> + </application> + +</manifest>+ +
Android 4.3 以前を実行する端末をサポートする
+ +{@link android.content.Intent#ACTION_OPEN_DOCUMENT} インテントは、Android 4.4 以降を実行する端末でのみ利用可能です。Android 4.3 以前を実行する端末に対応するためにアプリケーションで {@link android.content.Intent#ACTION_GET_CONTENT} をサポートするには、Android 4.4 以降を実行する端末のマニフェストで {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にする必要があります。 + + + + + +ドキュメント プロバイダと {@link android.content.Intent#ACTION_GET_CONTENT} は互いに排他的な関係にあると考える必要があります。 + +両方を同時にサポートする場合、アプリはシステム ピッカー UI に 2 度表示され、格納されたデータへの 2 つの異なる方法を提供します。 + +これではユーザーも操作に迷ってしまいます。
+ +ここでは、Android バージョン 4.4 以降を実行する端末で {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にする際に推奨される方法を紹介します。 + +
+ +-
+
- {@code res/values/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。
+
<bool name="atMostJellyBeanMR2">true</bool>
+
+ - {@code res/values-v19/} にある {@code bool.xml} リソース ファイルに、次の行を追加します。
+
<bool name="atMostJellyBeanMR2">false</bool>
+
+ - 4.4 (API レベル 19)以降のバージョンに対して {@link android.content.Intent#ACTION_GET_CONTENT} インテント フィルタを無効にするには、アクティビティ エイリアスを追加します。
+
+
+次に例を示します。
+
+
+<!-- This activity alias is added so that GET_CONTENT intent-filter + can be disabled for builds on API level 19 and higher. --> +<activity-alias android:name="com.android.example.app.MyPicker" + android:targetActivity="com.android.example.app.MyActivity" + ... + android:enabled="@bool/atMostJellyBeanMR2"> + <intent-filter> + <action android:name="android.intent.action.GET_CONTENT" /> + <category android:name="android.intent.category.OPENABLE" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="image/*" /> + <data android:mimeType="video/*" /> + </intent-filter> +</activity-alias> +
+
+
コントラクト
+ +通常、カスタム コンテンツ プロバイダを作成するときには、コンテンツ プロバイダのデベロッパー ガイドに記載があるように、コントラクト クラスを実装するタスクが必要になります。 + + +コントラクト クラスは {@code public final} クラスであり、URI、列名、MIME タイプ、プロバイダに関連するその他のメタデータを含みます。 + +コントラクト クラスは SAF によって提供されるため、独自に作成する必要はありません。 + +
+ +-
+
- {@link android.provider.DocumentsContract.Document} +
- {@link android.provider.DocumentsContract.Root} +
たとえば、ドキュメント プロバイダでドキュメントやルートを照会したときには、カーソルに次のような列が返されることがあります。 +
+ +private static final String[] DEFAULT_ROOT_PROJECTION = + new String[]{Root.COLUMN_ROOT_ID, Root.COLUMN_MIME_TYPES, + Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE, + Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID, + Root.COLUMN_AVAILABLE_BYTES,}; +private static final String[] DEFAULT_DOCUMENT_PROJECTION = new + String[]{Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, + Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_FLAGS, Document.COLUMN_SIZE,}; ++ +
サブクラス DocumentsProvider
+ +カスタム ドキュメント プロバイダの作成の次の手順では、抽象クラス {@link android.provider.DocumentsProvider} をサブクラス化します。 +少なくとも、次のメソッドを実装する必要があります。 +
+ +-
+
- {@link android.provider.DocumentsProvider#queryRoots queryRoots()} + +
- {@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} + +
- {@link android.provider.DocumentsProvider#queryDocument queryDocument()} + +
- {@link android.provider.DocumentsProvider#openDocument openDocument()} +
これらは実装する必要があるメソッドですが、これ以外にも多くのメソッドを実装できます。 +詳細については、{@link android.provider.DocumentsProvider} をご覧ください。 +
+ +queryRoots を実装する
+ +{@link android.provider.DocumentsProvider#queryRoots +queryRoots()} を実装すると、{@link android.provider.DocumentsContract.Root} で定義される列を使って、ドキュメント プロバイダのすべてのルート ディレクトリを指す {@link android.database.Cursor} が返されます。 + +
+ +次のスニペットの {@code projection} パラメータは、呼び出し側が取得する特定のフィールドを表します。 +スニペットは新しいカーソルを作成し、それに行を 1 つ追加します。—[ダウンロード] や [画像] と同じように、1 つのルートに対して最上位のディレクトリが 1 つになります。 + +ほとんどのプロバイダでルートは 1 つになります。複数のユーザー アカウントを使用するような場合は、1 つ以上のルートを設定できます。 +その場合、カーソルに 2 つ目の行を追加します。 +
+ ++@Override +public Cursor queryRoots(String[] projection) throws FileNotFoundException { + + // Create a cursor with either the requested fields, or the default + // projection if "projection" is null. + final MatrixCursor result = + new MatrixCursor(resolveRootProjection(projection)); + + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; + } + + // It's possible to have multiple roots (e.g. for multiple accounts in the + // same app) -- just add multiple cursor rows. + // Construct one row for a root called "MyCloud". + final MatrixCursor.RowBuilder row = result.newRow(); + row.add(Root.COLUMN_ROOT_ID, ROOT); + row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary)); + + // FLAG_SUPPORTS_CREATE means at least one directory under the root supports + // creating documents. FLAG_SUPPORTS_RECENTS means your application's most + // recently used documents will show up in the "Recents" category. + // FLAG_SUPPORTS_SEARCH allows users to search all documents the application + // shares. + row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | + Root.FLAG_SUPPORTS_RECENTS | + Root.FLAG_SUPPORTS_SEARCH); + + // COLUMN_TITLE is the root title (e.g. Gallery, Drive). + row.add(Root.COLUMN_TITLE, getContext().getString(R.string.title)); + + // This document id cannot change once it's shared. + row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir)); + + // The child MIME types are used to filter the roots and only present to the + // user roots that contain the desired type somewhere in their file hierarchy. + row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir)); + row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace()); + row.add(Root.COLUMN_ICON, R.drawable.ic_launcher); + + return result; +}+ +
queryChildDocuments を実装する
+ +{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} を実装すると、{@link android.provider.DocumentsContract.Document} で定義される列を使って、指定したディレクトリ内のすべてのファイルを指す {@link android.database.Cursor} が返されます。 + + + +
+ +ピッカー UI でアプリケーション ルートを選択すると、このメソッドが呼び出されます。ルートの下のディレクトリの子ドキュメントを取得します。 +ルートだけでなく、ファイル階層内の任意のレベルで呼び出せます。 +このスニペットでは、要求した列を持つ新しいカーソルが作成され、親ディレクトリのすぐ下のそれぞれの子の情報がカーソルに追加されます。子は、画像、別のディレクトリなど—任意のファイルとなります。 + + +
+ +@Override +public Cursor queryChildDocuments(String parentDocumentId, String[] projection, + String sortOrder) throws FileNotFoundException { + + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + final File parent = getFileForDocId(parentDocumentId); + for (File file : parent.listFiles()) { + // Adds the file's display name, MIME type, size, and so on. + includeFile(result, null, file); + } + return result; +} ++ +
queryDocument を実装する
+ +{@link android.provider.DocumentsProvider#queryDocument queryDocument()} を実装すると、{@link android.provider.DocumentsContract.Document} で定義される列を使って、指定したファイルを指す {@link android.database.Cursor} が返されます。 + + + +
+ +{@link android.provider.DocumentsProvider#queryDocument queryDocument()} メソッドでは、特定のファイルの情報ではなく、{@link android.provider.DocumentsProvider#queryChildDocuments queryChildDocuments()} に渡したのと同じ情報が返されます。 + + +
+ + +@Override +public Cursor queryDocument(String documentId, String[] projection) throws + FileNotFoundException { + + // Create a cursor with the requested projection, or the default projection. + final MatrixCursor result = new + MatrixCursor(resolveDocumentProjection(projection)); + includeFile(result, documentId, null); + return result; +} ++ +
openDocument を実装する
+ +指定したファイルを表す {@link android.os.ParcelFileDescriptor} を返すには、{@link android.provider.DocumentsProvider#openDocument +openDocument()} を実装する必要があります。 +他のアプリは、返された {@link android.os.ParcelFileDescriptor} を使ってデータをストリーミングします。 +ユーザーがファイルを選択するとシステムがこのメソッドを呼び出し、クライアント アプリは {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()} を呼び出してファイルへのアクセスを要求します。次に例を示します。 + + +
+ +@Override +public ParcelFileDescriptor openDocument(final String documentId, + final String mode, + CancellationSignal signal) throws + FileNotFoundException { + Log.v(TAG, "openDocument, mode: " + mode); + // It's OK to do network operations in this method to download the document, + // as long as you periodically check the CancellationSignal. If you have an + // extremely large file to transfer from the network, a better solution may + // be pipes or sockets (see ParcelFileDescriptor for helper methods). + + final File file = getFileForDocId(documentId); + + final boolean isWrite = (mode.indexOf('w') != -1); + if(isWrite) { + // Attach a close listener if the document is opened in write mode. + try { + Handler handler = new Handler(getContext().getMainLooper()); + return ParcelFileDescriptor.open(file, accessMode, handler, + new ParcelFileDescriptor.OnCloseListener() { + @Override + public void onClose(IOException e) { + + // Update the file with the cloud server. The client is done + // writing. + Log.i(TAG, "A file with id " + + documentId + " has been closed! + Time to " + + "update the server."); + } + + }); + } catch (IOException e) { + throw new FileNotFoundException("Failed to open document with id " + + documentId + " and mode " + mode); + } + } else { + return ParcelFileDescriptor.open(file, accessMode); + } +} ++ +
セキュリティ
+ +たとえば、ドキュメント プロバイダがパスワードで保護されたクラウド ストレージ サービスであり、ファイル共有を開始する前にユーザーがログインしているかどうかを確認するとします。ユーザーがログインしていない場合、アプリはどのような動作を行う必要があるでしょうか。 + +このような場合、{@link android.provider.DocumentsProvider#queryRoots +queryRoots()} の実装のゼロルートを返すようにします。 +つまり、空のルートカーソルになります。
+ ++public Cursor queryRoots(String[] projection) throws FileNotFoundException { +... + // If user is not logged in, return an empty root cursor. This removes our + // provider from the list entirely. + if (!isUserLoggedIn()) { + return result; +} ++ +
その他に {@code getContentResolver().notifyChange()} を呼び出す手順もあります。{@link android.provider.DocumentsContract} については既に説明してあります。 +これを使ってこの URI を作成します。次のスニペットは、ユーザーのログイン ステータスが変わった場合に、ドキュメント プロバイダのルートを照会するようシステムに指示します。 + +ユーザーがログインしてない場合は、上述のように、{@link android.provider.DocumentsProvider#queryRoots queryRoots()} を呼び出すと空のカーソルが返されます。 + +こうすることで、ユーザーがプロバイダにログインしている場合にのみ、プロバイダのドキュメントを利用できます。 +
+ +private void onLoginButtonClick() { + loginOrLogout(); + getContentResolver().notifyChange(DocumentsContract + .buildRootsUri(AUTHORITY), null); +} +\ No newline at end of file diff --git a/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd b/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd new file mode 100644 index 0000000000000000000000000000000000000000..af8d005dac428d96aa1f427d4d3f6007f167b91f --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/accessing-resources.jd @@ -0,0 +1,337 @@ +page.title=リソースへのアクセス +parent.title=アプリケーション リソース +parent.link=index.html +@jd:body + +
クイックビュー
+-
+
- リソースは、{@code R.java} の整数を使うコード({@code R.drawable.myimage} など)を使用して参照できます。 + +
- リソースは、特殊な XML 構文({@code +@drawable/myimage} など)を使用して参照できます。 +
- さらに、{@link android.content.res.Resources} のメソッドを使用すると、アプリ リソースにアクセスできます。 + +
キークラス
+-
+
- {@link android.content.res.Resources} +
本書の内容
+-
+
- コードからリソースにアクセスする +
- XML からリソースにアクセスする
+
-
+
- スタイル属性を参照する +
+ - プラットフォーム リソースにアクセスする +
関連ドキュメント
+-
+
- リソースの提供 +
- Resource Types +
アプリケーションでリソースを提供すると(詳細は「リソースの提供」)、リソース ID を参照することで適用できるようになります。リソース ID はすべてプロジェクトの {@code R} クラスで定義します。これは {@code aapt} ツールが自動的に生成します。 + +
+ +アプリケーションをコンパイルすると、{@code aapt} が {@code R} クラスを生成します。このクラスには、{@code +res/} ディレクトリに含まれるの全リソースのリソース ID が入ります。 +リソースのそれぞれのタイプに対して、{@code R} サブクラス(例: ドローアブル リソースの場合はすべて {@code R.drawable})があり、そのタイプのそれぞれのリソースには、静的整数(例: {@code R.drawable.icon})があります。 + +この整数がリソース ID であり、リソースを取得するのに使用できます。 +
+ +{@code R} クラスではリソース ID を指定されていますが、リソース ID を探す必要はありません。リソース ID は常に次のように構成されます。 +
+-
+
- リソースタイプ: それぞれのリソースは、{@code +string}、{@code drawable}、{@code layout} のようなタイプにグループ化されます。さまざまなタイプに関する詳細は、「Resource Types」をご覧ください。 + +
- リソース名。これは、拡張子を除外したファイル名か、XML {@code android:name} 属性(リソースが文字列などの単純な値の場合)のいずれかになります。 + + +
リソースにアクセスするには次の 2 つの方法があります。
+-
+
- コード内: {@code R} クラスのサブクラスから次のような静的整数を使用します。
+
+
R.string.hello
+{@code string} はリソースタイプ、{@code hello} はリソース名です。多くの Android API が、リソース ID をこの形式で指定してリソースにアクセスします。 +コードでリソースにアクセスするをご覧ください。 +
+
+ - XML 内: {@code R} クラスで定義するリソース ID に対応する、次のような特殊な XML 構文を使用します。
+
+
@string/hello
+{@code string} はリソースタイプ、{@code hello} はリソース名です。この構文は、リソースで提供する値が想定される、XML リソース内の任意の場所に使用できます。 +XML からリソースにアクセスするをご覧ください。
+
+
コードでリソースにアクセスする
+ +リソース ID をメソッド パラメータとして渡すことで、コード内でリソースを使用できます。たとえば、{@link android.widget.ImageView#setImageResource(int) setImageResource()} を使って、{@link android.widget.ImageView} が {@code res/drawable/myimage.png} を使用するように設定できます。 + +
++ImageView imageView = (ImageView) findViewById(R.id.myimageview); +imageView.setImageResource(R.drawable.myimage); ++ +
さらに、{@link +android.content.res.Resources} のメソッドを使用して、個々のリソースを取得することもできます。{@link android.content.Context#getResources()} を使用すると、インスタンスを取得できます。 +
+ +元のファイルへのアクセス
+ +一般的な操作ではありませんが、元のファイルやディレクトリへのアクセスが必要になることがあります。その場合、{@code res/} からリソースを読み込むにはリソース ID が必要なため、{@code res/} にファイルを保存しても機能しません。その代わりに、{@code assets/} ディレクトリにリソースを保存します。 + + +
+{@code assets/} ディレクトリに保存したファイルにはリソース ID が付与されないため、{@code R} クラスや XML リソースからはそれらのファイルを参照できません。 +その代わりに、通常のファイル システムのように {@code assets/} ディレクトリ内のファイルを照会し、{@link android.content.res.AssetManager} を使用して未処理のデータを読み込みます。 + +
+ただし、単に(ビデオやオーディオなどの)未処理データの読み込みのみが必要となる場合は、ファイルを {@code res/raw/} ディレクトリに保存し、{@link +android.content.res.Resources#openRawResource(int) openRawResource()} を使用してバイトのストリームを読み込みます。 +
+ +構文
+ +次の構文を使用して、コード内のリソースを参照します。
+ ++[<package_name>.]R.<resource_type>.<resource_name> ++ +
-
+
- {@code <package_name>} は、リソースが配置されるパッケージの名前です(独自のパッケージからリソースを参照する場合は必要ありません)。 + +
- {@code <resource_type>} は、リソースタイプの {@code R} サブクラスです。 +
- {@code <resource_name>} は、拡張子以外のリソース ファイル名か、XML 要素の {@code android:name} 属性値(単純な値の場合)のいずれかになります。 + + +
リソースタイプの詳細やそれらの査証方法については、「Resource Types」をご覧ください。 +
+ + +使用例
+ +多くのメソッドでリソース ID パラメータを使うことができ、{@link android.content.res.Resources} のメソッドを使用すればリソースを取得できます。 +{@link +android.content.res.Resources} のインスタンスは、{@link android.content.Context#getResources +Context.getResources()} により取得できます。
+ + +次は、コードのリソースにアクセスする例です。
+ ++// Load a background for the current screen from a drawable resource +{@link android.app.Activity#getWindow()}.{@link +android.view.Window#setBackgroundDrawableResource(int) +setBackgroundDrawableResource}(R.drawable.my_background_image) ; + +// Set the Activity title by getting a string from the Resources object, because +// this method requires a CharSequence rather than a resource ID +{@link android.app.Activity#getWindow()}.{@link android.view.Window#setTitle(CharSequence) +setTitle}(getResources().{@link android.content.res.Resources#getText(int) +getText}(R.string.main_title)); + +// Load a custom layout for the current screen +{@link android.app.Activity#setContentView(int) +setContentView}(R.layout.main_screen); + +// Set a slide in animation by getting an Animation from the Resources object +mFlipper.{@link android.widget.ViewAnimator#setInAnimation(Animation) +setInAnimation}(AnimationUtils.loadAnimation(this, + R.anim.hyperspace_in)); + +// Set the text on a TextView object using a resource ID +TextView msgTextView = (TextView) findViewById(R.id.msg); +msgTextView.{@link android.widget.TextView#setText(int) +setText}(R.string.hello_message); ++ + +
警告: {@code +R.java} ファイルを手動で修正しないでください。—プロジェクトがコンパイルされると、{@code aapt} ツールによって生成されます。 +変更した場合は、次回のコンパイルの際に上書きされます。
+ + + +XML からリソースにアクセスする
+ +一部の XML 属性や要素の値は、既存のリソースへの参照を使用して定義できます。 +通常は、ウィジェットに文字列や画像を提供するレイアウト ファイルを作成する場合に、この方法を使用します。 +
+ +たとえば、レイアウトに {@link android.widget.Button} を追加する場合は、次のように、ボタンテキストの文字列リソースを使用します。 +
+ ++<Button + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/submit" /> ++ + +
構文
+ +次の構文を使用して、XML リソース内のリソースを参照します。
+ ++@[<package_name>:]<resource_type>/<resource_name> ++ +
-
+
- {@code <package_name>} は、リソースが配置されるパッケージの名前です(同一のパッケージからリソースを参照する場合は必要ありません) + +
- {@code <resource_type>} は、リソースタイプの {@code R} サブクラスです + +
- {@code <resource_name>} は、拡張子以外のリソース ファイル名か、XML 要素の {@code android:name} 属性値(単純な値の場合)のいずれかになります。 + + +
リソースタイプの詳細やそれらの査証方法については、「Resource Types」をご覧ください。 +
+ + +使用例
+ +場合によっては、XML の値にリソースを使用する必要がありますが(ウィジェットにドローアブル画像を適用するような場合など)、単純な値を受け入れる XML の任意の場所にリソースを使用できます。 +たとえば、カラーリソースと文字列リソースを持つ、次のようなリソースがあるとします。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="opaque_red">#f00</color> + <string name="hello">Hello!</string> +</resources> ++ +
これらのリソースを次のようなレイアウト ファイルに使用して、テキストカラーとテキストの文字列を設定できます。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="@color/opaque_red" + android:text="@string/hello" /> ++ +
この場合、リソースは独自のパッケージ内のものであることから、リソースの参照でパッケージ名を指定する必要はありません。 +システム リソースを参照するには、パッケージ名を含める必要があります。 +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<EditText xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:textColor="@android:color/secondary_text_dark" + android:text="@string/hello" /> ++ +
注: アプリケーションを他の言語にローカライズできるように、常に文字列リソースを使用するようにします。 +代替リソース(ローカライズされた文字列など)の作成方法についての詳細は、代替リソースを提供するをご覧ください。 + + +アプリケーションを他の言語にローカライズするための詳細なガイドは、「Localization」をご覧ください。 +
+ +XML でリソースを使用すれば、エイリアスを作成することもできます。たとえば、別のドローアブル リソースのエイリアスとなる、次のようなドローアブル リソースを作成できます。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/other_drawable" /> ++ +
これは冗長のように思われますが、代替リソースを使用する場合に大変便利です。詳細は、エイリアス リソースを作成するをご覧ください。 +
+ + + +スタイル属性を参照する
+ +スタイル属性リソースを使用すると、現在適用されているテーマの属性の値を参照できます。 +スタイル属性を参照すれば、ハードコードした値を指定しなくても、現在のテーマで与えられる標準的なバリエーションに合わせてスタイルを設定して、UI 要素の外観をカスタマイズできます。 + +本質的に、スタイル属性を参照するというのは、「現在のテーマのこの属性で定義されるスタイルを使用する」という意味になります。 +
+ +属性スタイルを参照する場合、名前構文は通常のリソース形式とほぼ同じですが、アットマーク({@code @})の代わりに疑問符({@code ?})を使用します。リソースタイプの部分は省略可能です。 + +例:
+ ++?[<package_name>:][<resource_type>/]<resource_name> ++ +
たとえば、次の例では、属性を参照して、テキスト カラーをシステム テーマの「プライマリ」テキスト カラーに合わせて設定します。 +
+ ++<EditText id="text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textColor="?android:textColorSecondary" + android:text="@string/hello_world" /> ++ +
ここでは、{@code android:textColor} 属性が、現在のテーマのスタイル属性の名前を指定しています。
+Android は、{@code android:textColorSecondary} スタイル属性に適用された値を、このウィジェットの {@code android:textColor} の値として使用できるようになりました。
+このコンテキストで属性リソースが必要なことはシステム リソース ツールで認識されているため、タイプ(ここでは ?android:attr/textColorSecondary
)を明示的に指定する必要はありません — {@code attr} タイプを除外できます。
+
+
+
プラットフォーム リソースにアクセスする
+ +Android には、スタイル、テーマ、レイアウトといった多数の標準的なリソースが用意されています。これらのリソースにアクセスするには、android
パッケージ名でリソース参照を修飾します。
+
+たとえば、Android には、{@link android.widget.ListAdapter} のリストアイテムに使用できるレイアウト リソースが用意されています。
+
+{@link android.app.ListActivity#setListAdapter(ListAdapter) +setListAdapter}(new {@link +android.widget.ArrayAdapter}<String>(this, android.R.layout.simple_list_item_1, myarray)); ++ +
この例では、{@link android.R.layout#simple_list_item_1} は、プラットフォームによって {@link android.widget.ListView} のアイテム向けに定義されるレイアウト リソースです。 +リストアイテムに独自のレイアウトを作成する代わりに、このレイアウトを使用できます。 +詳細については、「List View」のデベロッパー ガイドをご覧ください。 +
+ diff --git a/docs/html-intl/intl/ja/guide/topics/resources/overview.jd b/docs/html-intl/intl/ja/guide/topics/resources/overview.jd new file mode 100644 index 0000000000000000000000000000000000000000..28ffa94970c0e7f0cfea1ea0d3c16eae4e263d8e --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/overview.jd @@ -0,0 +1,103 @@ +page.title=リソースの概要 +@jd:body + +画像や文字列といったリソースは、常にアプリケーション コードの外部に置くようにすることで、独立して保持できるようになります。 +さらに、リソースを外部化することで、言語や画面サイズが異なるような特定の端末構成をサポートする代替リソースを提供できるようになります。異なる構成を持つ Android ベースの端末が増えていることから、この外部化がますます重要になってきています。 + + +異なる構成に互換性を持たせるには、リソースをタイプや構成ごとにグループ化するさまざまなサブディレクトリを使用して、プロジェクトの {@code res/} ディレクトリ内にリソースを整理する必要があります。 + + +
+ +すべてのリソースタイプに対して、アプリケーションのデフォルト レイアウトと複数の代替リソースを指定できます。 +
+-
+
- デフォルト リソースは、端末構成に関係なく使われるものであり、現在の構成に一致する代替リソースがない場合に使用されます。 + + +
- 代替リソースは、特定の構成で使うために作成したリソースです。 +リソースのグループを特定の構成に使用するよう指定するには、適切な構成修飾子をディレクトリ名の後ろに追加します。 + +
たとえば、デフォルトの UI レイアウトが {@code res/layout/} ディレクトリに保存してある場合、{@code res/layout-land/} ディレクトリにレイアウトを保存しておくことで、横向きの画面を使用する際の別のレイアウトを指定できます。 + + +Android は、現在の端末の構成とリソースのディレクトリ名をマッチングさせ、適切なリソースを自動的に適用します。 +
+ +図 1 は、代替リソースがない場合に、システムが 2 つの異なる端末に同じレイアウトを適用する様子を表しています。 +図 2 は、大きい画面の代替レイアウト リソースを追加した場合の、レイアウトの適用の様子を表しています。 +
+ +次のドキュメントには、アプリケーション リソースの整理、代替リソースの指定、アプリケーションでのアクセスなどに関する情報が詳細に記載されています。 +
+ +-
+
- リソースの提供 +
- アプリで提供可能なリソースの種類、保存場所、特定の端末構成用の代替リソースの作成方法。 + +
- リソースへのアクセス +
- アプリケーション コードまたは他の XML リソースからの参照による、提供済みリソースの使用方法。 + +
- 実行時の変更の処理 +
- アクティビティの実行中に生じた構成の変更の管理方法。 +
- Localization +
- 代替リソースを使用したアプリケーションのローカライズのためのボトムアップ ガイド。代替リソースの特定の使用方法を 1 つだけ解説していますが、複数のユーザーが利用する場合には非常に重要になります。 + + +
- Resource Types +
- 提供可能な各種リソースタイプのリファレンス。XML 要素、属性、構文について説明しています。 +たとえば、このリファレンスには、アプリケーション メニュー、ドローアブル、アニメーションなどの作成方法が記載されています。 + +
クイックビュー
+-
+
- {@code res/} のそれぞれのサブディレクトリにはさまざまなタイプのリソースがある +
- 代替リソースは設定固有のリソース ファイルを提供する +
- 特定の端末設定に依存しないように、デフォルトのリソースを常に入れておく + +
本書の内容
+-
+
- リソースタイプをグループ化する +
- 代替リソースを提供する
+
-
+
- 修飾子の名前のルール +
- エイリアス リソースを作成する +
+ - リソースとの最適な端末の互換性を提供する +
- Android が最適なリソースを見つける仕組み +
関連ドキュメント
+-
+
- リソースへのアクセス +
- Resource Types +
- 複数のスクリーンをサポートする + +
画像や文字列といったアプリケーション リソースは、常にコードの外部に置くようにすることで、独立して保持できるようになります。 +さらに、特別に名前を設定したリソース ディレクトリにグループ化することで、特定の端末設定に代替リソースを提供する必要があります。 +実行時には、現在の設定に基づいて、Android は適切なリソースを使用します。 +たとえば、画面サイズに応じて異なる UI レイアウトを提供したり、言語設定に応じて異なる文字列を提供したりできます。 + +
+ +アプリケーション リソースを外部化したら、プロジェクトの {@code R} クラスで生成されるリソース ID を使用してそれらのリソースにアクセスできます。 +アプリケーションでのリソースの使用方法については、「リソースへのアクセス」をご覧ください。 + +このドキュメントでは、Android プロジェクトでリソースをグループ化する方法と、特定の端末設定に代替リソースを提供する方法を説明します。 +
+ + +リソースタイプをグループ化する
+ +それぞれのタイプのリソースを、プロジェクトの {@code res/} ディレクトリの特定のサブディレクトリに配置する必要があります。 +次は、単純なプロジェクトのファイル階層の例です。
+ ++MyProject/ + src/ + MyActivity.java + res/ + drawable/ + graphic.png + layout/ + main.xml + info.xml + mipmap/ + icon.png + values/ + strings.xml ++ +
この例を見てわかるように、{@code res/} ディレクトリには、画像リソース、2 つのレイアウト リソース、ランチャー アイコンの {@code mipmap/} ディレクトリ、文字列リソース ファイルといった、すべてのリソース(サブディレクトリ内)が入ります。 + +リソース ディレクトリ名は重要です。表 1 に説明があります。 +
+ +注: Mipmap フォルダの使用方法については、「Managing Projects Overview」をご覧ください。 +
+ + + +ディレクトリ | +リソースタイプ | +
---|---|
animator/ |
+ プロパティ アニメーションを定義する XML ファイル。 + | +
anim/ |
+ トゥイーン アニメーションを定義する XML ファイル。 +(プロパティ アニメーションをこのディレクトリに保存することもできますが、2 つのタイプを区別するために、プロパティ アニメーションは {@code animator/} ディレクトリに保存することをお勧めします)。 + + | +
color/ |
+ 色の状態リストを定義する XML ファイル。「Color State List Resource」をご覧ください。 + | +
drawable/ |
+
+ ビットマップ ファイル({@code .png}、{@code .9.png}、{@code .jpg}、{@code .gif})または次のドローアブル リソース サブタイプにコンパイルされる XML ファイル: + +
「Drawable Resources」をご覧ください。 + |
+
mipmap/ |
+ さまざまなランチャー アイコン密度のドローアブル ファイル。{@code mipmap/} フォルダによるランチャー アイコンの管理方法については、「Managing Projects Overview」をご覧ください。 + + | +
layout/ |
+ ユーザー インターフェースのレイアウトを定義する XML ファイル。 + 「Layout Resource」をご覧ください。 | +
menu/ |
+ オプション メニュー、コンテキスト メニュー、サブ メニューといった、アプリケーション メニューを定義する XML ファイル。 +「Menu Resource」をご覧ください。 | +
raw/ |
+ 未加工の形式で保存する任意のファイル。これらのリソースを未加工の {@link java.io.InputStream} で開くには、{@link android.content.res.Resources#openRawResource(int) +Resources.openRawResource()} をリソース ID({@code R.raw.ファイル名})とともに呼び出します。 + +ただし、元のファイル名とファイル階層にアクセスする必要がある場合は、一部のリソースを {@code +assets/} ディレクトリ({@code res/raw/} の代わりに)に保存することを検討します。 +{@code assets/} のファイルにはリソース ID が付与されていないため、読み込むには {@link android.content.res.AssetManager} が必要です。 + |
+
values/ |
+ 文字列、整数、色など、単純な値を含む XML ファイル。 +その他の {@code res/} サブディレクトリの XML リソース ファイルは XML ファイル名に基づいて 1 つのリソースを定義しますが、{@code values/} ディレクトリのファイルは複数のリソースを表します。このディレクトリのファイルの場合、{@code <resources>} 要素のそれぞれの子が 1 つのリソースを定義します。 + + +たとえば、{@code <string>} 要素は {@code R.string} リソースを作成し、{@code <color>} 要素は {@code R.color} リソースを作成します。 + + +各リソースの定義には XML 要素を使用するため、ファイルには任意の名前を設定でき、1 つのファイル内にさまざまなリソースを配置できます。 +ただし、わかりやすくするために、一意のリソースタイプをそれぞれのファイルに配置することもできます。 +次は、このディレクトリで作成できるリソースのファイル名の変換例です。 + +
「String Resources」、「Style Resource」、「More Resource Types」をご覧ください。 + + + |
+
xml/ |
+ {@link +android.content.res.Resources#getXml(int) Resources.getXML()} を呼び出すことによって、実行時に読み込むことができる任意の XML ファイル。ここには、検索可能な設定など、各種の XML 設定ファイルが保存されます。 + + | +
警告: リソース ファイルを {@code res/} ディレクトリに直接保存しないでください。—コンパイラー エラーの原因になります。 +
+ +リソースの特定のタイプの詳細は、「Resource Types」のドキュメントをご覧ください。
+ +表 1 で定義したサブディレクトリに保存するリソースは、「デフォルト」のリソースとなります。 +つまり、これらのリソースはアプリケーションのデフォルトのデザインとコンテンツを定義します。ただし、Android が搭載された端末では別のタイプのリソースが呼び出されることがあります。たとえば、端末の画面サイズが通常のものよりも大きな場合、追加の画面スペースを利用する別のレイアウト リソースを提供する必要があります。 + + +また、端末の言語設定が異なる場合、使用するユーザー インターフェースのテキストを翻訳する、別の文字列リソースを提供します。 + +さまざまな端末設定にこれらの異なるリソースを提供するには、デフォルトのリソースに加えて、代替リソースを提供する必要があります。 + +
+ + +代替リソースを提供する
+ + +ほぼすべてのアプリケーションが、特定の端末設定をサポートするための代替リソースを提供します。 +たとえば、画面密度が異なる場合は代替ドローアブル リソースを含め、言語が異ならう場合は代替文字列リソースを含めます。 +実行時には、Android が現在の端末設定を検出し、アプリケーションに合ったリソースを読み込みます。 + +
+ +一連のリソースに設定固有の代替リソースを指定するには:
+-
+
- {@code
+<resources_name>-<config_qualifier>} の形式で名前を付けた {@code res/} に新しいディレクトリを作成します。
+
-
+
- {@code <resources_name>} は、対応するディレクトリ リソースのディレクトリ名です(表 1 で定義)。 + +
- {@code <qualifier>} は、リソースを使用する個々の設定を指定する名前です(表 2 で定義)。 + +
1 つ以上の {@code <qualifier>} を末尾に追加できます。それぞれの修飾子はダッシュを使用して区切ります。 +
+警告: 複数の修飾子を末尾に追加する場合は、表 2 に記載されているのと同じ順番で配置する必要があります。 +修飾子の順番に誤りがあると、リソースが無視されます。 +
+
+ - それぞれの代替リソースをこの新しいディレクトリに保存します。リソース ファイルの名前は、デフォルトのリソース ファイルと同じものにする必要があります。 + +
次に、デフォルト リソースと代替リソースの例を示します。
+ ++res/ + drawable/ + icon.png + background.png + drawable-hdpi/ + icon.png + background.png ++ +
{@code hdpi} 修飾子は、ディレクトリ内のリソースが高密度画面を持つ端末用であることを表します。 +これらのドローアブル ディレクトリの画像は特定の画面密度に合わせたサイズになっていますが、ファイル名は完全に同じになります。 + +このように、{@code icon.png} や {@code +background.png} 画像を参照するのに使用するリソース ID は常に同じになりますが、Android はリソース ディレクトリ名の修飾子により端末設定情報を比較して、各リソースの現在の端末に最適なバージョンを選択します。 + +
+ +Android では複数の設定修飾子をサポートしており、それぞれの修飾子をダッシュで区切ることで、1 つのディレクトリ名に複数の修飾子を追加できます。 +表 2 には、有効な設定修飾子が優先度順に記載されています。—参照ディレクトリに複数の修飾子を使用する場合、表に記載されている順番にディレクトリ名に追加する必要があります。 + + +
+ + + +設定 | +修飾子の値 | +説明 | +
---|---|---|
MCC と MNC | +例: + mcc310 +
+ mcc208-mnc00 + など + |
+
+ モバイル カントリーコード(MCC)です。端末の SIM カードにあるモバイル ネットワーク コード(MNC)が続くことがあります。
+たとえば、 端末が無線通信接続(GSM 電話)を使用する場合、MCC と MNC の値は SIM カードの値となります。 + +さらに、MCC のみを使用することもできます(たとえば、アプリケーションに国固有の法に関するリソースを含める場合)。 +言語のみに基づいて指定する場合は、代わりに言語と地域の修飾子(次のセクションで解説)を使用します。 +MCC と MNC 修飾子を使用する場合は、慎重に設定し、予測のとおりに機能することをテストします。 + +さらに、設定フィールド {@link +android.content.res.Configuration#mcc}、{@link +android.content.res.Configuration#mnc} もご覧ください。これらは、それぞれ、現在のモバイル カントリーコードとモバイル ネットワーク コードを表します。 + + |
+
言語と地域 | +例: + en + fr + en-rUS + fr-rFR + fr-rCA + など + |
+ 言語は 2 文字の ISO 639-1 言語コードで定義し、オプションで、2 文字の ISO 3166-1-alpha-2 地域コードを後ろに追加します(先頭に小文字の「{@code r}」が付きます)。 + + + + + コードでは大文字と小文字が区別されません。地域を区別するには、{@code r} 接頭辞を使用します。 + + 地域のみは指定できません。 +ユーザーがシステム設定で言語を変更すると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、実行時の変更の処理をご覧ください。 + +アプリケーションを他の言語にローカライズするための詳細なガイドは、「Localization」をご覧ください。 + +さらに、{@link android.content.res.Configuration#locale} 設定フィールドもご覧ください。これは、現在のロケールを表します。 + + |
+
レイアウトの方向 | +ldrtl + ldltr + |
+ アプリケーションのレイアウトの方向です。{@code ldrtl} は、「レイアウト方向は右から左」という意味になります。{@code ldltr} は、「レイアウト方向は左から右」という意味になります。この設定が暗黙的にデフォルト値となります。 + + +この設定は、レイアウト、ドローアブル、値など、任意のリソースに適用できます。 + +たとえば、アラビア語に何らかの特定なレイアウトを提供し、その他の「右から左」の言語(ペルシャ語やヘブライ語)に汎用的なレイアウトを提供する場合、次のように設定します。 + + ++res/ + layout/ + main.xml (Default layout) + layout-ar/ + main.xml (Specific layout for Arabic) + layout-ldrtl/ + main.xml (Any "right-to-left" language, except + for Arabic, because the "ar" language qualifier + has a higher precedence.) ++ 注: アプリで右から左のレイアウト機能を有効にするには、{@code + supportsRtl} を {@code "true"} に設定し、{@code targetSdkVersion} を 17 以上に設定します。 + +API レベル 17 で追加。 + |
+
smallestWidth | +sw<N>dp + 例: + sw320dp + sw600dp + sw720dp + など + |
+
+ 使用可能な画面領域の最小寸法で指定する、画面の基本サイズ。 +具体的には、端末の smallestWidth は画面に使用できる高さと幅の最小サイズとなります(画面の「使用できる最小幅」と考えることもできます)。 +画面の現在の方向に関係なく、この修飾子を使用することで、アプリケーションの UI に少なくとも {@code <N>} dps の幅を使用できます。 + + +たとえば、画面領域のレイアウトの最小寸法を常に 600 dp とする必要がある場合、この修飾子を使用してレイアウト リソース {@code +res/layout-sw600dp/} を作成できます。 +システムは、600dp の側が縦になるか横になるか関係なく、使用可能な画面の最小寸法が 600dp 以上の場合にのみこれらのリソースを使用します。 + +smallestWidth は端末の固定された画面サイズ特性です。画面の向きが変わっても、端末の smallestWidth は変更されません。 + +端末の smallestWidth では画面の装飾とシステム UI が考慮されます。たとえば、端末の画面に smallestWidth の軸に沿ったスペースを考慮した固定 UI 要素がある場合、これらの画面ピクセルは UI に使用できないことから、システムは実際の画面サイズよりも小さな smallestWidth を宣言します。つまり、使用する値は、レイアウトが必要とする実際の最小寸法とする必要があります(通常は、この値は、画面の現在の向きに関係なく、レイアウトがサポートする「最小幅」となります)。 + + + + + +次に、一般的な画面サイズに使用する値を示します。 +
アプリケーションで smallestWidth 修飾子の値が異なる複数のリソース ディレクトリを提供する場合、システムは端末の smallestWidth に最も近い(かつ超過しない)ものを使用します。 + + +API レベル 13 で追加。 +さらに、{@code +android:requiresSmallestWidthDp} 属性もご覧ください。これは、アプリケーションが互換性を持つ最小の smallestWidth と、端末の smallestWidth 値を保持する {@link +android.content.res.Configuration#smallestScreenWidthDp} 設定フィールドを宣言します。 + + +さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「Supporting Multiple Screens」のデベロッパー ガイドをご覧ください。 + + + |
+
使用可能な幅 | +w<N>dp + 例: + w720dp + w1024dp + など + |
+
+ リソースを使用する、使用可能な最小の画面幅を {@code dp} 単位で指定します。— アプリケーションでこの設定が異なる複数のリソース ディレクトリを提供する場合、システムは端末の現在の画面の幅に最も近い(かつ超過しない)ものを使用します。 + +この値は画面の装飾を考慮します。つまり、端末のディスプレイの左や右に何らかの固定 UI 要素がある場合、これらの UI 要素を考慮し、アプリケーションの使用可能なスペースを減らして、実際の画面サイズよりも小さな幅を使用します。 + + + + +API レベル 13 で追加。 +さらに、{@link android.content.res.Configuration#screenWidthDp} 設定フィールドもご覧ください。これは現在の画面の幅を保持します。 + +さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「Supporting Multiple Screens」のデベロッパー ガイドをご覧ください。 + + + |
+
使用可能な高さ | +h<N>dp + 例: + h720dp + h1024dp + など + |
+
+ リソースを使用する、使用可能な最小の画面幅を「dp」単位で指定します。— アプリケーションでこの設定が異なる複数のリソース ディレクトリを提供する場合、システムは端末の現在の画面の高さに最も近い(かつ超過しない)ものを使用します。 + +この値は画面の装飾を考慮します。つまり、端末のディスプレイの上や下に何らかの固定 UI 要素がある場合、これらの UI 要素を考慮し、アプリケーションの使用可能なスペースを減らして、実際の画面サイズよりも小さな高さを使用します。 + + + +固定されていない画面の装飾(全画面にした場合に非表示になる携帯電話のステータスバーなど)や、タイトルバーやアクションバーなどのウィンドウの装飾は、ここでは考慮されません。そのため、アプリケーションでは指定したスペースよりもやや小さなサイズに対処できるように準備をし置く必要があります。 + + + + + API レベル 13 で追加。 +さらに、{@link android.content.res.Configuration#screenHeightDp} 設定フィールドもご覧ください。これは現在の画面の幅を保持します。 + +さまざまな画面の設計とこの修飾子の使用方法についての詳細は、「Supporting Multiple Screens」のデベロッパー ガイドをご覧ください。 + + + |
+
画面サイズ | +
+ small + normal + large + xlarge
+ |
+
+
注: サイズ識別子を持つ場合でも、リソースがそのサイズの画面以外には対応しないということではありません。 +現在の端末に最適な識別子を持つ代替リソースを提供していない場合でも、システムによって最適なリソースが使用されることがあります。 + + +警告: すべてのリソースが現在の画面よりも大きなサイズ識別子を使用している場合、システムはそれらのリソースを使用せず、アプリケーションが実行時にクラッシュしてしまいます(たとえば、すべてのリソースに {@code +xlarge} 識別子のタグが付いているが、端末は通常サイズの画面である場合)。 + + +API レベル 4 で追加。 + +詳細については、「Supporting Multiple Screens」をご覧ください。 + +さらに、{@link android.content.res.Configuration#screenLayout} 設定フィールドもご覧ください。これは、画面のサイズが小、中、大のいずれかであるかを表します。 + + + |
+
画面アスペクト | +
+ long + notlong
+ |
+
+
API レベル 4 で追加。 +これは純粋に画面のアスペクト比を基準とします(「長い」画面は幅広の画面になります)。これは画面の向きには関係ありません。 + +さらに、{@link android.content.res.Configuration#screenLayout} 設定フィールドもご覧ください。これは、画面のサイズが長いかどうかを表します。 + + |
+
画面の向き | +
+ port + land
+ |
+
+
ユーザーが画面を回転すると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「実行時の変更の処理」をご覧ください。 + +さらに、{@link android.content.res.Configuration#orientation} 設定フィールドもご覧ください。これは、現在の端末の画面の向きを表します。 + + |
+
UI モード | +
+ car + desk + television + appliance
+ watch
+ |
+
+
API レベル 8 で追加。television は API 13 で追加。watch は API 20 で追加。 +端末をホルダーに装着したり、取り外したりしたときのアプリの反応については、「Determining and Monitoring the Docking State and Type」をご覧ください。 + + +ユーザーが端末をドックに装着すると、アプリケーションの実行中にこの値が変更されます。 +{@link +android.app.UiModeManager} を使用すると、これらのモードの一部を有効または無効にできます。実行時のアプリケーションに与える影響については、「実行時の変更の処理」をご覧ください。 + + |
+
ナイトモード | +
+ night + notnight
+ |
+
+
API レベル 8 で追加。 +ナイトモードを自動モード(デフォルト)のままにしておくと、時間を基準にしてモードが変更された場合に、アプリケーションの実行中にこの値が変更されます。 +{@link android.app.UiModeManager} を使用すると、このモードを有効または無効にできます。 +実行時のアプリケーションに与える影響については、「実行時の変更の処理」をご覧ください。 + + |
+
画面ピクセル密度(dpi) | +
+ ldpi + mdpi + hdpi + xhdpi + xxhdpi + xxxhdpi + nodpi + tvdpi
+ |
+
+
6 つのプライマリ密度のサイズの比率は 3:4:6:8:12:16 です(tvdpi 密度を除く)。 +そのため、ldpi では 9x9 のビットマップ、mdpi では 12x12 のビットマップ、hdpi では 18x18 のビットマップ、xhdpi では 24x24 のビットマップとなります。 + +画像リソースがテレビや他の特定の端末で正常に表示されず、tvdpi リソースを試す場合、拡張係数は 1.33*mdpi になります。 +たとえば、画面向けの 100px x 100px 画像は、tvdpi 向けにすると 133px x 133px となります。 + +注: 密度識別子を持つ場合でも、リソースがその密度の画面以外には対応しないということではありません。 +現在の端末に最適な識別子を持つ代替リソースを提供していない場合でも、システムによって最適なリソースが使用されることがあります。 + + +異なる画面密度を処理する方法や、Android が現在の密度に合わせてビットマップのサイズを変更する方法については、「Supporting Multiple Screens」をご覧ください。 + + + |
+
タッチスクリーン タイプ | +
+ notouch + finger
+ |
+
+
{@link android.content.res.Configuration#touchscreen} 設定フィールドもご覧ください。これは、端末上のタッチスクリーンのタイプを表します。 + + |
+
キーボードの使用可能状況 | +
+ keysexposed + keyshidden + keyssoft
+ |
+
+
ユーザーがハードウェア キーボードを開くと、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「実行時の変更の処理」をご覧ください。 + +さらに、設定フィールド {@link +android.content.res.Configuration#hardKeyboardHidden} と {@link +android.content.res.Configuration#keyboardHidden} もご覧ください。これは、ハードウェア キーボードの可視性、任意のキーボード(ソフトウェアを含む)の可視性、それぞれの可視性を表します。 + + |
+
主なテキストの入力方法 | +
+ nokeys + qwerty + 12key
+ |
+
+
さらに、{@link android.content.res.Configuration#keyboard} 設定フィールドもご覧ください。これは、使用可能な主なテキストの入力方法を表します。 + + |
+
ナビゲーション キーの使用可能状況 | +
+ navexposed + navhidden
+ |
+
+
ユーザーがナビゲーション キーを表示させると、アプリケーションの実行中にこの値が変更されます。 +実行時のアプリケーションに与える影響については、「実行時の変更の処理」をご覧ください。 + +さらに、{@link android.content.res.Configuration#navigationHidden} 設定フィールドもご覧ください。これは、ナビゲーション キーが非表示になっているかどうかを表します。 + + |
+
タップ以外の主なナビゲーション方法 | +
+ nonav + dpad + trackball + wheel
+ |
+
+
{@link android.content.res.Configuration#navigation} 設定フィールドもご覧ください。これは、利用可能なナビゲーション方法のタイプを表します。 + + |
+
プラットフォーム バージョン(API レベル) | +例: + v3 + v4 + v7 + など |
+
+ 端末がサポートする API レベル。たとえば、 |
+
注: Android 1.0 以降、いくつかの設定識別子が追加されているため、すべてのバージョンの Android がすべての識別子をサポートしているわけではありません。
+新しい識別子を使用すると、旧式の端末がその識別子を無視できるように、プラットフォーム バージョンの識別子が暗黙的に追加されます。
+たとえば、available-width の識別子は API レベル 13 で新たに追加されたため、w600dp
識別子を使用すると、自動的に v13
識別子が追加されます。
+
+問題を回避するために、常に一連のデフォルト リソースを含めるようにします(識別子のない一連のリソース)。
+詳細は、リソースとの最適な端末の互換性を提供するセクションをご覧ください。
+
+
修飾子の名前のルール
+ +ここでは、設定修飾子の名前の使用方法に関するルールを説明します。
+ +-
+
- リソースの 1 つのセットに複数の修飾子を指定できます。その場合は、ダッシュで区切ります。たとえば、
drawable-en-rUS-land
は画面が横向きの米国英語の端末に適用されます。 + +
+ - 識別子は表 2 の順番で使用します。次に例を示します。
+
+
-
+
- 誤:
drawable-hdpi-port/
+ - 正:
drawable-port-hdpi/
+
+ - 誤:
- 代替リソースのディレクトリはネストできません。
res/drawable/drawable-en/
などは使用できません。 +
+ - 値は大文字と小文字を区別します。大文字と小文字を区別するファイル システムの問題を回避するために、処理前にリソース コンパイラーがディレクトリ名を小文字に変換します。 + +読みやすくする場合にのみ、名前に大文字を使用します。 +
- それぞれの修飾子タイプに使用できる値は 1 つだけです。たとえば、スペインとフランスの両方に同じドローアブル ファイルを使用する場合も、ディレクトリ名を
drawable-rES-rFR/
とすることはできません。 + +その代わりに、該当するファイルを含むdrawable-rES/
とdrawable-rFR/
という名前の 2 つのリソース ディレクトリが必要になります。ただし、実際のところ、両方の場所で同じファイルを重複させる必要はありません。 + +代わりに、リソースのエイリアスを作成できます。 +後述のエイリアス リソースを作成するをご覧ください。 +
+
これらの修飾子を名前に持つディレクトリに代替リソースを保存すると、現在の端末設定に基づいて、Android がアプリケーションにリソースを自動的に適用します。 + +リソースが要求されるたびに、Android は要求されたリソース ファイルを持つ代替リソース ディレクトリを探し、最適なリソースを見つけます(後述)。 + +特定の端末設定に合う代替リソースがない場合、Android は対応するデフォルト リソース(設定識別子を含まない特定のリソースタイプ用の一連のリソース)を使用します。 + + +
+ + + +エイリアス リソースを作成する
+ +複数の端末で使用するリソースがある場合(ただし、デフォルト リソースとして提供しない場合)、同じリソースを複数の代替リソース ディレクトリに配置する必要はありません。 + +その代わりに、(場合によっては)デフォルト リソースのディレクトリに保存したリソースのエイリアスとして機能する代替リソースを作成できます。 + +
+ +注: すべてのリソースに、別のリソースへのエイリアスを作成できるメカニズムが備わっているわけではありません。 +特に、アニメーション、メニュー、未加工、{@code xml/} で指定されていないその他のリソースにはこの機能を使用できません。 +
+ +たとえば、アプリケーション アイコン {@code icon.png} について、ロケールごとに一意のバージョンが必要になるという状況を考えてみます。 +ただし、英語カナダとフランス語カナダの 2 つのロケールでは同じバージョンを使用する必要があります。 +英語カナダとフランス語カナダの両方のリソース ディレクトリに同じ画像をコピーする必要は実際にはありません。 + +代わりに、両方に使用する画像を {@code icon_ca.png} という名前({@code icon.png} 以外の名前)で保存し、デフォルトの {@code res/drawable/} ディレクトリに配置します。 + +次に {@code <bitmap>} 要素を使用して {@code icon_ca.png} リソースを参照する {@code icon.xml} ファイルを {@code +res/drawable-en-rCA/} と {@code res/drawable-fr-rCA/} に作成します。 +これにより、PNG ファイルを 1 つだけ作成し、それを指す小さな XML ファイルを 2 つ作成するだけで済みます +(次に、XML ファイルの例を示します)。
+ + +ドローアブル
+ +既存のドローアブルのエイリアスを作成するには、{@code <bitmap>} 要素を使用します。次に例を示します。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/icon_ca" /> ++ +
このファイルを {@code icon.xml} として({@code res/drawable-en-rCA/} などの代替リソース ディレクトリに)保存すると、{@code R.drawable.icon} として参照可能なリソースにコンパイルされますが、実際のところ、これは({@code res/drawable/} に保存されている){@code +R.drawable.icon_ca} リソースのエイリアスです。 + +
+ + +レイアウト
+ +既存のレイアウトのエイリアスを作成するには、{@code <merge>} にラップされる {@code <include>} 要素を使用します。 +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<merge> + <include layout="@layout/main_ltr"/> +</merge> ++ +
このファイルを {@code main.xml} として保存すると、{@code R.layout.main} として参照可能なリソースにコンパイルされますが、実際のところ、これは {@code R.layout.main_ltr} リソースのエイリアスです。 + +
+ + +文字列とその他の単純な値
+ +既存の文字列のエイリアスを作成するには、単に、目的の文字列のリソース ID を新しい文字列の値として使用します。 +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="hello">Hello</string> + <string name="hi">@string/hello</string> +</resources> ++ +
{@code R.string.hi} リソースは {@code R.string.hello} のエイリアスになりました。
+ +その他の単純な値も同様に機能します。 +次に色の例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="yellow">#f00</color> + <color name="highlight">@color/red</color> +</resources> ++ + + + +
リソースとの最適な端末の互換性を提供する
+ +アプリケーションで複数の端末設定をサポートするには、アプリケーションが使用するそれぞれのタイプのリソースに常にデフォルト リソースを提供することが重要です。 +
+ +たとえば、アプリケーションが複数の言語をサポートする場合は、言語と地域の修飾子を持たない {@code +values/} ディレクトリ(文字列の保存先)を常に用意します。すべての文字列ファイルをすべて言語と地域の修飾子を持つディレクトリに配置してしまうと、自分の文字列がサポートしていない言語に設定された端末でアプリケーションを実行すると、アプリケーションがクラッシュしてしまいます。 + +ただし、デフォルトの {@code values/} リソースを提供しておけば、アプリケーションは適切に実行されます(ユーザーがその言語を理解できない場合でも。—クラッシュは避けられます)。 + +
+ +同様に、画面の向きに基づいた異なるレイアウト リソースを提供する場合も、いずれかの方向をデフォルトに設定する必要があります。 +たとえば、横向きの {@code +layout-land/} と縦向きの {@code layout-port/} にレイアウト リソースを提供する代わりに、横向きの {@code layout/} と縦向きの {@code layout-port/} のようなリソースをデフォルトとして保存しておきます。 +
+ +予測しなかった設定でアプリケーションが実行されるだけでなく、新しいバージョンの Android では古いバージョンではサポートされない設定修飾子が追加されることもあるため、デフォルト リソースの提供が重要になります。 + +新しいリソース修飾子を使用するが、古いバージョンの Android とのコードの互換性を保持する場合、古いバージョンの Android でアプリケーションを実行するときにデフォルト リソースが提供されていないと、古いバージョンの Android では新しい修飾子の付いたリソースを使用できないために、アプリケーションがクラッシュします。 + + +たとえば、{@code +minSdkVersion} が 4 に設定されている場合に、ナイトモード(API レベル 8 で追加された {@code night} または {@code notnight})を使用してすべてのドローアブル リソースの修飾子を設定すると、API レベル 4 端末はドローアブル リソースにアクセスできず、クラッシュします。 +この場合、{@code notnight} をデフォルト リソースにする場合、その修飾子を除外することになるため、ドローアブル リソースは {@code drawable/} または {@code drawable-night/} のいずれかになります。 + +
+ +そこで、端末の最適な互換性を提供するには、アプリケーションを適切に実行するのに必要なリソースに常にデフォルト リソースを提供するようにします。 +次に、設定修飾子を使用して、特定の端末設定向けの代替リソースを作成します。 +
+ +このルールには次の例外があります。アプリケーションの {@code minSdkVersion} が 4 以上の場合、画像密度修飾子で代替のドローアブル リソースを提供するときには、デフォルトのドローアブル リソースを提供する必要はありません。 + +デフォルトのドローアブル リソースがない場合でも、Android は代替の画面密度のなかで最適なものを見つけて、必要に応じてビットマップのサイズを変更できます。 + +ただし、すべてのタイプに最適な操作性を提供するには、密度の 3 つのタイプすべてに代替ドローアブルを提供する必要があります。 +
+ + + +Android が最適なリソースを見つける仕組み
+ +代替を提供するリソースを要求すると、現在の端末設定に応じて Android が実行時に使用する代替リソースを選択します。 +Android が代替リソースを選択する方法説明するために、次のドローアブル ディレクトリを想定します。それぞれに同じ画像の異なるバージョンが入っています。 + +
+ ++drawable/ +drawable-en/ +drawable-fr-rCA/ +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ ++ +
さらに、次のような端末設定を想定します。
+ +
+ロケール = en-GB
+画面の向き = port
+画面ピクセル密度 = hdpi
+タッチスクリーン タイプ = notouch
+主なテキストの入力方法 = 12key
+
端末設定を使用可能な代替リソースに比較して、Android は {@code drawable-en-port} からドローアブルを選択します。 +
+ +システムは、次のロジックを使用して、使用するリソースを決定します。 +
+ + +-
+
- 端末設定に矛盾するリソース ファイルを排除します。
+
+en-GB
ロケールに矛盾するため、drawable-fr-rCA/
ディレクトリが排除されます。 ++drawable/ +drawable-en/ +
+drawable-fr-rCA/+drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/ +drawable-port-notouch-12key/ +例外: 画面ピクセル密度は、矛盾により排除されない修飾子の 1 つです。 +それぞれの画面密度はその時点で最適であると判断されたものであるため、端末の画面密度が hdpi の場合でも、
drawable-port-ldpi/
は排除されません。 + +詳細は、「Supporting Multiple Screens」のドキュメントをご覧ください。 +
+
+ - リスト(表 2)にある(次に)優先される修飾子を選択します(MCC から順に下がっていきます)。 + +
- この修飾子を含むリソース ディレクトリがあるかどうかを確認します。 +
- ない場合は、ステップ 2 に戻り、次の修飾子を調べます(この例では、言語識別子になるまですべて「いいえ」になります)。 + +
- 「はい」の場合は、ステップ 4 に進みます。 +
- この修飾子を持たないリソース ディレクトリを排除します。この例では、システムによって言語修飾子を含まないすべてのディレクトリが排除されます。 + +
- 残るディレクトリが 1 つになるまで、元に戻ってステップ 2、3、4 を繰り返します。このレイでは、次にマッチングするのが画面の向きの修飾子です。そのため、画面の向きを指定しないリソースは排除されます。
+
+
+
+
+drawable-en/+drawable-en-port/ +drawable-en-notouch-12key/+{@code drawable-en-port} ディレクトリが残ります。
+
+
-
+
++drawable/+drawable-en/ +drawable-en-port/ +drawable-en-notouch-12key/ +drawable-port-ldpi/+drawable-port-notouch-12key/+
例外: 対象となる修飾子が画面ピクセル密度の場合、Android は端末の画像密度に最も近いオプションを選択します。一般的に、Android では小さな元画像を拡大するよりも、大きな元画像を縮小する方法が使用されます。 + + +「Supporting Multiple Screens」をご覧ください。 +
+ + +この手順は要求した各リソースに対して実行されますが、システムはさらにいくつかの最適化を行います。 +たとえば、端末の設定が判明すると、マッチングしない代替リソースが排除されたりします。 +たとえば、設定言語が英語(「en」)の場合、言語修飾子が英語以外に設定されているリソース ディレクトリはチェック対象のリソースのプールに入ることはありません(言語修飾子のないリソース ディレクトリはそのままプールに入ります)。 + + +
+ +画面サイズ修飾子に基づいてリソースを選択する場合、最適なリソースがない場合、システムは現在の画面よりも小さな画面向けのリソースを使用します(たとえば、必要に応じて大きなサイズの画面が通常サイズの画面のリソースを使用します)。 + +ただし、使用できるリソースが現在の画面よりも大きなサイズのものしかない場合は、システムはそれらのリソースを使用せず、端末設定にあるその他のリソースがないときは、アプリケーションがクラッシュします(たとえば、すべてのリソースに {@code xlarge} 識別子のタグが付いているが、端末は通常サイズの画面である場合) + + + +
+ +注: (表 2 の)上位にある修飾子の方が、端末に正確に一致する修飾子の数よりも重要になります。
+たとえば、上のステップ 4 では、drawable-en
には一致するパラメータが 1 つしかありませんが(言語)、リストの最後の選択肢には、端末に正確に一致する修飾子が 3 つあります(画面の向き、タッチスクリーン タイプ、入力方法)。
+
+
+ただし、言語はこれらの他の修飾子よりも優先されるため、drawable-port-notouch-12key
は排除されます。
+
アプリケーションでのリソースの使用方法については、「リソースへのアクセス」をご覧ください。
diff --git a/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd b/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd new file mode 100644 index 0000000000000000000000000000000000000000..9bce95aee1152852999eca36e99a5bf3b20b6ac1 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/resources/runtime-changes.jd @@ -0,0 +1,281 @@ +page.title=実行時の変更の処理 +page.tags=アクティビティ,ライフサイクル +@jd:body + +本書の内容
+ + +関連ドキュメント
+ +端末の構成の中には、実行時に変化するものがあります(画面の向き、キーボードの可用性、言語など)。 +そのような変更が発生すると、Android は実行中の {@link android.app.Activity} を再起動します({@link android.app.Activity#onDestroy()} が呼び出され、その後に{@link +android.app.Activity#onCreate(Bundle) onCreate()} が呼び出されます)。 + +再起動の動作は、新しい端末構成に一致する代替リソースを使用してアプリケーションを自動的にリロードすることで、アプリケーションを新しい構成に適応させることを目的としています。 + +
+ +再起動を適切に処理するには、アクティビティが通常のアクティビティのライフサイクルを通じて事前の状態を格納することが重要です。その場合、アプリケーションの状態に関するデータを保存できるように、Android はアクティビティを破棄する前に {@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} を呼び出します。 + + + +その後、{@link android.app.Activity#onCreate(Bundle) onCreate()} か {@link +android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()} の際に状態を格納できます。 +
+ +アプリケーション自体がそのままの状態で再起動することをテストするには、アプリケーションでさまざまなタスクを実行中に、構成の変更(画面の向きの変更など)を呼び出す必要があります。 + +構成の変更を処理したり、ユーザーが電話を着信し、アプリケーション プロセスが破棄されるほど時間が経過してからアプリケーションに戻ったりするような場合には、ユーザーデータや状態を失うことなくいつでもアプリケーションを再起動できるようにする必要があります。 + + +アクティビティの状態を格納する方法については、「アクティビティのライフサイクル」をご覧ください。
+ +ただし、場合によっては、アプリケーションを再起動すると、大量のデータの復元にコストがかかり、操作性が悪くなることがあります。 +そのような場合、次の 2 つの方法で処理できます。 +
+ +-
+
- 構成の変更中にオブジェクトを保持する
+
構成の変更時にアクティビティを再起動できますが、ステートフル オブジェクトがアクティビティの新しいインスタンスに移動します。 +
+ +
+ - 構成の変更を自分で処理する
+
特定の構成変更の際に、システムがアクティビティを再起動しないようにしますが、必要に応じてアクティビティをアップデートできるように、構成が変更された場合には、コールバックを受け取ります。 + +
+
+
構成の変更中にオブジェクトを保持する
+ +アクティビティの再起動で大量のデータの復元、ネットワーク接続の再構築、他の負荷のかかる操作の実行が必要になる場合、構成変更のために完全な再起動を実行すると、操作性が悪くなってしまうことがあります。 + +さらに、システムの {@link +android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} コールバックによって保存される {@link android.os.Bundle} を使用して、アクティビティの状態を完全に復元できない場合もあります。—大きなオブジェクト(ビットマップなど)を扱うためのものではなく、内部のデータをシリアル化してから逆シリアル化を行うため、多くのメモリを消費することになり、構成の変更に時間がかかってしまいます。 + + +そのような場合、構成の変更によるアクティビティの再起動の際に、{@link +android.app.Fragment} を保持することで、再初期化の負担を軽減できます。 +このフラグメントには、保持しておきたいステートフル オブジェクトへの参照を含めることができます。 +
+ +構成変更により Android システムがアクティビティをシャットダウンするとき、保持するためのマークを設定しておくと、アクティビティのフラグメントが破棄されません。 +ステートフル オブジェクトを保持するために、アクティビティにこのようなフラグメントを追加しておくことができます。 +
+ +実行時の構成変更の際に、フラグメントにステートフル オブジェクトを保持するには:
+ +-
+
- {@link android.app.Fragment} クラスを拡張し、ステートフル オブジェクトへの参照を宣言します。 + +
- フラグメントを作成するときに、{@link android.app.Fragment#setRetainInstance(boolean)} を呼び出します。 + +
- フラグメントをアクティビティに追加します。 +
- アクティビティの再起動時にフラグメントを取得するには、{@link android.app.FragmentManager} を使用します。 + +
次は、フラグメントの定義の例です。
+ ++public class RetainedFragment extends Fragment { + + // data object we want to retain + private MyDataObject data; + + // this method is only called once for this fragment + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // retain this fragment + setRetainInstance(true); + } + + public void setData(MyDataObject data) { + this.data = data; + } + + public MyDataObject getData() { + return data; + } +} ++ +
警告: オブジェクトの格納が可能な間は、{@link +android.graphics.drawable.Drawable}、{@link android.widget.Adapter}、{@link android.view.View}、さらには {@link android.content.Context} に関連付けられているその他のオブジェクトのように、{@link android.app.Activity} に結び付いたオブジェクトを渡さないようにしてください。 + +オブジェクトを渡すと、元のアクティビティ インスタンスのビューやリソースがすべて漏えいしてしまいます +(リソースが漏えいすると、アプリケーションはリソースを保持しているがガーベジコレクションを実行できず、大量のメモリが失われてしまうことがあります)。 + +
+ +次に、{@link android.app.FragmentManager} を使用して、フラグメントをアクティビティに追加します。実行時に構成を変更する際にアクティビティを再び起動すると、フラグメントからデータ オブジェクトを取得できます。 + +次は、アクティビティの定義の例です。
+ ++public class MyActivity extends Activity { + + private RetainedFragment dataFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + // find the retained fragment on activity restarts + FragmentManager fm = getFragmentManager(); + dataFragment = (DataFragment) fm.findFragmentByTag(“data”); + + // create the fragment and data the first time + if (dataFragment == null) { + // add the fragment + dataFragment = new DataFragment(); + fm.beginTransaction().add(dataFragment, “data”).commit(); + // load the data from the web + dataFragment.setData(loadMyData()); + } + + // the data is available in dataFragment.getData() + ... + } + + @Override + public void onDestroy() { + super.onDestroy(); + // store the data in the fragment + dataFragment.setData(collectMyLoadedData()); + } +} ++ +
この例では、{@link android.app.Activity#onCreate(Bundle) onCreate()} がフラグメントを追加するか、フラグメントへの参照を復元します。さらに、{@link android.app.Activity#onCreate(Bundle) onCreate()} がステートフル オブジェクトをフラグメント インスタンスの内部に格納し、{@link android.app.Activity#onDestroy() onDestroy()} が保持しているフラグメント インスタンス内部のステートフル オブジェクトを更新します。 + + + +
+ + + + + +構成の変更を自分で処理する
+ +アプリケーションに特定の構成の変更の際にリソースを更新する必要がなく、パフォーマンスの制限によりアクティビティの再起動を回避する必要がある場合は、構成の変更をアクティビティ自身が処理することを宣言します。そうすることで、システムによってアクティビティが再起動されなくなります。 + + +
+ +注: 構成の変更を自分で処理すると、変更がシステムによって自動的に適用されることがないため、代替リソースの使用が非常に難しくなります。 + +この手法は、構成の変更による再起動を回避する際の最後の手段として検討する手法です。ほとんどの場合、アプリケーションでの使用は推奨されません。 +
+ +アクティビティで構成の変更を処理することを宣言するには、マニフェスト ファイルの該当する {@code <activity>} 要素を編集し、処理する構成を表す値とともに {@code +android:configChanges} 属性を配置します。 + +使用可能な値は、{@code +android:configChanges} 属性のドキュメントに一覧が記載されています(一般的には、画面の向きを変更した場合の再起動を回避するには {@code "orientation"} の値を、キーボードの可用性を変更した場合の再起動を回避するには {@code "keyboardHidden"} の値を使用します)。 + +パイプ記号の {@code |} 文字を使用して区切ることで、属性内に複数の構成値を宣言できます。 +
+ +たとえば、次のマニフェスト コードでは、画面の向きとキーボードの可用性の変更の両方を処理するアクティビティを宣言しています。 +
+ ++<activity android:name=".MyActivity" + android:configChanges="orientation|keyboardHidden" + android:label="@string/app_name"> ++ +
これで、これらのいずれかの構成が変更された場合でも、{@code MyActivity} が再起動することはなくなりました。代わりに、{@code MyActivity} が {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} への呼び出しを取得します。 +このメソッドには、新しい端末構成を指定する {@link android.content.res.Configuration} オブジェクトが渡されます。 + +{@link android.content.res.Configuration} のフィールドを読み込むことで新しい構成を判断し、インターフェースに使用するリソースを更新して適切に変更できます。 + +このメソッドが呼び出されると、アクティビティの {@link android.content.res.Resources} オブジェクトが更新され、新しい構成に基づいたリソースを返します。それにより、システムがアクティビティを再起動しなくても、UI の要素を簡単にリセットできます。 + + +
+ +警告: Android 3.2(API レベル 13)以降では、端末の画面の向きを縦から横に切り替えると、「画面サイズ」も変更されます。 + +そのため、API レベル 13 以降で開発を行う場合({@code minSdkVersion} 属性と {@code targetSdkVersion} 属性により宣言)、画面の向きによる実行時の再起動を回避するには、{@code "screenSize"} 値と一緒に {@code +"orientation"} 値を使用する必要があります。 + +つまり、{@code +android:configChanges="orientation|screenSize"} を宣言する必要があります。ただし、アプリケーションのターゲットが API レベル 12 以前の場合は、常にアクティビティ自身がこの構成の変更を処理します(Android 3.2 以降の端末で実行している場合でも、この構成の変更によりアクティビティが再起動されることはありません)。 + +
+ +たとえば、次の {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} の実装により現在の端末の画面の向きがチェックされます。 +
+ ++@Override +public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + // Checks the orientation of the screen + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ + Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); + } +} ++ +
{@link android.content.res.Configuration} オブジェクトは、変更された構成を除く、現在のすべての構成を表します。 +ほとんどの場合、構成の変更内容を正確に把握する必要はなく、代替の構成を提供するすべてのリソースを処理中の構成に割り当て直します。 + +たとえば、現在は {@link +android.content.res.Resources} オブジェクトが更新されたため、任意の {@link android.widget.ImageView} を {@link android.widget.ImageView#setImageResource(int) +setImageResource()} でリセットでき、新しい構成には最適なリソースが使用されます(「リソースの提供」をご覧ください)。 + +
+ +{@link +android.content.res.Configuration} フィールドの値は、{@link android.content.res.Configuration} クラスの特定の定数に一致する整数であることにご注意ください。 +それぞれのフィールドで使用する定数に関するドキュメントについては、{@link +android.content.res.Configuration} リファレンスの該当するフィールドをご覧ください。 +
+ +メモ: 構成の変更をアクティビティで処理することを宣言すると、代替を提供するすべての要素をリセットする操作が必要になります。 +画面の向きの変更を処理するアクティビティを宣言しており、縦向きと横向きで切り替わる画像がある場合、{@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} の際にそれぞれの要素に各リソースを割り当て直す必要があります。 + +
+ +これらの構成の変更に基づいてアプリケーションを更新する必要がない場合は、代わりに {@link +android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} を実装できません。 +このような場合、構成の変更前に使用していたすべてのリソースがそのまま使用され、アクティビティの再起動を回避した状態となります。 + +ただし、アプリケーションはいつでもシャットダウンして以前のままの状態で再起動できる状態にしておく必要があるため、通常のアクティビティのライフサイクルでは、状態を保持しない手段としてこの手法を使用しないようにします。 + +それは、アプリケーションの再起動を回避できない他の構成の変更があるだけでなく、ユーザーがアプリケーションを離れ、ユーザーがアプリケーションに戻る前に破棄されてしまうようなイベントを処理する必要があるためです。 + + +
+ +アクティビティで処理できる構成の変更についての詳細は、{@code +android:configChanges} のドキュメントと{@link android.content.res.Configuration} クラスをご覧ください。 +
diff --git a/docs/html-intl/intl/ja/guide/topics/ui/controls.jd b/docs/html-intl/intl/ja/guide/topics/ui/controls.jd new file mode 100644 index 0000000000000000000000000000000000000000..0bc2063764bb65397992166cad2a9d4343ae2591 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/controls.jd @@ -0,0 +1,90 @@ +page.title=入力コントロール +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + +入力コントロールは、アプリのユーザー インターフェースのインタラクティブなコンポーネントです。Android では、ボタン、テキスト フィールド、シークバー、チェックボックス、ズームボタン、トグルボタンなど UI で使用できるさまざまなコントロールが提供されています。 + +
+ +UI に入力コントロールを追加することは、XML レイアウトに XML 要素を追加するのと同じくらい簡単です。テキスト フィールドとボタンを含むレイアウトの例を次に示します。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="horizontal"> + <EditText android:id="@+id/edit_message" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:hint="@string/edit_message" /> + <Button android:id="@+id/button_send" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_send" + android:onClick="sendMessage" /> +</LinearLayout> ++ +
各入力コントロールでは、特定の一連の入力イベントがサポートされているため、ユーザーがテキストを入力したり、ボタンをタップしたりするときなどに、イベントを処理できます。 +
+ + +コモン コントロール
+アプリで使用できるコモン コントロールには、次のようなものがあります。それぞれの使い方の詳細については、各リンクをご覧ください。 +
+ +注: Android では、ここにリストされている以外にもいくつかコントロールが提供されています。 +他のコントロールについては、{@link android.widget} パッケージをご確認ください。アプリで、特定の種類の入力コントロールを必要とする場合、独自の カスタム コンポーネント をビルドできます。 +
+ +コントロール タイプ | +説明 | +関連クラス | +
---|---|---|
ボタン | +ユーザーがアクションを実行するために、押したり、クリックしたりできるプッシュボタン。 | +{@link android.widget.Button Button} | +
テキスト フィールド | +編集できるテキスト フィールド。AutoCompleteTextView ウィジェットを使って、オートコンプリート候補を表示するテキスト入力ウィジェットを作成できます。 |
+ {@link android.widget.EditText EditText}、{@link android.widget.AutoCompleteTextView} | +
チェックボックス | +ユーザーが切り替えることができる、オン、オフスイッチ。相互に排他的ではない選択可能なオプションのグループをユーザーに表示するときは、チェックボックスを使ってください。 | +{@link android.widget.CheckBox CheckBox} | +
ラジオボタン | +グループで選択できるオプションは 1 つのみであることを除き、チェックボックスと同様です。 | +{@link android.widget.RadioGroup RadioGroup}
+ {@link android.widget.RadioButton RadioButton} |
+
トグルボタン | +ライト インジケーター付きの、オン、オフボタン。 | +{@link android.widget.ToggleButton ToggleButton} | +
スピナー | +ユーザーが一連の値から 1 つを選択できるドロップダウン リスト。 | +{@link android.widget.Spinner Spinner} | +
ピッカー | +上下のボタンを使うか、スワイプして、1 つの値を選択するためのダイアログ。日付(月、日、年)の値を入力するには DatePicker code> ウィジェットを使い、時刻(時間、分、午前または午後)の値を入力するには TimePicker ウィジェットを使います。これにより、ユーザーのロケールが自動的に書式設定されます。 |
+ {@link android.widget.DatePicker}、{@link android.widget.TimePicker} | +
本書の内容
+-
+
- XML の記述 +
- XML リソースの読み込み +
- 属性
+
-
+
- ID +
- レイアウト パラメータ +
+ - レイアウトの位置 +
- サイズ、パディング、マージン +
- 共通レイアウト +
- アダプタを使ったレイアウトをビルドする + + +
キークラス
+-
+
- {@link android.view.View} +
- {@link android.view.ViewGroup} +
- {@link android.view.ViewGroup.LayoutParams} +
関連ドキュメント
+レイアウトでは、アクティビティやアプリ ウィジェットの UI のような、ユーザー インターフェースの視覚的構造が定義されます。次の 2 つの方法でレイアウトを宣言できます。 +
+-
+
- XML で UI 要素を宣言する。Android では、ウィジェットやレイアウトなどの View クラスとサブクラスに対応する単純な XML ボキャブラリが提供されます。 + +
- 実行時にレイアウト要素のインスタンスを作成する。アプリケーションで View と ViewGroup オブジェクトを作成できます。また、プログラムを使ってプロパティを操作することもできます。 + +
Android フレームワークでは、アプリケーション UI の宣言と管理に、これらのいずれかのメソッドまたは両方のメソッドを柔軟に使うことができます。たとえば、レイアウトに表示されるスクリーン要素やそのプロパティを含む、アプリケーションのデフォルト レイアウトを XML で宣言できます。スクリーン オブジェクトの状態を変更するコードをアプリケーション内で追加できます(実行時の XML での宣言を含む)。
+ +-
+
- ADT Plugin for Eclipse では、XML ファイルを開いて [レイアウト] タブを選択すると、XML のレイアウト プレビューが提供されます。 + + +
- レイアウトのデバッグに、Hierarchy Viewer ツールを使うこともできます。このツールでは、レイアウト プロパティ値の表示、パディングやマージンのインジケーターを使ったワイヤーフレームの描画、エミュレータや端末でデバッグする間のレンダリングされた全画面表示が提供されます。 + + + + +
- layoutopt ツールを使うと、効率性の低下やその他の問題について、レイアウトや階層を素早く解析できます。 + +
XML で UI を宣言する利点は、動作を制御するコードとアプリケーションの表示をうまく切り離すことができる点です。UI の記述は、アプリケーション コード外にあるため、ソースコードの変更や再コンパイルをすることなく、記述を修正したり改良したりできます。たとえば、異なる画面の向き、端末の画面サイズ、言語に対して XML レイアウトを作成できます。XML でレイアウトを宣言すると、UI の構造を簡単に視覚化できるため、問題のデバッグも簡単です。そのため、本書では XML でレイアウトを宣言する方法を中心に説明しています。実行時に View オブジェクトのインスタンスを作成することに関心がある場合は、{@link android.view.ViewGroup} と {@link android.view.View} クラス参照をご覧ください。 + +
+ +通常、UI 要素を宣言する XML ボキャブラリは、クラスとメソッドの構造と命名に厳密に従っており、要素名はクラス名に、属性名はメソッドに対応しています。実際、ほとんどの場合、直接的に対応しているため、クラスメソッドに対応する XML 属性を推測したり、与えられた XML 要素に対応するクラスを推測したりできます。ただし、すべてのボキャブラリが同一とは限りません。場合によっては、命名が若干異なります。たとえば、EditText 要素には、EditText.setText()
に対応する text
属性があります。
+
+
ヒント: 異なるレイアウト タイプの詳細については、共通レイアウト オブジェクトをご覧ください。 +また、Hello Views のチュートリアル ガイドには、さまざまなレイアウトのビルドに関するチュートリアルがあります。 +
+ +XML の記述
+ +Android の XML ボキャブラリを使って、HTML でウェブページを作成するのと同じ方法で(ネストした一連の要素を使って)、UI レイアウトとそれに含まれる画面要素を素早く設計できます。
+ +各レイアウト ファイルには、必ず 1 つのルート要素が含まれていて、そのルート要素は View または ViewGroup オブジェクトでなくてはなりません。ルート要素を定義すれば、追加のレイアウト オブジェクトやウィジェットを子の要素として追加して、レイアウトを定義するビュー階層を少しずつビルドできます。{@link android.widget.TextView} と {@link android.widget.Button} を保持するために、縦方向の {@link android.widget.LinearLayout} を使用する XML レイアウトの例を次に示します。 +
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Hello, I am a Button" /> +</LinearLayout> ++ +
XML でレイアウトを宣言した後、そのファイルを Android プロジェクトの res/layout/
ディレクトリ内で .xml
拡張子を付けて保存して、正しくコンパイルされるようにします。
+
レイアウト XML ファイルの構文の詳細については、「Layout Resources」のドキュメントをご覧ください。
+ +XML リソースの読み込み
+ +アプリケーションをコンパイルすると、各 XML レイアウト ファイルは {@link android.view.View} リソースにコンパイルされます。
+{@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()} コールバックの実装で、アプリケーション コードからレイアウト リソースを読み込んでください。これを行うには、{@link android.app.Activity#setContentView(int) setContentView()}
を呼び出し、R.layout.layout_file_name
の形式でレイアウト リソースへの参照を渡します。たとえば、XML レイアウトが main_layout.xml
として保存される場合、次のようにしてアクティビティに読み込みます。
+
+
+
+
+
+
+public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_layout); +} ++ +
アクティビティの onCreate()
コールバック メソッドは、アクティビティが起動されるときに、Android フレームワークによって呼び出されます(ライフサイクルに関する説明については、「アクティビティ」のドキュメントをご覧ください)。
+
+
+
属性
+ +すべての View と ViewGroup オブジェクトでは、独自のさまざまな XML 属性がサポートされています。一部の属性は、View オブジェクト特有のものですが(たとえば TextView では textSize
属性がサポートされています)、これらの属性はこのクラスを拡張可能な View オブジェクトによっても継承されます。一部は、ルート View クラスから継承されるため、すべての View オブジェクトに共通します(id
属性のような)。
+
+
+
+その他の属性は「レイアウト パラメータ」として考慮され、オブジェクトの親である ViewGroup オブジェクトとして定義された、View オブジェクトの特定のレイアウト方向を記述する属性となります。
+
+
ID
+ +ツリー内で View を一意に識別するために、すべての View オブジェクトには、それに関連付けられた整数の ID があることがあります。アプリケーションがコンパイルされると、この ID は整数として参照されますが、一般的にその ID は id
属性で文字列としてレイアウト XML ファイルに割り当てられます。これは、すべての View オブジェクトに共通の XML 属性で({@link android.view.View} クラスで定義)、非常に頻繁に使用されます。XML タグ内の ID の構文を次に示します。
+
+
+
+
+
android:id="@+id/my_button"+ +
文字列の先頭にあるアットマーク(@)は、その XML パーサーが ID の残りの文字列をパースして展開し、それを ID リソースとして識別する必要があることを示します。
+プラス記号(+)は、それが新しいリソース名で、作成してリソースに追加する(R.java
ファイル内で)必要があることを意味しています。
+Android フレームワークによって提供されるその他のさまざまな ID リソースがあります。
+Android リソース ID を参照するときは、プラス記号を使う必要はありませんが、次のように android
パッケージ名前空間を追加する必要があります。
+
android:id="@android:id/empty"+
android
パッケージ名前空間付きの場合、ローカルのリソースクラスからではなく android.R
リソースクラスから ID を参照するようになります。
+
ビューを作成してアプリケーションからそれを参照するには、次のような共通のパターンがあります。
+-
+
- レイアウト ファイルでビューとウィジェットを定義して、一意の ID を割り当てる。
+
+<Button android:id="@+id/my_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/my_button_text"/> +
+
+ - 次に、View オブジェクトのインスタンスを作成し、それを次のようにレイアウトから取得する(通常は、
{@link android.app.Activity#onCreate(Bundle) onCreate()}
メソッド内で)。 + ++Button myButton = (Button) findViewById(R.id.my_button); +
+
+
View オブジェクトの ID を定義することは、{@link android.widget.RelativeLayout} を作成するときに重要になります。相対レイアウトでは、兄弟ビューは一意の ID で参照される別の兄弟ビューに相対するレイアウトを定義できます。 + +
+ツリー全体で ID が一意である必要はありませんが、探しているツリーの一部では、一意である必要があります。ほとんどの場合、それはツリー全体になりますが、可能な時に完全に一意になるようにすることが最善です。 + +
+ + +レイアウト パラメータ
+ +layout_something
という名前の XML レイアウト属性では、含まれている ViewGroup に適した View に対するレイアウト パラメータが定義されます。
+
すべての ViewGroup クラスでは、{@link +android.view.ViewGroup.LayoutParams} を拡張するネストされたクラスが実装されます。このサブクラスには、各子ビューのサイズと位置を ViewGroup に合うように定義するプロパティ タイプが含まれています。 + +図 1 にあるように、親 ViewGroup によって、子 ViewGroup を含む、各子ビューのレイアウト パラメータが定義されます。 +
+ + + + +すべての LayoutParams サブクラスには、設定値に独自の構文があります。 +それぞれの子の要素では、その親に適した LayoutParams が定義される必要がありますが、自分の子に対して異なる LayoutParams を定義することもできます。 +
+ +すべての ViewGroup には、幅と高さ(layout_width
と layout_height
)が含まれていて、各ビューでそれが定義されている必要があります。
+多くの LayoutParams には、省略可能なマージンと境界線も含まれています。
+
+ +
必要になる頻度は少ない可能性はありますが、幅と高さを正確なサイズで指定することもできます。 +ほとんどの場合は、次の定数のいずれかを使って幅や高さを設定します。 +
+ +-
+
- wrap_content では、ビューがそのコンテンツに必要な寸法に合わせられます。 + +
- match_parent (API レベル 8 以前は fill_parent )では、ビューが親 ViewGroup で許容される最大サイズで表示されます。 + +
通常、ピクセルなどの絶対単位でレイアウトの幅と高さを指定することは推奨されません。 + +密度非依存ピクセル単位(dp)、 wrap_content、 +match_parentなどの相対測定を使う方が賢明です。そうすることで、さまざまな端末の画面サイズでアプリケーションが正しく表示されるようになります。使用可能な測定タイプは、「使用可能なリソース」のドキュメントで定義されています。 + + + +
+ + +レイアウトの位置
++ ビューの形状は、矩形です。ビューには、左と上の座標ペアで表される位置と、幅と高さで表される 2 次元があります。 + +位置と寸法の単位はピクセルです。 + +
+ +
+ {@link android.view.View#getLeft()} と {@link android.view.View#getTop()} メソッドを呼び出してビューの位置を取得できます。
+前者では、左またはビューを表す矩形の X 座標が返されます。
+後者では、上またはビューを表す矩形の Y 座標が返されます。
+これらのメソッドでは、両方とも親に相対するビューの位置が返されます。
+たとえば、getLeft()
で 20 が返される場合、そのビューはその直属の親の左端から右に 20 ピクセルの位置にあることを意味します。
+
+
+
+ 他にも、{@link android.view.View#getRight()} や {@link android.view.View#getBottom()} といった不要な計算を回避するさまざまな便利なメソッドが提供されています。
+
+ これらのメソッドでは、ビューを表す矩形の右端と下端の座標が返されます。
+たとえば、{@link android.view.View#getRight()} を呼び出すことは、getLeft() + getWidth()
の計算と同様です。
+
+
サイズ、パディング、マージン
++ ビューのサイズは、幅と高さで示します。実際に、ビューには幅と高さ 2 つの値がペアとして保持されています。 + +
+ ++ 最初のペアは、測定された幅と測定された高さと呼ばれます。 +これらの寸法で、その親内でのビューの大きさが定義されます。 +測定された寸法は、{@link android.view.View#getMeasuredWidth()} と {@link android.view.View#getMeasuredHeight()} を呼び出して取得できます。 + + +
+ ++ 2 番目のペアは、単に幅と高さと呼ばれたり、描画する幅と描画する高さと呼ばれたりします。 +これらの寸法は、描画時とレイアウト後に、画面上のビューの実サイズを定義するものです。 + +これらの値は、測定された幅や高さと異なる値にすることもできますが、必須ではありません。 +幅と高さは、{@link android.view.View#getWidth()} と {@link android.view.View#getHeight()} を呼び出して取得できます。 + +
+ ++ その寸法を測るために、ビューではパディングも考慮されます。パディングは、ビューの上下左右に対し、ピクセルで記述されます。 + + パディングを使って、特定のピクセル値でビュー コンテンツのオフセットを指定できます。 +たとえば、左側のパディングが 2 の場合は、左端から 2 ピクセル右にビューのコンテンツが寄せられます。 +パディングは {@link android.view.View#setPadding(int, int, int, int)} メソッドを使って設定でき、{@link android.view.View#getPaddingLeft()}、{@link android.view.View#getPaddingTop()}、{@link android.view.View#getPaddingRight()}、{@link android.view.View#getPaddingBottom()} を呼び出してクエリできます。 + + + +
+ ++ ビューではパディングを定義できますが、マージンについてはサポートされていません。 +ただし、ViewGroup ではそのようなサポートが提供されています。詳細については、{@link android.view.ViewGroup} と {@link android.view.ViewGroup.MarginLayoutParams} をご覧ください。 + + +
+ +寸法の詳細については、寸法の値をご覧ください。 + +
+ + + + + + + + + + + +共通レイアウト
+ +{@link android.view.ViewGroup} クラスの各サブクラスでは、ビュー内でネストするビューを表示する一意の方法が提供されます。 +Android プラットフォームにビルドされる共通のレイアウト タイプの一部を以下に示します。 +
+ +注: 別のレイアウト内で 1 つ以上のレイアウトをネストして UI を設計できますが、レイアウトの階層はできる限り浅くしておくようにしてください。 + +ネストが浅いレイアウトの場合、レイアウトの描画がより速くなります。深いビュー階層より、ワイドなビュー階層の方がより良いと言えます。 +
+ + + + + + + + + + + + + +アダプタを使ったレイアウトをビルドする
+ +レイアウトのコンテンツが動的または事前設定されていないとき、{@link android.widget.AdapterView} のサブクラスのレイアウトを使って、実行時にビューでレイアウトを設定できます。 +{@link android.widget.AdapterView} クラスのサブクラスでは、{@link android.widget.Adapter} を使ってそのレイアウトにデータがバインドされます。 + +{@link android.widget.Adapter} はデータソースと {@link android.widget.AdapterView} レイアウト間の仲介として動作します。{@link android.widget.Adapter} によって、配列やデータベース クエリのようなソースからデータが取得され、各エントリが {@link android.widget.AdapterView} レイアウトに追加できるビューに変換されます。 + + +
+ +アダプタでサポートされている共通レイアウトには次が含まれます。
+ + + + + + + +データを使ったアダプタビューを書き込む
+ +{@link android.widget.AdapterView} インスタンスを {@link android.widget.Adapter} にバインドして、{@link android.widget.ListView} や {@link android.widget.GridView} などの {@link android.widget.AdapterView} を入力できます。外部ソースのデータが取得され、各データエントリを表す {@link +android.view.View} が作成されます。 + +
+ +Android ではさまざまな種類のデータの取得と {@link android.widget.AdapterView} のビューのビルドに役立つ {@link android.widget.Adapter} のサブクラスがいくつか提供されます。 +最も一般的なアダプタは次の 2 つです。 +
+ +-
+
- {@link android.widget.ArrayAdapter} +
- データソースが配列の場合に、このアダプタを使います。デフォルトでは、{@link
+android.widget.ArrayAdapter} によって各アイテムで {@link
+java.lang.Object#toString()} が呼び出され、そのコンテンツが {@link
+android.widget.TextView} に配置されることで、各配列アイテムのビューが作成されます。
+
たとえば、{@link +android.widget.ListView} に表示する文字列の配列がある場合、コンストラクタを使って新しい {@link android.widget.ArrayAdapter} を初期化して、各文字列と文字列配列のレイアウトを指定します。 +
++ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_list_item_1, myStringArray); +
+このコンストラクタの引数を次に示します。
+-
+
- アプリの {@link android.content.Context} +
- 配列の各文字列に対して {@link android.widget.TextView} を含むレイアウト +
- 文字列配列 +
次に、{@link android.widget.ListView} で {@link android.widget.ListView#setAdapter setAdapter()} を呼び出します。 +
++ListView listView = (ListView) findViewById(R.id.listview); +listView.setAdapter(adapter); +
+ +各アイテムの概観をカスタマイズするには、自分の配列内のオブジェクトに {@link +java.lang.Object#toString()} メソッドをオーバーライドします。または、たとえば各配列アイテムに {@link android.widget.ImageView} が必要な場合など、{@link android.widget.TextView} 以外の各アイテムの表示を作成するには、{@link +android.widget.ArrayAdapter} クラスを拡張し、{@link android.widget.ArrayAdapter#getView +getView()} をオーバーライドして、各アイテムに必要なビュータイプが返されるようにします。 + +
+ +
+
+ - {@link android.widget.SimpleCursorAdapter} +
- {@link android.database.Cursor} から取得されたデータの場合は、このアダプタを使います。{@link android.widget.SimpleCursorAdapter} を使う場合は、{@link android.database.Cursor} で各行に使うレイアウトを指定して、{@link android.database.Cursor} のどの列をレイアウトのビューに挿入するのかを指定してください。
+
+
+たとえば、人の名前と電話番号のリストを作成する場合は、それぞれの人の行と、その名前と番号の列を含む {@link
+android.database.Cursor} を返すクエリを実行します。
+
+次に、それぞれの結果に対して {@link
+android.database.Cursor} のどの列をレイアウトに含めるかを指定する文字列配列と、各列が配置されるべき対応するビューを指定する整数配列を作成します。
+
+
+String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER}; +int[] toViews = {R.id.display_name, R.id.phone_number}; +
+{@link android.widget.SimpleCursorAdapter} のインスタンスを作成するとき、各結果に使うレイアウト、結果を含む {@link android.database.Cursor}、次の 2 つの配列を渡します。 +
++SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); +ListView listView = getListView(); +listView.setAdapter(adapter); +
+次に、{@link android.widget.SimpleCursorAdapter} によって、対応する {@code toViews} ビューに各 {@code +fromColumns} アイテムを挿入して提供されたレイアウトを使って {@link android.database.Cursor} で各行のビューが作成されます。 +
.
+
アプリケーションのライフサイクル中に、アダプタによって読み取られる基礎となるデータを変更する場合は、{@link android.widget.ArrayAdapter#notifyDataSetChanged()} を呼び出してください。 +これによって、データが変更されたアタッチされたビューが通知され、それ自体を更新する必要があることが通知されます。 +
+ + + +クリック イベントを処理する
+ +{@link android.widget.AdapterView.OnItemClickListener} インターフェースを実装して {@link android.widget.AdapterView} の各アイテムでのクリック イベントに応答できます。 +次に例を示します。
+ ++// Create a message handling object as an anonymous class. +private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, int position, long id) { + // Do something in response to the click + } +}; + +listView.setOnItemClickListener(mMessageClickedHandler); ++ + + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd b/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd new file mode 100644 index 0000000000000000000000000000000000000000..358fc304f60ab861614ec8ea969f918a8a90ec66 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/dialogs.jd @@ -0,0 +1,798 @@ +page.title=ダイアログ +page.tags=alertdialog,dialogfragment + +@jd:body + + + +
本書の内容
+-
+
- Dialog Fragment を作成する +
- アラート ダイアログをビルドする
+
-
+
- ボタンを追加する +
- リストを追加する +
- カスタム レイアウトを作成する +
+ - ダイアログのホストにイベントを渡す +
- ダイアログを表示する +
- 全画面でまたは埋め込まれたフラグメントとしてダイアログを表示する + + +
- ダイアログを閉じる +
キークラス
+-
+
- {@link android.app.DialogFragment} +
- {@link android.app.AlertDialog} +
関連ドキュメント
+-
+
- ダイアログ デザインのガイド +
- ピッカー(日付ダイアログと時刻ダイアログ) +
ダイアログは、ユーザーによる意思決定や追加情報の入力用に表示される小さなウィンドウです。 +ダイアログは全画面に表示されることはなく、通常はユーザーが処理を続ける前にアクションを起こす必要があるモーダル イベントに使用されます。 +
+ +ダイアログ デザイン
+ダイアログをデザインする方法について(言語に対する推奨を含む)は、ダイアログ デザインのガイドをお読みください。 +
+{@link android.app.Dialog} クラスは、ダイアログの基本クラスですが、{@link android.app.Dialog} ディレクトリのインスタンスを作成することは避けてください。代わりに、次のいずれかのサブクラスを使用します。 + +
+-
+
- {@link android.app.AlertDialog} +
- タイトル、最大 3 つのボタン、選択可能なアイテムやカスタム レイアウトのリストを表示できるダイアログ。 + +
- {@link android.app.DatePickerDialog} または {@link android.app.TimePickerDialog} +
- ユーザーが日付または時刻を選択できるようにあらかじめ定義された UI を含むダイアログ。 +
ProgressDialog を使用しない
+Android には、進捗バーを含むダイアログを表示する {@link android.app.ProgressDialog} という別のダイアログ クラスがあります。 +ただし、読み込み中または不確定な進捗状況を表示する必要がある場合は、Progress & Activity のデザイン ガイドラインに従って、レイアウトで {@link android.widget.ProgressBar} を使用してください。 + + +
+これらのクラスでは、ダイアログのスタイルと構造が定義されますが、ダイアログのコンテナとして {@link android.support.v4.app.DialogFragment} を使用してください。{@link android.support.v4.app.DialogFragment} クラスでは、{@link android.app.Dialog} オブジェクトでメソッドを呼び出す代わりに、ダイアログの作成と表示の管理に必要なすべてのコントロールが提供されます。 + + + +
+ +{@link android.support.v4.app.DialogFragment} を使ってダイアログを管理すると、ライフサイクル イベント([戻る] ボタンを押したときや画面を回転したときなど)が正しく処理されます。 + +{@link +android.support.v4.app.DialogFragment} クラスを使用すると、従来の {@link +android.support.v4.app.Fragment} のように、大きな UI で埋め込み可能なコンポーネントとしてダイアログの UI を再利用することもできます(ダイアログ UI を大小の画面で異なって表示させる場合など)。 + +
+ +このガイドの次のセクションでは、{@link android.app.AlertDialog} オブジェクトと組み合わせて {@link +android.support.v4.app.DialogFragment} を使用する方法について説明します。 +日付や時刻ピッカーを作成する場合は、「Pickers」のガイドをご覧ください。 +
+ +注: {@link android.app.DialogFragment} クラスは 元々 Android 3.0(API レベル 11)で追加されたため、このドキュメントではサポート ライブラリと一緒に提供される {@link
+android.support.v4.app.DialogFragment} クラスの使用方法について説明します。
+
+アプリにこのライブラリを追加すると、Android 1.6 以降を実行する端末で、{@link android.support.v4.app.DialogFragment} とその他のさまざまな API を使うことができます。
+
+アプリの最小バージョンで API レベル 11 以降がサポートされている場合、{@link
+android.app.DialogFragment} のフレームワーク バージョンを使用できますが、このドキュメントのリンクはサポート ライブラリ API 向けであることにご注意ください。
+
+サポート ライブラリを使用するときは、android.app.DialogFragment
ではなく、android.support.v4.app.DialogFragment
クラス をインポートしてください。
+
+
Dialog Fragment を作成する
+ +{@link android.support.v4.app.DialogFragment} を拡張して {@link android.support.v4.app.DialogFragment#onCreateDialog +onCreateDialog()} コールバック メソッドで {@link android.app.AlertDialog} を作成することで、さまざまなダイアログ デザイン(カスタム レイアウトやダイアログのデザインガイドで説明されているものを含む)を実現できます。 + + + +
+ +{@link android.support.v4.app.DialogFragment} で管理される基本的な {@link android.app.AlertDialog} を次に示します。 +
+ ++public class FireMissilesDialogFragment extends DialogFragment { + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Use the Builder class for convenient dialog construction + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // FIRE ZE MISSILES! + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); + // Create the AlertDialog object and return it + return builder.create(); + } +} ++ +
このクラスのインスタンスを作成してオブジェクトで {@link +android.support.v4.app.DialogFragment#show show()} を呼び出すと、図 1 のようなダイアログが表示されます。 +
+ +次のセクションでは、{@link android.app.AlertDialog.Builder} API を使ったダイアログの作成について詳細を説明します。 +
+ +ダイアログの複雑さに応じて、{@link android.support.v4.app.DialogFragment} ですべての基本的なフラグメントのライフサイクル メソッドを含む、他のさまざまなコールバック メソッドを実装できます。 + + + + + + + +
アラート ダイアログをビルドする
+ + +{@link android.app.AlertDialog} クラスを使って、さまざまなダイアログ デザインをビルドできます。ほとんどの場合、必要なダイアログ クラスはこれだけです。図 2 のように、アラート ダイアログには 3 つの領域があります。 + +
+ +-
+
- タイトル
+
この領域は省略可能で、コンテンツ エリアが詳細メッセージ、リスト、カスタム レイアウトで占有されている場合にのみ使う必要があります。 +単純なメッセージや質問(図 1 にあるダイアログなど)を記述する場合は、タイトルは必要ありません。 +
+ - コンテンツ エリア
+
メッセージ、リスト、その他のカスタム レイアウトを表示できます。
+ - アクション ボタン
+
1 つのダイアログ内に置くアクション ボタンは、3 つ以内にする必要があります。
+
{@link android.app.AlertDialog.Builder} クラスでは、カスタム レイアウトなど、これらの種類のコンテンツを含む {@link android.app.AlertDialog} を作成できます。 + +
+ +{@link android.app.AlertDialog} をビルドするには:
+ ++// 1. Instantiate an {@link android.app.AlertDialog.Builder} with its constructor +AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + +// 2. Chain together various setter methods to set the dialog characteristics +builder.setMessage(R.string.dialog_message) + .setTitle(R.string.dialog_title); + +// 3. Get the {@link android.app.AlertDialog} from {@link android.app.AlertDialog.Builder#create()} +AlertDialog dialog = builder.create(); ++ +
次のトピックでは、{@link android.app.AlertDialog.Builder} クラスを使ってさまざまなダイアログの属性を定義する方法を示します。 +
+ + + + +ボタンを追加する
+ +図 2 のようなアクション ボタンを追加するには、{@link android.app.AlertDialog.Builder#setPositiveButton setPositiveButton()} と {@link android.app.AlertDialog.Builder#setNegativeButton setNegativeButton()} メソッドを呼び出します。 + +
+ ++AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); +// Add the buttons +builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User clicked OK button + } + }); +builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + } + }); +// Set other dialog properties +... + +// Create the AlertDialog +AlertDialog dialog = builder.create(); ++ +
set...Button()
メソッドには、ボタンのタイトル(文字列リソースで指定)と、ユーザーがボタンを押したときに実行するアクションを定義する {@link android.content.DialogInterface.OnClickListener} が必要です。
+
+
+
追加できるアクション ボタンは、次の 3 つです。
+-
+
- Positive +
- アクションを受け入れて続ける場合に使います(「OK」アクション)。 +
- Negative +
- アクションをキャンセルする場合に使います。 +
- Neutral +
- ユーザーがアクションを続けたくない可能性があり、キャンセルしたいとは限らない場合に使います。 +ポジティブ ボタンとネガティブ ボタンの間に表示されます。 +たとえば、「後で通知する」のようなアクションの場合です。 +
各ボタンタイプのいずれか 1 つのみを {@link +android.app.AlertDialog} に追加できます。つまり、2 つ以上の「ポジティブ」ボタンを置くことはできません。
+ + + +リストを追加する
+ +{@link android.app.AlertDialog} API で使用できるリストは次の 3 種類です。
+-
+
- 従来の排他的選択リスト +
- 固定の排他的選択リスト(ラジオボタン) +
- 固定の複数選択リスト(チェックボックス) +
図 3 のように、排他的選択リストを作成するには、{@link android.app.AlertDialog.Builder#setItems setItems()} メソッドを使います。 +
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.pick_color) + .setItems(R.array.colors_array, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // The 'which' argument contains the index position + // of the selected item + } + }); + return builder.create(); +} ++ +
リストは、ダイアログのコンテンツ エリアに表示されるため、ダイアログにはメッセージとリストの両方は表示できません。{@link android.app.AlertDialog.Builder#setTitle setTitle()} でダイアログのタイトルを設定してください。 + +リストのアイテムを指定するには、{@link +android.app.AlertDialog.Builder#setItems setItems()} を呼び出して配列を渡します。{@link +android.app.AlertDialog.Builder#setAdapter setAdapter()} を使ってリストを指定することもできます。 + +こうすることで、{@link android.widget.ListAdapter} を使って、データベースからなど、ダイナミック データを含むリストを返すことができます。 +
+ +{@link android.widget.ListAdapter} を使ってリストを返すことを選択する場合は、必ず {@link android.support.v4.content.Loader} を使ってコンテンツが非同期で読み込まれるようにします。 + +この詳細については、「Building Layouts with an Adapter」と「ローダ」のガイドをご覧ください。 + + +
+ +注: デフォルトでは、次の固定選択リストのいずれかを使っていない場合、リストアイテムをタップするとダイアログが閉じられます。 +
+ +固定の複数選択または排他的選択リストを追加する
+ +複数選択アイテム(チェックボックス)または排他的選択アイテム(ラジオボタン)のリストを追加するには、{@link android.app.AlertDialog.Builder#setMultiChoiceItems(Cursor,String,String, +DialogInterface.OnMultiChoiceClickListener) setMultiChoiceItems()} または {@link android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} メソッドをそれぞれ使用します。 + + +
+ +{@link java.util.ArrayList} で選択されたアイテムを保存する、図 4 にあるような複数選択リストを作成する方法を次に示します。 + +
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + mSelectedItems = new ArrayList(); // Where we track the selected items + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Set the dialog title + builder.setTitle(R.string.pick_toppings) + // Specify the list array, the items to be selected by default (null for none), + // and the listener through which to receive callbacks when items are selected + .setMultiChoiceItems(R.array.toppings, null, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, + boolean isChecked) { + if (isChecked) { + // If the user checked the item, add it to the selected items + mSelectedItems.add(which); + } else if (mSelectedItems.contains(which)) { + // Else, if the item is already in the array, remove it + mSelectedItems.remove(Integer.valueOf(which)); + } + } + }) + // Set the action buttons + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // User clicked OK, so save the mSelectedItems results somewhere + // or return them to the component that opened the dialog + ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + ... + } + }); + + return builder.create(); +} ++ +
従来のリストとラジオボタンを含むリストでは、「排他的選択」アクションが提供されますが、ユーザーの選択を固定させたい場合は、{@link +android.app.AlertDialog.Builder#setSingleChoiceItems(int,int,DialogInterface.OnClickListener) +setSingleChoiceItems()} を使用してください。つまり、ダイアログを後でもう一度開く場合は、ユーザーの現在の選択を表示し、ラジオボタンを含むリストを作成します。 + + +
+ + + + + +カスタム レイアウトを作成する
+ +ダイアログでカスタム レイアウトが必要な場合は、レイアウトを作成し、{@link +android.app.AlertDialog.Builder} オブジェクトで {@link +android.app.AlertDialog.Builder#setView setView()} を呼び出して {@link android.app.AlertDialog} にそのレイアウトを追加します。 +
+ +デフォルトでは、カスタム レイアウトは、ダイアログ ウィンドウ全体に表示されますが、{@link android.app.AlertDialog.Builder} メソッドを使ってボタンとタイトルを追加できます。 +
+ +以下は、図 5 にあるダイアログのレイアウト ファイルです。
+ + ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ImageView + android:src="@drawable/header_logo" + android:layout_width="match_parent" + android:layout_height="64dp" + android:scaleType="center" + android:background="#FFFFBB33" + android:contentDescription="@string/app_name" /> + <EditText + android:id="@+id/username" + android:inputType="textEmailAddress" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="4dp" + android:hint="@string/username" /> + <EditText + android:id="@+id/password" + android:inputType="textPassword" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="16dp" + android:fontFamily="sans-serif" + android:hint="@string/password"/> +</LinearLayout> ++ +
ヒント: デフォルトでは、{@code "textPassword"} 入力タイプを使うために、{@link android.widget.EditText} 要素を設定すると、フォント ファミリーが monospace に設定されるため、フォント ファミリーを {@code "sans-serif"} に変えて、両方のテキスト フィールドで同じフォント スタイルが使用されるようにしてください。 + + +
+ +{@link android.support.v4.app.DialogFragment} でレイアウトをインフレートするには、{@link android.app.Activity#getLayoutInflater()} で {@link android.view.LayoutInflater} を取得して {@link android.view.LayoutInflater#inflate inflate()} を呼び出します。最初のパラメータは、レイアウト リソース ID で、2 番目のパラメータはレイアウトの親ビューです。その後、{@link android.app.AlertDialog#setView setView()} を呼び出してダイアログのレイアウトを配置できます。 + + + + + +
+ ++@Override +public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + LayoutInflater inflater = getActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + builder.setView(inflater.inflate(R.layout.dialog_signin, null)) + // Add action buttons + .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // sign in the user ... + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + LoginDialogFragment.this.getDialog().cancel(); + } + }); + return builder.create(); +} ++ +
ヒント: カスタム ダイアログが必要な場合は、{@link android.app.Dialog} API を使う代わりに、{@link android.app.Activity} をダイアログとして表示できます。 + +アクティビティを作り、{@code +<activity>} マニフェスト要素でそのテーマを {@link android.R.style#Theme_Holo_Dialog Theme.Holo.Dialog} に設定します。 + +
+ ++<activity android:theme="@android:style/Theme.Holo.Dialog" > ++
これだけです。これで、アクティビティは全画面でなく、ダイアログ ウィンドウに表示されるようになります。
+ダイアログのホストにイベントを渡す
+ +ユーザーがダイアログのアクション ボタンのいずれかをタップするか、そのリストからアイテムを選択すると、{@link android.support.v4.app.DialogFragment} によって必要なアクションが実行される場合がありますが、ダイアログを開くアクティビティやフラグメントにイベントを配信したい場合もよくあります。 + + +これを行うには、クリック イベントの各タイプのメソッドでインターフェースを定義します。次に、ダイアログからアクション イベントを受け取るホスト コンポーネントでインターフェースを実装します。 + +
+ +ホスト アクティビティにイベントを配信するインターフェースを定義する {@link android.support.v4.app.DialogFragment} を次に示します。 +
+ ++public class NoticeDialogFragment extends DialogFragment { + + /* The activity that creates an instance of this dialog fragment must + * implement this interface in order to receive event callbacks. + * Each method passes the DialogFragment in case the host needs to query it. */ + public interface NoticeDialogListener { + public void onDialogPositiveClick(DialogFragment dialog); + public void onDialogNegativeClick(DialogFragment dialog); + } + + // Use this instance of the interface to deliver action events + NoticeDialogListener mListener; + + // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + mListener = (NoticeDialogListener) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + ... +} ++ +
ダイアログをホスティングするアクティビティによって、ダイアログ フラグメントのコンストラクタを使ってダイアログのインスタンスが作成され、{@code NoticeDialogListener} インターフェースの実装によってダイアログのイベントが受信されます。 + +
+ ++public class MainActivity extends FragmentActivity + implements NoticeDialogFragment.NoticeDialogListener{ + ... + + public void showNoticeDialog() { + // Create an instance of the dialog fragment and show it + DialogFragment dialog = new NoticeDialogFragment(); + dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); + } + + // The dialog fragment receives a reference to this Activity through the + // Fragment.onAttach() callback, which it uses to call the following methods + // defined by the NoticeDialogFragment.NoticeDialogListener interface + @Override + public void onDialogPositiveClick(DialogFragment dialog) { + // User touched the dialog's positive button + ... + } + + @Override + public void onDialogNegativeClick(DialogFragment dialog) { + // User touched the dialog's negative button + ... + } +} ++ +
ホスト アクティビティによって、上記の {@link android.support.v4.app.Fragment#onAttach onAttach()} コールバック メソッドで適用される {@code NoticeDialogListener} が実装されるため、ダイアログ フラグメントではインターフェース コールバック メソッドを使ってアクティビティにクリック イベントを配信できます。 + + +
+ ++public class NoticeDialogFragment extends DialogFragment { + ... + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Build the dialog and set up the button click handlers + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.dialog_fire_missiles) + .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the positive button event back to the host activity + mListener.onDialogPositiveClick(NoticeDialogFragment.this); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Send the negative button event back to the host activity + mListener.onDialogNegativeClick(NoticeDialogFragment.this); + } + }); + return builder.create(); + } +} ++ + + +
ダイアログを表示する
+ +ダイアログを表示する場合、{@link +android.support.v4.app.DialogFragment} のインスタンスを作成して {@link android.support.v4.app.DialogFragment#show +show()} を呼び出し、{@link android.support.v4.app.FragmentManager} とダイアログ フラグメントのタグ名を渡します。 +
+ +{@link android.support.v4.app.FragmentActivity} から {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()} を、または {@link +android.support.v4.app.Fragment} から {@link +android.support.v4.app.Fragment#getFragmentManager()} を呼び出して {@link android.support.v4.app.FragmentManager} を取得できます。 + +次に例を示します。
+ ++public void confirmFireMissiles() { + DialogFragment newFragment = new FireMissilesDialogFragment(); + newFragment.show(getSupportFragmentManager(), "missiles"); +} ++ +
2 番目の引数 {@code "missiles"} は、固有のタグ名で、システムはこれを使って必要な時にフラグメントの状態を保存して復元します。 +そのタグを使って、{@link android.support.v4.app.FragmentManager#findFragmentByTag +findFragmentByTag()} を呼び出してフラグメントを操作することもできます。 +
+ + + + +全画面でまたは埋め込まれたフラグメントとしてダイアログを表示する
+ +場合によっては、UI の一部をダイアログとして表示させ、それ以外の場合には、たとえば端末の画面の大小に応じて、全画面や埋め込まれたフラグメントとして表示させるよう UI を設計できます。 + +{@link android.support.v4.app.DialogFragment} クラスは、埋め込み可能な {@link +android.support.v4.app.Fragment} として動作できるため、この柔軟性を実現できます。 +
+ +ただし、この場合は、{@link android.app.AlertDialog.Builder AlertDialog.Builder} やその他の {@link android.app.Dialog} オブジェクトを使ってダイアログをビルドできません。 +{@link android.support.v4.app.DialogFragment} を埋め込み可能にする場合、レイアウトでダイアログの UI を定義し、{@link android.support.v4.app.DialogFragment#onCreateView +onCreateView()} コールバックでレイアウトを読み込んでください。 + + +
+ +ダイアログまたは埋め込み可能なフラグメントのいずれかとして(purchase_items.xml
という名前のレイアウトを使って)表示できる {@link android.support.v4.app.DialogFragment} の例を次に示します。
+
+public class CustomDialogFragment extends DialogFragment { + /** The system calls this to get the DialogFragment's layout, regardless + of whether it's being displayed as a dialog or an embedded fragment. */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout to use as dialog or embedded fragment + return inflater.inflate(R.layout.purchase_items, container, false); + } + + /** The system calls this only when creating the layout in a dialog. */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // The only reason you might override this method when using onCreateView() is + // to modify any dialog characteristics. For example, the dialog includes a + // title by default, but your custom layout might not need it. So here you can + // remove the dialog title, but you must call the superclass to get the Dialog. + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + return dialog; + } +} ++ +
画面サイズに基づいて、フラグメントをダイアログとしてまたは全画面の UI として表示するかどうかを決めるコードの一例も示します。 +
+ ++public void showDialog() { + FragmentManager fragmentManager = getSupportFragmentManager(); + CustomDialogFragment newFragment = new CustomDialogFragment(); + + if (mIsLargeLayout) { + // The device is using a large layout, so show the fragment as a dialog + newFragment.show(fragmentManager, "dialog"); + } else { + // The device is smaller, so show the fragment fullscreen + FragmentTransaction transaction = fragmentManager.beginTransaction(); + // For a little polish, specify a transition animation + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); + // To make it fullscreen, use the 'content' root view as the container + // for the fragment, which is always the root view for the activity + transaction.add(android.R.id.content, newFragment) + .addToBackStack(null).commit(); + } +} ++ +
フラグメントのトランザクション実行の詳細については、「フラグメント」のガイドをご覧ください。 +
+ +この例では、mIsLargeLayout
ブール値によって、現在の端末でアプリの大きなレイアウト デザインを使う(その結果、全画面でなく、このフラグメントをダイアログとして表示する)かどうかが指定されます。
+
+この種のブール値を設定する最良の方法は、異なる画面サイズに対して別のリソース値でブールリソース値を宣言することです。
+
+次に、異なる画面サイズのブールリソースを 2 種類示します。
+
+<!-- Default boolean values --> +<resources> + <bool name="large_layout">false</bool> +</resources> ++ + +
+<!-- Large screen boolean values --> +<resources> + <bool name="large_layout">true</bool> +</resources> ++ +
アクティビティの {@link android.app.Activity#onCreate onCreate()} メソッド中に、{@code mIsLargeLayout} 値を初期化できます。 +
+ ++boolean mIsLargeLayout; + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mIsLargeLayout = getResources().getBoolean(R.bool.large_layout); +} ++ + + +
大画面でアクティビティをダイアログとして表示する
+ +小画面のときにダイアログを全画面の UI として表示するのではなく、大画面のときに {@link android.app.Activity} をダイアログとして表示することで、同じ結果を得ることができます。 + +どちらの方法を選択するかはアプリのデザインによって異なりますが、アプリが小画面で設計されていて、存在期間が短いアクティビティをダイアログとして示すことでタブレットでの使用感を改善するときには、ほとんどの場合、アクティビティをダイアログとして表示する方法が役立ちます。 + + +
+ +大画面のときにのみ、アクティビティをダイアログとして表示するには、{@link android.R.style#Theme_Holo_DialogWhenLarge Theme.Holo.DialogWhenLarge} テーマを {@code +<activity>} マニフェスト要素に適用します。 + +
+ ++<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" > ++ +
テーマを使ったアクティビティのスタイル指定についての詳細は、「Styles and Themes」をご覧ください。
+ + + +ダイアログを閉じる
+ +{@link android.app.AlertDialog.Builder} で作成したアクション ボタンのいずれかがタップされると、システムはダイアログを閉じます。 +
+ +また、リストでラジオボタンやチェックボックスが使われている場合を除き、ダイアログ リストでアイテムがタップされると、ダイアログが閉じます。 +それ以外の場合は、{@link +android.support.v4.app.DialogFragment} で {@link android.support.v4.app.DialogFragment#dismiss()} を呼び出してダイアログを手動で閉じることができます。 +
+ +ダイアログが閉じるときに、特定のアクションを実行する必要がある場合は、{@link +android.support.v4.app.DialogFragment} で {@link +android.support.v4.app.DialogFragment#onDismiss onDismiss()} メソッドを実装できます。 +
+ +ダイアログをキャンセルすることもできます。これは、ユーザーがタスクを完了せずに、明示的にダイアログを離れたことを示す特別なイベントです。 +ユーザーが [戻る] ボタンを押す、ダイアログ領域外の画面をタップする、または開発者が {@link +android.app.Dialog} で明示的に {@link android.app.Dialog#cancel()} を呼び出す(ダイアログの [キャンセル] ボタンに応じてなど)場合に実行されます。 + +
+ +上記の例のように、{@link +android.support.v4.app.DialogFragment} クラスで {@link android.support.v4.app.DialogFragment#onCancel onCancel()} を実装してキャンセル イベントに応答できます。 +
+ +注: システムによって、{@link android.support.v4.app.DialogFragment#onCancel onCancel()} コールバックを呼び出す各イベントで {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} が呼び出されます。 + +ただし、{@link android.app.Dialog#dismiss Dialog.dismiss()} や {@link +android.support.v4.app.DialogFragment#dismiss DialogFragment.dismiss()} を呼び出す場合、システムによって {@link android.support.v4.app.DialogFragment#onDismiss onDismiss()} が呼び出されますが、{@link android.support.v4.app.DialogFragment#onCancel onCancel()} は呼び出されません。 + + +通常は、ユーザーがダイアログのポジティブボタンを押すときに、{@link android.support.v4.app.DialogFragment#dismiss dismiss()} を呼び出して、ビューからダイアログが削除されるようにしてください。 + +
+ + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/menus.jd b/docs/html-intl/intl/ja/guide/topics/ui/menus.jd new file mode 100644 index 0000000000000000000000000000000000000000..7d8090e7a0ad616101036c53a2f87b5548df786f --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/menus.jd @@ -0,0 +1,1031 @@ +page.title=メニュー +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + +本書の内容
+-
+
- XML でのメニューの定義 +
- オプション メニューの作成 + + +
- コンテキスト メニューの作成 + + +
- ポップアップ メニューの作成
+
-
+
- クリック イベントを処理する +
+ - メニュー グループの作成 + + +
- インテントに基づくメニュー アイテムの追加 + + +
キークラス
+-
+
- {@link android.view.Menu} +
- {@link android.view.MenuItem} +
- {@link android.view.ContextMenu} +
- {@link android.view.ActionMode} +
関連ドキュメント
+ +メニューは、さまざまなタイプのアプリケーションで共通するユーザー インターフェースです。使い慣れた一貫した操作感を提供するには、{@link android.view.Menu} API を使ってアクティビティでユーザーのアクションとその他のオプションを表示する必要があります。 + +
+ +Android 3.0(API レベル 11)からは、Android 搭載端末では専用の Menu ボタンを表示する必要はなくなりました。 +この変更により、Android アプリでは従来の 6 アイテムのメニューパネルの依存関係から離れて、共通のユーザー アクションを表示するアクションバーを提供する必要があります。 + +
+ +一部のメニュー アイテムのデザインと操作感は変わりましたが、一連のアクションとオプションを定義する意味論は、引き続き {@link android.view.Menu} API に基づきます。 +このガイドでは、すべてのバージョンの Android で表示されるメニューやアクションの基本的な 3 タイプを作成する方法について説明します。 + +
+ +-
+
- オプション メニューとアクションバー +
- オプション メニューは、アクティビティの主なメニュー アイテムのコレクションです。
+ここには、「検索」、「メールの作成」、「設定」のような、アプリにグローバルな影響があるアクションを配置する必要があります。
+
+
Android 2.3 以前のバージョン向けに開発している場合は、ユーザーは Menu ボタンを押してオプション メニューパネルを表示できます。 +
+Android 3.0 以降の場合、オプション メニューのアイテムは、画面上のアクション アイテムとオーバーフロー オプションの組み合わせでアクションバーに表示されます。 +Android 3.0 からは、Menu ボタンが廃止されたため(一部の端末にはこのボタンがありません)、アクションバーを使ってアクションや他のオプションにアクセスできるよう移行する必要があります。 + + +
+オプション メニューの作成のセクションをご覧ください。
+
+
+ - コンテキスト メニューとコンテキスト アクション モード + +
- コンテキスト メニューは、ユーザーが要素を長押しクリックするときに表示されるフローティング メニューです。
+ここでは、選択したコンテンツやコンテキスト フレームに影響するアクションが提供されます。
+
+
Android 3.0 以降向けに開発している場合は、コンテキスト アクション モードを使って選択されたコンテンツでのアクションを有効にする必要があります。このモードでは、画面最上部にあるバーで選択されたコンテンツに影響するアクション アイテムが表示され、ユーザーは複数のアイテムを選択できます。 + +
+コンテキスト メニューの作成のセクションをご覧ください。
+
+
+ - ポップアップ メニュー +
- ポップアップ メニューでは、メニューを呼び出すビューに固定された縦方向のリストでアイテムが表示されます。
+特定のコンテンツに関連するアクションの概要を表示したり、コマンドの 2 番目の部分のオプションを表示したりする場合に適しています。
+ポップアップ メニューのアクションは対応するコンテンツに直接影響を与えないようにしてください(そのためにコンテキスト アクションがあります)。
+
+ポップアップ メニューは、アクティビティのコンテンツ領域に関連する拡張されたアクション用です。
+
+
ポップアップ メニューの作成のセクションをご覧ください。
+
+
XML でのメニューの定義
+ +Android では、すべてのメニュータイプに、メニュー アイテムを定義するための標準の XML 形式が提供されます。 +アクティビティのコードでメニューをビルドするのではなく、メニューとそのすべてのアイテムを XML メニュー リソースで定義してください。 +その際、アクティビティやフラグメントでメニュー リソースをインフレートできます({@link android.view.Menu} オブジェクトとして読み込む)。 + +
+ +メニュー リソースを使うことは、次のような理由で優れた方法と言えます。
+-
+
- XML でメニュー構造の視覚化が簡単になる。 +
- メニューのコンテンツを、アプリケーションの振る舞いコードと区別する。 +
- 別のプラットフォーム バージョン、画面サイズ、その他の構成用に、アプリリソース フレームワークを活用して、代替のメニュー構成を作ることができる。 + +
メニューを定義するには、プロジェクトの res/menu/
ディレクトリ内で XML ファイルを作成し、次の要素を含むメニューをビルドします。
+
-
+
<menu>
+ - メニュー アイテムのコンテナである {@link android.view.Menu} を定義します。
<menu>
要素は、ファイルのルートノードである必要があります。また、1 つ以上の<item>
と<group>
要素を持つことができます。 + +
+
+ <item>
+ - メニューで 1 つのアイテムを表示する {@link android.view.MenuItem} を作成します。この要素には、サブメニューを作成するために、ネストされた
<menu>
要素を含めることができます。 +
+
+ <group>
+ - 省略可能な {@code <item>} 要素の非表示コンテナ。メニュー アイテムでアクティブ状態や可視性のようなプロパティを共有できるよう、メニュー アイテムを分類できます。 +詳細については、メニュー グループの作成のセクションをご覧ください。 + +
game_menu.xml
という名前のメニュー例を次に示します。
+<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/new_game" + android:icon="@drawable/ic_new_game" + android:title="@string/new_game" + android:showAsAction="ifRoom"/> + <item android:id="@+id/help" + android:icon="@drawable/ic_help" + android:title="@string/help" /> +</menu> ++ +
<item>
要素では、アイテムの概観と動作を定義するために使用できるいくつかの属性がサポートされています。
+上記メニューのアイテムには、次の属性が含まれます。
-
+
- {@code android:id} +
- ユーザーがアイテムを選択するときに、アプリケーションがそのアイテムを認識できるようにする、アイテム固有のリソース ID。 + +
- {@code android:icon} +
- アイテムのアイコンとして使用するための、ドローアブルへの参照。 +
- {@code android:title} +
- アイテムのタイトルとして使用するための、文字列への参照。 +
- {@code android:showAsAction} +
- このアイテムがアクションバーのアクション アイテムとして、いつ、どのように表示される必要があるかを指定。 +
これらの属性は使用する必要のある最も重要なものですが、他にもさまざまな属性があります。サポートされているすべての属性については、「Menu Resource」のドキュメントをご覧ください。 +
+ +サブメニューを除くすべてのメニューで、{@code <item>} の子として {@code <menu>} 要素を追加すると、アイテムにサブメニューを追加できます。 +PC アプリケーションのメニューバー(ファイル、編集、表示など)にあるアイテムのように、アプリケーションにトピックで分類できる多くの機能がある場合は、サブメニューが役立ちます。 + +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/file" + android:title="@string/file" > + <!-- "file" submenu --> + <menu> + <item android:id="@+id/create_new" + android:title="@string/create_new" /> + <item android:id="@+id/open" + android:title="@string/open" /> + </menu> + </item> +</menu> ++ +
アクティビティでメニューを使うには、{@link android.view.MenuInflater#inflate(int,Menu) +MenuInflater.inflate()} を使って、メニュー リソースをインフレートする(XML リソースをプログラム可能なオブジェクトに変換する)必要があります。 +次のセクションでは、各メニュー アイテムのメニューをインフレートする方法を説明します。 +
+ + + +オプション メニューの作成
+ +オプション メニューでは、「検索」、「メールの作成」、「設定」のような、現在のアクティビティ コンテキストに関連するアクションとその他のオプションを含める必要があります。 +
+ +オプション メニューのアイテムが画面上のどこに表示されるかは、開発対象のアプリケーションのバージョンによって異なります。 +
+ +-
+
- Android 2.3.x(API レベル 10)以前 向けにアプリケーションを開発した場合、ユーザーが Menu ボタンを押すときに、図 1 のように、オプション メニューのコンテンツが画面下部に表示されます。 + +開いて最初に表示される部分は、最大 6 つのメニュー アイテムで構成されるアイコン メニューです。 + +7 つ以上のメニュー アイテムが含まれている場合、Android では 6 番目以降のアイテムがオーバーフロー メニューに配置されます。それらのアイテムは、もっと見る を選択して開くことができます。 + + + +
- Android 3.0(API レベル 11)以降向けにアプリケーションを開発した場合、オプション メニューのアイテムはアクションバーに表示されます。
+デフォルトでは、システムによってアクション オーバーフローにすべてのアイテムが配置され、ユーザーはアクションバー右端にあるアクション オーバーフロー アイコンを使ってそのアイテムを表示できます。端末に Menu ボタンがある場合はそのボタンを押して表示できます。
+
+重要なアクションにすみやかにアクセスできるようにするには、対応する {@code <item>} 要素に {@code android:showAsAction="ifRoom"} を追加して、いくつかのアイテムをアクションバーに表示させるようプロモートできます(図 2を参照)。
+
+
+
+
アクション アイテムと他のアクションバーの動作の詳細については、「Action Bar」のガイドをご覧ください。
+注: Android 3.0 以降向けに開発していない場合でも、同様の効果のために、自分のアクションバー レイアウトをビルドできます。 +アクションバー付きで以前のバージョンの Android をサポートする方法の一例については、アクションバーの互換性のサンプルをご覧ください。 + +
+
+
{@link android.app.Activity} サブクラスや {@link android.app.Fragment} サブクラスのいずれかからオプション メニューのアイテムを宣言できます。 +アクティビティとフラグメントの両方でオプション メニューのアイテムを宣言する場合、それらは UI に統合されます。まず、アクティビティのアイテムが表示され、次にアクティビティに各フラグメントが追加される順序で各フラグメントのアイテムが表示されます。 + + +必要に応じて、移動する必要のある各 {@code <item>} で {@code android:orderInCategory} 属性を使ってメニュー アイテムの順序を並べ替えることができます。 +
+ +アクティビティのオプション メニューを指定するには、{@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をオーバーライドします(フラグメントは独自の {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} コールバックを提供)。 +このメソッドでは、メニュー リソース(XML で定義)をコールバックで提供される {@link +android.view.Menu} にインフレートできます。 +次に例を示します。
+ ++@Override +public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = {@link android.app.Activity#getMenuInflater()}; + inflater.inflate(R.menu.game_menu, menu); + return true; +} ++ +
{@link android.view.Menu#add(int,int,int,int) +add()} を使ってメニュー アイテムを追加し、{@link android.view.MenuItem} API でそのプロパティを修正するために、{@link android.view.Menu#findItem findItem()} でアイテムを取得することもできます。 +
+ +Android 2.3.x 以前向けにアプリケーションを開発した場合、システムは {@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、ユーザーが初めてそのメニューを開いたときにオプション メニューが作成されます。 +Android 3.0 以降向けに開発した場合、アクティビティの開始時にシステムが {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、アクションバーにアイテムが表示されるようにします。 + +
+ + + +クリック イベントを処理する
+ +ユーザーがオプション メニューからアイテムを選択すると(アクションバーのアクション アイテムを含む)、アクティビティの {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()} メソッドが呼び出されます。 +このメソッドでは、選択された {@link android.view.MenuItem} が渡されます。{@link android.view.MenuItem#getItemId()} を呼び出してアイテムを識別できます。これにより、メニュー アイテムに対して一意の ID が返されます(メニュー リソースで {@code android:id} 属性を定義するか、{@link android.view.Menu#add(int,int,int,int) add()} メソッドに指定された整数で)。 + + +この ID を既知のメニュー アイテムと突き合わせて適切なアクションを実行できます。 +次に例を示します。
+ ++@Override +public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.new_game: + newGame(); + return true; + case R.id.help: + showHelp(); + return true; + default: + return super.onOptionsItemSelected(item); + } +} ++ +
メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、{@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のスーパークラスの実装を呼び出す必要があります(デフォルトの実装では fause が返されます)。 + +
+ +アクティビティにフラグメントが含まれる場合は、システムはまずアクティビティに対して {@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} を呼び出し、次に {@code true} が返されるまで、またはすべてのフラグメントが呼び出されるまで、各フラグメントが追加された順序で、各フラグメントに対して呼び出します。 + +
+ +ヒント: Android 3.0 では、{@code android:onClick} 属性を使って、メニュー アイテムのクリックでの動作を XML で定義できます。 +その属性値は、メニューを使ってアクティビティによって定義されるメソッド名である必要があります。 +そのメソッドは、パブリックであり、1 つの {@link android.view.MenuItem} パラメータを使用できる必要があります。システムがこのメソッドを呼び出すと、選択したメニュー アイテムが渡されます。 + +詳細と例については、「Menu Resource」のドキュメントをご覧ください。
+ +ヒント: アプリケーションに複数のアクティビティが含まれていて、その一部で同じオプション メニューが提供されている場合、{@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} と {@link android.app.Activity#onOptionsItemSelected(MenuItem) +onOptionsItemSelected()} メソッドのみを実装するアクティビティを作成することを検討します。 + +その後、同じオプション メニューを共有する必要のある各アクティビティのこのクラスを拡張します。 +この方法で、メニューの動作を継承するメニュー アクションとそれぞれの子クラスを処理するためのコードを 1 セットで管理できます。子孫アクティビティの 1 つにメニュー アイテムを追加する場合は、そのアクティビティの {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} をオーバーライドします。 + + +元のメニュー アイテムが作成されるように、{@code super.onCreateOptionsMenu(menu)} を呼び出し、{@link +android.view.Menu#add(int,int,int,int) menu.add()} で新しいメニュー アイテムを追加します。 +各メニュー アイテムのスーパークラスの行動をオーバーライドすることもできます。 +
+ + +実行時におけるメニュー アイテムの変更
+ +システムが {@link android.app.Activity#onCreateOptionsMenu(Menu) +onCreateOptionsMenu()} を呼び出した後、入力する {@link android.view.Menu} のインスタンスは残り、何らかの理由でメニューが無効にならない限り、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をもう一度呼び出すことはありません。 + +ただし、初期のメニュー状態を作成し、アクティビティのライフサイクル中に変更しないという目的の場合に限って、{@link +android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を使用する必要があります。 +
+ +アクティビティのライフサイクル中に発生するイベントに基づいてオプション メニューを変更する場合は、{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} メソッドでそれを実行できます。 + +このメソッドは、現在存在している {@link android.view.Menu} オブジェクトを渡し、それを編集(アイテムの追加、削除、無効化など)できるようにします。 + +(フラグメントでも {@link +android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} コールバックが提供されます)。
+ +Android 2.3.x 以前では、ユーザーが Menu ボタンを押してオプション メニューを開くたびに、システムによって {@link +android.app.Activity#onPrepareOptionsMenu(Menu) +onPrepareOptionsMenu()} が呼び出されます。 +
+ +Android 3.0 以降では、メニュー アイテムがアクションバーに表示されるときに、オプション メニューが常に開かれるとみなされます。 +イベントが発生し、メニューをアップデートするときは、{@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} を呼び出して、システムが {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} を呼び出すようリクエストする必要があります。 + +
+ +注: 現在フォーカスされている {@link android.view.View} に基づいてオプション メニューでアイテムを変更しないでください。 + +タッチモードの場合(ユーザーがトラックボールやリモコンの矢印ボタンを使うとき)、ビューはフォーカスを取得できないため、オプション メニューのアイテム変更のベースとしてフォーカスを使用しないでください。 + +{@link +android.view.View} に状況依存のメニュー アイテムを提供する場合は、コンテキスト メニューを使います。
+ + + + +コンテキスト メニューの作成
+ +コンテキスト メニューでは、UI の特定のアイテムやコンテキスト フレームに影響するアクションが提供されます。どのビューでもコンテキスト メニューを提供できますが、ほとんどの場合は、{@link +android.widget.ListView}、{@link android.widget.GridView}、各アイテムでユーザーが直接実行できるその他のビュー コレクションのアイテムに使用されます。 + +
+ +コンテキスト アクションを提供するには次の 2 つの方法があります。
+-
+
- フローティング コンテキスト メニューで。メニューは、ユーザーが長押しクリックする(押したままにする)と、コンテキスト メニューのサポートを宣言するビュー上で、メニュー アイテムのフローティング リストとして表示されます。 + +ユーザーは、一度に 1 つのアイテムでコンテキスト アクションを実行できます。 + + +
- コンテキスト アクション モードで。このモードは、選択されたアイテムに影響するアクション アイテムと一緒に画面最上部にコンテキスト アクションバーを表示する {@link android.view.ActionMode} のシステム実装です。 + +このモードがアクティブなとき、ユーザーは一度に複数のアイテムでアクションを実行できます(アプリで許可されている場合)。 + +
注: コンテキスト アクション モードは、Android 3.0(API レベル 11)以降で使用可能で、使用可能な場合にコンテキスト アクションを表示するのに適した方法です。 + +アプリで 3.0 以前のバージョンをサポートする場合、その端末ではフローティング コンテキスト メニューを使う必要があります。 +
+ + +フローティング コンテキスト メニューの作成
+ +フローティング コンテキスト メニューを提供するには:
+-
+
- {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} を呼び出し、{@link android.view.View} を渡して、コンテキスト メニューに関連付ける必要のある {@link android.view.View} を登録します。
+
+
+
アクティビティで {@link android.widget.ListView} や {@link android.widget.GridView} が使用され、各アイテムに同じコンテキスト メニューを提供する場合、{@link android.widget.ListView} や {@link android.widget.GridView} を {@link +android.app.Activity#registerForContextMenu(View) registerForContextMenu()} に渡してコンテキスト メニューにすべてのアイテムを登録します。 + +
+
+
+ - {@link android.app.Activity} や {@link android.app.Fragment} に {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} メソッドを実装します。
+
+
登録されたビューが長押しクリック イベントを受け取ると、システムは {@link +android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} メソッドを呼び出します。 +通常、ここでメニュー リソースをインフレートして、メニュー アイテムを定義します。次に例を示します。 +
++@Override +public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); +} +
+ +{@link android.view.MenuInflater} では、メニュー リソースからコンテキスト メニューをインフレートできます。そのコールバック メソッド パラメータには、ユーザーが選択した {@link android.view.View} と選択されたアイテムに関する追加情報を提供する {@link android.view.ContextMenu.ContextMenuInfo} オブジェクトが含まれます。 + + +アクティビティに、それぞれ別のコンテキスト メニューを提供する複数のビューがある場合、これらのパラメータを使ってインフレートするコンテキスト メニューを決定できます。 + +
+
+
+ - {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()} を実装します。
+
ユーザーがメニュー アイテムを選択すると、システムによってこのメソッドが呼び出され、適切なアクションを実行できるようになります。 +次に例を示します。
+ ++@Override +public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + switch (item.getItemId()) { + case R.id.edit: + editNote(info.id); + return true; + case R.id.delete: + deleteNote(info.id); + return true; + default: + return super.onContextItemSelected(item); + } +} +
+ +{@link android.view.MenuItem#getItemId()} メソッドは、選択されたメニュー アイテムの ID を照会します。XML でメニューを定義するのセクションで説明されているように、{@code +android:id} 属性を使って XML で各メニュー アイテムを割り当てる必要があります。 + +
+ +メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、スーパークラスの実装にメニュー アイテムを渡す必要があります。 +アクティビティにフラグメントが含まれる場合、そのアクティビティは最初にこのコールバックを受け取ります。 +未処理のときにスーパークラスを呼び出すと、システムは {@code true} や {@code false} が返されるまで、各フラグメントのそれぞれのコールバック メソッドに 1 つずつ、各フラグメントが追加された順序でイベントを渡します。 + +{@link android.app.Activity} と {@code android.app.Fragment} のデフォルトの実装では {@code +false} が返されるため、未処理のときは常にスーパークラスを呼び出す必要があります。 +
+
+
コンテキスト アクション モードの使用
+ +コンテキスト アクション モードは、{@link android.view.ActionMode} のシステム実装で、ユーザーによるコンテキスト アクション実行のための操作に焦点が置かれています。 +ユーザーがアイテムを選択してこのモードを有効にすると、画面の最上部にコンテキスト アクションバーが表示され、現在選択中のアイテムで実行できるアクションが表示されます。 + +このモードが有効な間は、ユーザーは複数のアイテムを選択したり(許可されている場合)、アイテムを選択解除したり、アクティビティ内を移動し続けたり(許可されている範囲内で)することができます。 + +ユーザーがすべてのアイテムの選択を解除したり、Back ボタンをしたり、またはバーの左端で Done アクションを選択したりすると、このアクション モードは無効になり、コンテキスト アクションバーは表示されなくなります。 + +
+ +注: コンテキスト アクションバーをアクションバーと関連付ける必要はありません。 +コンテキスト アクションバーが、視覚的にアクションバーの位置にかかる場合でも、個別に操作できます。 + +
+ +Android 3.0(API レベル 11)以降向けに開発中の場合、通常はフローティング コンテキスト メニューではなく、コンテキスト アクション モードを使ってコンテキスト アクションを表示します。 +
+ +コンテキスト アクションを提供するビューでは、通常は次の 2 つのイベントのいずれかまたは両方で、コンテキスト アクションを呼び出す必要があります。 +
+-
+
- ユーザーがビューで長押しクリックする。 +
- ユーザーがチェックボックスまたは同様の UI コンポーネントをビュー内で選択する。 +
アプリケーションがどのようにコンテキスト アクション モードを呼び出して各アクションの動作を定義するかは、デザインによって異なります。 +基本的に次の 2 つのデザインがあります。
+-
+
- 個別の任意のビューでのコンテキスト アクション用。 +
- {@link +android.widget.ListView} または {@link android.widget.GridView} のアイテム グループでのバッチ コンテキスト アクション用(ユーザーが複数のアイテムを選択し、そのすべてにアクションを実行できるようにする)。 + +
次のセクションでは、各シナリオに必要な設定について説明します。
+ + +個別のビューに対してコンテキスト アクション モードを有効にする
+ +ユーザーが特定のビューを選択するときにのみ、コンテキスト アクション モードを呼び出すには、次のことを行う必要があります。 +
+-
+
- {@link android.view.ActionMode.Callback} インターフェースを実装します。このコールバック メソッドでは、コンテキスト アクションバーに対してアクションを指定して、アクション アイテムでのイベント クリックに応答し、アクション モードのその他のライフサイクル イベントを処理できます。 + + +
- ユーザーがビューを長押しクリックしたときなど、バーを表示するときに、{@link android.app.Activity#startActionMode startActionMode()} を呼び出します。 + +
次に例を示します。
+ +-
+
- {@link android.view.ActionMode.Callback ActionMode.Callback} インターフェースを実装します。
+
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { + + // Called when the action mode is created; startActionMode() was called + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate a menu resource providing context menu items + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context_menu, menu); + return true; + } + + // Called each time the action mode is shown. Always called after onCreateActionMode, but + // may be called multiple times if the mode is invalidated. + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; // Return false if nothing is done + } + + // Called when the user selects a contextual menu item + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_share: + shareCurrentItem(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + // Called when the user exits the action mode + @Override + public void onDestroyActionMode(ActionMode mode) { + mActionMode = null; + } +}; +
+ +これらのイベント コールバックは、これらのそれぞれもイベントに関連する {@link +android.view.ActionMode} オブジェクトを渡すこと以外は、オプション メニューのコールバックとほぼ同じです。{@link +android.view.ActionMode} API を使って、{@link android.view.ActionMode#setTitle setTitle()} と {@link +android.view.ActionMode#setSubtitle setSubtitle()}(選択されているアイテム数を表示するのに役立つ)でタイトルとサブタイトルを変更するなど、CAB にさまざまな変更を行うことができます。 + +
+ +また、上記のサンプルでは、アクション モードが破棄されるときに {@code mActionMode} 変数が null に設定されます。 +次のステップでは、それがどのように初期化され、アクティビティやフラグメントでどのようにメンバー変数を保存するのが役立つかについて説明します。 +
+
+
+ - {@link android.app.Activity#startActionMode startActionMode()} を呼び出して、{@link
+android.view.View} で長押しクリックに応答するときなど、適切な時にコンテキスト アクション モードを有効にします。
+
+
+
+someView.setOnLongClickListener(new View.OnLongClickListener() { + // Called when the user long-clicks on someView + public boolean onLongClick(View view) { + if (mActionMode != null) { + return false; + } + + // Start the CAB using the ActionMode.Callback defined above + mActionMode = getActivity().startActionMode(mActionModeCallback); + view.setSelected(true); + return true; + } +}); +
+ +{@link android.app.Activity#startActionMode startActionMode()} を呼び出すと、システムは作成された {@link android.view.ActionMode} を返します。 +メンバー変数でこれを保存すると、その他のイベントに応じてコンテキスト アクションバーを変更できます。 +上記の例では、{@link android.view.ActionMode} を使って、{@link android.view.ActionMode} インスタンスがアクティブな状態である場合に、アクション モードを開始する前にメンバーが null であるかどうかを確認して、そのインスタンスが再作成されないようにしています。 + + +
+
+
バッチ コンテキスト アクションを ListView または GridView で有効にする
+ +{@link android.widget.ListView} や {@link +android.widget.GridView}(または {@link android.widget.AbsListView} の別の拡張)にアイテムのコレクションがあり、ユーザーがバッチ アクションを実行できるようにする場合は、次のことを行う必要があります。 +
+ +-
+
- {@link android.widget.AbsListView.MultiChoiceModeListener} インターフェースを実装して、{@link android.widget.AbsListView#setMultiChoiceModeListener +setMultiChoiceModeListener()} で ViewGroup にそれを設定する。 +リスナのコールバック メソッドでは、コンテキスト アクションバーに対してアクションを指定して、アクション アイテムでのイベント クリックに応答し、{@link android.view.ActionMode.Callback} インターフェースから継承されるその他のコールバックを処理できます。 + + + +
- {@link +android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL} 引数で {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} を呼び出す。 +
次に例を示します。
+ ++ListView listView = getListView(); +listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); +listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, + long id, boolean checked) { + // Here you can do something when items are selected/de-selected, + // such as update the title in the CAB + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // Respond to clicks on the actions in the CAB + switch (item.getItemId()) { + case R.id.menu_delete: + deleteSelectedItems(); + mode.finish(); // Action picked, so close the CAB + return true; + default: + return false; + } + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate the menu for the CAB + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.context, menu); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Here you can make any necessary updates to the activity when + // the CAB is removed. By default, selected items are deselected/unchecked. + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // Here you can perform updates to the CAB due to + // an {@link android.view.ActionMode#invalidate} request + return false; + } +}); ++ +
これだけです。これで、ユーザーが長押しクリックでアイテムを選択すると、システムは {@link +android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()} メソッドを呼び出して、特定のアクションでコンテキスト アクションバーを表示するようになります。 +コンテキスト アクションバーが表示されている間は、追加のアイテムを選択できます。 +
+ +コンテキスト アクションによって一般的なアクション アイテムが提供されるとき、ユーザーが長押しクリックの動作に気付かない可能性があることを考慮して、アイテムを選択できるようにチェックボックスや同様の UI 要素を追加したい場合もあります。 + +ユーザーがチェックボックスをオンにするとき、{@link android.widget.AbsListView#setItemChecked setItemChecked()} でオンにされた状態にそれぞれのリストアイテムを設定して、コンテキスト アクション モードを呼び出すことができます。 + +
+ + + + +ポップアップ メニューの作成
+ +図 4.右上のオーバーフローボタンに固定された Gmail アプリのポップアップ メニュー。 +
+{@link android.widget.PopupMenu} は {@link android.view.View} に固定されるモーダル メニューです。スペースがある場合にはアンカービューの下に、スペースがない場合はビューの上に表示されます。 +次の場合に役立ちます。
+-
+
- 特定のコンテンツに関連するアクションにオーバーフロー スタイルのメニューを提供する(図 4 にある Gmail のメールヘッダーなど)。
+
+
注: これは、通常は選択したコンテンツに影響するアクション用であるコンテキスト メニューとは異なります。 +選択したコンテンツに影響するアクションには、コンテキスト アクション モードやフローティング コンテキスト メニューを使います。 +
+ - コマンド センテンスの 2 番目の部分を提供する(別の「追加」オプションを含むポップアップ メニューを生成する「追加」とマークされたボタンなど)。 + +
- 固定選択を保持しない {@link android.widget.Spinner} のようなドロップダウンを提供する。 + +
注: {@link android.widget.PopupMenu} は API レベル 11 以降で使用できます。 +
+ +XML でメニューを定義する場合の、ポップアップ メニューの表示方法について、次に示します。
+-
+
- そのコンストラクタを使って {@link android.widget.PopupMenu} のインスタンスを作成します。これにより、メニューが固定される必要のある、現在のアプリケーションの {@link android.content.Context} と {@link android.view.View} が取得されます。 + + +
- {@link android.view.MenuInflater} を使って、{@link +android.widget.PopupMenu#getMenu() PopupMenu.getMenu()} によって返される {@link +android.view.Menu} オブジェクトにメニュー リソースをインフレートします。API レベル 14 以降では、代わりに {@link android.widget.PopupMenu#inflate PopupMenu.inflate()} を使うことができます。 + +
- {@link android.widget.PopupMenu#show() PopupMenu.show()} を呼び出します。 +
ポップアップ メニューを表示する {@link android.R.attr#onClick android:onClick} 属性を含むボタンの一例を以下に示します。 +
+ ++<ImageButton + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_overflow_holo_dark" + android:contentDescription="@string/descr_overflow_button" + android:onClick="showPopup" /> ++ +
アクティビティでは、次のようにポップアップ メニューが表示されます。
+ ++public void showPopup(View v) { + PopupMenu popup = new PopupMenu(this, v); + MenuInflater inflater = popup.getMenuInflater(); + inflater.inflate(R.menu.actions, popup.getMenu()); + popup.show(); +} ++ +
API レベル 14 以降では、{@link +android.widget.PopupMenu#inflate PopupMenu.inflate()} でメニューをインフレートする 2 行を組み合わせることができます。
+ +ユーザーがアイテムを選択するか、メニュー領域外をタップすると、メニューが閉じます。 +{@link +android.widget.PopupMenu.OnDismissListener} を使って dismiss イベントをリッスンできます。
+ +クリック イベントを処理する
+ +ユーザーがアイテム メニューを選択するときにアクションを実行するには、{@link +android.widget.PopupMenu.OnMenuItemClickListener} インターフェースを実装し、{@link android.widget.PopupMenu#setOnMenuItemClickListener +setOnMenuItemclickListener()} を呼び出して {@link +android.widget.PopupMenu} でそれを登録する必要があります。 +ユーザーがアイテムを選択すると、インターフェースで {@link +android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} コールバックが呼び出されます。 +
+ +次に例を示します。
+ ++public void showMenu(View v) { + PopupMenu popup = new PopupMenu(this, v); + + // This activity implements OnMenuItemClickListener + popup.setOnMenuItemClickListener(this); + popup.inflate(R.menu.actions); + popup.show(); +} + +@Override +public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.archive: + archive(item); + return true; + case R.id.delete: + delete(item); + return true; + default: + return false; + } +} ++ + +
メニュー グループの作成
+ +メニュー グループは、特定の特徴を共有するメニュー アイテムのコレクションです。グループを使って次のことを実行できます。 +
+-
+
- {@link android.view.Menu#setGroupVisible(int,boolean) +setGroupVisible()} ですべてのアイテムを表示または非表示にする +
- {@link android.view.Menu#setGroupEnabled(int,boolean) +setGroupEnabled()} ですべてのアイテムを有効または無効にする +
- {@link +android.view.Menu#setGroupCheckable(int,boolean,boolean) setGroupCheckable()} ですべてのアイテムをオンにできるかどうかを指定する +
メニュー リソースの {@code <group>} 要素内で {@code <item>} 要素をネストするか、{@link +android.view.Menu#add(int,int,int,int) add()} メソッドでグループ ID を指定して、グループを作成できます。 +
+ +グループを含むメニュー リソースの一例を次に示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menu_save" + android:icon="@drawable/menu_save" + android:title="@string/menu_save" /> + <!-- menu group --> + <group android:id="@+id/group_delete"> + <item android:id="@+id/menu_archive" + android:title="@string/menu_archive" /> + <item android:id="@+id/menu_delete" + android:title="@string/menu_delete" /> + </group> +</menu> ++ +
グループ内のアイテムは、最初のアイテムと同じレベルで表示されます(メニューの 3 つのアイテムすべてが兄弟)。 +ただし、グループ ID を参照するか、上記のメソッドを使って、グループ内の 2 つのアイテムの特徴を変更できます。 +システムが、グループ化されたアイテムを分けることもありません。 +たとえば、各アイテムに {@code +android:showAsAction="ifRoom"} を宣言する場合、その両方がアクションバーまたはアクション オーバーフローに表示されます。 +
+ + +オンにできるメニュー アイテムの使用
+ +メニューは、オプションのオンとオフを切り替えるインターフェースとして役立ちます。スタンドアロンのオプションにはチェックボックスを、相互に排他的なオプションのグループにはラジオボタンを使います。 + +図 5 に、ラジオボタン付きのオンにできるアイテムを含むサブメニューを示します。 +
+ +注: アイコン メニューのメニュー アイテム(オプション メニューから)ではチェックボックスやラジオボタンを表示できません。 +アイコン メニューのアイテムをオンにできるようにする場合、状態が変わるごとにアイコンやテキストを入れ替えて、オンにされた状態を手動で示す必要があります。 + +
+ +個々のメニュー アイテムには {@code <item>} 要素の {@code +android:checkable} 属性を、グループ全体には {@code <group>} 要素の {@code android:checkableBehavior} 属性を使って、オンにできる動作を定義できます。 +たとえば、このメニュー グループのすべてのアイテムはラジオボタンでオンにできます。 +
+ ++<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:checkableBehavior="single"> + <item android:id="@+id/red" + android:title="@string/red" /> + <item android:id="@+id/blue" + android:title="@string/blue" /> + </group> +</menu> ++ +
{@code android:checkableBehavior} 属性では、次のいずれかが許容されます。 +
-
+
- {@code single} +
- グループから 1 つのアイテムのみをオンにできる(ラジオボタン) +
- {@code all} +
- すべてのアイテムをオンにできる(チェックボックス) +
- {@code none} +
- どのアイテムもオンにできない +
{@code <item>} 要素の {@code android:checked} 属性を使って、デフォルトのオンにされた状態をアイテムに適用でき、{@link +android.view.MenuItem#setChecked(boolean) setChecked()} メソッドを使ってコード内でそれを変更できます。 +
+ +オンにできるアイテムが選択されると、システムは {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような、それぞれの item-selected コールバック メソッドを呼び出します。 +チェックボックスやラジオボタンによって自動的にその状態が変わることはないため、ここでチェックボックスの状態を設定する必要があります。 + +{@link android.view.MenuItem#isChecked()} で、アイテムの現在の状態(ユーザーが選択する前の状態)を照会できます。その後、{@link android.view.MenuItem#setChecked(boolean) setChecked()} でオンにされた状態を設定します。 + +次に例を示します。
+ ++@Override +public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.vibrate: + case R.id.dont_vibrate: + if (item.isChecked()) item.setChecked(false); + else item.setChecked(true); + return true; + default: + return super.onOptionsItemSelected(item); + } +} ++ +
この方法でオンにされた状態を設定しない場合には、アイテム(チェックボックスまたはラジオボタン)の表示状態はユーザーがオンにしたときに変更されません。 + +状態を設定すると、アクティビティはアイテムのオンにされた状態を維持して、ユーザーが後でメニューを開いたときに、開発者が設定したオンにされた状態が表示されるようになります。 + +
+ +注: オンにできるメニュー アイテムは、セッション単位ベースのみでの使用を意図したもので、アプリケーションが破棄された後は、保存されません。 + +ユーザー用に保存するアプリケーション設定がある場合は、共有のプリファレンスを使ってデータを保存してください。 +
+ + + +インテントに基づくメニュー アイテムの追加
+ +{@link android.content.Intent} を使ってメニュー アイテムでアクティビティが起動されるようにしたい場合もあります(自分のアプリケーションのアクティビティであるか、別のアプリケーションのアクティビティであるかにかかわらず)。 +使用するインテントがわかっていて、インテントを開始する必要のある特定のメニュー アイテムがある場合は、適切な on-item-selected コールバック メソッド({@link +android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような)中に、{@link android.app.Activity#startActivity(Intent) startActivity()} でインテントを実行できます。 + + +
+ +ただし、ユーザーの端末にインテントを処理するアプリケーションが含まれているかどうかが不明な場合、それを呼び出すメニュー アイテムを追加すると、そのインテントによってアクティビティが解決されないためにメニュー アイテムが機能しなくなることがあります。 + + +これを解決するために、Android では、インテントを処理する端末で Android によってアクティビティが検出されるときに、メニュー アイテムがメニューに動的に追加されるようにします。 +
+ +インテントを受け入れる使用可能なアクティビティに基づいてメニュー アイテムを追加するには:
+-
+
- {@link android.content.Intent#CATEGORY_ALTERNATIVE} や {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} カテゴリでインテントを定義します。その他の要件も必要です。 + + +
- {@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +Menu.addIntentOptions()} を呼び出します。その際、Android によって、インテントを実行できるアプリケーションが検索され、メニューにそのアプリケーションが追加されます。 + +
インテントを満たすアプリケーションがインストールされていない場合、メニュー アイテムは追加されません。 +
+ +注: {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} は、現在画面で選択されている要素の処理に使われます。 + +このため、{@link +android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) +onCreateContextMenu()} でメニューを作成するときにのみ、それが使われる必要があります。
+ +次に例を示します。
+ ++@Override +public boolean onCreateOptionsMenu(Menu menu){ + super.onCreateOptionsMenu(menu); + + // Create an Intent that describes the requirements to fulfill, to be included + // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. + Intent intent = new Intent(null, dataUri); + intent.addCategory(Intent.CATEGORY_ALTERNATIVE); + + // Search and populate the menu with acceptable offering applications. + menu.addIntentOptions( + R.id.intent_group, // Menu group to which new items will be added + 0, // Unique item ID (none) + 0, // Order for the items (none) + this.getComponentName(), // The current activity name + null, // Specific items to place first (none) + intent, // Intent created above that describes our requirements + 0, // Additional flags to control items (none) + null); // Array of MenuItems that correlate to specific items (none) + + return true; +}+ +
定義されたインテントに一致するインテント フィルタが提供されていることを見つけた各アクティビティに対して、メニュー アイテムのタイトルにインテント フィルタの android:label
の値を、メニュー アイテムのアイコンにアプリケーション アイコンを使って、メニュー アイテムが追加されます。
+
+{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
+addIntentOptions()} メソッドによって、追加されたメニュー アイテム数が返されます。
+
注: {@link +android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) +addIntentOptions()} を呼び出すとき、最初の引数で指定されたメニュー グループによって、すべてのメニュー アイテムがオーバーライドされます。 +
+ + +アクティビティを他のメニューに追加できるようにする
+ +他のアプリケーションにアクティビティのサービスを提供して、アプリケーションを他のメニューに含めることができるようにすることもできます(前述の役割を逆にする)。 +
+ +他のアプリケーションのメニューに含まれるようにするには、通常どおりインテント フィルタを定義する必要がありますが、インテント フィルタのカテゴリに、{@link android.content.Intent#CATEGORY_ALTERNATIVE} や {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} 値を含めるようにしてください。 + + +次に例を示します。
++<intent-filter label="@string/resize_image"> + ... + <category android:name="android.intent.category.ALTERNATIVE" /> + <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> + ... +</intent-filter> ++ +
インテント フィルタの記述の詳細については、「インテントとインテント フィルタ」をご覧ください。 +
+ +この方法を使ったサンプル アプリケーションについては、Note Pad のサンプルコードをご覧ください。 + +
diff --git a/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd b/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd new file mode 100644 index 0000000000000000000000000000000000000000..f341256a3225be22b136bff83747f143f65165a6 --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/notifiers/notifications.jd @@ -0,0 +1,979 @@ +page.title=通知 +@jd:body + +本書の内容
+-
+
- 設計上の考慮事項 +
- 通知を作成する
+
-
+
- 必須通知コンテンツ +
- 省略可能な通知コンテンツと設定 +
- 通知アクション +
- 通知の優先度 +
- 簡単な通知を作成する +
- 通知に拡張レイアウトを適用する +
- 互換性を確保する +
+ - 通知を管理する + + +
- アクティビティの開始時にナビゲーションを維持する + + +
- 通知に進捗状況を表示する + + +
- 通知メタデータ +
- ヘッドアップ通知 +
- ロック画面通知 + +
- カスタム通知レイアウト +
キークラス
+-
+
- {@link android.app.NotificationManager} +
- {@link android.support.v4.app.NotificationCompat} +
ビデオ
+-
+
- + Notifications in 4.1 + + +
関連ドキュメント
+-
+
- + Android Design: Notifications + +
+ 通知は、アプリケーションの通常の UI 以外で、ユーザーに表示できるメッセージです。システムが通知を発行通知すると、通知はまず通知エリアにアイコンで表示されます。 + +通知の詳細を確認するには、ユーザーが通知ドロワーを開く必要があります。 +ドロワー通知エリアと通知ドロワーはどちらも、システムによって制御されているエリアであり、ユーザーはいつでも見ることができます。 + +
+ + + + + +注: 別途記載がある場合を除き、このガイドでは、バージョン 4 の サポート ライブラリの {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} クラスについて記述しています。クラス {@link android.app.Notification.Builder Notification.Builder} は、Android 3.0(API レベル 11)で追加されました。 + + + +
+ +設計上の考慮事項
+ +通知は、Android ユーザー インターフェースの重要なパーツであり、独自の設計ガイドラインが設けられています。Android 5.0 (API レベル 21)で導入されたマテリアル デザインの変更は特に重要です。詳細については、「マテリアル デザイン」をご覧ください。 + + +通知とその操作の設計方法については、通知設計ガイドをご覧ください。 +
+ +通知を作成する
+ +通知のための UI 情報とアクションを、{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} オブジェクトに指定します。通知自体を作成するには、{@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()} を呼び出します。これにより、指定された UI 情報とアクションを含む {@link android.app.Notification} オブジェクトが返されます。 + + + +通知を発行するには、{@link android.app.NotificationManager#notify NotificationManager.notify()} を呼び出して、この {@link android.app.Notification} オブジェクトをシステムに渡します。 + +
+ +必須通知コンテンツ
++ {@link android.app.Notification} オブジェクトの必須コンテンツは次のとおりです。 +
+-
+
- + 小さなアイコン。{@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()} で設定します。 + + +
- + タイトル。{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} で設定します。 + + +
- + 詳細テキスト。{@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()} で設定します。 + + +
省略可能な通知コンテンツと設定
++ 上記以外のすべての通知設定とコンテンツは省略可能です。省略可能な通知設定とコンテンツについては、{@link android.support.v4.app.NotificationCompat.Builder} のリファレンスをご覧ください。 + +
+ +通知アクション
++ 通知アクションは省略可能ですが、通知には、少なくとも 1 つのアクションを追加する必要があります。 + アクションは、ユーザーが通知からアプリケーションの {@link android.app.Activity} に直接移動することを可能にします。ユーザーは、移動先で、イベントを確認したりさらに作業を行ったりすることができます。 + + +
++ 1 つの通知が複数のアクションを提供することもあります。そのため、ユーザーが通知をクリックした時にトリガーされるアクションを必ず定義してください。通常、このアクションは、アプリケーション内で {@link android.app.Activity} を開きます。 + +また、アラームのスヌーズやテキスト メッセージへの即時返信などの追加のアクションを実行するボタンを、通知に追加することもできます。この機能は、Android 4.1 から利用できるようになりました。 + +追加のアクション ボタンを使用する場合、それらのボタンの機能をアプリの {@link android.app.Activity} で利用できるようにする必要があります。詳細については、互換性の確保についてのセクションをご覧ください。 + + +
++ {@link android.app.Notification} 内部では、アクションは、アプリケーションで {@link android.app.Activity} を開始する {@link android.content.Intent} が含まれる {@link android.app.PendingIntent} によって定義されます。 + + +{@link android.app.PendingIntent} を操作と関連付けるには、{@link android.support.v4.app.NotificationCompat.Builder} の該当するメソッドを呼び出します。 + +たとえば、ユーザーが通知ドロワーで通知のテキストをクリックしたときに {@link android.app.Activity} を開始する場合、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} を呼び出して {@link android.app.PendingIntent} を追加します。 + + + +
++ ユーザーが通知をクリックしたときに {@link android.app.Activity} を開始することは、最も一般的なアクション シナリオです。 +ユーザーが通知を閉じた場合に {@link android.app.Activity} を開始することもできます。 +Android 4.1 以降では、アクション ボタンから {@link android.app.Activity} を開始できます。 +詳細については、{@link android.support.v4.app.NotificationCompat.Builder} のリファレンスをご覧ください。 + +
+ +通知の優先度
++ 必要に応じて、通知の優先度を設定できます。通知の優先度は、通知の表示方法についての端末 UI へのヒントの役割を果たします。 + + 通知の優先度を設定するには、{@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) otificationCompat.Builder.setPriority()} を呼び出し、{@link android.support.v4.app.NotificationCompat} 優先度定数の 1 つを渡します。 + + +優先度レベルには、{@link android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2)から {@link android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2)までの 5 段階あります。優先度レベルが設定されていない場合、優先度はデフォルト値の {@link android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0)になります。 + + + + + +
+適切な優先順位の設定方法については、通知設計ガイドの「Correctly set and manage notification priority」をご覧ください。 + + +
+ +簡単な通知を作成する
++ 次のスニペットでは、ユーザーに通知がクリックされたときに起動するアクティビティを指定する簡単な通知を作成しています。 +このコードでは {@link android.support.v4.app.TaskStackBuilder} オブジェクトを作成し、そのオブジェクトを使用して、アクションのための {@link android.app.PendingIntent} を作成していることにご注意ください。 + +詳細は、アクティビティの開始時のナビゲーションの維持セクションで説明しています。 + + +
++NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("My notification") + .setContentText("Hello World!"); +// Creates an explicit intent for an Activity in your app +Intent resultIntent = new Intent(this, ResultActivity.class); + +// The stack builder object will contain an artificial back stack for the +// started Activity. +// This ensures that navigating backward from the Activity leads out of +// your application to the Home screen. +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack for the Intent (but not the Intent itself) +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent that starts the Activity to the top of the stack +stackBuilder.addNextIntent(resultIntent); +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); +mBuilder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// mId allows you to update the notification later on. +mNotificationManager.notify(mId, mBuilder.build()); ++
これで、ユーザーに通知が行われました。
+ +通知に拡張レイアウトを適用する
++ 通知を拡張ビューに表示するには、まず {@link android.support.v4.app.NotificationCompat.Builder} オブジェクトを任意の標準ビュー オプションで作成します。 + +次に、{@link android.support.v4.app.NotificationCompat.Builder#setStyle Builder.setStyle()} を拡張レイアウト オブジェクトを引数に指定して呼び出します。 + +
++ 通知の拡張機能は、Android 4.1 より前のバージョンでは利用できないことにご注意ください。Android 4.1 とそれ以前のプラットフォームでの通知の処理方法については、互換性の確保についてのセクションをご覧ください。 + + +
++ たとえば、次のコード スニペットでは、先ほどのスニペットで作成した通知を変更して、拡張レイアウトを使用するようにしています。 + +
++NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("Event tracker") + .setContentText("Events received") +NotificationCompat.InboxStyle inboxStyle = + new NotificationCompat.InboxStyle(); +String[] events = new String[6]; +// Sets a title for the Inbox in expanded layout +inboxStyle.setBigContentTitle("Event tracker details:"); +... +// Moves events into the expanded layout +for (int i=0; i < events.length; i++) { + + inboxStyle.addLine(events[i]); +} +// Moves the expanded layout object into the notification object. +mBuilder.setStyle(inBoxStyle); +... +// Issue the notification here. ++ +
互換性を確保する
+ ++ 通知機能をセットするメソッドはサポート ライブラリのクラス {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} に登録されていますが、特定のバージョンですべての通知機能が利用できるわけではありません。 + + + たとえば、アクション ボタンは拡張通知の機能ですが、拡張通知自体が Android 4.1 以上でしか利用できないため、Android 4.1 以上でのみ表示されます。 + + +
++ 可能な限り互換性を確保するには、{@link android.support.v4.app.NotificationCompat NotificationCompat} とそのサブクラス、特に {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} を使用して通知を作成します。 + + +さらに、通知の実装時に次の処理を行ってください。 +
+-
+
-
+ ユーザーが利用しているバージョンにかかわらず、通知機能のすべてをすべてのユーザーに提供します。
+それには、アプリの {@link android.app.Activity} からすべての機能が利用できるようにする必要があります。このために、新しい {@link android.app.Activity} を追加した方がよい場合もあります。
+
+
+
+ たとえば、{@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} を使用してメディア再生の開始と停止を行うコントロールを提供する場合、まずこのコントロールをアプリの {@link android.app.Activity} に実装します。 + + + +
+
+ - + ユーザーが通知をクリックしたときにその {@link android.app.Activity} が起動するようにして、すべてのユーザーがその機能にアクセスできるようにします。 +それには、{@link android.app.Activity} のための {@link android.app.PendingIntent} を作成する必要があります。 + +{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} を呼び出し、{@link android.app.PendingIntent} を通知に追加してください。 + + + +
- + 利用したい拡張通知機能を通知に追加します。追加した機能は、ユーザーが通知をクリックしたときに開始する {@link android.app.Activity} でも利用できることにご注意ください。 + + + +
通知を管理する
++ 同じタイプのイベントのために通知を複数回発行する場合、そのたびに新しい通知を作成することは避ける必要があります。 +新しい通知を作成する代わりに、以前の通知を更新して一部の値を変更することやいくつかの値を追加することを検討してください。 + +
++ たとえば、Gmail は新しいメールが届いたことを、未読メッセージの数を増やし通知に各メールの概要を追加することで、ユーザーに通知します。 +これは、通知の「スタッキング」と呼ばれています。詳細については、通知設計ガイドをご覧ください。 + + +
++ 注: この Gmail 機能には、「受信トレイ」の拡張レイアウトが必要です。これは、Android 4.1 以降で利用可能な拡張通知機能の 1 つです。 + +
++ 次のセクションでは、通知の更新方法と通知の削除方法を説明します。 +
+通知を更新する
++ 後で更新できるように通知をセットアップするには、{@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()} を呼び出し、通知 ID を指定して通知を発行します。 + + 発行後に通知を更新するには、{@link android.support.v4.app.NotificationCompat.Builder} オブジェクトを更新または作成し、そのオブジェクトから {@link android.app.Notification} オブジェクトをビルドし、以前使用した ID と同じ ID で {@link android.app.Notification} を発行します。 + + +以前の通知がそのまま表示されている場合は、{@link android.app.Notification} オブジェクトのコンテンツから、その通知が更新されます。 + +以前の通知が閉じられている場合は、代わりに新しい通知が作成されます。 + +
++ 次のスニペットでは、発生したイベントの数を反映するために通知が更新されています。 +このスニペットは通知をスタックし、概要を表示します。 +
++mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Sets an ID for the notification, so it can be updated +int notifyID = 1; +mNotifyBuilder = new NotificationCompat.Builder(this) + .setContentTitle("New Message") + .setContentText("You've received new messages.") + .setSmallIcon(R.drawable.ic_notify_status) +numMessages = 0; +// Start of a loop that processes data and then notifies the user +... + mNotifyBuilder.setContentText(currentText) + .setNumber(++numMessages); + // Because the ID remains unchanged, the existing notification is + // updated. + mNotificationManager.notify( + notifyID, + mNotifyBuilder.build()); +... ++ + +
通知を削除する
++ 次のいずれかが発生するまで、通知は表示され続けます。 +
+-
+
- + ユーザーが通知を個別に閉じるか、[Clear All] を使用して通知をすべて閉じる(通知を削除することができる場合)。 + + +
- + 作成時に {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} の呼び出しが行われた通知を、ユーザーがクリックする。 + + + +
- + 特定の通知 ID を指定して {@link android.app.NotificationManager#cancel(int) cancel()} を呼び出す(このメソッドは、実行中の処理に関する通知も削除します)。 + + +
- + {@link android.app.NotificationManager#cancelAll() cancelAll()} を呼び出す(このメソッドは、それまでに発行したすべての通知を削除します)。 + + +
アクティビティの開始時にナビゲーションを維持する
++ 通知から {@link android.app.Activity} を開始する場合、ユーザーが期待するナビゲーション操作を変えないようにする必要があります。 +たとえば、 [戻る] がクリックされた場合、アプリケーションの標準的なワークフローでは、ホーム画面に戻る必要があります。また、 + [最近使ったアプリ] がクリックされた場合、{@link android.app.Activity} を別のタスクとして表示する必要があります。 +このナビゲーション操作を変えないようにするには、新たなタスクで {@link android.app.Activity} を開始する必要があります。 +{@link android.app.PendingIntent} を設定して新たなタスクを生成する方法は、開始する {@link android.app.Activity} の性質によって異なります。 + +通常は、次の 2 つの場合があります。 +
+-
+
- + 通常のアクティビティ + +
-
+ アプリケーションの標準的なワークフローの一部である {@link android.app.Activity} を開始します。
+この場合、{@link android.app.PendingIntent} を設定して新たなタスクを開始し、{@link android.app.PendingIntent} にバックスタックを提供します。これにより、アプリケーションの標準的な
+
+ 「戻る」 動作を再現します。
+
+ Gmail アプリからの通知は、このタイプのアクティビティの一例です。1 つの電子メール メッセージの通知をクリックすると、メッセージそれ自体が表示されます。 +[戻る] をタップすると、通知から移動してきたのでなくホーム画面から Gmail に移動してきたかのように、Gmail からホーム画面に戻ります。 + + +
++ これは、通知のタップ時に使用していたアプリケーションに関係なく発生します。 +たとえば、Gmail でメッセージを作成しているときに、1 つのメールの通知をクリックすると、すぐにそのメールに移動します。 +その場合、 [戻る] + をタップすると、作成中のメッセージに戻るのではなく、受信トレイ、ホーム画面の順に移動します。 + +
+
+ - + 特殊なアクティビティ + +
- + ユーザーは、この {@link android.app.Activity} を、通知から開始した場合のみ見ることができます。 + ある意味では、通知自体に表示するのは難しい情報を提供することで、この {@link android.app.Activity} が通知を拡張しているということができます。 +このタイプのアクティビティでは、{@link android.app.PendingIntent} を設定して新たなタスクを開始します。 +ただし、開始した {@link android.app.Activity} はアプリケーションのアクティビティ フローには含まれていないので、バックスタックを作成する必要はありません。 + +たとえば、 [戻る] をクリックすると、ユーザーはホーム画面に移動します。 + + +
通常のアクティビティの PendingIntent を設定する
++ ダイレクト エントリの {@link android.app.Activity} を開始する {@link android.app.PendingIntent} を設定するには、次の手順に従います。 + +
+-
+
-
+ マニフェストに、アプリケーションの {@link android.app.Activity} の階層を定義します。
+
-
+
-
+ Android 4.0.3 以前へのサポートを追加します。これには、
<meta-data>
要素を<activity>
の子として追加して、開始する {@link android.app.Activity} の親を指定します。 + + + + ++ この要素に、
+android:name="android.support.PARENT_ACTIVITY"
を設定します。 + +<parent_activity_name>
が親<activity>
要素のandroid:name
の値の場合は、android:value="<parent_activity_name>"
を設定します。 + + + + + +例については、以下の XML をご覧ください。 +
+ -
+ また、Android 4.1 以降のサポートを追加します。これには、開始する {@link android.app.Activity} の
<activity>
要素に、android:parentActivityName
属性を追加します。 + + + + +
+
+ 最終的な XML は、次のようになります。 +
++<activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +<activity + android:name=".ResultActivity" + android:parentActivityName=".MainActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".MainActivity"/> +</activity> +
+
+ -
+ Android 4.0.3 以前へのサポートを追加します。これには、
-
+ {@link android.app.Activity} を開始する {@link android.content.Intent} に基づくバックスタックを作成します。
+
+
-
+
- + {@link android.app.Activity} を開始する {@link android.content.Intent} を作成します。 + +
- + {@link android.app.TaskStackBuilder#create TaskStackBuilder.create()} を呼び出して、スタック ビルダーを作成します。 + + +
-
+ {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} を呼び出し、バックスタックをスタック ビルダーに追加します。
+
+ マニフェストに定義した階層のそれぞれの {@link android.app.Activity} ごとに、バックスタックに、{@link android.app.Activity} を開始する {@link android.content.Intent} が含まれます。
+
+このメソッドは、新たなタスクでスタックを開始するためのフラグも追加します。
+
+
+ 注: {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} の引数は開始した {@link android.app.Activity} への参照ですが、このメソッドの呼び出しによって、{@link android.app.Activity} を開始する {@link android.content.Intent} が追加されることはありません。 + + + +追加は、次の d. で行われます。 +
+
+ - + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()} を呼び出して、通知から {@link android.app.Activity} を開始する {@link android.content.Intent} を追加します。 + + + a. で作成した {@link android.content.Intent} を、引数として {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()} に渡します。 + + + +
- + 必要に応じて、{@link android.support.v4.app.TaskStackBuilder#editIntentAt TaskStackBuilder.editIntentAt()} を呼び出し、スタック上の {@link android.content.Intent} オブジェクトに引数を追加します。 + +これは、場合によっては、ターゲット {@link android.app.Activity} に、ユーザーが + + [戻る] を使って移動したときに、適切なデータが表示されるようにするために必要です。 + +
- + {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()} を呼び出し、このバックスタックのための {@link android.app.PendingIntent} を取得します。 + + この {@link android.app.PendingIntent} は、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} の引数として使用できます。 + + + +
+
+ 次のコード スニペットでは、上記の処理を行っています。 +
++... +Intent resultIntent = new Intent(this, ResultActivity.class); +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent to the top of the stack +stackBuilder.addNextIntent(resultIntent); +// Gets a PendingIntent containing the entire back stack +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); +... +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +builder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mNotificationManager.notify(id, builder.build()); ++ +
特殊なアクティビティの PendingIntent を設定する
++ 次のセクションでは、特殊なアクティビティのための {@link android.app.PendingIntent} の設定方法を説明します。 + +
++ 特殊な {@link android.app.Activity} はバックスタックを必要としません。そのため、マニフェストにその {@link android.app.Activity} の階層を定義する必要はありません。また、バックスタックを作成するために {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} を呼び出す必要もありません。 + + + +代わりに、マニフェストを利用して {@link android.app.Activity} のタスク オプションを設定し、{@link android.app.PendingIntent#getActivity getActivity()} を呼び出して {@link android.app.PendingIntent} を作成します。 + + +
+-
+
-
+ マニフェストで、{@link android.app.Activity} の
<activity>
要素に、次の属性を追加します。 + + +-
+
-
+
android:name="activityclass"
+
+ - + アクティビティの完全修飾クラス名。 + +
-
+
android:taskAffinity=""
+
+ - + コードにセットした {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} フラグと組み合わせて、{@link android.app.Activity} がアプリケーションのデフォルトのタスクに入ることがないようにします。 + + +アプリケーションのアフィニティがデフォルトのままの既存タスクは影響を受けません。 + + +
-
+
android:excludeFromRecents="true"
+
+ - + 新しいタスクを、 [最近使ったアプリ] から除外し、ユーザーが新しいタスクに間違って戻ることがないようにします。 + + +
+ 次のスニペットは、この要素を示しています。 +
++<activity + android:name=".ResultActivity" +... + android:launchMode="singleTask" + android:taskAffinity="" + android:excludeFromRecents="true"> +</activity> +... +
+
+ -
+
-
+ 通知をビルドし発行します。
+
-
+
- + {@link android.app.Activity} を開始する {@link android.content.Intent} を作成します。 + + +
- + フラグ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} と {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK} を指定して {@link android.content.Intent#setFlags setFlags()} を呼び出し、{@link android.app.Activity} を新しい空のタスクで開始するように設定します。 + + + + + +
- + {@link android.content.Intent} に、必要に応じてオプションを設定します。 + +
- + {@link android.app.PendingIntent#getActivity getActivity()} を呼び出し、{@link android.content.Intent} から {@link android.app.PendingIntent} を作成します。 + + この {@link android.app.PendingIntent} は、{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} の引数として使用できます。 + + + +
+ 次のコード スニペットでは、上記の処理を行っています。 +
++// Instantiate a Builder object. +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +// Creates an Intent for the Activity +Intent notifyIntent = + new Intent(this, ResultActivity.class); +// Sets the Activity to start in a new, empty task +notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); +// Creates the PendingIntent +PendingIntent notifyPendingIntent = + PendingIntent.getActivity( + this, + 0, + notifyIntent, + PendingIntent.FLAG_UPDATE_CURRENT +); + +// Puts the PendingIntent into the notification builder +builder.setContentIntent(notifyPendingIntent); +// Notifications are issued by sending them to the +// NotificationManager system service. +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Builds an anonymous Notification object from the builder, and +// passes it to the NotificationManager +mNotificationManager.notify(id, builder.build()); +
+
+
通知に進捗状況を表示する
++ 通知には、進行中の処理の状況をユーザーに示すアニメーション表示の進捗インジケーターを表示できます。 +その処理にどれくらいの時間がかかるかと、ある時点でその処理がどれだけ完了しているかを見積もることができる場合、「確定(determinate)」タイプのインジケーター(プログレスバー)を使用します。 + +処理にかかる時間を見積もることができない場合は、「不確定(indeterminate)」タイプのインジケーター(アクティビティ インジケーター)を使用します。 + +
++ 進捗インジケーターは、{@link android.widget.ProgressBar} クラスのプラットフォーム実装で表示されます。 + +
++ Android 4.0 以降のプラットフォーム上で進捗インジケーターを使用するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を呼び出します。 +それ以前のバージョンでは、{@link android.widget.ProgressBar} ビューを含むカスタム通知レイアウトを作成する必要があります。 + + +
++ 次のセクションでは、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を使用して、通知に進捗状況を表示する方法を説明します。 + +
+ +範囲固定の進捗インジケーターを表示する
+
+ 確定プログレスバーを表示するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(max, progress, false)} を呼び出して通知にバーを追加してから、その通知を発行します。
+
+処理の進行に合わせて、progress
の値を増やし、通知を更新します。
+処理の最後には、progress
が max
と等しくなります。
+{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} を呼び出す一般的な方法は、max
に 100 を設定して、処理の「進捗度」の値である progress
の値を増やすことです。
+
+
+
+
+ 処理の完了時には、プログレスバーを表示したままにすることも、削除することもできます。いずれの場合でも、通知のテキストを更新して、処理が完了したことを示すことを忘れないでください。 + + プログレスバーを削除するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} を呼び出します。 + +次に例を示します。 +
++... +mNotifyManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mBuilder = new NotificationCompat.Builder(this); +mBuilder.setContentTitle("Picture Download") + .setContentText("Download in progress") + .setSmallIcon(R.drawable.ic_notification); +// Start a lengthy operation in a background thread +new Thread( + new Runnable() { + @Override + public void run() { + int incr; + // Do the "lengthy" operation 20 times + for (incr = 0; incr <= 100; incr+=5) { + // Sets the progress indicator to a max value, the + // current completion percentage, and "determinate" + // state + mBuilder.setProgress(100, incr, false); + // Displays the progress bar for the first time. + mNotifyManager.notify(0, mBuilder.build()); + // Sleeps the thread, simulating an operation + // that takes time + try { + // Sleep for 5 seconds + Thread.sleep(5*1000); + } catch (InterruptedException e) { + Log.d(TAG, "sleep failure"); + } + } + // When the loop is finished, updates the notification + mBuilder.setContentText("Download complete") + // Removes the progress bar + .setProgress(0,0,false); + mNotifyManager.notify(ID, mBuilder.build()); + } + } +// Starts the thread by calling the run() method in its Runnable +).start(); ++ + +
進行中アクティビティ インジケーターを表示する
++ 不確定アクティビティ インジケーターを表示するには、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}(最初の 2 つの引数は無視されます)を使用して通知に追加し、通知を発行します。 + +このインジケーターの外見は、アニメーションが常時表示されていること以外はプログレスバーと同じです。 + +
++ 処理の開始時に通知を発行します。通知を変更するまで、アニメーションは表示され続けます。 +処理が完了したら、{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} を呼び出し、次に通知を更新してアクティビティ インジケーターを削除します。 + + + この操作を行わないと、処理が完了してもアニメーションが表示され続けることになります。また、通知のテキストを更新して、処理が完了したことを示すことを忘れないでください。 + +
++ アクティビティ インジケーターの仕組みについては、上記のスニペットをご覧ください。次のコード行を探します。 +
++// Sets the progress indicator to a max value, the current completion +// percentage, and "determinate" state +mBuilder.setProgress(100, incr, false); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); ++
+ 見つけたコードを次のコードに置き換えます。 +
++ // Sets an activity indicator for an operation of indeterminate length +mBuilder.setProgress(0, 0, true); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); ++ +
通知メタデータ
+ +通知は、次の {@link android.support.v4.app.NotificationCompat.Builder} メソッドを使用して割り当てるメタデータによって、ソートされることがあります。 +
+ +-
+
- {@link android.support.v4.app.NotificationCompat.Builder#setCategory(java.lang.String) setCategory()} は、端末が優先モードの場合のアプリ通知の処理方法を設定します(たとえば、通知が着信、インスタント メッセージ、アラームを知らせる場合など)。 + + +
- {@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) setPriority()} は優先度フィールドに {@code PRIORITY_MAX} または {@code PRIORITY_HIGH} が設定されている通知が、音声または振動を発する通知の場合、小さなフローティング ウィンドウに表示されるようにします。 + + +
- {@link android.support.v4.app.NotificationCompat.Builder#addPerson(java.lang.String) addPerson()} を使用すると、通知に人物のリストを追加できます。 +アプリは、このリストを利用して、システムに合図を送り、特定の人達からの通知をグループ化したり、それらの人達からの通知を重要度が高い通知としてランク付けしたりします。 + + +
ヘッドアップ通知
+ +Android 5.0(API レベル 21)では、端末がアクティブな場合(端末がロックされておらず、画面がオンになっている場合)に、小さなフローティング ウィンドウ(ヘッドアップ通知とも呼ばれます)に通知を表示することができます。 + +これらの通知は、ヘッドアップ通知がアクション ボタンも表示すること以外は、通知をコンパクトにしたものと同じように表示されます。 + +使用中のアプリから移動しなくても、ユーザーは、ヘッドアップ通知に反応したりヘッドアップ通知を閉じたりすることができます。 +
+ +ヘッドアップ通知のトリガーとなる条件には、たとえば以下のようなものがあります。
+ +-
+
- ユーザーのアクティビティが全画面モードであること(アプリが {@link android.app.Notification#fullScreenIntent} を使用していること)、または + +
- その通知が高い優先度を持ち、着信音または振動を使用していること + +
ロック画面通知
+ +Android 5.0(API レベル 21)では、通知をロック画面に表示できるようになりました。 +アプリは、この機能を利用してメディア再生コントロールやその他の一般的なアクションを提供できます。 +ユーザーは設定でロック画面に通知を表示するかどうか選ぶことができます。また、開発者も、アプリからの通知をロック画面に表示するかどうか指定できます。 +
+ +可視性を設定する
+ +アプリでは、保護されたロック画面に表示される通知の表示の詳細レベルをコントロールできます。 +{@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()} を呼び出し、次の値のいずれかを指定してください。 +
+ +-
+
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} では、通知のフルコンテンツが表示されます。 + +
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_SECRET} では、ロック画面に、通知のいずれの部分も表示しません。 + +
- {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} では、通知のアイコンやコンテンツのタイトルなどの基本的な情報を表示しますが、通知のフルコンテンツは表示されません。 + +
{@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} を設定すると、特定の内容を非表示にした代替バージョンの通知コンテンツを提供できます。 +たとえば、SMS アプリで 3 件の新しいテキスト メッセージがあることを示す通知を表示する場合に、メッセージ コンテンツと送信者を非表示にできます。 + +この代替通知を提供するには、{@link android.support.v4.app.NotificationCompat.Builder} を使用してまず置換用の通知を作成し、 +プライベート通知オブジェクトを作成したら、その置換用の通知をプライベート通知オブジェクトに {@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()} メソッドを使用してアタッチしてください。 + + +
+ +ロック画面でのメディア再生をコントロールする
+ +Android 5.0(API レベル 21)では、{@link android.media.RemoteControlClient} を使用したメディア コントロールは、ロック画面に表示されません。このクラスは廃止済みです。 +代わりに、{@link android.app.Notification.MediaStyle} テンプレートと {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} メソッドを使用します。このメソッドは、アクションをクリックできるアイコンに変換します。 + + +
+ +注: このテンプレートと {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} メソッドはサポート ライブラリには含まれません。そのため、これらの機能は Android 5.0 以降でのみ動作します。 + +
+ +Android 5.0 でロック画面にメディア再生コントロールを表示するには、可視性を上記の{@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC} に設定します。 +その後、次のサンプルコードに従って、アクションを追加し {@link android.app.Notification.MediaStyle} テンプレートを設定します。 + +
+ ++Notification notification = new Notification.Builder(context) + // Show controls on lock screen even when user hides sensitive content. + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setSmallIcon(R.drawable.ic_stat_player) + // Add media control buttons that invoke intents in your media service + .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 + .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 + .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 + // Apply the media style template + .setStyle(new Notification.MediaStyle() + .setShowActionsInCompactView(1 /* #1: pause button */) + .setMediaSession(mMediaSession.getSessionToken()) + .setContentTitle("Wonderful music") + .setContentText("My Awesome Band") + .setLargeIcon(albumArtBitmap) + .build(); ++ +
注: {@link android.media.RemoteControlClient} の廃止は、他の点でもメディアのコントロールに影響を与えています。 +新しい API でのメディア セッションの管理と再生のコントロールの詳細については、メディア再生コントロールをご覧ください。 + +
+ + + +カスタム通知レイアウト
++ 通知フレームワークでは、カスタム通知レイアウトを定義することができます。カスタム通知レイアウトは、{@link android.widget.RemoteViews} オブジェクトに通知の外観を定義します。 + + カスタム レイアウトの通知は通常の通知と似ていますが、XML レイアウト ファイルに定義された {@link android.widget.RemoteViews} が使用されています。 + +
++ カスタム通知レイアウトで使用できる高さは、通知ビューによって異なります。標準ビュー レイアウトでは 64 dp までで、拡張ビュー レイアウトでは 256 dp までです。 + +
++ カスタム通知レイアウトを定義するには、まず、XML レイアウト ファイルをインフレートする {@link android.widget.RemoteViews} オブジェクトのインスタンスを作成します。 +次に、{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} などのメソッドを呼び出す代わりに、{@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()} を呼び出します。 + + +コンテンツの詳細をカスタム通知に設定するには、{@link android.widget.RemoteViews} のメソッドを使用してビューの子の値を設定します。 + + +
+-
+
-
+ 別ファイルに通知の XML レイアウトを作成します。ファイル名はどのような名前でもかまいませんが、拡張子は必ず
.xml
にします。 + +
+ - + アプリで、{@link android.widget.RemoteViews} メソッドを使用して、通知のアイコンとテキストを定義します。 +{@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()} を呼び出して、この {@link android.widget.RemoteViews} オブジェクトを {@link android.support.v4.app.NotificationCompat.Builder} にセットします。 + +{@link android.widget.RemoteViews} オブジェクトに背景 {@link android.graphics.drawable.Drawable} を設定することは避けてください。文字が読めなくなる場合があります。 + + + +
+ {@link android.widget.RemoteViews} クラスには、通知のレイアウトに {@link android.widget.Chronometer} や {@link android.widget.ProgressBar} を簡単に追加できるメソッドも含まれています。 + +通知のカスタム レイアウトの作成についての詳細は、{@link android.widget.RemoteViews} のリファレンスをご覧ください。 + +
++ 警告: カスタム通知レイアウトを使用する場合、そのカスタム通知レイアウトがさまざまな画面の向きと解像度で適切に表示されるかどうか、十分に注意してください。 +すべてのビュー レイアウトでさまざまな画面の向きと解像度への対応に注意する必要がありますが、通知ドロワーのスペースが限られているため、通知では特に注意する必要があります。 + +カスタム レイアウトは複雑にし過ぎないようにしてください。また、必ずさまざまな構成でテストするようにしてください。 + +
+ +カスタム通知のテキストにスタイル リソースを使用する
++ カスタム通知のテキストには、必ずスタイル リソースを使用してください。通知の背景色は端末やバージョンによって異なりますが、スタイル リソースを使用することで、この問題に対処できます。 + +Android 2.3 以降では、標準の通知レイアウトのテキストのスタイルは、システムによって定義されています。 +Android 2.3 以降を対象とするアプリケーションで同じスタイルを使用する場合は、表示される背景でテキストを読むことができるかご確認ください。 + +
diff --git a/docs/html-intl/intl/ja/guide/topics/ui/overview.jd b/docs/html-intl/intl/ja/guide/topics/ui/overview.jd new file mode 100644 index 0000000000000000000000000000000000000000..08d93560cb4e0bb0cce656da5fdaafece6adce5b --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/overview.jd @@ -0,0 +1,71 @@ +page.title=UI の概要 +@jd:body + + +Android アプリのすべてのユーザー インターフェース エレメントは、{@link android.view.View} と {@link android.view.ViewGroup} オブジェクトを使ってビルドされています。 +{@link android.view.View} は、ユーザーが相互操作できる、画面上で何かを描画するオブジェクトです。 +{@link android.view.ViewGroup} は、インターフェースのレイアウトを定義するために、その他の {@link android.view.View}(と {@link android.view.ViewGroup})オブジェクトを保持するオブジェクトです。 + +
+ +Android では、共通の入力コントロール(ボタンやテキスト フィールドなど)とさまざまなレイアウトモデル(線形レイアウトや相対レイアウトなど)を提供する {@link android.view.View} と {@link android.view.ViewGroup} サブクラスの両方が提供されています。 + +
+ + +ユーザー インターフェースのレイアウト
+ +アプリの各コンポーネントのユーザー インターフェースは、図 1 のように、{@link +android.view.View} と {@link android.view.ViewGroup} オブジェクトの階層を使って定義されます。各ビューグループは、子ビューをまとめる非表示のコンテナであり、子ビューは UI の一部を描画する入力コントロールまたはその他のウィジェットです。この階層ツリーは、必要に応じて単純にまたは複雑にすることができますが、パフォーマンスの点では単純な階層ツリーが最適です。 + + + +
+ + + + +レイアウトを宣言するには、コードで {@link android.view.View} オブジェクトのインスタンスを作成してツリーのビルドを始めることができますが、レイアウトを定義する最も簡単で効率的な方法は XML ファイルを使用することです。XML では HTML のように、人が見える構造でレイアウトが提供されます。 + +
+ +ビューの XML 要素名は、それが表す Android クラスによって決まります。<TextView>
要素は UI で {@link android.widget.TextView} ウィジェットを、<LinearLayout>
要素は {@link android.widget.LinearLayout} ビューグループを作成します。
+
+
+
たとえば、テキストビューとボタンを含む単純な縦レイアウトは次のようになります。
++<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + <TextView android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a TextView" /> + <Button android:id="@+id/button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="I am a Button" /> +</LinearLayout> ++ +
アプリでレイアウト リソースを読み込むとき、Android はレイアウトの各ノードを初期化して、他の動作の定義、オブジェクト状態の照会、レイアウトの変更をするのに使用できるランタイム オブジェクトにします。 + +
+ +UI レイアウト作成のガイドについては、XML レイアウトをご覧ください。 + + + +
ユーザー インターフェース コンポーネント
+ +{@link android.view.View} と {@link android.view.ViewGroup} オブジェクトを使用してすべての UI をビルドする必要はありません。 +Android では、コンテンツの定義に必要な標準的な UI レイアウトを提供する複数のアプリ コンポーネントが提供されます。 +これらの各 UI コンポーネントには、それぞれのドキュメントで説明されている固有の API(アクションバー、ダイアログ、状態通知など)があります。 +
+ + diff --git a/docs/html-intl/intl/ja/guide/topics/ui/settings.jd b/docs/html-intl/intl/ja/guide/topics/ui/settings.jd new file mode 100644 index 0000000000000000000000000000000000000000..9e6bb9d04169c0bc5b6d0de07450bee32f2e154e --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/settings.jd @@ -0,0 +1,1202 @@ +page.title=設定 +page.tags=preference,preferenceactivity,preferencefragment + +@jd:body + + +本書の内容
+-
+
- 概要
+
-
+
- プリファレンス +
+ - XML にプリファレンスを定義する
+
-
+
- 設定グループを作成する +
- インテントを使用する +
+ - プリファレンス アクティビティを作成する +
- プリファレンス フラグメントを使用する +
- デフォルト値を設定する +
- プリファレンス ヘッダーを使用する + + +
- プリファレンスを読み込む + + +
- ネットワークの使用を管理する +
- カスタム プリファレンスを作成する + + +
キークラス
+-
+
- {@link android.preference.Preference} +
- {@link android.preference.PreferenceActivity} +
- {@link android.preference.PreferenceFragment} +
関連ドキュメント
+ +多くの場合、アプリケーションには、ユーザーがアプリの機能や動作を変更できる設定が含まれています。たとえば、一部のアプリでは、通知を有効にするかどうかや、アプリケーションがクラウドとデータを同期する頻度を、ユーザーが指定できます。 + +
+ +アプリに設定機能を提供するには、Android の {@link android.preference.Preference} API を使用して、他の Android アプリ(システム設定を含む)の操作と整合性のあるインターフェースを構築する必要があります。 + +このドキュメントでは、{@link android.preference.Preference} API を使用して、アプリの設定機能を構築する方法について説明します。 +
+ +設定の設計
+設定の設計方法については、設定のデザインガイドをご覧ください。
+概要
+ +設定は、{@link android.view.View} オブジェクトを使用してユーザー インターフェースを作成する方法ではなく、XML ファイルで宣言された {@link android.preference.Preference} クラスの各種のサブクラスを使用する方法で作成されます。 + +
+ +1 つの {@link android.preference.Preference} オブジェクトが、1 つの設定の構成要素になります。 +各 {@link android.preference.Preference} はアイテムとしてリストに表示され、ユーザーが設定を変更するための適切な UI を提供します。 +たとえば、{@link android.preference.CheckBoxPreference} はチェックボックスを表示するリストアイテムを作成し、{@link android.preference.ListPreference} は、選択リスト付きのダイアログを開くアイテムを作成します。 + +
+ +追加した各 {@link android.preference.Preference} は、アプリの設定のためのデフォルトの {@link android.content.SharedPreferences} ファイルに設定を保存するためにシステムが使用する対応するキーと値のペアを持ちます。 + +ユーザーが設定を変更する場合、システムが {@link android.content.SharedPreferences} ファイルの対応する値を更新します。 +関連する {@link android.content.SharedPreferences} ファイルを直接操作することが必要なのは、ユーザーの設定に基づいてアプリの動作を決定するために値を読み込むことが必要な場合のみです。 + +
+ +各設定の {@link android.content.SharedPreferences} に保存される値のデータ型は、次のいずれかにすることができます。 +
+ +-
+
- Boolean +
- Float +
- Int +
- Long +
- String +
- String {@link java.util.Set} +
アプリの設定の UI は {@link android.view.View} オブジェクトではなく {@link android.preference.Preference} で作成されているため、リストの設定を表示するには、専用の {@link android.app.Activity} サブクラスまたは {@link android.app.Fragment} サブクラスを使用する必要があります。 + + +
+ +-
+
- アプリが 3.0 よりも前のバージョンの Android(API レベル 10 以下)をサポートしている場合は、{@link android.preference.PreferenceActivity} クラスを継承してアクティビティを作成する必要があります。 + +
- Android 3.0 以降では、代わりに、アプリの設定を表示する {@link android.preference.PreferenceFragment} をホストする従来の {@link android.app.Activity} を使用します。ただし、設定のグループが複数ある場合は、{@link android.preference.PreferenceActivity} を使用して大きな画面用の 2 ペイン レイアウトを作成することもできます。 + + + +
{@link android.preference.PreferenceActivity} と {@link android.preference.PreferenceFragment} のインスタンスの設定方法は、プリファレンス アクティビティを作成するとプリファレンス フラグメントを使用するセクションをご覧ください。 + +
+ + +プリファレンス
+ +アプリの各設定は、{@link android.preference.Preference} クラスの個々のサブクラスに相当します。 +各サブクラスには、設定のタイトルやデフォルト値などを指定できる一連の核となるプロパティが含まれています。 +また、各サブクラスは、専用のプロパティとユーザー インターフェースを提供しています。 +たとえば、図 1. は、SMS アプリの設定のスクリーンショットです。 +設定画面の各リスト アイテムは、それぞれ異なる {@link android.preference.Preference} オブジェクトに基づいています。 +
+ +以下は、最も一般的なプリファレンスの一部です。
+ +-
+
- {@link android.preference.CheckBoxPreference} +
- 有効または無効にする設定のチェックボックス付きのアイテムを表示します。保存される値は、Boolean です(オンの場合、
true
)。 +
+
+ - {@link android.preference.ListPreference} +
- ラジオボタンのリスト付きのダイアログを開きます。保存される値は、サポートされるデータ型(上記参照)であればどのデータ型にもできます。 + + +
- {@link android.preference.EditTextPreference} +
- {@link android.widget.EditText} ウィジェット付きのダイアログを開きます。保存される値は、{@link java.lang.String} です。 + +
その他のサブクラスと対応するプロパティについては、{@link android.preference.Preference} クラスをご覧ください。 +
+ +もちろん、組み込みのクラスがすべてのニーズを満たすわけではなく、アプリケーションがより特殊な機能を必要とする可能性もあります。 +たとえば、プラットフォームは、現時点では、数字や日付を選択するための {@link android.preference.Preference} クラスを提供していません。 +そのため、独自の {@link android.preference.Preference} サブクラスを定義することが必要になる場合もあります。 +詳細については、カスタム プリファレンスを作成するセクションをご覧ください。
+ + + +XML にプリファレンスを定義する
+ +実行時に新しい {@link android.preference.Preference} オブジェクトのインスタンスを作成することもできますが、{@link android.preference.Preference} オブジェクトの階層で XML に設定のリストを定義する必要があります。 + +XML ファイルは更新が容易な簡単に読むことができる構造を持つため XML ファイルを使用して設定のコレクションを定義することをお勧めします。 +また、アプリの設定は通常、事前設定されていますが、設定のコレクションを実行時に変更することもできます。 +
+ +各 {@link android.preference.Preference} サブクラスは、{@code <CheckBoxPreference>} などのクラス名と一致する XML 要素で定義できます。 +
+ +この XML ファイルは、{@code res/xml/} ディレクトリに保存する必要があります。この XML ファイルには好きな名前を付けることができますが、一般的には、{@code preferences.xml} という名前が使用されています。 +階層の分岐(この分岐がそれ自身の設定のリストを開きます)が {@link android.preference.PreferenceScreen} のネストされたインスタンスを使用して宣言されているため、必要なファイルは通常 1 ファイルのみです。 + +
+ +注: 複数ペイン レイアウトの設定を作成する場合は、フラグメントごとに別々の XML ファイルが必要です。 +
+ +XML ファイルのルートノードは、{@link android.preference.PreferenceScreen <PreferenceScreen>} 要素にする必要があります。 +この要素内に、各 {@link android.preference.Preference} を追加します。 +{@link android.preference.PreferenceScreen <PreferenceScreen>} 要素内に追加したそれぞれの子は、設定のリストで 1 つのアイテムとして表示されます。 + +
+ +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="pref_sync" + android:title="@string/pref_sync" + android:summary="@string/pref_sync_summ" + android:defaultValue="true" /> + <ListPreference + android:dependency="pref_sync" + android:key="pref_syncConnectionType" + android:title="@string/pref_syncConnectionType" + android:dialogTitle="@string/pref_syncConnectionType" + android:entries="@array/pref_syncConnectionTypes_entries" + android:entryValues="@array/pref_syncConnectionTypes_values" + android:defaultValue="@string/pref_syncConnectionTypes_default" /> +</PreferenceScreen> ++ +
この例には、{@link android.preference.CheckBoxPreference} と {@link android.preference.ListPreference} が含まれています。 +どちらのアイテムにも次の 3 つの属性が含まれています。
+ +-
+
- {@code android:key} +
- この属性は、データ値を保持するプリファレンスで必要です。設定の値を {@link android.content.SharedPreferences} に保存するときにシステムが使用する一意のキー(文字列)を指定します。
+
+
+
プリファレンスが {@link android.preference.PreferenceCategory} または{@link android.preference.PreferenceScreen} の場合、またはプリファレンスが {@link android.content.Intent} の呼び出しを指定している場合({@code <intent>} 要素を使用)、または {@link android.app.Fragment} の表示を指定している場合({@code android:fragment} 属性を使用)のみ、インスタンスでこの属性は必要ありません。 + + +
+
+ - {@code android:title} +
- この属性は、ユーザーに表示される設定の名前です。 +
- {@code android:defaultValue} +
- この属性は、システムが {@link android.content.SharedPreferences} ファイルに設定する必要がある初期値を指定します。 +すべての設定のデフォルト値を指定する必要があります。 + +
その他のサポートされている属性については、{@link android.preference.Preference}(と対応するサブクラス)のドキュメントをご覧ください。 +
+ + +設定のリストが 10 アイテムを超える場合は、タイトルを追加して設定のグループを定義するか、それらのグループを別の画面に表示することをお勧めします。 + +詳細については、次のセクションで説明します。
+ + +設定グループを作成する
+ +10 以上の設定のリストがある場合、ユーザーが目を通して把握し処理することが難しくなる場合があります。 +この問題を解決するには、設定の一部またはすべてをグループに分割し、1 つの長いリストを複数の短いリストに変えます。 + +関連設定のグループは、次の 2 つの方法のいずれかで表示できます。
+ + + +これらのグループ化方法の 1 つまたは両方を利用して、アプリの設定を整理できます。使用する方法と設定の分割方法を決定する際は、Android Design のSettings ガイドのガイドラインに従ってください。 + +
+ + +タイトルを使用する
+ +設定のグループの間に見出しを入れる場合(図 2. 参照)、{@link android.preference.Preference} オブジェクトをグループごとに 1 つの {@link android.preference.PreferenceCategory} 内にセットしてください。 + +
+ +次に例を示します。
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <PreferenceCategory + android:title="@string/pref_sms_storage_title" + android:key="pref_key_storage_settings"> + <CheckBoxPreference + android:key="pref_key_auto_delete" + android:summary="@string/pref_summary_auto_delete" + android:title="@string/pref_title_auto_delete" + android:defaultValue="false"... /> + <Preference + android:key="pref_key_sms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_sms_delete"... /> + <Preference + android:key="pref_key_mms_delete_limit" + android:dependency="pref_key_auto_delete" + android:summary="@string/pref_summary_delete_limit" + android:title="@string/pref_title_mms_delete" ... /> + </PreferenceCategory> + ... +</PreferenceScreen> ++ + +
サブ画面を使用する
+ +設定のグループをサブ画面に配置する場合(図 3. 参照)、{@link android.preference.Preference} オブジェクトのグループを {@link android.preference.PreferenceScreen} 内にセットしてください。 + +
+ + + + +次に例を示します。
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- opens a subscreen of settings --> + <PreferenceScreen + android:key="button_voicemail_category_key" + android:title="@string/voicemail" + android:persistent="false"> + <ListPreference + android:key="button_voicemail_provider_key" + android:title="@string/voicemail_provider" ... /> + <!-- opens another nested subscreen --> + <PreferenceScreen + android:key="button_voicemail_setting_key" + android:title="@string/voicemail_settings" + android:persistent="false"> + ... + </PreferenceScreen> + <RingtonePreference + android:key="button_voicemail_ringtone_key" + android:title="@string/voicemail_ringtone_title" + android:ringtoneType="notification" ... /> + ... + </PreferenceScreen> + ... +</PreferenceScreen> ++ + +
インテントを使用する
+ +設定画面ではなく、ウェブページを表示するためのウェブブラウザなどの別のアクティビティを開くプリファレンス アイテムが必要になることもあります。 +ユーザーがプリファレンス アイテムを選択したときに {@link android.content.Intent} が呼び出されるようにするには、対応する {@code <Preference>} 要素の子として {@code <intent>} 要素を追加します。 + +
+ +たとえば、次の方法で、プリファレンス アイテムを使用してウェブページを開くことができます。
+ ++<Preference android:title="@string/prefs_web_page" > + <intent android:action="android.intent.action.VIEW" + android:data="http://www.example.com" /> +</Preference> ++ +
次の属性を使用して、明示的なインテントと黙示的なインテントの両方を作成できます。
+ +-
+
- {@code android:action} +
- {@link android.content.Intent#setAction setAction()} メソッドで割り当てるアクション。 + +
- {@code android:data} +
- {@link android.content.Intent#setData setData()} メソッドで割り当てるデータ。 +
- {@code android:mimeType} +
- {@link android.content.Intent#setType setType()} メソッドで割り当てる MIME タイプ。 + +
- {@code android:targetClass} +
- {@link android.content.Intent#setComponent setComponent()} メソッドでのコンポーネント名のクラス部分。 + +
- {@code android:targetPackage} +
- {@link android.content.Intent#setComponent setComponent()} メソッドでのコンポーネント名のパッケージ部分。 + +
プリファレンス アクティビティを作成する
+ +アクティビティに設定を表示するには、{@link android.preference.PreferenceActivity} クラスを継承します。 +このクラスは、{@link android.preference.Preference} オブジェクトの階層に基づいて設定のリストを表示する従来の {@link android.app.Activity} クラスを継承したものです。 + +{@link android.preference.PreferenceActivity} は、ユーザーが変更を行ったときに、各 {@link android.preference.Preference} に対応する設定を自動的に保存します。 + +
+ +注: Android 3.0 以降向けにアプリケーションを開発する場合は、代わりに {@link android.preference.PreferenceFragment} を使用する必要があります。 +プリファレンス フラグメントの使用についての詳細は、次のセグメントをご覧ください。 +
+ +注意する必要があるのは、{@link android.preference.PreferenceActivity#onCreate onCreate()} のコールバック時に、ビューのレイアウトをロードしてはならないことを忘れないでください。 +代わりに {@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} を呼び出し、XML ファイルで宣言済みのプリファレンスをアクティビティに追加する必要があります。 + +以下は、{@link android.preference.PreferenceActivity} を機能させるために最小限必要なコードです。 +
+ ++public class SettingsActivity extends PreferenceActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } +} ++ +
ユーザーがプリファレンスを変更するとすぐに、ユーザーの設定のチェックが必要なときに他のアプリケーション コンポーネントが読み取ることができるデフォルトの {@link android.content.SharedPreferences} ファイルにシステムによって変更が保存されるため、実際一部のアプリではこのコードで十分です。 + +ただし、多くのアプリでは、プリファレンスに発生する変化をリッスンするために、もう少し多くのコードが必要になります。{@link android.content.SharedPreferences} ファイルの変更のリッスンについての詳細は、プリファレンスの読み取りについてのセクションをご覧ください。 + + +
+ + + + +プリファレンス フラグメントを使用する
+ +Android 3.0(API レベル 11)以降向けに開発を行っている場合は、{@link android.preference.PreferenceFragment} を使用して {@link android.preference.Preference} オブジェクトのリストを表示する必要があります。 + +{@link android.preference.PreferenceFragment} はどのアクティビティにでも追加できます — {@link android.preference.PreferenceActivity} を使用する必要はありません。 +
+ +作成するアクティビティの種類にかかわらず、フラグメントを使用すると、アクティビティを単体で使用する場合と比べて、柔軟なアーキテクチャを持つアプリケーションを作成できます。 + +そのため、可能な限り {@link android.preference.PreferenceActivity} ではなく、{@link android.preference.PreferenceFragment} を使用して設定の表示を管理することをお勧めします。 + +
+ +{@link android.preference.PreferenceFragment} の実装は、{@link android.preference.PreferenceFragment#onCreate onCreate()} メソッドを {@link android.preference.PreferenceFragment#addPreferencesFromResource addPreferencesFromResource()} を使用してプリファレンス ファイルをロードするように定義するだけと簡単です。 + + +次に例を示します。
+ ++public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.preferences); + } + ... +} ++ +
他の {@link android.app.Fragment} と同様に、このフラグメントは {@link android.app.Activity} に追加できます。 +次に例を示します。
+ ++public class SettingsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SettingsFragment()) + .commit(); + } +} ++ +
注: {@link android.preference.PreferenceFragment} は、独自の {@link android.content.Context} オブジェクトを持ちません。 +{@link android.content.Context} オブジェクトが必要な場合は、{@link android.app.Fragment#getActivity()} を呼び出すことができます。 +ただし、{@link android.app.Fragment#getActivity()} はフラグメントがアクティビティにアタッチされている場合にのみ呼び出すようにしてください。 +フラグメントがまだアタッチされていない場合や、ライフサイクルの終了時にデタッチされた場合は、{@link android.app.Fragment#getActivity()} は null を返します。 + +
+ + +デフォルト値を設定する
+ +作成するプリファレンスは、多くの場合、アプリケーションにとって重要ないくつかの動作を定義します。そのため、ユーザーが最初にプリケーションを開いたときに、各 {@link android.preference.Preference} のデフォルト値で、関連する {@link android.content.SharedPreferences} ファイルを初期化する必要があります。 + + +
+ +まず、{@code android:defaultValue} 属性を使用して、XML ファイルの各 {@link android.preference.Preference} オブジェクトにデフォルト値を指定してください。 + +指定する値は、対応する {@link android.preference.Preference} オブジェクトで使用できるデータ型であればどのようなデータ型でもかまいません。 +次に例を示します。 +
+ ++<!-- default value is a boolean --> +<CheckBoxPreference + android:defaultValue="true" + ... /> + +<!-- default value is a string --> +<ListPreference + android:defaultValue="@string/pref_syncConnectionTypes_default" + ... /> ++ +
次に、アプリケーションのメイン アクティビティ、およびユーザーがアプリケーションを最初に開いたときに表示されるその他のアクティビティの {@link android.app.Activity#onCreate onCreate()} メソッドから、{@link android.preference.PreferenceManager#setDefaultValues setDefaultValues()} を呼び出します。 + + +
+ ++PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false); ++ +
{@link android.app.Activity#onCreate onCreate()} 時に、このメソッドを呼び出すと、アプリケーションがデフォルト設定で適切に初期化されます。アプリケーションには、動作(セルラー ネットワーク上でデータをダウンロードするかどうかなど)を決定するために、デフォルト設定を読み込むことが必要な場合があります。 + + +
+ +このメソッドは次の 3 つの引数を取ります。
+-
+
- アプリケーションの {@link android.content.Context}。 +
- デフォルト値を設定するプリファレンス XML ファイルのリソース ID。 +
- デフォルト値を複数回設定すべきかどうかを示すブール値。
+
false
の場合、デフォルト値は過去にこのメソッドが 1 度も呼ばれたことがない場合(または、デフォルト値の共有プリファレンス ファイルの{@link android.preference.PreferenceManager#KEY_HAS_SET_DEFAULT_VALUES} が false の場合)のみ設定されます。 + +
+
この 3 番目の引数を false
に設定している限り、アクティビティが開始するたびに、ユーザーが保存したプリファレンスをデフォルト値にリセットして上書きすることなく、安全にこのメソッドを呼び出すことができます。
+
+この引数を true
に設定した場合は、以前の値がすべてデフォルト値で上書きされます。
+
プリファレンス ヘッダーを使用する
+ +まれに、最初の画面がサブ画面のリストのみを表示するように設定を設計した方がよい場合もあります(図 4. と図. 5 のシステム設定アプリなど)。 + +このような設計を Android 3.0 以降で開発する場合、ネストした {@link android.preference.PreferenceScreen} 要素でサブ画面を作成するのではなく、Android 3.0 の新しい「ヘッダー」機能を使用する必要があります。 + +
+ +ヘッダーを使用して設定を作成するには、次の準備が必要です。
+-
+
- 設定をグループごとに {@link android.preference.PreferenceFragment} の別々のインスタンスに分けます。 +この場合、設定のグループごとに、個別の XML ファイルが必要になります。 + +
- 各設定グループをリストアップし対応する設定のリストを含むのがどのフラグメントかを宣言する XML ヘッダー ファイルを作成します。 + +
- {@link android.preference.PreferenceActivity} クラスを継承し、設定をホストします。 +
- {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} コールバックを実装して、ヘッダー ファイルを指定します。 + + +
この設計を使用する大きなメリットは、大きな画面で実行する場合に、{@link android.preference.PreferenceActivity} によって自動的に図. 4 の 2 ペイン レイアウトで表示されることです。 +
+ +アプリケーションが 3.0 より前のバージョンの Android をサポートしている場合でも、3.0 より前の端末で従来の多画面階層をサポートしながら、{@link android.preference.PreferenceFragment} を使用して 3.0 以降の端末で 2 ペイン表示を行うことができます(詳細については、旧バージョンでのプリファレンス ヘッダーのサポートについてのセクションをご覧ください)。 + + + +
+ + + + + + + + +ヘッダー ファイルを作成する
+ +ヘッダーのリストの設定の各グループは、ルート {@code <preference-headers>} 要素内の単独の {@code <header>} 要素によって指定されます。 +次に例を示します。
+ ++<?xml version="1.0" encoding="utf-8"?> +<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsActivity$SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <!-- key/value pairs can be included as arguments for the fragment. --> + <extra android:name="someKey" android:value="someHeaderValue" /> + </header> +</preference-headers> ++ +
{@code android:fragment} 属性を使用して、各ヘッダーは、ユーザーがヘッダーを選択したときに開く {@link android.preference.PreferenceFragment} のインスタンスを宣言します。 +
+ +{@code <extras>} 要素を使用すると、キーと値のペアを {@link android.os.Bundle} のフラグメントに渡すことができます。 +{@link android.app.Fragment#getArguments()} を呼び出すことで、フラグメントは引数を取得できます。 +さまざまな理由でフラグメントに引数を渡す場合がありますが、各グループの {@link android.preference.PreferenceFragment} の同じサブクラスを再利用し、引数を使用してフラグメントがロードするプリファレンス XML ファイルを指定することは、効果的な引数の使い方の 1 つです。 + + +
+ +たとえば、次のフラグメントは、各ヘッダーが {@code "settings"} キーを使用して {@code <extra>} 引数を定義している場合、複数の設定グループで再利用できます。 +
+ ++public static class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String settings = getArguments().getString("settings"); + if ("notifications".equals(settings)) { + addPreferencesFromResource(R.xml.settings_wifi); + } else if ("sync".equals(settings)) { + addPreferencesFromResource(R.xml.settings_sync); + } + } +} ++ + + +
ヘッダーを表示する
+ +プリファレンス ヘッダーを表示するには、{@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} コールバックメソッドを実装し、{@link android.preference.PreferenceActivity#loadHeadersFromResource loadHeadersFromResource()} を呼び出す必要があります。 + + +次に例を示します。
+ ++public class SettingsActivity extends PreferenceActivity { + @Override + public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); + } +} ++ +
ユーザーがヘッダーのリストからアイテムを選択した場合、システムが対応する {@link android.preference.PreferenceFragment} を開きます。 +
+ +注: プリファレンス ヘッダーを使用する場合、アクティビティで必要なタスクはヘッダーのロードのみであるため、{@link android.preference.PreferenceActivity} のサブクラスが {@link android.preference.PreferenceActivity#onCreate onCreate()} メソッドを実装する必要はありません。 + + +
+ + +旧バージョンでプリファレンス ヘッダーをサポートする
+ +アプリケーションが Android 3.0 よりも前のバージョンをサポートしている場合でも、3.0 以降で実行するときに、ヘッダーを使用して 2 ペイン レイアウトを提供できます。 +必要なことは、3.0 よりも前のバージョンの Android で使用するために、ヘッダー アイテムのように動作する基本的な {@link android.preference.Preference <Preference>} 要素を使用する追加のプリファレンス XML ファイルを作成することだけです。 + + +
+ +新しい {@link android.preference.PreferenceScreen} を開く代わりに、各 {@link android.preference.Preference <Preference>} 要素が、ロードするプリファレンス XML ファイルが指定されている {@link android.preference.PreferenceActivity} に {@link android.content.Intent} を送ります。 + + +
+ +たとえば、以下は Android 3.0 以降で使用されるプリファレンス ヘッダーの XML ファイル({@code res/xml/preference_headers.xml})です。 +
+ ++<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> + <header + android:fragment="com.example.prefs.SettingsFragmentOne" + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" /> + <header + android:fragment="com.example.prefs.SettingsFragmentTwo" + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" /> +</preference-headers> ++ +
また、以下は Android 3.0 よりも前のバージョンに同じヘッダーを提供するプリファレンス ファイル({@code res/xml/preference_headers_legacy.xml})です。 +
+ ++<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <Preference + android:title="@string/prefs_category_one" + android:summary="@string/prefs_summ_category_one" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_ONE" /> + </Preference> + <Preference + android:title="@string/prefs_category_two" + android:summary="@string/prefs_summ_category_two" > + <intent + android:targetPackage="com.example.prefs" + android:targetClass="com.example.prefs.SettingsActivity" + android:action="com.example.prefs.PREFS_TWO" /> + </Preference> +</PreferenceScreen> ++ +
{@code <preference-headers>} のサポートは Android 3.0 で追加されたため、Android 3.0 以降で実行されている場合のみ、システムは {@link android.preference.PreferenceActivity} の {@link android.preference.PreferenceActivity#onBuildHeaders onBuildHeaders()} を呼び出します。 + +「レガシー」ヘッダー ファイル({@code preference_headers_legacy.xml})をロードするには、Android のバージョンを確認し、Android 3.0({@link android.os.Build.VERSION_CODES#HONEYCOMB})よりも前のバージョンの場合、{@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} を呼び出す必要があります。 + + + + +次に例を示します。
+ ++@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ... + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} + +// Called only on Honeycomb and later +@Override +public void onBuildHeaders(List<Header> target) { + loadHeadersFromResource(R.xml.preference_headers, target); +} ++ +
残りの手順は、アクティビティに渡される {@link android.content.Intent} を処理して、ロードするプリファレンス ファイルを指定するだけです。 +それには、インテントのアクションを取得し、プリファレンス XML の {@code <intent>} タグで使用した既知のアクション文字列と比較します。 +
+ ++final static String ACTION_PREFS_ONE = "com.example.prefs.PREFS_ONE"; +... + +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String action = getIntent().getAction(); + if (action != null && action.equals(ACTION_PREFS_ONE)) { + addPreferencesFromResource(R.xml.preferences); + } + ... + + else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } +} ++ +
{@link android.preference.PreferenceActivity#addPreferencesFromResource addPreferencesFromResource()} の連続呼び出しは、すべてのプリファレンスを 1 つのリストにスタックすることに注意してください。そのため、else if ステートメントを使用して条件を適切に記述して、1 度のみ呼び出されるようにしてください。 + + +
+ + + + + +プリファレンスを読み込む
+ +デフォルトでは、アプリのプリファレンスは、静的メソッド {@link android.preference.PreferenceManager#getDefaultSharedPreferences PreferenceManager.getDefaultSharedPreferences()} を呼び出すとアプリケーション内のどこからでもアクセス可能なファイルに保存されます。 + + +このメソッドは、{@link android.preference.PreferenceActivity} で使用される {@link android.preference.Preference} オブジェクトに関連するすべてのキーと値のペアを含む {@link android.content.SharedPreferences} を返します。 + + +
+ +たとえば、次の方法で、アプリケーションのその他のアクティビティからプリファレンスの値の 1 つを読み込むことができます。 +
+ ++SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); +String syncConnPref = sharedPref.getString(SettingsActivity.KEY_PREF_SYNC_CONN, ""); ++ + + +
プリファレンスの変化をリッスンする
+ +さまざまな理由で、ユーザーがプリファレンスを変更してすぐに通知を受け取ることが必要になることがあります。 +プリファレンスの 1 つに変化が発生したときにコールバックを受け取るには、 {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener SharedPreference.OnSharedPreferenceChangeListener} インターフェースを実装し、{@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()} を呼び出して {@link android.content.SharedPreferences} オブジェクトにリスナを登録します。 + + + + +
+ +このインターフェースには、コールバック メソッドが {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged onSharedPreferenceChanged()} 1 つのみしか含まれておらず、アクティビティの一部として簡単に実装できます。 + + +次に例を示します。
+ ++public class SettingsActivity extends PreferenceActivity + implements OnSharedPreferenceChangeListener { + public static final String KEY_PREF_SYNC_CONN = "pref_syncConnectionType"; + ... + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(KEY_PREF_SYNC_CONN)) { + Preference connectionPref = findPreference(key); + // Set summary to be the user-description for the selected value + connectionPref.setSummary(sharedPreferences.getString(key, "")); + } + } +} ++ +
この例では、メソッドが、変更された設定が、既知のプリファレンス キーの設定かどうかチェックしています。メソッドは {@link android.preference.PreferenceActivity#findPreference findPreference()} を呼び出して、変更された {@link android.preference.Preference} オブジェクトを取得しています。これにより、メソッドは、ユーザー選択の説明として表示されるアイテムの概要を変更できます。 + + +つまり、その設定が {@link android.preference.ListPreference} またはその他の複数選択可の設定の場合、設定が変更されたときに {@link android.preference.Preference#setSummary setSummary()} を呼び出して現在のステータス(図 5. のスリープ設定など)を表示する必要があります。 + + +
+ +注: Android Design の Settings に説明されているように、ユーザーがプリファレンスを変更するごとに、{@link android.preference.ListPreference} の概要を更新して最新の設定を表示することをお勧めします。 + +
+ +アクティビティでの適切なライフサイクル管理のために、{@link android.app.Activity#onResume} と {@link android.app.Activity#onPause} のそれぞれのコールバック時に、{@link android.content.SharedPreferences.OnSharedPreferenceChangeListener} の登録と登録解除を行うことをお勧めします。 + +
+ ++@Override +protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); +} + +@Override +protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); +} ++ +
警告: {@link android.content.SharedPreferences#registerOnSharedPreferenceChangeListener registerOnSharedPreferenceChangeListener()} を呼び出す場合、現時点では、プリファレンス マネージャーにはリスナへの強い参照を格納できません。 + + +リスナへの強い参照を格納しない場合は、リスナがガベージ コレクションの影響を受けやすくなります。 +リスナが必要な間存在し続けるオブジェクトのインスタンス データ内に、リスナへの参照を保持することをお勧めします。 + +
+ +たとえば、以下のコードでは、呼び出し元は、リスナへの参照を保持していません。 +結果として、リスナはガベージ コレクションの影響を受けることになり、その後のいずれかの時点でエラーになります。 +
+ ++prefs.registerOnSharedPreferenceChangeListener( + // Bad! The listener is subject to garbage collection! + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}); ++ +
そのため、リスナが必要な間存在し続けるオブジェクトのインスタンス データ フィールドに、リスナへの参照を格納してください。 +
+ ++SharedPreferences.OnSharedPreferenceChangeListener listener = + new SharedPreferences.OnSharedPreferenceChangeListener() { + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + // listener implementation + } +}; +prefs.registerOnSharedPreferenceChangeListener(listener); ++ +
ネットワークの使用を管理する
+ + +Android 4.0 以降では、フォアグラウンドとバックグラウンドでのアプリケーションのネットワーク データの使用量を、システムの設定アプリケーションでユーザーが確認できます。 +また、ユーザーは、個々のアプリのバックグラウンド データの使用を無効にできます。 +アプリのバックグラウンドからのデータへのアクセスをユーザーが無効にすることを防ぐには、データ接続を効率的に使用することと、アプリケーションの設定でアプリのデータの利用方法をユーザーが調整できるようにすることが必要です。 + +
+ +
たとえば、データを同期する頻度や、Wi-Fi 上でのみアップロードやダウンロードを実行するようにするかどうか、ローミング時にデータを使用するかどうかなどを、ユーザーが設定できるようにすることができます。 +これらをユーザーが管理できる場合、システム設定に設定した限度にデータ使用量が近づいたときに、データへのアプリのアクセスをユーザーが無効にする可能性は減少します。ユーザーはアプリのアクセスを無効にする代わりに、アプリのデータの使用量を厳密に管理できます。 + + +
+ +アプリのデータ使用を管理するために {@link android.preference.PreferenceActivity} に必要なプリファレンスを追加したら、マニフェスト ファイルに {@link android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} のインテント フィルタを追加する必要があります。 + +次に例を示します。
+ ++<activity android:name="SettingsActivity" ... > + <intent-filter> + <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> +</activity> ++ +
このインテント フィルタは、これがアプリケーションのデータ使用をコントロールしているアクティビティであるとシステムに示します。 +これにより、ユーザーがシステム設定アプリからアプリのデータ使用量を調べるときに、[View application settings] ボタンを使用できるようになります。このボタンを押すと、{@link android.preference.PreferenceActivity} が開始し、アプリのデータ使用量を調整できるようになります。 + + +
+ + + + + + + +カスタム プリファレンスを作成する
+ +Android フレームワークには、異なる設定タイプの UI を作成できるさまざまな {@link android.preference.Preference} サブクラスが含まれています。ただし、番号ピッカーや日付ピッカーなど、組み込みソリューションがない場合に必要な設定が存在する可能性もあります。 + + +このような場合、{@link android.preference.Preference} クラスまたは他のサブクラスの 1 つを継承して、カスタム プリファレンスを作成する必要があります。 +
+ +{@link android.preference.Preference} クラスを継承する場合、次のことが必要です。 +
+ +-
+
- ユーザーがその設定を選択したときに表示されるユーザー インターフェースを指定する。 +
- 適切なタイミングで設定の値を保存する。 +
- {@link android.preference.Preference} が表示されるときに、現在の値(またはデフォルト値)で初期化する。 + +
- システムによってリクエストされた場合にデフォルト値を提供する。 +
- {@link android.preference.Preference} が独自の UI(ダイアログなど)を提供している場合、状態を保存し復元してライフサイクルの変化を処理する(ユーザーが画面を回転させた場合など)。 + +
以下の各セクションでは、上記の各事項を実現する方法を説明します。
+ + + +ユーザー インターフェースを指定する
+ +{@link android.preference.Preference} クラスを直接継承する場合、{@link android.preference.Preference#onClick()} を実装して、ユーザーがアイテムを選択したときに発生するアクションを定義する必要があります。 + +ただし、大部分のカスタム設定では、手順が簡単な {@link android.preference.DialogPreference} を継承してダイアログを表示する方法が利用されています。 +{@link android.preference.DialogPreference} を継承する場合、クラス コンストラクタで {@link android.preference.DialogPreference#setDialogLayoutResource setDialogLayoutResourcs()} を呼び出してダイアログのレイアウトを指定する必要があります。 + + +
+ +たとえば、以下のカスタム {@link android.preference.DialogPreference} のコンストラクタでは、レイアウトを宣言しデフォルトのポジティブとネガティブのダイアログ ボタンのテキストを指定しています。 + +
+ ++public class NumberPickerPreference extends DialogPreference { + public NumberPickerPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setDialogLayoutResource(R.layout.numberpicker_dialog); + setPositiveButtonText(android.R.string.ok); + setNegativeButtonText(android.R.string.cancel); + + setDialogIcon(null); + } + ... +} ++ + + +
設定の値を保存する
+ +設定の値が整数の場合、またはブール値を保存する{@link android.preference.Preference#persistBoolean persistBoolean()} の場合、{@link android.preference.Preference#persistInt persistInt()} など、{@link android.preference.Preference} クラスの {@code persist*()} メソッドのいずれかを呼び出すことで、設定の値をいつでも保存できます。 + + +
+ +注: 各 {@link android.preference.Preference} には、1 つのデータ型のデータのみ保存できます。そのため、カスタム {@link android.preference.Preference} で使用されているデータ型に対応する {@code persist*()} メソッドを使用する必要があります。 + +
+ +設定をいつ保存したらよいかは、継承する {@link android.preference.Preference} クラスによって異なります。 +{@link android.preference.DialogPreference} を継承する場合、ポジティブな結果でダイアログが閉じられたとき(ユーザーが [OK] ボタンを選択したとき)のみ、値を保存する必要があります。 + +
+ +{@link android.preference.DialogPreference} が閉じられたときには、システムが {@link android.preference.DialogPreference#onDialogClosed onDialogClosed()} メソッドを呼び出します。
+このメソッドには、ユーザーの結果が「Positive」かどうかを指定するブール値の引数が含まれています — この値が true
の場合はユーザーがポジティブ ボタンを選択しているということであり、新しい値を保存する必要があります。
+
+次に例を示します。
+
+@Override +protected void onDialogClosed(boolean positiveResult) { + // When the user selects "OK", persist the new value + if (positiveResult) { + persistInt(mNewValue); + } +} ++ +
この例では、mNewValue
は、設定の現在の値を保持するクラスの 1 つです。
+{@link android.preference.Preference#persistInt persistInt()} を呼び出すと、値が {@link android.content.SharedPreferences} ファイルに保存されます(この {@link android.preference.Preference} の XML ファイルに指定されたキーを自動的に使用して保存されます)。
+
+
現在の値を初期化する
+ +システムは {@link android.preference.Preference} を画面に追加すると、{@link android.preference.Preference#onSetInitialValue onSetInitialValue()} を呼び出し、その設定用に保存されている値がある場合は通知します。 + +保存されている値がない場合、この呼び出しによりデフォルト値が設定されます。 +
+ +この {@link android.preference.Preference#onSetInitialValue onSetInitialValue()} メソッドは、ブール値の restorePersistedValue
を、その設定用に値が保存済みかどうか示すために渡します。
+
+true
の場合、{@link android.preference.Preference} クラスの {@code getPersisted*()} メソッド(整数用の {@link android.preference.Preference#getPersistedInt getPersistedInt()} など)のいずれかを呼び出して保存されている値を取得する必要があります。
+
+
+通常は保存されている値を取得するのは、UI を更新して以前保存した値を反映させるためです。
+
+
restorePersistedValue
が false
の場合、2 番目の引数で渡されたデフォルト値を使用する必要があります。
+
+@Override +protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + if (restorePersistedValue) { + // Restore existing state + mCurrentValue = this.getPersistedInt(DEFAULT_VALUE); + } else { + // Set default state from the XML attribute + mCurrentValue = (Integer) defaultValue; + persistInt(mCurrentValue); + } +} ++ +
各 {@code getPersisted*()} メソッドは、値が保存されていない場合またはキーが存在しない場合に使用するデフォルト値を指定する引数を取ります。 +上記の例では、{@link android.preference.Preference#getPersistedInt getPersistedInt()} が保存されている値を返すことができない場合に備えて、ローカル定数がデフォルト値を指定するために使用されています。 + +
+ +警告: defaultValue
は、restorePersistedValue
が true
の場合、常に null になるため、{@code getPersisted*()} メソッドでデフォルト値として使用できません。
+
+
デフォルト値を提供する
+ +{@link android.preference.Preference} クラスのインスタンスがデフォルト値を指定している場合({@code android:defaultValue} 属性を使用)、システムは、オブジェクトのインスタンスを作成するときに {@link android.preference.Preference#onGetDefaultValue onGetDefaultValue()} を呼び出してデフォルト値を取得します。 + + +システムでデフォルト値を {@link android.content.SharedPreferences} に保存するには、このメソッドを実装する必要があります。 + +次に例を示します。
+ ++@Override +protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, DEFAULT_VALUE); +} ++ +
このメソッドは、属性の配列と取得する必要がある {@code android:defaultValue} のインデックス位置を提供しており、これらはデフォルト値を保存するために必要な情報のすべてです。 +属性からデフォルト値を抽出するためにこのメソッドの実装が必要なのは、デフォルト値が定義されていないときのために属性のローカル デフォルト値を指定する必要があるためです。 + +
+ + + +プリファレンスの状態を保存し復元する
+ +レイアウトの {@link android.view.View} と同じく、{@link android.preference.Preference} サブクラスは、アクティビティやフラグメントが再開される場合(ユーザーが画面を回転させた場合など)に状態の保存と復元を担当します。 + +{@link android.preference.Preference} クラスの状態を適切に保存し復元するには、ライフサイクル コールバック メソッドの {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} と {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} を実装する必要があります。 + + + +
+ +{@link android.preference.Preference} の状態は、{@link android.os.Parcelable} インターフェースを実装するオブジェクトによって定義されます。 +Android フレームワークでは、このようなオブジェクトである{@link android.preference.Preference.BaseSavedState} クラスが状態オブジェクトを定義するための起点として提供されています。 + +
+ +{@link android.preference.Preference} クラスが状態を保存する方法を定義するには、{@link android.preference.Preference.BaseSavedState} クラスを継承する必要があります。 +いくつかのメソッドをオーバーライドして {@link android.preference.Preference.BaseSavedState#CREATOR} オブジェクトを定義してください。 + +
+ +大部分のアプリでは、次の実装をコピーして、{@link android.preference.Preference} サブクラスが整数以外のデータ型のデータを保存している場合は、{@code value} を処理している行を変更するだけで使用できます。 + +
+ ++private static class SavedState extends BaseSavedState { + // Member that holds the setting's value + // Change this data type to match the type saved by your Preference + int value; + + public SavedState(Parcelable superState) { + super(superState); + } + + public SavedState(Parcel source) { + super(source); + // Get the current preference's value + value = source.readInt(); // Change this to read the appropriate data type + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + // Write the preference's value + dest.writeInt(value); // Change this to write the appropriate data type + } + + // Standard creator object using an instance of this class + public static final Parcelable.Creator<SavedState> CREATOR = + new Parcelable.Creator<SavedState>() { + + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; +} ++ +
{@link android.preference.Preference.BaseSavedState} の上記の実装をアプリに追加(通常、{@link android.preference.Preference} サブクラスのサブクラスとして追加)するとともに、{@link android.preference.Preference} サブクラスの {@link android.preference.Preference#onSaveInstanceState onSaveInstanceState()} と {@link android.preference.Preference#onRestoreInstanceState onRestoreInstanceState()} を実装する必要があります。 + + + + +
+ +次に例を示します。
+ ++@Override +protected Parcelable onSaveInstanceState() { + final Parcelable superState = super.onSaveInstanceState(); + // Check whether this Preference is persistent (continually saved) + if (isPersistent()) { + // No need to save instance state since it's persistent, + // use superclass state + return superState; + } + + // Create instance of custom BaseSavedState + final SavedState myState = new SavedState(superState); + // Set the state's value with the class member that holds current + // setting value + myState.value = mNewValue; + return myState; +} + +@Override +protected void onRestoreInstanceState(Parcelable state) { + // Check whether we saved the state in onSaveInstanceState + if (state == null || !state.getClass().equals(SavedState.class)) { + // Didn't save the state, so call superclass + super.onRestoreInstanceState(state); + return; + } + + // Cast state to custom BaseSavedState and pass to superclass + SavedState myState = (SavedState) state; + super.onRestoreInstanceState(myState.getSuperState()); + + // Set this Preference's widget to reflect the restored state + mNumberPicker.setValue(myState.value); +} ++ diff --git a/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd b/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd new file mode 100644 index 0000000000000000000000000000000000000000..1cff3f62d0229041aa5008bd48c540c97edd8c3d --- /dev/null +++ b/docs/html-intl/intl/ja/guide/topics/ui/ui-events.jd @@ -0,0 +1,291 @@ +page.title=入力イベント +parent.title=ユーザー インターフェース +parent.link=index.html +@jd:body + + + +
Android では、アプリケーションでのユーザーの操作からイベントをインターセプトする方法が複数用意されていますが、ユーザー インターフェース内のイベントをインターセプトする場合は、ユーザーが操作する個々の View オブジェクトからイベントを取得することになります。 + +View クラスは、このための手段を提供しています。
+ +レイアウトを構成するために使用する各種の View クラスには、UI イベントの処理に役に立ついくつかのパブリック コールバック メソッドが含まれています。
+これらのパブリック コールバック メソッドは、オブジェクトで対応するアクションが発生したときに Android フレームワークによって呼び出されます。
+たとえば、ビュー(ボタンなど)がタップされたときには、そのオブジェクト上で onTouchEvent()
メソッドが呼び出されます。
+このようなイベントをインターセプトするには、クラスを継承しメソッドをオーバーライドする必要があります。
+ただし、このようなイベントを処理するたびに View オブジェクトを継承することは、実用的とは言えません。
+そのため、View クラスには、簡単に定義できるコールバックを持つネストされたインターフェースのコレクションも含まれています。
+これらのインターフェースは、イベントリスナと呼ばれ、UI へのユーザーの操作を取得するために使用されます。
+
通常は、イベントリスナを使用して、ユーザーの操作をリッスンすることになりますが、カスタム コンポーネントを作成するために View クラスを継承する場合や、 +処理を工夫するために {@link android.widget.Button} クラスを継承することもできます。 + +その場合は、クラスのイベント ハンドラを使用して、クラスにデフォルトのイベント動作を定義できます。 +
+ + +イベントリスナ
+ +イベントリスナは、コールバック メソッド 1 つを含む {@link android.view.View} クラスのインターフェースです。 +以下のメソッドは、イベントリスナが登録されているビューが UI アイテムへのユーザーの操作によってトリガーされたときに、Android フレームワークによって呼び出されます。 +
+ +イベントリスナ インターフェースに含まれているのは、以下のコールバック メソッドです。
+ +-
+
onClick()
+ - {@link android.view.View.OnClickListener} のメソッド。ユーザーがアイテムをタップしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを押したときに、呼び出されます。 + + + +
onLongClick()
+ - {@link android.view.View.OnLongClickListener} のメソッド。ユーザーがアイテムをタップしてホールドしたとき(タッチモードの場合)、またはナビゲーション キーまたはトラックボールでアイテムにフォーカスを合わせ、適切な「エンター」キーまたはトラックボールを長押し(1 秒間)したときに、呼び出されます。 + + + +
onFocusChange()
+ - {@link android.view.View.OnFocusChangeListener} のメソッド。ナビゲーション キーやトラックボールを使用してユーザーがアイテムに移動してきたときまたはアイテムから離れるときに、呼び出されます。 + +
onKey()
+ - {@link android.view.View.OnKeyListener} のメソッド。ユーザーがアイテムにフォーカスを合わせて端末のハードウェア キーを押したとき、または離したときに、呼び出されます。 + +
onTouch()
+ - {@link android.view.View.OnTouchListener} のメソッド。画面(アイテムの境界線内)での押す、離す、移動操作などのタップイベントと認定されるアクションをユーザーが実行した場合に呼び出されます。 + + +
onCreateContextMenu()
+ - {@link android.view.View.OnCreateContextMenuListener} のメソッド。コンテキスト メニュー(「長押しクリック」し続けると作成されます)の作成中に呼び出されます。 +コンテキスト メニューについての詳細は、「メニュー」のデベロッパー ガイドをご覧ください。 + + +
これらのメソッドは、それぞれのインターフェースにおける唯一のメソッドです。これらのいずれかのメソッドを定義しイベントを処理するには、ネストされたインターフェースをアクティビティに実装するか、ネストされたインターフェースを匿名クラスとして定義します。次に、その実装のインスタンスを対応する View.set...Listener()
メソッドに渡します。
+
+
+(例: {@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}
を呼び出し、{@link android.view.View.OnClickListener OnClickListener} の実装を渡します)。
+
+
次の例は、ボタンへの on-click リスナの登録方法を示しています。
+ ++// Create an anonymous implementation of OnClickListener +private OnClickListener mCorkyListener = new OnClickListener() { + public void onClick(View v) { + // do something when the button is clicked + } +}; + +protected void onCreate(Bundle savedValues) { + ... + // Capture our button from layout + Button button = (Button)findViewById(R.id.corky); + // Register the onClick listener with the implementation above + button.setOnClickListener(mCorkyListener); + ... +} ++ +
OnClickListener をアクティビティの一部として実装すると、余分なクラスのロードとオブジェクトの割り当てを避けることができます。 +次に例を示します。
++public class ExampleActivity extends Activity implements OnClickListener { + protected void onCreate(Bundle savedValues) { + ... + Button button = (Button)findViewById(R.id.corky); + button.setOnClickListener(this); + } + + // Implement the OnClickListener callback + public void onClick(View v) { + // do something when the button is clicked + } + ... +} ++ +
上の例の onClick()
コールバックには戻り値がありませんが、イベントリスナ メソッドの中には、ブール値を返すことが必要なものもあることに注意してください。
+ブール値が示す事柄はイベントによって異なります。
+以下はその例です。
-
+
{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}
- イベントを消費済みでこれ以上イベントを引き継ぐべきでないかどうかを示すブール値を返します。 +つまり、イベントが処理済みでイベントの停止が必要なことを示す場合は、true を返します。イベントが未処理の場合や、他の on-click リスナへのイベントの引き継ぎが必要な場合は、false を返します。 + + +
+ {@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}
- イベントを消費済みでこれ以上イベントを引き継ぐべきでないかどうかを示すブール値を返します。 + + つまり、イベントが処理済みでイベントの停止が必要なことを示す場合は、true を返します。イベントが未処理の場合や、他の on-key リスナへのイベントの引き継ぎが必要な場合は、false を返します。 + +
+ {@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}
- リスナがイベントを消費しているかどうかを示すブール値を返します。 +ここで注意する必要があるのは、このイベントが相互にフォローし合う複数のアクションを含むことがあることです。 +ダウン アクション イベントが受け取られたときに false を返すと、そのイベントを消費しておらず、そのイベントから続けて発生するアクションに関心がないことを示すことになります。 + +そのため、指での操作などのそのイベント内のその他のアクションや操作の最後に発生する アップ アクション イベントで、呼び出されることはなくなります。 +
+
ハードウェア キー イベントは常に、その時点でフォーカスがあるビューに届けられることに注意してください。ハードウェア・キー・イベントは、ビュー階層の一番上から下に適切な対象に到達するまでディスパッチされます。
+ビュー(またはビューの子)にフォーカスがある場合、イベントが {@link android.view.View#dispatchKeyEvent(KeyEvent)
+dispatchKeyEvent()}
メソッドを介して伝わっていると判断できます。
+ビューを通じてキーイベントを取得する別の方法としては、{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}
と {@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}
を使用してアクティビティ内のすべてのイベントを受け取る方法もあります。
+
+
また、アプリケーションのテキスト入力について検討する際は、多くの端末にソフトウェア入力メソッドしかないことに注意してください。
+ソフトウェア入力メソッドでは、キーの利用は必要ありません。音声入力や手書き入力などを利用できるものもあります。入力メソッドがキーボードに似たインターフェースを提供していたとしても、そのインターフェースは通常、{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}
ファミリーのイベントをトリガーしません。
+
+アプリケーションの使用をハードウェア キーボード付きの端末に限定するのではない限り、制御するために特定のキーを押すことが必要な UI は作成しないでください。
+
+特に、ユーザーのリターンキー押下時に入力を検証するような処理は行わないようにし、代わりに {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE} などのアクションを使用して入力メソッドにアプリケーションが求める反応を伝えてください。そうすることで、入力メソッドが UI を意味のあるものにします。
+
+ソフトウェア入力メソッドの動作を推測し、その推測に基づいて、書式設定済みのテキストをアプリケーションに提供することは避けてください。
+
注: Android では、まずイベント ハンドラが呼び出され、次にクラス定義から適切なデフォルト ハンドラが呼び出されます。 +そのため、これらのイベントリスナから true が返された場合、イベントの他のイベントリスナへの伝播は止まり、ビューのデフォルトのイベント ハンドラへのコールバックもブロックされます。 + +そのため、イベントを終了させたいことが確実な場合のみ、true を返すようにしてください。
+ + +イベント ハンドラ
+ +ビューからカスタム コンポーネントを作成する場合、デフォルトのイベント ハンドラとして使用される複数のコールバック メソッドを定義できます。イベント ハンドリングに使用される次のような一般的なコールバックの一部については、詳細をカスタム コンポーネントについてのドキュメントでご覧いただけます。 + + + +
+-
+
{@link android.view.View#onKeyDown}
- 新しいキーイベントの発生時に呼び出されます。
+ {@link android.view.View#onKeyUp}
- キー アップ イベントの発生時に呼び出されます。
+ {@link android.view.View#onTrackballEvent}
- トラックボール モーション イベントの発生時に呼び出されます。
+ {@link android.view.View#onTouchEvent}
- タッチスクリーン モーション イベント発生時に呼び出されます。
+ {@link android.view.View#onFocusChanged}
- ビューがフォーカスを取得した場合または失った場合に呼び出されます。
+
View クラスに含まれていないメソッドの中にも、イベントの処理の方法に直接関係するメソッドがいくつかあります。 +そのため、レイアウト内の複雑なイベントを管理する場合は、以下のメソッドの使用を検討してください。 +
+-
+
{@link android.app.Activity#dispatchTouchEvent(MotionEvent) + Activity.dispatchTouchEvent(MotionEvent)}
- {@link android.app.Activity} が、すべてのタップイベントをウィンドウにディスパッチされる前にインターセプトできるようにします。 +
+ {@link android.view.ViewGroup#onInterceptTouchEvent(MotionEvent) + ViewGroup.onInterceptTouchEvent(MotionEvent)}
- {@link android.view.ViewGroup} が、イベントが子ビューにディスパッチされたときにイベントを監視できるようにします。 +
+ {@link android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean) + ViewParent.requestDisallowInterceptTouchEvent(boolean)}
- このメソッドを親ビュー上で呼び出すことで、{@link + android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}
による親ビューのタップイベントのインターセプトを許可しないことを示すことができます。 +
+
タッチモード
++ユーザーが方向キーまたはトラックボールを使用してユーザー インターフェースを操作する場合、入力を受け付けるアイテムがどのアイテムなのかユーザーが知ることができるようにアクション可能なアイテム(ボタンなど)にフォーカスを与えることが必要になります。 + +ただし、端末にタッチ機能がある場合は、ユーザーはタップでインターフェースの操作を開始するため、アイテムをハイライトすることや、特定のビューにフォーカスを与えることは必要ではなくなりました。 + +そのため、「タッチモード」と名付けられた操作モードが存在します。 + +
++タッチ可能な端末では、ユーザーが画面をタップすると、端末がタッチモードになります。 +端末がタッチモードの場合、テキスト編集ウィジェットなどの {@link android.view.View#isFocusableInTouchMode} が true のビューのみがフォーカス可能であり、ボタンなどのタップ可能なその他のビューは、タップされたときにフォーカスされることはありません。それらのビューは、押されたときに、on-click リスナを起動します。 + + + +
++ユーザーが方向キーを押すか、またはトラックボールをスクロールすると、端末はタッチモードから抜け、ビューがフォーカスを取得します。 +これにより、ユーザーは、画面をタップすることなく、ユーザー インターフェースの操作を再開できます。 + +
++タッチモード状態は、システム全体(すべてのウィンドウとアクティビティ)で維持されます。端末が現在タッチモードかどうか確認するには、{@link android.view.View#isInTouchMode} を呼び出します。 + + +
+ + +フォーカスの処理
+ +フレームワークは、ユーザーに入力に応じて、通常のフォーカス移動を処理します。フレームワークが処理するフォーカス移動には、ビューが削除されたり非表示になったり、新しいビューが利用可能になったりしたことによるフォーカスの変化も含まれます。
+
+ビューは、{@link android.view.View#isFocusable()}
メソッドで、フォーカスが取得可能なことを示します。
+ビューのフォーカスの取得可否を変更するには、{@link android.view.View#setFocusable(boolean) setFocusable()}
を呼び出します。
+タッチモードでは、{@link android.view.View#isFocusableInTouchMode()}
でビューがフォーカスを取得可能かどうか確認できます。ビューのフォーカスの取得可否は、{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}
で変更できます。
+
+
+
フォーカスの移動は、所定の方向で最も近くにあるアイテムを見つけるアルゴリズムに基づきますが、 +まれに、デフォルトのアルゴリズムが開発者の意図する動作と一致しない場合もあります。 +この場合、レイアウト ファイルの + +nextFocusDown、 nextFocusLeft、 nextFocusRight、 +nextFocusUp の各 XML 属性を明示的にオーバーライドできます。これらの属性のいずれかを、フォーカスの移動元のビューに追加します。 +フォーカスの移動先のビューの ID になる属性の値を定義します。 +次に例を示します。
++<LinearLayout + android:orientation="vertical" + ... > + <Button android:id="@+id/top" + android:nextFocusUp="@+id/bottom" + ... /> + <Button android:id="@+id/bottom" + android:nextFocusDown="@+id/top" + ... /> +</LinearLayout> ++ +
本来、上記の縦方向のレイアウトでは、1 番上のボタンから上に移動しようとしても、2 番目のボタンから下に移動しようしても、どこにもフォーカスが移動しないはずでしたが、上記の処理により、 +1 番上のボタンによって 1 番下のボタンが + nextFocusUp として定義され(逆の場合も同様)、フォーカスが、上から下と下から上に順番に移動するようになります。 +
+ +UI でビューをフォーカス可能にする場合は(従来は、ビューはフォーカス可能ではありません)、レイアウトの宣言で android:focusable
XML 属性をビューに追加し、値を
+
+ true に設定します。また、android:focusableInTouchMode
を使用して、タッチモードのときにビューをフォーカス可能にすることもできます。
+
特定のビューへのフォーカスをリクエストするには、{@link android.view.View#requestFocus()}
を呼び出します。
フォーカス イベントをリッスンするには(ビューがフォーカスを受け取ったときまたは失ったときに通知を受け取るには)、上記のイベントリスナのセクションの説明に従って {@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}
を使用します。
+
+
Android 6.0 Marshmallow
-次期バージョンの Android に向けて準備しましょう。 - Nexus 5、6、9、Nexus Player でアプリをテストします。
- - +Android N Developer Preview
++ Get ready for the next version of Android! + Test your apps on Nexus and other devices. Support new system + behaviors to save power and memory. + Extend your apps with multi-window UI, + direct reply notifications and more. +
+ - スタートガイド -- + Learn more + + +
-
+
- + + + Get the SDK + + +
- + + + Browse sample code + + +
- + + + Watch stories + + +
Build Beautiful Apps
本書の内容 - - 詳細を表示 - 詳細を非表示
- --
-
- アプリのリンク機能 -
- アプリの自動バックアップ -
- 認証 - - -
- ダイレクト シェア -
- 音声インタラクション -
- Assist API -
- 通知 -
- Bluetooth スタイラスのサポート -
- Bluetooth Low Energy のスキャンの改善 -
- アクセス ポイント2.0 リリース 1 のサポート -
- 4K ディスプレイ モード -
- テーマ化可能な ColorStateLists -
- オーディオ機能 -
- ビデオ機能 -
- カメラ機能
-
-
-
- Flashlight API -
- カメラの再処理 -
- - Android for Work の機能 -
API の変更点
- - -M Developer Preview では、ユーザーやアプリ開発者に Android プラットフォームの次期リリースの新機能をいち早く試していただくことができます。 - -このドキュメントでは、いくつかの注目すべき API の概要について説明します。
- -M Developer Preview は、Developer の早期導入者とテスターを対象としています。 -是非 -M Developer Preview を試してフィードバックをご提供ください。あなたのご意見が、Android フレームワークの方向性を決定する上で貴重な情報になります。 - -
- -注意: M Developer Preview を使用したアプリは、Google Play ストアには公開しないでください。 -
- -注: このドキュメントには、まだ developer.android.com のリファレンス マテリアルにないクラスやメソッドが多数登場します。 -このドキュメントでは、API エレメントは {@code code style} 形式で記載されています(ハイパーリンクなし)。 -これらのエレメントに関する API ドキュメント(準備段階)については、プレビューのリファレンスをダウンロードしてください。 -
- -重要な動作の変更点
- -過去に Android にアプリを公開したことがある場合は、アプリがプラットフォームの変更による影響を受ける場合があります。 -
- -詳細については、Behavior Changes をご覧ください。
- -アプリのリンク機能
-このプレビューでは、アプリのリンク機能を強化することで Android のインテント システムが向上しました。この機能では、所有するウェブドメインにアプリを関連付けることができます。 -この関連付けに基づいて、プラットフォームが特定のウェブリンクの処理に使用するデフォルトのアプリを決めることができ、ユーザーにアプリを選択させる操作をスキップできます。この機能の実装方法については、 -アプリのリンク機能をご覧ください。 - - - -
アプリの自動バックアップ
-システムで、アプリの自動フルデータ バックアップと復元を実行できるようになりました。この動作は、M Preview を対象としたアプリでデフォルトで有効になっています。追加のコードは必要ありません。 -ユーザーが Google アカウントを削除すると、バックアップ データも削除されます。 -この機能の仕組みとファイル システムでバックアップ対象を設定する方法については、 -アプリの自動バックアップをご覧ください。 -
- -認証
-このプレビューでは、サポートされる端末での指紋スキャンを使用したユーザー認証や、端末のロック解除メカニズム(ロック画面のパスワードなど)を使って最後にユーザーが認証された時期の確認などを行える新しい API が提供されます。 - -これらの API は、Android キーストローク システムと共に使用します。 -
- -指紋認証
- -指紋スキャンでユーザーを認証するには、新しい -{@code android.hardware.fingerprint.FingerprintManager} クラスのインスタンスを取得して、 -{@code FingerprintManager.authenticate()} メソッドを呼び出します。アプリは、指紋センサー付きの、互換性のある端末上で実行している必要があります。 -指紋認証フローのユーザー インターフェースをアプリに実装し、UI には標準の Android 指紋アイコンを使用する必要があります。Android 指紋アイコン({@code c_fp_40px.png})はサンプルアプリに含まれています。指紋認証を使用するアプリを複数開発する場合は、それぞれのアプリで個別にユーザーの指紋を認証する必要があります。 - - - - -
- -アプリでこの機能を使用するには、まずマニフェストに {@code USE_FINGERPRINT} パーミッションを追加する必要があります。 -
- --<uses-permission - android:name="android.permission.USE_FINGERPRINT" /> -- - - -
アプリでの指紋認証の実装については、 -指紋ダイアログのサンプルをご覧ください。 -
- -この機能をテストする場合は、次の手順を使用します。
--
-
- Android SDK Tools Revision 24.3 をインストールします(まだインストールしていない場合)。 -
- -[設定] > [セキュリティ] > [指紋] の登録手順に従い、エミュレータに新しい指紋を登録します。 -
- エミュレータを使って、次のコマンドで指紋のタッチ ベントをエミュレートします。
-同じコマンドを使って、ロック画面やアプリでの指紋のタッチイベントをエミュレートします。
-
-
-adb -e emu finger touch <finger_id> -
-Windows では、{@code telnet 127.0.0.1
-}、 -{@code finger touch } の順に実行する必要がある場合があります。 -
-
資格情報の確認
-アプリでは、ユーザーがいつ、最後に端末のロックを解除したかに基づいて、ユーザーを認証できます。この機能によって、ユーザーがアプリ固有のパスワードを覚えたり、開発者が独自の認証ユーザー インターフェースを実装したりする必要性がなくなります。 - -アプリでこの機能を使用する場合は、ユーザー認証用の公開鍵か秘密鍵を実装する必要があります。 -
- -ユーザーが正常に認証された後、同じキーを再使用できるタイムアウト期間を設定するには、{@link javax.crypto.KeyGenerator} か -{@link java.security.KeyPairGenerator} のセットアップ後に新しい -{@code android.security.keystore.KeyGenParameterSpec.setUserAuthenticationValidityDurationSeconds()} メソッドを呼び出します。 - -現在、この機能は対象暗号化操作で動作します。 -
- -再認証ダイアログを過度に表示しないようにします。アプリでは、まず暗号オブジェクトを使用し、タイムアウトした場合は -{@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence) createConfirmDeviceCredentialIntent()} メソッドを使用してユーザーをアプリ内で再認証するようにします。 - - -
- -アプリでのこの機能の実装については、 -資格情報の確認サンプルをご覧ください。 -
- -ダイレクト シェア
- - - -このプレビューでは、ユーザーが直感的にすばやく共有できるようにする API が提供されます。アプリで特定のアクティビティを起動するダイレクト シェアのターゲットを定義すると、それらのダイレクト シェアのターゲットは [共有] メニューに表示されるようになります。 - -この機能を使うと、他のアプリ内にある連絡先などのターゲットにコンテンツを共有できます。 -たとえば、ダイレクト シェアのターゲットによって他のソーシャル ネットワーク アプリのアクティビティが起動し、そのアプリ内の特定の友人やコミュニティに直接コンテンツを共有できるようになります。 - -
- -ダイレクト シェアのターゲットを有効にするには、まず
-{@code android.service.} を拡張するクラスを定義する必要があります。
-{@code chooser.ChooserTargetService} クラス。マニフェストで
-{@code ChooserTargetService} を宣言します。その宣言内で、
-{@code BIND_CHOOSER_TARGET_SERVICE} パーミッションと、
-{@code SERVICE_INTERFACE} アクションを使ったインテント フィルタを指定します。
次の例は、マニフェストで {@code ChooserTargetService} を宣言する方法を示しています。 -
--<service android:name=".ChooserTargetService" - android:label="@string/service_name" - android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"> - <intent-filter> - <action android:name="android.service.chooser.ChooserTargetService" /> - </intent-filter> -</service> -- -
{@code ChooserTargetService} に公開するアクティビティごとに、 {@code "android.service.chooser.chooser_target_service"} という名前の
-{@code
-<activity android:name=".MyShareActivity” - android:label="@string/share_activity_label"> - <intent-filter> - <action android:name="android.intent.action.SEND" /> - </intent-filter> -<meta-data - android:name="android.service.chooser.chooser_target_service" - android:value=".ChooserTargetService" /> -</activity> -- -
音声インタラクション
--このプレビューでは、音声アクションと共に使用することでアプリに対話形式の音声操作をビルドできる新しい音声インタラクション API が提供されます。 - - -{@code android.app.Activity.isVoiceInteraction()} メソッドを呼び出して、アクティビティが音声アクションへの応答として開始されたかどうかを確認します。 -音声アクションへの応答であった場合、アプリで -{@code android.app.VoiceInteractor} クラスを使用してユーザーに音声の確認や、オプションのリストからの選択などを要求できます。 -音声アクションの実装の詳細については、 -音声アクションの開発者サイトをご覧ください。 -
- -Assist API
--このプレビューでは、アシスタントを介してユーザーがアプリを操作できる新しい方法が用意されています。この機能を使用するには、ユーザーが現在のコンテキストを使うようアシスタントを有効にする必要があります。 -有効にすると、ホーム ボタンを長押しすることで、すべてのアプリ内でアシスタントを呼び出すことができます。 -
--{@link android.view.WindowManager.LayoutParams#FLAG_SECURE} フラグを設定すると、アプリが現在のコンテキストをアシスタントと共有しないようにできます。新しい {@code android.app.Activity.AssistContent} クラスを使用すると、プラットフォームがアシスタントに渡す標準的な情報セットの他に、アプリで追加の情報を共有できます。 - -
- -アプリから追加のコンテキストをアシスタントに提供するには、次の手順を使用します。
- --
-
- {@link android.app.Application.OnProvideAssistDataListener} インターフェースを実装します。 -
- -{@link android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener) registerOnProvideAssistDataListener()} を使用してこのリスナーを登録します。 -
- アクティビティ固有の文脈情報を提供するには、 -{@link android.app.Activity#onProvideAssistData(android.os.Bundle) onProvideAssistData()} コールバックと、任意で新しい -{@code Activity.onProvideAssistContent()} コールバックをオーバーライドします。 -
通知
-このプレビューでは、通知に関して次のような API の変更点が追加されています。
--
-
- 新しいアラームのみの Do not disturb モードに相当する新しい {@code NotificationListenerService.INTERRUPTION_FILTER_ALARMS} フィルタレベル。 - -
- ユーザーが予定したリマインダを他のイベント({@link android.app.Notification#CATEGORY_EVENT})やアラーム({@link android.app.Notification#CATEGORY_ALARM})から区別する際に使用される新しい{@code Notification.CATEGORY_REMINDER} カテゴリの値。 - - - -
- {@code Notification.Builder.setSmallIcon(Icon)} メソッドや {@code Notification.Builder.setLargeIcon(Icon)} メソッド経由で通知にアタッチできる新しい {@code android.graphics.drawable.Icon} クラス。 - - -
- 現在どの通知がアクティブなのかをアプリが検出できるようにする新しい {@code NotificationManager.getActiveNotifications()} メソッド。 -この機能を使用するアプリの実装については、アクティブな通知のサンプルをご覧ください。 - -
Bluetooth スタイラスのサポート
-このプレビューでは、Bluetooth スタイラスを使用したユーザー入力のサポートが強化されました。互換性のある Bluetooth スタイラスと電話やタブレットをペアリングして接続できます。 -接続されている間、タッチスクリーンからの位置情報とスタイラスからの筆圧やボタン情報を合わせることで、タッチスクリーン単独の場合よりも表現の幅が大きく広がります。 - -新しい -{@code View.onStylusButtonPressListener} コールバックと {@code GestureDetector.OnStylusButtonPressListener} コールバックをアクティビティに登録すると、スタイラスのボタンが押されたことをアプリがリッスンし、次のアクションを実行できるようになります。 - -
- -スタイラスのボタン操作を検出するには、{@link android.view.MotionEvent} メソッドと定数を使用します。 -
--
-
- ユーザーがスタイラスでアプリ画面のボタンをタップすると、 -{@link android.view.MotionEvent#getToolType(int) getTooltype()} メソッドが -{@link android.view.MotionEvent#TOOL_TYPE_STYLUS} を返します。 -
- M Preview を対象としたアプリでは、ユーザーがプライマリのスタイラス ボタンを押すと -{@link android.view.MotionEvent#getButtonState() getButtonState()} メソッドが {@code MotionEvent.STYLUS_BUTTON_PRIMARY} を返します。 - -スタイラスにセカンダリ ボタンがある場合は、ユーザーがそのボタンを押したときに同じメソッドで {@code MotionEvent.STYLUS_BUTTON_SECONDARY} が返されます。 -ユーザーが同時に両方のボタンを押した場合は、両方の値が OR で返されます({@code STYLUS_BUTTON_PRIMARY|STYLUS_BUTTON_SECONDARY}) - - -
- -以前のプラットフォーム バージョンを対象としたアプリでは、 -{@link android.view.MotionEvent#getButtonState() getButtonState()} メソッドは -{@link android.view.MotionEvent#BUTTON_SECONDARY}(プライマリのスタイラス ボタンが押されたとき)、 -{@link android.view.MotionEvent#BUTTON_TERTIARY}(セカンダリのスタイラス ボタンが押されたとき)、または両方を返します。 - -
Bluetooth Low Energy のスキャンの改善
--アプリで Bluetooth Low Energy スキャンを実行する場合は、新しい -{@code android.bluetooth.le.ScanSettings.Builder.setCallbackType()} メソッドを使って、設定された -{@link android.bluetooth.le.ScanFilter} に一致する宣伝パケットが最初に見つかったときと、それが長期間見つからない場合に通知する目的でのみコールバックが必要であると指定できます。 - -このスキャン アプローチは、以前のプラットフォーム バージョンで提供されていたものよりもはるかに効率的です。 - -
- -アクセス ポイント 2.0 リリース 1 のサポート
--このプレビューでは、Nexus 6 と Nexus 9 端末のアクセス ポイント2.0 Release 1 仕様のサポートが追加されました。アクセス ポイント 2.0 の資格情報をアプリに提供するには、 -{@code setPlmn()} や {@code setRealm()} などの -{@link android.net.wifi.WifiEnterpriseConfig} クラスの新しいメソッドを使用します。 -{@link android.net.wifi.WifiConfiguration} オブジェクトで、 -{@link android.net.wifi.WifiConfiguration#FQDN} フィールドと {@code providerFriendlyName} フィールドを設定できます。新しい {@code ScanResult.PasspointNetwork} プロパティは、検出されたネットワークがアクセス ポイント 2.0 のアクセス ポイントを表しているかどうかを示します。 - - -
- -4K ディスプレイ モード
-互換性のあるハードウェアで、ディスプレイの解像度を 4K レンダリングにアップグレードするようアプリから要求できるようになりました。 -現在の物理的解像度を照会するには、新しい -{@code android.view.Display.Mode} API を使用します。UI が低い論理的解像度で描画されていて、より高い物理的解像度にアップスケールされた場合は、 -{@code Display.Mode.getPhysicalWidth()} メソッドが返す物理的解像度が {@link android.view.Display#getSize(android.graphics.Point) getSize()} で報告される論理的解像度と異なる場合があります。 - -
- -アプリ ウィンドウの -{@code WindowManager.LayoutParams.preferredDisplayModeId} プロパティを設定することで、アプリの実行時に物理的解像度を変更するようシステムに要求できます。この機能は、4K ディスプレイの解像度に切り替えたい場合に便利です。 -4K ディスプレイ モード中、UI は引き続き元の解像度(1080p など)で表示され、4K にアップスケールされますが、 -{@link android.view.SurfaceView} オブジェクトではコンテンツをネイティブの解像度で表示する場合があります。 -
- -テーマ化可能な ColorStateLists
-M Preview を実行する端末で、テーマの属性が -{@link android.content.res.ColorStateList} でサポートされるようになりました。 -{@link android.content.res.Resources#getColorStateList(int) getColorStateList()} メソッドと -{@link android.content.res.Resources#getColor(int) getColor()} メソッドは廃止されました。これらの API を呼び出す場合は、代わりに新しい {@code Context.getColorStateList()} メソッドか -{@code Context.getColor()} メソッドを呼び出します。 -これらのメソッドは、{@link android.support.v4.content.ContextCompat} の v4 appcompat ライブラリにもあります。 -
- -オーディオ機能
- -このプレビューでは、次のように Android でのオーディオ処理が改善されました。
--
-
- 新しい {@code android.media.midi} API を使った MIDI プロトコルのサポート。 -これらの API を使用して MIDI イベントを送受信できます。 - -
- デジタル オーディオの録音を作成して、それぞれのオブジェクトを再生し、システムのデフォルトをオーバーライドするオーディオ ソースとシンク プロパティを構成するための新しい {@code android.media.AudioRecord.Builder} クラスと {@code android.media.AudioTrack.Builder} クラス - -。 -
- オーディオと入力端末を関連付ける API フック。これは、ユーザーが Android TV に接続されているゲーム コントローラーやリモート コントロールから音声検索を開始できるアプリの場合に特に便利です。ユーザーが検索を開始すると、システムが新しい -{@code android.app.Activity.onSearchRequested()} コールバックを呼び出します。 - -ユーザーの入力端末に組み込みのマイクがあるかどうかを確認するには、そのコールバックから {@link android.view.InputDevice} オブジェクトを取得して、新しい -{@code InputDevice.hasMic()} メソッドを呼び出します。 - -
- アタッチされたすべてのソースとシンク オーディオ端末の一覧を取得できる新しい {@code android.media.AudioDevicesManager} クラス。 -また、オーディオ端末の接続時と接続解除時にアプリで通知を受けたい場合は、 -{@code android.media.OnAudioDeviceConnectionListener} オブジェクトを指定することもできます。 - -
ビデオ機能
-このプレビューでは、ビデオ処理の API に次のような新機能が追加されました。
--
-
- アプリでオーディオ ストリームとビデオ ストリームを同調してレンダリングできる新しい {@code android.media.MediaSync}。 -オーディオ バッファはノンブロッキング方式で送信され、コールバック経由で返されます。 -ダイナミック再生レートもサポートしています。 - -
- アプリで開かれたセッションが、リソース マネージャーによって再要求されたことを示す新しい {@code MediaDrm.EVENT_SESSION_RECLAIMED} イベント。 -アプリが DRM セッションを使用する場合は、必ずこのイベントを処理し、再要求されたセッションは使用しないようにします。 - - -
- リソース マネージャーがコーデックで使用されたメディア リソースを再要求したことを示す新しい {@code MediaCodec.CodecException.ERROR_RECLAIMED} エラーコード。 -この例外では、コーデックはターミナル状態に移動するため、解放する必要があります。 - - -
- 同時に発生できるコーデック インスタンスの最大数のヒントを得られる新しい {@code MediaCodecInfo.CodecCapabilities.getMaxSupportedInstances()} インターフェース。 - - -
- 高速または低速モーション再生におけるメディアの再生レートを設定する新しい {@code MediaPlayer.setPlaybackParams()} メソッド。 -ビデオと共にオーディオの再生を自動的に延ばしたり早めたりもします。 - -
カメラ機能
-このプレビューでは、カメラのフラッシュやカメラによる画像の再処理にアクセスするための新しい API が用意されています。 -
- -Flashlight API
-カメラ端末にフラッシュ ユニットが付属している場合は、{@code CameraManager.setTorchMode()} メソッドを呼び出すことで、カメラ端末を開かずにフラッシュ ユニットのタッチモードのオン/オフを切り替えることができます。 -アプリには、フラッシュ ユニットやカメラ端末のフラッシュの独占所有権はありません。 -トーチモードは、カメラ端末が利用不可になったときや、トーチを付けている他のカメラリソースが利用不可になったときにオフになり、利用できなくなります。 - -他のアプリでも {@code setTorchMode()} を呼び出してトーチモードをオフにできます。 -最後にトーチモードをオンにしたアプリが閉じられると、トーチモードはオフになります。 -
- --{@code CameraManager.registerTorchCallback()} メソッドを呼び出すことで、トーチモードの状態に関する通知を受けるようコールバックを登録できます。コールバックを初めて登録したときに、現在検知されているすべてのフラッシュ ユニット付きのカメラ端末のトーチモードの状態が即座に呼び出されます。 - -トーチモードが正常にオン/オフされると、 -{@code CameraManager.TorchCallback.onTorchModeChanged()} メソッドが呼び出されます。
- -Reprocessing API
-{@link android.hardware.camera2 Camera2} API は、YUV とプライベートな不透明形式の画像の再処理をサポートするよう拡張されました。 -アプリは、再処理機能が利用可能かどうかを {@code CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES} 経由で確認します。 -端末が再処理をサポートしている場合は、 -{@code CameraDevice.createReprocessableCaptureSession()} を呼び出して再処理可能なカメラ撮影セッションを作成し、入力バッファの再処理の要求を作成できます。 - -
- -入力バッファのフローをカメラの再処理入力に接続するには、{@code ImageWriter} クラスを使用します。 -空のバッファを取得するには、次のプログラミング モデルを使用します。
- --
-
- {@code ImageWriter.dequeueInputImage()} メソッドを呼び出します。 -
- 入力バッファにデータを入力します。 -
- {@code ImageWriter.queueInputImage()} メソッドを呼び出して、バッファをカメラに送ります。 -
{@code ImageWriter} オブジェクトを -{@code android.graphics.ImageFormat.PRIVATE} 画像と共に使用する場合、アプリから直接画像データにアクセスすることはできません。 -代わりに、{@code ImageWriter.queueInputImage()} メソッドをバッファコピーなしで呼び出して、{@code ImageFormat.PRIVATE} 画像を直接 -{@code ImageWriter} に渡します。 -
- -{@code ImageReader} クラスで {@code android.graphics.ImageFormat.PRIVATE} 形式の画像ストリームがサポートされるようになりました。 -これにより、アプリが -{@code ImageReader} 出力画像の循環的な画像のキューを維持でき、1 つ以上の画像を選択して、それらをカメラの再処理用に -{@code ImageWriter} に送ることができます。
- -Android for Work の機能
-このプレビューには、次のような Android for Work 用の新しい API が含まれています。
--
-
- 企業の専用端末の制御の強化:デバイス オーナーは次の設定を制御でき、企業の専用端末を管理しやすくなります。
-
-
-
-
-
- -{@code DevicePolicyManager.setKeyguardEnabledState()} メソッドを使ったキーガードの無効化と有効化。 -
- -{@code DevicePolicyManager.setStatusBarEnabledState()} メソッドを使ったステータスバー(クイック設定、通知、Google Now を起動するスワイプアップのジェスチャ)の無効化と有効化。 - -
- {@link android.os.UserManager} の定数 {@code DISALLOW_SAFE_BOOT} を使ったセーフブートの無効化と有効化。 - -
- -{@link android.provider.Settings.Global} の定数 {@code STAY_ON_WHILE_PLUGGED_IN} を使った電源接続時の画面オフの回避。 -
- - デバイス オーナーによるアプリのサイレント インストールとアンインストール:デバイス オーナーでは、{@link android.content.pm.PackageInstaller} API を使って、Google Play for Work から独立してアプリケーションをサイレントにインストール、アンインストールできます。 - -デバイス オーナー経由で、ユーザー操作なしでアプリを取得したりインストールしたりできる端末を提供できます。 -この機能は、Google アカウントのアクティベートなしでキオスクや同様の端末のワンタッチ プロビジョニングを有効にする際に便利です。 - -
- 企業証明書のサイレント アクセス: ユーザーが証明書の選択を求められる前にアプリが -{@link android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity,android.security.KeyChainAliasCallback,java.lang.String[],java.security.Principal[],java.lang.String,int,java.lang.String) choosePrivateKeyAlias()} を呼び出すと、プロファイルやデバイス オーナーが {@code DeviceAdminReceiver.onChoosePrivateKeyAlias()} メソッドを呼び出して要求元のアプリケーションにエイリアスをサイレントに提供できるようになりました。 - - -この機能によって、ユーザー操作なしでマネージド アプリが証明書にアクセスできるようになります。 - -
- システムアップデートの自動受信。 -{@code DevicePolicyManager.setSystemUpdatePolicy()} を使ってシステムアップデートのポリシーを設定することで、デバイス オーナーがキオスク端末などでシステムアップデートを自動的に受信できるようにしたり、ユーザーが操作しないようアップデートを最大 30 日間保留したりできます。 - -さらに、管理者はアップデートを実行する時間枠を、キオスク端末が使用されていない時間帯などに設定できます。 -利用可能なシステムアップデートがある場合、システムは Work Policy Controller アプリにシステムアップデートのポリシーがあるかどうかを確認し、それに基づいて動作します。 - - - -
-
-代理証明書のインストール:プロファイルやデバイス オーナーで、サードパーティ アプリが次の {@link android.app.admin.DevicePolicyManager} 証明書の管理 API を呼び出す権限を付与できるようになりました。
-
-
-
-
-
- {@link android.app.admin.DevicePolicyManager#getInstalledCaCerts(android.content.ComponentName) -getInstalledCaCerts()} -
- {@link android.app.admin.DevicePolicyManager#hasCaCertInstalled(android.content.ComponentName,byte[]) -hasCaCertInstalled()} -
- {@link android.app.admin.DevicePolicyManager#installCaCert(android.content.ComponentName,byte[]) -installCaCert()} -
- {@link android.app.admin.DevicePolicyManager#uninstallCaCert(android.content.ComponentName,byte[]) -uninstallCaCert()} -
- {@link android.app.admin.DevicePolicyManager#uninstallAllUserCaCerts(android.content.ComponentName) -uninstallAllUserCaCerts()} -
- {@link android.app.admin.DevicePolicyManager#installKeyPair(android.content.ComponentName,java.security.PrivateKey,java.security.cert.Certificate,java.lang.String) -installKeyPair()} -
- - 企業のファクトリー リセット制限:デバイス オーナーをプロビジョニングする際、
-{@code DeviceManagerPolicy.EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS} バンドルを設定して、ファクトリー リセット保護(FRP)をロック解除するようパラメータを構成できます。
-NFC プログラマー アプリでは、端末が FRP のロック解除するようリセットされ、端末がプロビジョニングされた後にこれらのパラメータを提供でき、事前に Google アカウントを設定しておく必要はありません。
-
-これらのパラメータを修正しない場合、FRP は続行し、事前にアクティブ化された Google の資格情報なしで端末がアクティベートされないようにします。
-
-
-
さらに、Google Play サービスでアプリの制限を設定することで、デバイス オーナーは FRP のロック解除用の別の Google アカウントを指定して、端末でアクティベートされたアカウントを置き換えることができます。 -
-
-
- - データ使用のトラッキングプロファイルやデバイス オーナーでは、新しい -{@code android.app.usage.NetworkStatsManager} メソッドを使用して、[設定] > [データ] に表示されるデータ使用の統計を照会できます。 -プロファイル オーナーには、管理するプロファイルのデータを照会するパーミッションが自動的に付与され、デバイス オーナーは管理されたプライマリ ユーザーの使用データへのアクセス権が付与されます。 - - -
- 実行時パーミッションの管理:
-
プロファイルやデバイス オーナーは、 -{@code DevicePolicyManager.setPermissionPolicy()} を使用するすべてのアプリケーションのすべての実行時の要求に対するパーミッション ポリシーを設定でき、通常のとおりユーザーにパーミッションを付与するよう要求する、自動的に付与する、パーミッションをサイレントに拒否する、のいずれかを行うことができます。 - -後者のポリシーが設定されている場合、ユーザーはプロファイルやデバイス オーナーによって選択された内容を [設定] にあるアプリのパーミッション画面で修正できません。 - -
- - 設定の VPN:VPN アプリは、[設定] > [その他] > [VPN] に表示されます。さらに、VPN の使用に関する通知は、その VPN の構成状況によるものになります。 - - -プロファイル オーナーの場合、通知は VPN が マネージド プロファイル、個人プロファイル、または両方のどれに構成されているかによって、それ固有のものになります。 -デバイス オーナーの場合、通知は VPN が端末全体に構成されているかどうかによって、それ固有のものになります。 - -
- ワーク ステータスの通知:マネージド プロファイルからのアプリのアクティビティがフォアグラウンドにある場合は、ステータスバーのブリーフケース アイコンが表示されます。 -さらに、端末がマネージド プロファイルのアプリのアクティビティに直接ロック解除されている場合、ユーザーがワーク プロファイル内にいることがトースト通知で表示されます。 - - - -
- M Developer Preview のすべての API の変更点の詳細については、API Differences Report をご覧ください。 -
diff --git a/docs/html-intl/intl/ja/preview/backup/index.jd b/docs/html-intl/intl/ja/preview/backup/index.jd deleted file mode 100644 index b558cdd0843c71e1f3f983f902c8b907710615ef..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/ja/preview/backup/index.jd +++ /dev/null @@ -1,327 +0,0 @@ -page.title=アプリの自動バックアップ -page.tags=バックアップ, previewresources, androidm -page.keywords=バックアップ,自動バックアップ,プレビュー -page.image=images/cards/card-auto-backup_2x.png -@jd:body - -本書の内容
--
-
- 概要 -
- データのバックアップを設定する -
- バックアップ設定をテストする -
- 既知の問題 -
- アプリ内のデータ作成や環境設定は、多大な労力と時間を必要とする作業です。 -端末が破損したり、新しい端末にアップグレードしたりする場合に、そのデータを保持することが、快適な操作性を提供する上で非常に重要です。 -Android M Preview を実行する端末では、アプリデータを Google ドライブに自動的にバックアップすることで、前述のような状況でも快適な操作性を実現できます。 - -アプリデータは、ユーザーが端末を変更したりアップグレードしたりした場合に自動的に復元されます。 - -
- -- 自動バックアップは、Android M Preview を実行する端末にインストールされているすべてのアプリで有効になっています。追加のアプリコードは必要ありません。 -ユーザーは、自動データ バックアップを使用しないよう選択することもできます。 -また、バックアップするアプリのデータを制限することもできます。 -
- -- このドキュメントでは、新しいシステムの動作と、バックアップするアプリデータを指定する方法について説明します。 - -
- -概要
- -- 自動バックアップ機能では、アプリがユーザーの端末上に作成するデータを、ユーザーの Google ドライブ アカウントにアップロードして暗号化することで、そのデータを保持します。 -開発者やユーザーにデータ ストレージの費用が発生することはなく、保存されたデータはユーザー個人のドライブ容量にはカウントされません。 -M Preview の期間中、ユーザーは 1 つの Android アプリにつき最大 25 MB までのデータを保存できます。 - -
- -- 自動バックアップは、端末がアイドル中で、電源に接続されていて、Wi-Fi に接続されている場合に、24 時間ごとに実行されます。 -これらの条件を満たしたとき、バックアップ マネージャー サービスが利用可能なすべてのバックアップ データをクラウドにアップロードします。 -ユーザーが新しい端末に切り替えたり、バックアップされたアプリをアンインストールしたり再インストールしたりした場合、復元操作によりバックアップされたデータが新しくインストールされたアプリのデータ ディレクトリにコピーされます。 - - -
- -- 注: アプリが以前の Android バックアップ サービスを利用している場合、この新しい動作は適用されず、既存のバックアップ動作が引き続き適用されます。 - - -
- - -自動的に除外されたデータファイル
- -- 一時ファイルやキャッシュなど、バックアップする必要のないアプリデータもあるため、自動バックアップ サービスではデフォルトで一部のデータ ファイルを除外します。 - -
- --
-
- {@link android.content.Context#getCacheDir - getCacheDir()} メソッドと {@link android.content.ContextWrapper#getCodeCacheDir getCodeCacheDir()} - メソッドに参照されるディレクトリ内のファイル。 - - -
- -{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} - メソッドに参照されるディレクトリ内のものを除く、外部ストレージ内のファイル。 - - -
- -{@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} メソッドに参照されるディレクトリ内のファイル。 - -
データのバックアップを設定する
- -- 前のセクションの自動除外ファイル一覧にあるものを除いて、M Preview 端末にインストールされたすべてのアプリで作成されるデータがバックアップ対象です。 -そこからさらに、アプリ マニフェストの設定を使用して、アプリからバックアップするデータを制限したり設定したりできます。 - -
- -対象データと除外データ
- -- アプリに必要なデータとその保存方法によって、特定のファイルやディレクトリを対象とするか、除外するかの明確なルールが必要になる場合があります。 -自動バックアップ サービスでは、XML 構成ファイルとアプリ マニフェストを使ってそのようなバックアップ ツールを設定できます。 - -アプリ マニフェストでは、次の例のように、バックアップ スキームの構成ファイルを指定できます。 - -
- --<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="MNC"/> - <uses-sdk android:targetSdkVersion="MNC"/> - <app ... - android:fullBackupContent="@xml/mybackupscheme"> - </app> - ... -</manifest> -- -
- このサンプル コードでは、android:fullBackupContent
属性がアプリの開発プロジェクトの res/xml/
ディレクトリにある mybackupscheme.xml
という名前の XML ファイルを指定しています。
-
-この構成ファイルには、バックアップ対象とするファイルのルールが含まれています。
-次のサンプル コードは、バックアップから特定のファイルを除外する構成ファイルを示しています。
-
-
-<?xml version="1.0" encoding="utf-8"?> -<full-backup-content> - <exclude domain="database" path="device_info.db"/> -</full-backup-content> -- -
- この例のバックアップ構成では、特定のデータベース ファイルのみをバックアップから除外しています。 - それ以外のファイルはすべてバックアップされます。 -
- -バックアップ設定の構文
- -- バックアップ サービスの設定では、バックアップに含める、または除外するファイルを指定できます。 -データ バックアップ設定の xml ファイルの構文は次のとおりです。 -
- --<full-backup-content> - <include domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> - <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> -</full-backup-content> -- -
- 次のエレメントと属性を使って、バックアップに含める、または除外するファイルを指定できます。 - -
- --
-
-
-
<include>
。システムにデフォルトでアプリのすべてのデータをバックアップさせるのではなく、バックアップするリソースを自身で指定する場合、このエレメントを使用します。 -<include>
タグを指定すると、システムはこのエレメントで指定されたリソースのみをバックアップします。 - - -
-
- -
-
<exclude>
。バックアップから除外するリソースを指定するには、このエレメントを使用します。 -システムは、このエレメントで指定されたリソース以外のすべてのアプリ データをバックアップします。 - -
-
- -
-
domain.
バックアップに含める、または除外するリソースのタイプ。この属性を指定する際に有効な値: - -
-
- -
-
-
-
-
-
root
。リソースがアプリのルート ディレクトリにあることを指定します。 -
-
- -
-
file
。 -{@link android.content.Context#getFilesDir getFilesDir()} メソッドで返されるディレクトリ内のリソースに相当します。 -
-
- -
-
database
。 -{@link android.content.Context#getDatabasePath getDatabasePath()} メソッドや -{@link android.database.sqlite.SQLiteOpenHelper} クラスを使用して返されるデータベースに相当します。 -
-
- -
-
sharedpref
。 -{@link android.content.Context#getSharedPreferences getSharedPreferences()} メソッドで返される -{@link android.content.SharedPreferences} オブジェクトに相当します。 -
-
- -
-
external
。リソースが外部ストレージにあることを指定し、 -{@link android.content.Context#getExternalFilesDir getExternalFilesDir()} - メソッドで返されるディレクトリ内のファイルに相当します。 -
-
- -
-
path
。バックアップに含める、または除外するリソースへのファイルパス。 - -
-
- -
-
データ バックアップの禁止
- -
- マニフェストのアプリ エレメントにある android:allowBackup
属性を false
に設定すると、一切のデータを自動バックアップしないように選択できます。
-
-この設定を、次のサンプル コードで示します。
-
-<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.my.appexample"> - <uses-sdk android:minSdkVersion="MNC"/> - <uses-sdk android:targetSdkVersion="MNC"/> - <app ... - android:allowBackup="false"> - </app> - ... -</manifest> -- - -
バックアップ設定をテストする
- -- バックアップ設定を作成したら、アプリでデータが保存され、正常に復元されることをテストして確認する必要があります。 - -
- - -バックアップのログの有効化
- -- バックアップで XML ファイルがどのように解析されるかを確認するため、テストのバックアップを実行する前にログ機能を有効にします。 - -
- --$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE -- -
バックアップのテスト
- -手動でバックアップを実行するには、まず次のコマンドを呼び出してバックアップ マネージャーを初期化する必要があります。 - -
- --$ adb shell bmgr run -- -
- 次に、次のコマンドを使って、アプリのパッケージ名を <PACKAGE>
パラメータで指定して手動でアプリケーションをバックアップします。
-
-
-$ adb shell bmgr fullbackup <PACKAGE>- - -
復元のテスト
- -
- アプリのバックアップ後に手動で復元を開始するには、アプリのパッケージ名を <PACKAGE>
パラメータで指定します。
-
-
-$ adb shell bmgr restore <PACKAGE> -- -
- 警告: このアクションを実行すると、アプリが停止し、復元操作を実行する前にデータが消去されます。 - -
- -- アプリをアンインストールしてから再インストールすることで、アプリの復元プロセスを開始します。アプリのインストールが完了すると、アプリデータが自動的にクラウドから復元されます。 - -
- - -バックアップのトラブルシューティング
- -- 問題が発生した場合は、[設定] > [バックアップ]でバックアップをオン/オフに切り替え、端末を工場出荷時の状態にリセットするか、次のコマンドを呼び出して、バックアップ データと関連メタデータを消去できます。 - - -
- -$ adb shell bmgr wipe <TRANSPORT> <PACKAGE>- -
- <TRANSPORT>
には、com.google.android.gms
というプレフィクスが付く必要があります。
- Transport の一覧を取得するには、次のコマンドを呼び出します。
-
$ adb shell bmgr list transports- -
既知の問題
- -自動バックアップ サービスには、次のような既知の問題があります。
- --
-
- Google Cloud Messaging - プッシュ通知に Google Cloud Messaging を使用するアプリの場合、Messaging の登録時に返された登録 ID をバックアップすると、復元されたアプリのプッシュ通知が破損することがあるという既知の問題があります。古い登録 ID がバックアップされている場合を除いて、新しい端末へのインストール後は、新しい 登録 ID 用の API を照会することが重要です。 - - - - -これを回避するには、バックアップ対象ファイルから登録 ID を除外します。 - - -
本書の内容
- --
-
- 実行時パーミッション -
- 省電力の最適化
-
-
-
- Doze -
- App Standby -
- - 追加可能なストレージ端末 -
- Apache HTTP Client の削除 -
- AudioManager の変更点 -
- テキスト選択 -
- Android キーストロークの変更点 -
- Wi-Fi とネットワークの変更点 -
- カメラ サービスの変更点 -
- ART ランタイム -
- APK の検証 -
- Android for Work の変更点 -
API の変更点
- - - -関連ドキュメント
- - -M Developer Preview には、新機能以外にもさまざまなシステムの変更点や API の動作の変更点が盛り込まれています。 -このドキュメントでは、アプリ開発において把握しておくべき主な変更点について説明します。 -
- -過去に Android にアプリを公開したことがある場合は、アプリがこれらの変更による影響を受ける場合があることに注意してください。 -
- -実行時パーミッション -
このプレビューでは、アプリのパーミッションを実行時にユーザーが直接管理できる新しいパーミッション モデルが採用されました。 -このモデルによって、ユーザーに対するパーミッションの可視性と制御性が向上し、アプリ開発者にとってはアプリのインストールや自動アップデート プロセスの効率が上がります。ユーザーはインストール済みアプリのパーミッションを個別に付与したり取り消したりできます。 - -
- -M Preview を対象としたアプリでは、必ずパーミッションを実行時に確認、要求するようにします。 -アプリにパーミッションが付与されているかどうかを確認するには、新しい {@code Context.checkSelfPermission()} メソッドを呼び出します。 -パーミッションを要求するには、新しい -{@code Activity.requestPermission()} メソッドを呼び出します。アプリが M を対象としていない場合でも、新しいパーミッション モデルでアプリをテストするようにしてください。 -
- -アプリで新しいパーミッションをサポートする際の詳細については、Developer Preview ページの -Permissions をご覧ください。 -アプリへの影響を評価する際のヒントについては、Testing Guide をご覧ください。 -
- -省電力の最適化
-このプレビューでは、アイドル中の端末やアプリに対する新しい省電力の最適化機能が採用されています。
- -Doze
-端末が電源に接続されておらず、画面が一定時間オフ状態の場合は Doze モードに入り、システムをスリープ状態に保ちます。 -このモードでは、端末は定期的に通常の操作を短時間再開することで、アプリを同期したり、システムが保留中の操作を行ったりすることができます。 - -
- -Doze 中は、アプリに次の制限が適用されます。
--
-
- アプリで優先度の高い Google Cloud Messaging の通知を受信する場合以外、ネットワーク アクセスは無効になります。 - -
- Wake ロック は無視されます。 -
- {@link android.app.AlarmManager} クラスを使ってスケジュールされたアラームは無効になりますが、{@link android.app.AlarmManager#setAlarmClock setAlarmClock()} メソッドと {@code AlarmManager.setAndAllowWhileIdle()} を使って設定したアラームは除きます。 - - -
- WiFi スキャンは実行されません。 -
- 同期アダプタ と {@link android.app.job.JobScheduler} の同期とジョブは実行できません。 - -
端末が Doze モードでなくなると、保留中のすべての同期とジョブが実行されます。
-この機能をテストするには、M Preview を実行する端末を開発マシンに接続して、次のコマンドを呼び出します。 - -
--$ adb shell dumpsys battery unplug -$ adb shell dumpsys deviceidle step -$ adb shell dumpsys deviceidle -h --
注: -Google Cloud Messaging の次期リリースでは、高優先度のメッセージを指定できます。 - -アプリが高優先度の GCM メッセージを受信する場合は、端末が Doze 中でも短時間のネットワーク アクセスが付与されます。 - -
- -アプリで Doze をテストする方法のヒントについては、 -Testing Guide をご覧ください。 -
- -App Standby
-このプレビューでは、アクティブに使用されていないアプリをシステムがアイドル状態であるとみなす場合があります。 -システムが次の信号を検出しない場合、一定時間の経過後にアプリはアイドル状態であるとみなされます。 -
- --
-
- アプリがユーザーによって明示的に起動された。 -
- アプリのプロセスが現在フォアグラウンドにある(アクティビティかフォアグラウンド サービスとしてか、他のアクティビティかフォアグラウンド サービスによって使用されている)。 - -
- アプリがロック画面や通知トレイに表示される通知を生成する。 - -
- ユーザーが、アプリに最適化が適用されないよう [設定] で明示的に指定する。 - -
端末が電源に接続されていない場合、アイドル中のみなされたアプリのネットワーク アクセスは無効になり、同期とジョブは保留されます。 -端末が電源に接続されると、アプリのネットワーク アクセスは許可され、保留中のすべてのジョブと同期が実行されます。 -端末が長時間アイドル状態の場合、アイドル中のアプリは 1 日 1 回程度ネットワーク アクセスが許可されます。 -
- -この機能をテストするには、M Preview を実行する端末を開発マシンに接続して、次のコマンドを呼び出します。 - -
--$ adb shell dumpsys battery unplug -$ adb shell am set-idle <packageName> true -$ adb shell am set-idle <packageName> false -$ adb shell am get-idle <packageName> -- -
注: -Google Cloud Messaging(GCM)の次期リリースでは、高優先度のメッセージを指定できます。 - -アプリが高優先度の GCM メッセージを受信する場合は、アプリがアイドル 中でも短時間のネットワーク アクセスが付与されます。 - -
- -アプリで App Standby をテストする方法のヒントについては、 -Testing Guide をご覧ください。 -
- -追加可能なストレージ端末
--このプレビューでは、SD カードなどの外部ストレージ端末を追加できます。外部ストレージ端末を追加すると、端末が内部ストレージのように動作するよう暗号化とフォーマットが行われます。 -この機能によって、アプリとアプリの個人データをストレージ端末間で移動できるようになります。 -アプリを移動する際、システムはマニフェストの -{@code android:installLocation} を遵守します。 - -
- -アプリが次の API やフィールドにアクセスする場合は、アプリが内部ストレージ端末と外部ストレージ端末間で移動する際に返されるファイルパスが動的に変化することに注意してください。ファイルパスの構築時は、これらの API を動的に呼び出すことを強くお勧めします。ハードコードされたファイル パスを使用したり、過去にビルドした完全修飾ファイルパスをそのまま使用したりしないでください。 - - -
- --
-
- {@link android.content.Context} メソッド:
-
-
-
- {@link android.content.Context#getFilesDir() getFilesDir()} -
- {@link android.content.Context#getCacheDir() getCacheDir()} -
- {@link android.content.Context#getCodeCacheDir() getCodeCacheDir()} -
- {@link android.content.Context#getDatabasePath(java.lang.String) getDatabasePath()} -
- {@link android.content.Context#getDir(java.lang.String,int) getDir()} -
- {@link android.content.Context#getNoBackupFilesDir() getNoBackupFilesDir()} -
- {@link android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()} -
- {@link android.content.Context#getPackageCodePath() getPackageCodePath()} -
- {@link android.content.Context#getPackageResourcePath() getPackageResourcePath()} -
- - {@link android.content.pm.ApplicationInfo} フィールド:
-
-
-
- {@link android.content.pm.ApplicationInfo#dataDir dataDir} -
- {@link android.content.pm.ApplicationInfo#sourceDir sourceDir} -
- {@link android.content.pm.ApplicationInfo#nativeLibraryDir nativeLibraryDir} -
- {@link android.content.pm.ApplicationInfo#publicSourceDir publicSourceDir} -
- {@link android.content.pm.ApplicationInfo#splitSourceDirs splitSourceDirs} -
- {@link android.content.pm.ApplicationInfo#splitPublicSourceDirs splitPublicSourceDirs} -
-
Developer Preview のこの機能をデバッグするには、USB On-The-Go(OTG)ケーブルで Android 端末に接続された USB ドライブの追加を有効にして、次のコマンドを実行します。 -
- --$ adb shell sm set-force-adoptable true -- -
Apache HTTP Client の削除
-このプレビューでは、Apache HTTP クライアントのサポートが削除されました。アプリでこのクライアントを使用していて、Android 2.3(API レベル 9)以上を対象としている場合は、代わりに {@link java.net.HttpURLConnection} クラスを使用します。 - -この API は透過的データ圧縮と応答のキャッシュによってネットワーク使用を軽減し、電源の消費を最小化するため、効率性が向上します。 -Apache HTTP API を引き続き使用するには、まず {@code build.gradle} ファイルで次のコンパイル時の依存関係を宣言する必要があります。 - -
--android { - useLibrary 'org.apache.http.legacy' -} --
Android は、OpenSSL から -BoringSSL ライブラリに移行しています。 -アプリで Android NDK を使用している場合は、{@code libcrypto.so} や {@code libssl.so} など、NDK API の一部でない暗号化ライブラリにリンクしないでください。 -これらのライブラリは パブリック API ではなく、リリースや端末に対する通知なしで変更されたり、中断したりする可能性があります。また、セキュリティ上の脆弱性を露呈する場合もあります。 - -代わりに、ネイティブ コードを変更して JNI 経由で Java の暗号化 API を呼び出すか、希望の暗号化ライブラリに静的リンクします。 - -
- -AudioManager の変更点
-{@link android.media.AudioManager} クラスで音量を直接設定したり、特定のストリームをミュートにしたりする方法はサポートされなくなりました。 -{@link android.media.AudioManager#setStreamSolo(int,boolean) -setStreamSolo()} メソッドは廃止されたため、代わりに -{@code AudioManager.requestAudioFocus()} メソッドを呼び出す必要があります。同様に、 -{@link android.media.AudioManager#setStreamMute(int,boolean) setStreamMute()} メソッドも廃止され、代わりに {@code AudioManager.adjustStreamVolume()} メソッドを呼び出して、値に {@code ADJUST_MUTE} か {@code ADJUST_UNMUTE} を渡します。 - -
- -テキスト選択
- - - -ユーザーがアプリ内でテキストを選択するとき、 -切り取り、コピー、貼り付けなどのテキスト選択のアクションを -フローティング ツール バーに表示できるようになりました。 -個別のビューに対してコンテキスト アクション モードを有効にするにあるように、コンテキスト アクションバーに関するユーザー操作の実装も同様です。 - -
- -テキスト選択にフローティング ツール バーを実装するには、既存のアプリに次の変更を加えます。 -
--
-
- {@link android.view.View} オブジェクトか {@link android.app.Activity} オブジェクトで、{@link android.view.ActionMode} の呼び出しを -{@code startActionMode(Callback)} から {@code startActionMode(Callback, ActionMode.TYPE_FLOATING)} に変更します。 - -
- 既存の {@code ActionMode.Callback} の実装を、{@code ActionMode.Callback2} に拡張します。 - -
- {@code Callback2.onGetContentRect()} メソッドをオーバーライドして、ビューのコンテンツの {@link android.graphics.Rect} オブジェクト)テキスト選択の四角形など)の座標を指定します。 - -
- 四角形の位置が有効でなくなり、無効な要素がこれのみである場合は、{@code ActionMode.invalidateContentRect()} メソッドを呼び出します。 - -
-Android Support Library revision 22.2 を使用している場合、フローティング ツール バーに下方互換性はなく、デフォルトで appcompat が代わりに {@link android.view.ActionMode} オブジェクトを制御することに注意してください。 - -これにより、フローティング ツール バーは表示されなくなります。 -{@link android.support.v7.app.AppCompatActivity} で -{@link android.view.ActionMode} がサポートされるようにするには、 -{@code android.support.v7.app.AppCompatActivity.getDelegate()} を呼び出して、返された -{@link android.support.v7.app.AppCompatDelegate} オブジェクトで -{@code android.support.v7.app.AppCompatDelegate.setHandleNativeActionModesEnabled()} を呼び出し、 入力パラメータを {@code false} に設定します。 -この呼び出して、{@link android.view.ActionMode} オブジェクトの制御がフレームワークに戻ります。 -M Preview を実行する端末ではフレームワークによる -{@link android.support.v7.app.ActionBar} やフローティング ツール バー モードのサポートが可能ですが、M Preview 以前の端末では -{@link android.support.v7.app.ActionBar} モードのみがサポートされます。
- -Android キーストロークの変更点
-このプレビューでは、 -Android Keystore プロバイダによる DSA のサポートがなくなります。 -ECDSA は引き続きサポートされます。
- -停止時に暗号化を必要としないキーが、ロック画面の(ユーザーや端末の管理者などによる)無効時やリセット時に削除されなくなりました。 -停止時に暗号化を必要とするキーは、これらのイベント時に削除されます。 -
- -Wi-Fi とネットワークの変更点
- -このプレビューでは、Wi-Fi API とネットワーク API の動作に次のような変更点が追加されました。
--
-
- オブジェクトの作成者である場合のみ、アプリで{@link android.net.wifi.WifiConfiguration} オブジェクトの状態を変更できます。 -ユーザーや他のアプリによって作成された -{@link android.net.wifi.WifiConfiguration} オブジェクトは変更、削除できません。 - -
- -以前は、 -{@link android.net.wifi.WifiManager#enableNetwork(int,boolean) enableNetwork()} で -{@code disableAllOthers=true} 設定を使ってアプリから端末を特定の Wi-Fi ネットワークに接続させた場合、端末はセルラー データなどの他のネットワークから切断されていました。 -このプレビューでは、端末が他のネットワークから切断されないようになりました。アプリの {@code targetSdkVersion} が {@code “20”} 以下の場合は、選択した Wi-Fi ネットワークに固定されます。 - -アプリの {@code targetSdkVersion} が {@code “21”} 以上の場合は、マルチネットワーク API( -{@link android.net.Network#openConnection(java.net.URL) openConnection()}メソッド、 -{@link android.net.Network#bindSocket(java.net.Socket) bindSocket()}メソッド、新しい -{@code ConnectivityManager.bindProcessToNetwork()} メソッドなど)を使用してネットワーク トラフィックが選択したネットワークに送られるようにします。 - - -
カメラ サービスの変更点
-このプレビューでは、カメラ サービスの共有リソースへのアクセスモデルが、以前の "先着順" モデルから、"優先度順" に変更されました。 - -この動作の変更には、次のようなものがあります。
--
-
- カメラ端末を開いて構成するなど、カメラのサブシステム リソースへのアクセスは、クライアント アプリケーション プロセスの "優先度" に基づいて与えられます。 -通常、ユーザーに表示されているアクティビティやフォアグラウンドにあるアクティビティのあるアプリケーション プロセスの優先度が最も高くなり、カメラ リソースの取得や使用の信頼性が高まります。 - - -
- 優先度の低いアプリでアクティブなカメラ クライアントは、より優先度の高いアプリケーションがカメラを使おうとした際に使用が中断される場合があります。 -廃止された {@link android.hardware.Camera} API では、使用が中断されたクライアントに -{@link android.hardware.Camera.ErrorCallback#onError(int,android.hardware.Camera) onError()} が呼び出されます。 - -{@link android.hardware.camera2 Camera2} API では、使用が中断されたクライアントに -{@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected(android.hardware.camera2.CameraDevice) onDisconnected()} が呼び出されます。 - -
- 適切なカメラ ハードウェア付きの端末では、別のアプリケーション プロセスを独立して開き、別のカメラ端末を同時に使用できます。 -ただし、同時アクセスによってパフォーマンスや開いているカメラ端末の性能が著しく低下するマルチプロセスの使用が検出可能になり、カメラ サービスでは許可されなくなりました。 - -この変更によって、同じカメラ端末にアクセスしようとしているアプリが他になくても、優先度の低いクライアントによる使用が中断される場合があります。 - - - -
- -現在のユーザーを変更すると、アプリ内で前のユーザー アカウントで所有していたアクティブなカメラ クライアントが中断させられることになります。 -カメラへのアクセスは、現在の端末ユーザーが所有するユーザー プロファイルのみに制限されます。つまり、ユーザーが別のアカウントに切り替えた場合、"ゲスト" アカウントはカメラのサブシステムを使用するプロセスを実行したまま去ることはできません。 - - - -
ART ランタイム
-ART ランタイムで、 -{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} メソッドに対するアクセスルールを正常に実装できるようになりました。この変更によって、以前のバージョンで Dalvik がアクセス ルールを正しく確認できなかった問題が解決しました。アプリで -{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} メソッドを使用していて、アクセス チェックをオーバーライドしたい場合は、 {@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} メソッドを使って入力パラメータを {@code true} に設定します。 - - - - -アプリで -v7 appcompat ライブラリや -v7 recyclerview ライブラリを使用する場合は、これらのライブラリの最新バージョンを使用するようアプリをアップデートする必要があります。 -アップデートしない場合は、XML から参照するカスタム クラスがアップデートされていて、クラス コンストラクタがアクセス可能であることを確認しておく必要があります。 -
- -このプレビューでは、動的リンクの動作がアップデートされました。動的リンクでは、ライブラリの {@code soname} とそのパス( -public bug 6670)の違いを認識でき、{@code soname} が実装されています。 - - -以前動作していたアプリで間違った {@code DT_NEEDED} エントリを持つもの(ビルドマシンのファイル システムの絶対パスなど)は、読み込み時に失敗する場合があります。 -
- -{@code dlopen(3) RTLD_LOCAL} フラグは正常に実装されました。 -{@code RTLD_LOCAL} はデフォルトのため、 -{@code RTLD_LOCAL} を明示的に使用しない {@code dlopen(3)} への呼び出しは影響を受けます(アプリで明示的に {@code RTLD_GLOBAL} を使用している場合を除く)。 -{@code RTLD_LOCAL} では、後に -{@code dlopen(3)} への呼び出しで読み込まれたライブラリで記号は使用できません({@code DT_NEEDED} エントリによって参照された場合とは逆)。
- - -APK の検証
-プラットフォームでより厳しい APK の検証が行われるようになりました。APK がマニフェスト ファイルで宣言されているにもかかわらず、APK 自体に存在しない場合、その APK は破損しているとみなされます。 -コンテンツが一部でも削除された場合は、APK の再署名が必要になります。 -
- -Android for Work の変更点
-このプレビューには、次のような Android for Work に関する動作の変更点が含まれています。
--
-
- 個人のコンテキストでの仕事用の連絡先ユーザーが過去の通話履歴を表示したときに、Google Dialer -Call Log に仕事用の連絡先が表示されるようになりました。{@code DevicePolicyManager.setCrossProfileCallerIdDisabled()} を {@code true} に設定すると、Google Dialer Call Log に仕事用プロファイルの連絡先は表示されなくなります。 - -{@code DevicePolicyManager.setBluetoothContactSharingDisabled()} を {@code false} に設定した場合のみ、Bluetooth 経由で端末に仕事用の連絡先と個人用の連絡先を表示できます。 - -デフォルトでは、{@code true} に設定されています。 - - -
- WiFi 設定の削除:プロファイル オーナーによって追加された WiFi 設定(@link android.net.wifi.WifiManager#addNetwork(android.net.wifi.WifiConfiguration) -addNetwork()} メソッドへの呼び出しなどを介して)は、その仕事用プロファイルが削除されると同時に削除されます。 - - -
- WiFi 設定のロック:アクティブなデバイス オーナーによって作成された WiFi 設定は、ユーザーが修正したり削除したりできなくなりました。 -ユーザーに {@link android.os.UserManager} 定数 -{@link android.os.UserManager#DISALLOW_CONFIG_WIFI} が設定されていない限り、ユーザー自身の WiFi 設定を作成、修正することはできます。 - -
- Google アカウントの追加経由での Work Policy Controller のダウンロード:Work Policy Controller(WPC)アプリ経由で管理する必要のある Google アカウントがマネージド コンテキスト外で端末に追加されると、アカウントの追加フローでユーザーに適切な WPC をインストールするよう要求します。この動作は、初期の端末のセットアップ ウィザードでの -[設定]> [アカウント] で追加されるアカウントにも適用されます。 - - - -
- 特定の DevicePolicyManager API の動作の変更点:
-{@link android.app.admin.DevicePolicyManager#setCameraDisabled(android.content.ComponentName,boolean) setCameraDisabled()} メソッドの呼び出しは、呼び出し元のユーザーのカメラにのみ影響を与えます。マネージド プロファイルから呼び出した場合は、プライマリ ユーザーで実行しているカメラ アプリに影響はありません。
-
-さらに、
-{@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,int) setKeyguardDisabledFeatures()} メソッドは、デバイス オーナーに加えてプロファイル オーナーでも利用可能になりました。
-プロファイル オーナーは、これらのキーガード制限を設定できます:
-
-
-
-
- プロファイルの親ユーザーのキーガード設定に影響を与える {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} と {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_FINGERPRINT}。 - - -
- マネージド プロファイルのアプリケーションで生成された通知のみに影響を与える {@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}。 - -
-
Android Preview SDK のコンポーネントをダウンロード、インストールする前に、次の利用規約に同意する必要があります。 -
- -利用規約
- -本書の内容
- - -Legacy downloads
- -- Android M Preview SDK には、アプリとプラットフォームの次期リリースで提供される新しい API とのテストに役立つ開発ツール、Android システム ファイル、ライブラリ ファイルが含まれています。 -このドキュメントでは、アプリのテスト用にダウンロードできる Preview のコンポーネントを入手する方法について説明します。 - -
- - -Android 6.0 SDK
- -- Preview SDK Android SDK マネージャー経由でダウンロードできます。Preview SDK のダウンロードと設定の詳細については、Set Up the Preview SDK をご覧ください。 - -
- - -デベロッパー ドキュメント
- -- デベロッパー ドキュメントのダウンロード パッケージでは、詳細な Preview の API リファレンス情報や API の比較レポートが提供されます。 -
- -Description | -Download / Checksums | -
---|---|
Android M Preview 3 Developer Docs |
- m-preview-3-developer-docs.zip - MD5: d99b14b0c06d31c8dfecb25072654ca3 - SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1 - |
-
ハードウェアのシステム イメージ
- -- これらのシステム イメージでは、テスト用に物理端末にプラットフォームのプレビュー バージョンをインストールできます。 -端末にこれらのイメージを 1 つ以上設定すると、アプリをインストールして、プラットフォームの次期バージョンでアプリがどのように動作するかをテストできます。 -端末にシステム イメージをインストールするプロセスでは、端末からすべてのデータが削除されるため、システム イメージのインストール前にデータをバックアップする必要があります。 - - -
- -- 警告: 次の Android システム イメージはプレビュー版であり、今後変更される可能性があります。デベロッパーによるシステム イメージの使用は、Android SDK Preview 使用許諾契約に準拠するものとします。 -Android Preview システム イメージは安定したリリースではなく、お使いのコンピュータ システム、端末、データに影響を与える可能性のあるエラーや欠陥が含まれている場合があります。 - -プレビュー版の Android システム イメージは工場出荷版の OS と同等のテストを受けておらず、お使いの電話やインストールされているサービス、アンインストールの動作停止を引き起こす場合があります。 - - -
- -Device | -Download / Checksums | -
---|---|
Nexus 5 (GSM/LTE) "hammerhead" |
- hammerhead-MPA44I-preview-2ebbc049.tgz - MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb - SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3 - |
-
Nexus 6 "shamu" |
- shamu-MPA44I-preview-62b9c486.tgz - MD5: ac6e58da86125073d9c395257fd42664 - SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff - |
-
Nexus 9 "volantis" |
- volantis-MPA44I-preview-5c30a6e2.tgz - MD5: 7f83768757913d3fea945a661020d185 - SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699 - |
-
Nexus Player "fugu" |
- fugu-MPA44I-preview-2860040a.tgz - MD5: 438da8d37da9e341a69cfb16a4001ac5 - SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98 - |
-
端末にイメージをインストールする
- -- テスト用に端末イメージを使用するには、互換性のある端末にインストールする必要があります。次の手順に従って、システム イメージをインストールします。 - -
- --
-
- この一覧の中からいずれかのシステム イメージ パッケージをダウンロードして、解凍します。 -
- 保持するデータを端末からバックアップします。 -
- -developers.google.com/android - の手順に従って端末にイメージをフラッシュします。 -
- 注: 開発用端末に Preview のシステム イメージをフラッシュすると、OTA アップデートを通じて次のプレビュー リリースに自動的にアップグレードされます。 - -
- -端末を工場出荷時の仕様に戻す
- -- Preview をアンインストールして、工場出荷時の仕様に戻すには、 -developers.google.com/android にアクセス -して、端末にフラッシュするイメージをダウンロードします。同じページの手順に従って端末にイメージをフラッシュします。 - -
- -本書の内容
- -- Android インテント システムは、アプリでコンテンツや要求を処理できるようにする柔軟なメカニズムです。 - 複数のアプリが、それぞれのインテント フィルタに一致する URI パターンを宣言できます。デフォルトのローンチ ハンドラを持たないウェブリンクをユーザーがクリックしたとき、一致するインテント フィルタが宣言されているアプリの一覧から選択するダイアログがプラットフォームによってユーザーに表示されます。 - - -
- -- Android M Developer Preview でサポートされる App Links では、既存のリンク処理が改善され、アプリ開発者が所有するウェブドメインとアプリを関連付けられるようになりました。 -デベロッパーがこの関連を作成すると、プラットフォームが特定のウェブリンクの処理に使用するデフォルトのアプリを自動的に決めることができ、ユーザーにアプリを選択させる操作をスキップできます。 - - -
- - -ウェブサイトの関連付けを宣言する
- -- ウェブサイトのオーナーは、アプリのリンクを設定するための関連を宣言する必要があります。サイトのオーナーは、ドメインのよく知られた場所で {@code statements.json} という名前の JSON ファイルをホストすることで、アプリとの関係を宣言します。 - - -
- -http://<domain>:<optional port>/.well-known/statements.json- -
- 注: - M Developer Preview の間、JSON ファイルは http プロトコルを介して検証されます。プラットフォームの正式リリースでは、ファイルは暗号化された https プロトコルで検証されます。 - -
- -- この JSON ファイルは、このドメイン下の URL のデフォルトのハンドラとして使用する必要のある Android アプリを示します。 -アプリは、次のフィールドに基づいて識別されます。 -
- --
-
- {@code package_name}:アプリのマニフェストで宣言されたパッケージ名。 - -
- {@code sha256_cert_fingerprints}:アプリの署名証明書の SHA256 のフィンガープリント。
- Java Keytool を使用して、次のコマンドでフィンガープリントを生成できます。
-
keytool -list -v -keystore my-release-key.keystore
-
-
- 次のファイル一覧は、 -{@code statements.json} ファイルのコンテンツと形式の例を示しています。 -
- --[{ - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "<package name>", - "sha256_cert_fingerprints": ["6C:EC:C5:0E:34:AE....EB:0C:9B"] - } -}] -- - -
App Link の検証を要求する
- -- アプリから、インテント フィルタのデータ エレメントのホスト名で定義されたアプリのリンクを、それぞれのウェブドメインでホストされる {@code statements.json} ファイルに対してプラットフォームが自動的に検証するよう要求できます。 - -アプリリンクの検証を要求するには、次のマニフェスト コード スニペットのように {@code android:autoVerify} - 属性をマニフェスト内の目的のインテント フィルタに追加します。 - -
- --<activity ...> - <intent-filter android:autoVerify="true"> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="http" android:host="www.android.com" /> - <data android:scheme="https" android:host="www.android.com" /> - </intent-filter> -</activity> -- -
- {@code android:autoVerify} 属性がアプリ マニフェストに存在する場合、プラットフォームはアプリのインストール時にアプリのリンクを検証しようとします。 -プラットフォームがアプリのリンクを正常に検証できない場合、アプリはウェブリンクの処理に適したアプリとして設定されません。 -次回ユーザーがいずれかのリンクを開いたとき、プラットフォームはユーザーに再度ダイアログを表示します。 - - -
- -- 注: テスト時に、ユーザーがシステムの設定アプリを使ってサポートされているリンクを開くアプリを明示的に有効にしていると、誤検出が原因で検証が失敗する場合があります。この場合、ダイアログは表示されず、リンクは直接アプリに送られますが、これは検証が成功したからではなく、ユーザーの設定に基づいて動作したからです。 - - - -
- - -App Link 設定を管理する
- -- ユーザーが希望する方法で URL を処理するように、ユーザー側でアプリのリンク設定を変更できます。アプリのリンクは、システムの設定アプリの [設定] > [アプリ] > [アプリ情報] > [デフォルトでの起動] で確認、管理できます。 - - -
diff --git a/docs/html-intl/intl/ja/preview/features/runtime-permissions.jd b/docs/html-intl/intl/ja/preview/features/runtime-permissions.jd deleted file mode 100644 index f582756c816ce26f854259277593ecc35bc0e170..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/ja/preview/features/runtime-permissions.jd +++ /dev/null @@ -1,794 +0,0 @@ -page.title=パーミッション -page.tags=previewresources, androidm -page.keywords=パーミッション,実行時,プレビュー -page.image={@docRoot}preview/features/images/permissions_check.png -@jd:body - - -クイックビュー
--
-
- アプリのターゲットが M Preview SDK の場合、インストール時ではなく実行時に、パーミッションを付与するようユーザーに求めます。 - -
- ユーザーはいつでもアプリの [設定] 画面からパーミッションを取り消すことができます。 - -
- アプリは実行時に毎回、必要なパーミッションがあることを確認する必要があります。 - -
本書の内容
--
-
- 概要 -
- 実行時のパーミッションのコード -
- 実行時のパーミッションをテストする -
- ベスト プラクティス -
- M Developer Preview では、アプリをインストールしてアップグレードするユーザーのプロセスを効率化する新しいアプリのパーミッション モデルが導入されました。 -M Preview で実行しているアプリで新しいパーミッション モデルがサポートされている場合、ユーザーはアプリをインストールまたはアップグレードするときにパーミッションを付与する必要はありません。その代わりに、アプリは必要になるとパーミッションを要求し、パーミッションを確認するよう求めるダイアログが表示されます。 - - - - -
- -- アプリで新しいパーミッション モデルがサポートされている場合、以前のバージョンの Android を実行している端末で、以前のパーミッション モデルを使ってインストールして実行することもできます。 - - -
- -- 概要 -
- -- M Developer Preview とともに、プラットフォームでは新しいアプリのパーミッション モデルが導入されました。 -この新しいモデルの主要なコンポーネントの概要を次に示します。 -
- --
-
- - パーミッションを宣言する: アプリは、以前の Android プラットフォームと同様に、マニフェストで必要なすべてのパーミッションを宣言します。 - - - -
-
- パーミッション グループ: パーミッションは、その機能に基づいてパーミッション グループに分けられます。
-たとえば、
CONTACTS
パーミッション グループにはユーザーの連絡先とプロフィール情報を読み書きするパーミッションが含まれます。 - - -
-
- -
-
インストール時に付与される制限付きのパーミッション: ユーザーがアプリをインストールまたはアップデートするとき、{@link - android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL} に該当する、アプリが要求するすべてのパーミッションがアプリに付与されます。 - - - たとえば、目覚まし時計とインターネットのパーミッションは {@link - android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL} に該当するため、インストール時に自動的にそれらのパーミッションが付与されます。 - -
- -システムは、システムアプリと署名のパーミッションに記載のとおり、アプリの署名とシステムのパーミッションも付与することがあります。 - -ユーザーは、インストール時にパーミッションを付与するように促すメッセージは表示されません。 -
-
-
- - - 実行時にユーザーがパーミッションを付与する: アプリがパーミッションを要求すると、ユーザーにダイアログが表示されます。その後、アプリのコールバック関数を呼び出して、パーミッションが付与されているかどうかを知らせます。 - -ユーザーがパーミッションを付与する場合、アプリ マニフェストで宣言されたパーミッションの機能領域にあるすべてのパーミッションがアプリに付与されます。 - - - - -
- このパーミッション モデルにより、パーミッションを要求する機能に対するアプリの動作方法が変わります。 -このモデルに合わせるために、従う必要のある開発プラクティスの概要を次に示します。 - -
- --
-
-
- - 常にパーミッションを確認する: アプリがパーミッションを必要とするアクションを実行する必要があるとき、まずパーミッションが既にあるかどうかを確認する必要があります。 - -パーミッションがない場合、そのパーミッションを付与するよう要求します。 - - - -
- - パーミッションの不足をスムーズに処理する: アプリに適切なパーミッションが付与されていない場合、エラーが完全に処理される必要があります。 - - たとえば、追加機能に対してのみパーミッションが必要な場合、アプリはその機能を無効にできます。 -アプリが機能するためにパーミッションが必須である場合、アプリはすべての機能を無効にしてパーミッションを付与する必要があることをユーザーに知らせることがあります。 - - - - -
- - パーミッションは取り消し可能: ユーザーはいつでもアプリのパーミッションを取り消すことができます。 -アプリのパーミッションをオフにすると、アプリに通知されません。 -アプリは制限されたアクションを実行する前に、必要なパーミッションがあることを確認する必要があります。 - - -
- 注: アプリのターゲットが M Developer Preview の場合、新しいパーミッション モデルを使う必要があります。 - -
- -- M Developer Preview のローンチ時点では、すべての Google アプリで新しいパーミッション モデルが完全に実装されているわけではありません。 -Google はこれらのアプリを M Developer Preview 中にアップデートして、パーミッションの切り替え設定を完全に実装します。 - - -
- -- 注: アプリに独自の API サーフェスがある場合、まず呼び出し側にそのデータへのアクセスに必要なパーミッションがあることを確認しないままパーミッションをプロキシしないでください。 - - -
- -- システムアプリと署名のパーミッション -
- -- 本来、ユーザーがアプリをインストールするとき、システムはアプリに - {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL - PROTECTION_NORMAL} のみを付与します。ただし、特定の環境では、アプリにより多くのパーミッションが付与されます。 - -
- --
-
- アプリがシステム イメージの一部である場合、そのマニフェストにリストされているすべてのパーミッションが自動的に付与されます。 - - - -
- アプリが {@link - android.content.pm.PermissionInfo#PROTECTION_SIGNATURE PROTECTION_SIGNATURE} に該当するマニフェストでパーミッションを要求し、アプリがこれらのパーミッションを宣言したアプリと同じ証明書で署名される場合、要求しているアプリに対してこれらのパーミッションがインストール時に付与されます。 - - - - -
- - -どちらの場合でも、ユーザーはシステムの [設定] 画面に移動して [アプリ] > [app_name] > [パーミッション] を選ぶと、いつでもパーミッションを取り消すことができます。アプリは実行時にパーミッションを継続して確認し、必要に応じて要求する必要があります。 - - -
- -- 上方互換と下方互換 -
- -- アプリのターゲットが M Developer Preview 以外の場合、M Preview 端末でも以前のパーミッション モデルを引き続き使います。 -ユーザーがアプリをインストールするとき、ユーザーはアプリのマニフェストでリストされているすべてのパーミッションを付与するように要求されます。 - - -
- -- 注: M Developer Preview を実行している端末で、ユーザーはアプリの [設定] 画面から従来のアプリを含むすべてのアプリのパーミッションをオフにできます。 - -従来のアプリに対してパーミッションをオフにすると、適切な機能がサイレント状態で無効になります。 -アプリがそのパーミッションを必要とする操作を実行しようとするとき、その操作によって必ずしも例外が発生するとは限りません。 - -代わりに、空のデータセットを返す、エラーを示す、または予期しない動作を返すことがあります。 -たとえば、パーミッションなしでカレンダーを照会すると、メソッドは空のデータセットを返します。 - -
- -- M Preview を実行していない端末で新しいパーミッション モデルを使ってアプリをインストールする場合、他のすべてのアプリと同様に扱われ、インストール時に、すべての宣言されたパーミッションを付与するようユーザーに求めます。 - - - -
- -- 注: Preview リリースの場合、M Preview SDK に SDK の最小バージョンを設定して Preview SDK でコンパイルする必要があります。 -つまり、Developer Preview 中は従来のプラットフォームでそのようなアプリをテストできません。 - - -
- -パーミッションとインテント
- -- 多くの場合、アプリがタスクを実行するには 2 つの方法から選択できます。 -アプリ自体が操作を実行するパーミッションを要求できます。 -アプリでインテントを使うようにして、別のアプリがそのタスクを実行するようにすることもできます。 - -
- -
- たとえば、端末のカメラで写真を撮る機能がアプリに必要だとします。
-アプリは android.permission.CAMERA
パーミッションをリクエストでき、それによりアプリが直接カメラにアクセスできるようになります。
-
-そのとき、アプリはカメラの API を使ってカメラを制御し、写真を撮ります。
-このアプローチにより、アプリが写真のプロセスを完全に制御し、カメラの UI をアプリに組み込むことができます。
-
-
-
- ただし、そのような制御が不要な場合は、{@link - android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} インテントを使うだけで画像を要求できます。 -インテントを開始すると、カメラアプリ(デフォルトのカメラアプリがない場合)を選んでアプリで写真を撮るよう求めるメッセージが表示されます。 - -カメラアプリはアプリの {@link - android.app.Activity#onActivityResult onActivityResult()} メソッドに写真を返します。 -
- -- 同様に、ユーザーの連絡先にアクセスするなどして電話をかける必要がある場合、適切なインテントを作成するか、パーミッションを要求して適切なオブジェクトに直接アクセスできます。 - -各アプローチにはメリットとデメリットがあります。 - -
- -- パーミッションを使う場合: -
- --
-
- 操作を実行するとき、アプリによってユーザーの操作感が完全に制御されます。 -ただし、そのような幅広い制御により、適切な UI を設計する必要があるため、タスクが複雑化します。 - - - -
- 操作を初めて実行するときに、ユーザーに一度だけパーミッションの付与を求めるメッセージが表示されます。 -その後、アプリはユーザーからの介入は必要とせずに操作を実行できます。 -ただし、ユーザーがパーミッションを付与しない(または後でパーミッションを取り消す)場合、アプリは操作を一切実行できなくなります。 - - - -
- インテントを使う場合: -
- --
-
- 操作用に UI を設計する必要はありません。インテントを処理するアプリでは UI が提供されますが、これはユーザーの操作感を制御できないことを意味します。 - -ユーザーはこれまでに見たことのないアプリと相互操作することになります。 - - - -
- 操作に対してデフォルトのアプリを持たないユーザーの場合、ユーザーにアプリの選択を求めるメッセージが表示されます。ユーザーがデフォルトのハンドラを指定しない場合、操作のたびに別のダイアログで指定する必要があることがあります。 - - - - -
実行時のパーミッションのコード
- -- アプリのターゲットが新しい M Developer Preview の場合、新しいパーミッション モデルを使う必要があります。 -つまり、マニフェストで必要なパーミッションを宣言する他に、実行時にパーミッションがあることを確認し、まだパーミッションがない場合にはパーミッションを要求します。 - - - -
- -- 新しいパーミッション モデルを有効にする -
- -
- 新しい M Developer Preview パーミッション モデルを有効にするには、アプリの targetSdkVersion
属性を "MNC"
に、compileSdkVersion
を "android-MNC"
に設定します。
-
-このように設定することで、新しいパーミッション機能すべてが有効になります。
-
-
- Preview リリースの場合、minSdkVersion
を "MNC"
に設定して Preview SDK でコンパイルする必要があります。
-
-
- M Preview のみに対するパーミッションの設計 -
- -
- アプリ マニフェストで新しい <uses-permission-sdk-m>
要素を使って、M Developer Preview のみで必要なパーミッションを表示できます。
-このようにしてパーミッションを宣言すると、アプリを以前の端末にインストールする場合はユーザーにメッセージが表示されないか、アプリにパーミッションが付与されません。<uses-permission-sdk-m>
要素を使うと、新しいパーミッションを追加してインストールをアップデートするときにパーミッションの付与を強制せずにアプリのバージョンがアップデートされます。
-
-
-
-
-
-
-
- M Developer Preview を使ってアプリが端末で実行されている場合、<uses-permission-sdk-m>
は <uses-permission>
と同じように動作します。
-
-
- アプリをインストールするとき、パーミッションの付与を求めるメッセージは表示されず、アプリは必要なときにパーミッションを要求します。
-
-
- パーミッションについてのダイアログを表示する -
- -- アプリで新しい M Developer Preview パーミッション モデルが使われている場合、M Preview を実行している端末でアプリを初めて起動するとき、すべての権限を付与する必要はありません。 - -その代わりに、アプリは必要なときにパーミッションを要求します。 -アプリがパーミッションを要求すると、ユーザーにダイアログが表示されます。 - -
- -
- SDK 22 以降がインストールされた端末でアプリを実行する場合、アプリでは以前のパーミッション モデルが使われます。
-ユーザーがアプリをインストールすると、アプリがそのマニフェストで要求するすべてのパーミッションの付与を求めるメッセージが表示されます。ただし、<uses-permission-sdk-m>
というラベルの付いたパーミッションは例外です。
-
-
-
アプリが実行されているプラットフォームを確認する
- -
- このパーミッション モデルは、M Developer Preview を実行している端末でのみサポートされます。
-これらのメソッドのいずれかを呼び出す前に、アプリは {@link android.os.Build.VERSION#CODENAME
- Build.VERSION.CODENAME} の値を確認してどのプラットフォーム上で実行されているのかを確認する必要があります。
-
-端末で M Developer Preview が実行されている場合、{@link android.os.Build.VERSION#CODENAME CODENAME} は "MNC"
です。
-
-
アプリに必要なパーミッションがあるかどうかを確認する
- -ユーザーがパーミッションを要求する動作を行うと、アプリは現在この操作を実行するためのパーミッションがあるかどうかを確認します。
-
-
-確認するために、アプリは Context.checkSelfPermission(permission_name)
を呼び出します。ユーザーが既にパーミッションを付与していることをアプリが認識している場合でも、ユーザーはいつでもアプリのパーミッションを取り消すことができるため、この確認が行われます。
-
-
-たとえば、ユーザーがアプリを使って写真を撮る場合、アプリは Context.checkSelfPermission(Manifest.permission.CAMERA)
を呼び出します。
-
-
パーミッション グループ | -パーミッション | -
---|---|
android.permission-group.CALENDAR |
-
-
|
-
android.permission-group.CAMERA |
-
-
|
-
android.permission-group.CONTACTS |
-
-
|
-
android.permission-group.LOCATION |
-
-
|
-
android.permission-group.MICROPHONE |
-
-
|
-
android.permission-group.PHONE |
-
-
|
-
android.permission-group.SENSORS |
-
-
|
-
android.permission-group.SMS |
-
-
|
-
必要に応じてパーミッションを要求する
- -アプリに必要なパーミッションがない場合、アプリは Activity.requestPermissions(String[], int)
メソッドを呼び出して適切なパーミッションを要求します。
-
-アプリは必要なパーミッションと整数の「要求コード」を渡します。
-
- このメソッドは非同期に機能します。このメソッドはすぐに返され、ユーザーがダイアログ ボックスに応答した後、システムはその結果と一緒にアプリのコールバック メソッドを呼び出し、アプリが requestPermissions()
に渡すのと同じ「要求コード」を渡します。
-
-
-
次のコードは、ユーザーの連絡先を読み込むパーミッションがアプリにあることを確認し、必要に応じてパーミッションを要求します。 -
- --if (checkSelfPermission(Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, - MY_PERMISSIONS_REQUEST_READ_CONTACTS); - - // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an - // app-defined int constant - - return; -} -- -
パーミッションの要求への応答を処理する
- -
- アプリがパーミッションを要求すると、システムによってダイアログ ボックスが表示されます。
-ユーザーが応答すると、システムはアプリの Activity.onRequestPermissionsResult(int, String[], int[])
を呼び出し、ユーザーの応答を渡します。
-
-アプリはそのメソッドをオーバーライドする必要があります。コールバックには開発者が requestPermissions()
に渡したのと同じ要求コードが渡されます。
-
-たとえばアプリが READ_CONTACTS
アクセスを要求する場合、次のコールバック メソッドが含まれる可能性があります。
-
-
-
-@Override -public void onRequestPermissionsResult(int requestCode, - String permissions[], int[] grantResults) { - switch (requestCode) { - case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - - // permission was granted, yay! do the - // calendar task you need to do. - - } else { - - // permission denied, boo! Disable the - // functionality that depends on this permission. - } - return; - } - - // other 'switch' lines to check for other - // permissions this app might request - } -} -- -
ユーザーがパーミッションを付与すると、システムは、機能領域のアプリ マニフェストがリストするすべてのパーミッションを付与します。 -ユーザーが要求を拒否する場合は、適切なアクションを取ってください。 -たとえば、このパーミッションに応じて、すべてのメニュー アクションを無効にできます。 - - -
- -
- ユーザーにパーミッションの付与を確認するとき、ユーザーにそのパーミッションについて再度確認しないようにするオプションがあります。
-この場合、アプリが requestPermissions()
を使ってパーミッションを確認すると、システムはその要求をすぐに拒否します。
-
-この場合、システムはユーザーが要求を再度明示的に拒否する場合と同様に onRequestPermissionsResult()
を呼び出します。
-
-このため、アプリではユーザーとの直接的なやり取りが発生することが想定されません。
-
-
実行時のパーミッションをテストする
- - -- アプリのターゲットが M Developer Preview の場合、パーミッションが正しく処理されることをテストする必要があります。 -アプリ起動時に特定のパーミッションがアプリにあることは想定できません。 -アプリが初めて起動されるとき、パーミッションがない可能性が高く、ユーザーはいつでもパーミッションを取り消すまたは復元できます。 - - -
- -- アプリがすべてのパーミッションの状況下で確実に正しく動作することをテストしてください。 -M Preview SDK とともに、新しい Android デバッグ ブリッジ(adb)コマンドが導入され、試す必要のあるあらゆるパーミッション設定でアプリをテストできます。 - - - -
- -- 新しい adb コマンドとオプション -
- -- M Preview SDK Platform-tools では、アプリがパーミッションをどう処理するかをテストするための、いくつかの新しいコマンドが導入されました - -
- -- パーミッション付きでインストールする -
- -
- adb
- install
コマンドの新しい -g
オプションを使ってアプリをインストールし、そのマニフェストにリストされるすべてのパーミッションを付与できます。
-
-
-$ adb install -g <path_to_apk> -- -
- パーミッションの付与と取り消し -
- -- 新しい ADB Package Manager(pm)コマンドを使って、インストールされているアプリにパーミッションを付与したり取り消したりできます。この機能は自動化されたテストに役立ちます。 - - -
- -
- パーミッションを付与するには、Package Manager の grant
コマンドを使います。
-
-$ adb pm grant <package_name> <permission_name> -- -
- たとえば、com.example.myapp パッケージ パーミッションを付与してオーディオを録音するには、このコマンドを使います。 - -
- --$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO -- -
- パーミッションを取り消すには、Package Manager の revoke
コマンドを使います。
-
-$ adb pm revoke <package_name> <permission_name> -- -
ベスト プラクティス
- -- 新しいパーミッション モデルにより、ユーザーはよりスムーズな操作感を得られ、アプリを簡単にインストールできるようになり、アプリが実行している内容に満足します。 - -新しいモデルを最大限に活用するために、次のベスト プラクティスをお勧めします。 - -
- - -必要なパーミッションのみを要求する
- -- パーミッションを要求するたびに、ユーザーに決定するよう強制します。 - ユーザーが要求を却下すると、アプリの機能が低下します。 - これらの要求回数は最小限にしてください。 -
- -- たとえば、アプリがパーミッションを要求する代わりに、インテントを使って必要な機能を取得できる場合がよくあります。 - -アプリが携帯電話のカメラで写真を撮る必要がある場合、そのアプリでは {@link - android.provider.MediaStore#ACTION_IMAGE_CAPTURE - MediaStore.ACTION_IMAGE_CAPTURE} インテントを使用できます。 -アプリがインテントを実行すると、写真を撮るためのインストール済みのカメラアプリを選ぶようユーザーに促します。 - - -
- -- ユーザーを疲れさせない -
- -- ユーザーにパーミッションをたくさん要求すると、ユーザーを疲れさせてしまい、アプリが終了される原因になります。代わりに、ユーザーには必要なパーミッションのみを要求してください。 - - -
- -- アプリ対して 1 つ以上のパーミッションが必須である場合もあります。その場合は、アプリの起動後すぐに、すべてのパーミッションを要求することが合理的である場合があります。 - -たとえば、カメラアプリを作成する場合、アプリは端末のカメラにアクセスする必要があります。 -アプリを初めて起動するときにカメラの使用についてのパーミッションを求められても驚かないはずです。 - -ただし、同じアプリにユーザーの連絡先と写真を共有する機能もある場合は、最初の起動時にパーミッションを要求しない方が無難です。 - -その代わりに、ユーザーが「共有」機能を使うまで待ち、そのときにパーミッションを要求します。 - -
- -- アプリにチュートリアルが含まれる場合は、チュートリアルのシーケンスの最後で、アプリに必須のパーミッションを要求する方が合理的です。 - -
- -- パーミッションが必要な理由を説明する -
- -
- requestPermissions()
を呼び出すとき、システムによって表示されるパーミッション ダイアログにはアプリが必要としているパーミッションは表示されますが、理由は表示されません。
-
-これによりユーザーが困惑する場合もあります。
- requestPermissions()
を呼び出す前に、アプリがパーミッションを必要としている理由をユーザーに説明するのはよい方法です。
-
-
- たとえば、カメラアプリでは、位置情報サービスを使って写真に位置情報タグを付けられるようにする場合があります。
-通常のユーザーは、写真に位置情報が含まれる場合があることを認識していない可能性があり、なぜカメラアプリで位置情報が必要なのか困惑する可能性があります。
-
-この場合、アプリが requestPermissions()
を呼び出す前に、この機能についてユーザーに知らせることをお勧めします。
-
-
-
- その方法として、これらの要求をアプリのチュートリアルに組み込むこともできます。チュートリアルでは、アプリの各機能を順番に表示できるので、必要なパーミッションを説明できます。
-
-たとえば、カメラアプリのチュートリアルでは、「連絡先と写真を共有する」機能について説明し、ユーザーの連絡先を参照するためにアプリにパーミッションが必要であることをユーザーに知らせることができます。
-
-
-その後、アプリは requestPermissions()
を呼び出して、ユーザーにそのアクセスを求めることができます。
-もちろん、すべてのユーザーがチュートリアルに従うわけではないため、アプリの通常操作中にパーミッションを確認して要求することも必要です。
-
-
-
Android M Developer Preview
-- 次期バージョンの Android に向けて準備しましょう。Nexus 5、6、9、Nexus Player でアプリをテストします。 -実行時パーミッション、 Doze、App Standby 省電力機能、新しい サポート テクノロジーなどの新機能をご覧ください。 - - -
- - - - スタートガイド -- - - - Developer Preview 3 (final SDK) -
リソース
--
-
- - - - 問題の報告 - - -
- - - Join G+ コミュニティ - - -
-Android SDK Preview をインストールする前に、次の利用規約に同意する必要があります。 -以下に記載するとおり、これは、Android SDK のプレビュー バージョンであり、変更される可能性があります。デベロッパーご自身の責任においてご使用ください。Android SDK Preview は安定したリリースではなく、お使いのコンピュータ システム、端末、データに深刻な影響を与える可能性のあるエラーまたは欠陥が含まれている場合があります。 -
- --以下は、Android SDK Preview の使用許諾契約です(以下「本契約」)。 -
-- Developer Preview 2 is now available -
- --
-
- - - - Read the Notes - - -
- - - - Get the Update - - -
- - - - Report Issues - -
- Android M Developer Preview では、Android の次のバージョンでアプリをテストして最適化するためのすべてを備えています。 - -M Developer Preview ツールをダウンロードするだけで、無料ですぐにご利用いただけます。 - -
- -- ハードウェアとエミュレータのシステム イメージ -
- -- Nexus 5、6、9、Nexus Player(TV 向け)やエミュレータでアプリをテストしましょう。 - -
-- 最新プラットフォーム コード -
- -- プレビューで複数のアップデートが提供されますので、最新プラットフォームの変更に応じてテストできます。 - -
-- OTA でのアップデート -
- -- デバイスに初期プレビューをコピーしたら、無線経由でアップデートを入手できます。 - -
-- 新しい動作と機能 -
- -- 新しい実行時パーミッション モデルや省電力機能など、新しいプラットフォームの動作をあらかじめサポートする - -
-- 開発者が報告した問題に対する優先度ウィンドウ -
- -- 最初の数週間で開発者から報告のあった問題について優先度を設定し、可能な限り早くテストを行いフィードバックを提供できるようにします。 - -
-- フィードバックとサポート -
- -- Issue Tracker で問題を報告し、フィードバックをお送りください。 - M Developer コミュニティ で他の開発者とつながりましょう。 - -
-- タイムラインとアップデート -
- -- M Developer Preview は 5 月 28 日から最終の Android M SDK まで実行されます。Android M SDK はまもなく、2015 年第三四半期に予定されている正式公開の前にリリースされます。 - - -
- -- 開発の主なマイルストーンごとにテスト端末へアップデートを配信する予定としています。 - 暫定マイルストーンは以下のとおりです。 -
- --
-
- - Preview 1(初期プレビュー リリース、5 月下旬) - - -
- - Preview 2(6 月下旬/7 月上旬) - - -
- - Preview 3(最終近く、7 月下旬) - -
- アップデートは第三四半期後半に予定されている最終 SDK で終了します。最終版では新しい Android に対する正式な API や最終的なシステム動作や機能が提供されます。 - - -
- -- Android M でのテストや開発に際しては、Preview アップデートがリリースされるたびに開発環境を最新に保つことを強くお勧めします。 - - プロセスをより容易にするため、既に Preview ビルドがインストールされた端末に無線経由でアップデート(OTA)を配信します。また手動でダウンロードして展開できるシステム イメージもご提供します。 - - -
-- 注: 最終 SDK とシステム イメージは OTA では配信できません。代わりにテスト端末に手動でコピーする必要があります。 - - -
- -- Preview アップデートをご利用いただけるようになった際は Android デベロッパー ブログ、このサイト、Android M デベロッパー コミュニティでお知らせします。 - - -
- -- Preview の内容 -
- -- M Developer Preview では、ご利用のアプリをさまざまな画面サイズ、ネットワーク、テクノロジー、CPU や GPU チップセット、ハードウェア設計でテストするために必要なあらゆるものを備えています。 - - -
- -- SDK ツール -
- -- 各コンポーネントは Android Studio の SDK Manager でダウンロードできます。 -
- --
-
- M Developer Preview SDK ツール - - -
- M Developer Preview エミュレータ システム イメージ(32 ビット版と 64 ビット版) - - - -
- M Developer Preview Android TV 版エミュレータ システム イメージ(32 ビット版) - - -
- ハードウェアのシステム イメージ -
- -- Nexus 端末向けハードウェア システム イメージは、ダウンロード ページからダウンロードできます。 - -
- --
-
- - Nexus 5(GSM と LTE)“hammerhead” 端末システム イメージ - - -
- - Nexus 6 “shamu” 端末システム イメージ - - -
- - Nexus 9(Wi-Fi)“volantis” 端末システム イメージ - - -
- - Nexus Player(AndroidTV)“fugu” 端末システム イメージ - -
- ドキュメントとサンプル コード -
- -- 次のドキュメント リソースで Preview についての詳細をご確認いただけます。 -
- --
-
- - SDK のセットアップでは、はじめの手順をステップ バイ ステップでご説明しています。 - - - -
- - Testing Guide と Behavior Changes では、テストでカバーされる主な分野について示しています。 - - -
- 新しい API のドキュメントである API 概要、ダウンロード可能な API リファレンスや、主な機能のデベロッパー ガイドであるパーミッション、アプリのバックアップなどをご提供しています。 - - - - - - -
- - パーミッションや他の新しい機能をサポートする方法について、サンプル コードでお試しいただけます。 - - - -
- - 現行バージョンのリリース ノートで M Developer Preview の変更メモや差分レポートなどをご覧いただけます。 - - -
- サポート リソース -
- -- M Developer Preview でのテストや開発について、次のサポート リソースをご確認いただけます。 - -
- --
-
- M Developer Preview Issue Tracker は、主なフィードバック チャンネルとしてご利用になれます。 - -バグやパフォーマンスの問題、一般的なフィードバックなど Issue Tracker からご連絡いただけます。 -また、既知の問題 -やその回避策をご確認いただけます。 - - -
- Android M Developer コミュニティは Google+ のコミュニティで、Android M を使っている他のデベロッパーとつながることができます。Android M に関する現象や考えを共有したり、疑問点を解消したりできます。 - - - - -
- 対象、プレビュー API、公開 -
- -
- Android M Developer Preview は開発リリースのみであり、標準 API レベルはありません。
-アプリのテストで互換性の問題は除外する場合(強く推奨します)、アプリのtargetSdkVersion
を “MNC”
に設定することで M Developer Preview を対象にできます。
-
-
-
-
- Android M Developer Preview ではプレビュー API を配信しています。現在 2015 年度第三四半期に予定されている最終 SDK がリリースされるまで、API は正式版ではありません。 - -つまり、時間がたつにつれて API の細かな変更が見込まれます(特にプログラムの最初の数週間)。 - -Android M Developer Preview でアップデートがあればその都度変更の概要をご提供します。 - -
- -- プレビュー API は変更される可能性がありますが、実行時パーミッションや省電力機能などのシステムの基幹にかかわる機能には変更はありませんので、すぐにテストしていただけます。 - - -
- -- 公開に関して、Google Play では M Developer Preview 対象アプリは公開できません。 -Android M 最終 SDK が利用可能になれば正式な Android M API レベルを対象にして、Google Play でアプリを公開できるようになります。 - -それまでは、Android M 対象のアプリをテスターに配布する場合は電子メールで送付したりご自分のサイトから直接ダウンロードしてもらったりしてください。 - - -
- -- 開始するには -
- -- アプリのテストをはじめるには: -
- --
-
- API 概要や Behavior Changes で新しい機能やご自分のアプリへの影響についてご確認ください。 - -特に、実行時パーミッション モデルや省電力機能、自動バックアップ機能についてお確かめください。 - - - - -
- Setting up the Preview SDK の手順に従い、ご利用の環境をセットアップしてテスト端末を構成してください。 - - - - -
- コピー手順に従い、最新の M Developer Preview システム イメージを Nexus 5、6、9、Nexus Player にコピーします。 - -1 度開発端末に Preview 環境をコピーすると、アップデートが無線経由(OTA)で配信されます。 - - - -
- M Preview API リファレンスやM Preview サンプルをダウンロードして、新しい API の機能についてさらに学び、ご自分のアプリで活用する方法についてご確認ください。 - - - - - -
- Android M Developer コミュニティに参加して最新のニュースを入手し、Preview に取り組んでいる他のデベロッパーとつながってください。 - - - -
- Android M Developer Preview プログラムへのご参加ありがとうございます。 -
diff --git a/docs/html-intl/intl/ja/preview/samples.jd b/docs/html-intl/intl/ja/preview/samples.jd deleted file mode 100644 index 6c44f4dd2c81791aa573de7b1009f3b3a512f726..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/ja/preview/samples.jd +++ /dev/null @@ -1,70 +0,0 @@ -page.title=サンプル -page.image=images/cards/samples-new_2x.png -@jd:body - -- 以下のコードサンプルは、M Developer Preview 用に提供しています。サンプルを Android Studio でダウンロードするには、[File] > [Import Samples] メニュー オプションを選択します。 - -
- -- 注: 以下のダウンロード可能なプロジェクトは、Gradle と Android Studio でご利用いただくために提供しています。 - -
- - -実行時パーミッション
- -- Android M では、システムのパーミッションの仕組みが変わります。ユーザーは、パーミッション要求の承認をインストール時ではなく、実行時に求められるようになります。 -このサンプルでは、このパーミッションの要求方法を紹介しています。 - -
- - - -資格情報の確認
- -- このサンプルでは、アプリで端末の資格情報を認証手段として使用する方法を紹介しています。 -
- - - -指紋ダイアログ
- -- このサンプルでは、ユーザーを認証するために登録された指紋をアプリで識別する方法を紹介しています。 - -
- - - -アプリの自動バックアップ
- -- Android M では、アプリの設定の自動バックアップが導入されました。このサンプルでは、設定のバックアップを管理するためにアプリにフィルタリング ルールを追加する方法を紹介しています。 - -
- - - -Camera 2 Raw
- -
- このサンプルでは、Camera2
API を使用して、RAW カメラバッファをキャプチャし、DNG
ファイルとして保存する方法を紹介しています。
-
-
アクティブ通知
- -
- このサンプルでは、その時点でアプリに表示されている通知の数を NotificationManager
を使って調べる方法を紹介しています。
-
-
-
本書の内容
- -M Developer Preview SDK は、Android SDK Manager から入手できます。このドキュメントは、Android SDK Manager の使用方法やプロジェクトの作成方法などの Android アプリ開発についての知識をお持ちの方を対象にしています。 - -Android アプリを初めて開発する場合は、まず Building Your First App のトレーニング レッスンをご覧ください。 - -
- -Android Studio 1.3 を入手する
- -Developer Preview は、現在プレビュー段階にある Android Studio 1.3 に最適化されています。 -Preview SDK をご使用になる場合は、Android Studio 1.3 のプレビュー版をインストールすることをお勧めします。 -
- -注意: Android Studio 1.3 の Canary プレビューは、現在も開発中です。 -メインの開発用マシンを Developer Preview のテストに使用する場合、テスト用に 2 つ目の Android Studio をインストールできます。 - -
- -Android Studio 1.3 プレビューをインストールするには:
- --
-
- Android Studio をダウンロードして起動します。 - - - -
- [Settings] ウィンドウを開きます(Windows では、 [File] > [Settings] を選択すると開くことができます)。
-[Appearance & Behavior] > [System Settings] > [Updates] を選択します。
-
-
-
-
OSX では、Android Studio の [Preferences] ウィンドウで、[Appearance & Behavior] パネルを見つけることができます。 - -
-
-
- - [Updates] パネルで、[Automatically check updates for:] に -[Canary Channel] を選択します。 - - -
- [Updates] パネルで、[Check Now] を選択して最新の Canary ビルドの有無を確認します。 -メッセージが表示されたら、最新の Canary ビルドをダウンロードしてインストールします。 - - -
Preview SDK を入手する
- -開発環境に Preview SDK コンポーネントを追加するには:
- --
-
- Android Studio 1.3 プレビューを起動します。 - - -
- [Settings] ウィンドウを開きます(Windows では、 [File] > [Settings] を選択すると開くことができます)。
-[Appearance & Behavior] > [System Settings] > [Updates] を選択します。
-
-
-
-
OSX では、Android Studio の [Preferences] ウィンドウで、[Appearance & Behavior] パネルを見つけることができます。 - -
-
-
- - [Updates] パネルで、[Automatically check updates for:] に -[Canary Channel] を、[Automatically check updates for Android SDK:] に -[Preview Channel] を選択します。 - - -
- [Android SDK Manager] を起動します。(Android Studio 1.3 では、SDK Manager はスタンドアロン アプリケーションではなくなり Android Studio に統合されました。) - - - - -
- [Platforms] セクションで、[Android MNC Preview] を選択します。 - - - -
- [Tools] セクションで、最新の Android [SDK Tools]、[Platform-tools]、[Build-tools] を選択します。 - - - - -
- [Install packages] をクリックし、すべてのパッケージの使用許諾契約に同意します。 - - - -
- [Settings] ウィンドウを開き、[Appearance & Behavior] > [System Settings] > [Android SDK] を選択し、M Developer Preview がインストールされていることを確認します。 - - - -
- [Android SDK] パネルで、[SDK Platforms] を選択します。 -[Android MNC Preview] が [Installed] と表示されているはずです。 -また、[SDK Tools] タブを開き、最新のツールがインストールされていることを確認します。 - - - -
上記の手順を完了すると、開発環境でプレビュー コンポーネントを利用できるようになります。 -
- - -プロジェクトを作成または更新する
- -- プレビュー API を使用するには、プレビュー コンポーネントを使用するために開発プロジェクトを作成または更新する必要があります。 - -
- - -新しいプロジェクトを作成する
- -- Preview SDK を使用してプロジェクトを作成するときには、Android Studio を使用することをお勧めします。Creating a Project に記載されている手順に従い、プロジェクト ウィザードで [Form Factors] 画面が表示されるまで操作を進めます。 - -次に、以下の手順に従い、Preview SDK 用に構成されたプロジェクトを作成します。 - -
- --
-
- [Phone and Tablet] をチェックします。 -
- [Minimum SDK] で、[MNC: Android M (Preview)] を選択します。 - -
既存のプロジェクトを更新する
- -
- 既存のプロジェクトを使用する場合は、プロジェクト構成を変更してプレビュー API を有効にする必要があります。開発環境で、モジュールの build.gradle
ファイルを開き、次のように値を設定します。
-
-
-
-
-
compileSdkVersion
に'android-MNC'
を設定します。
- minSdkVersion
に'MNC'
を設定します。
- targetSdkVersion
に'MNC'
を設定します。
-
テスト用にセットアップする
- -- Preview SDK でアプリをテストするには、プレビュー版のプラットフォームを使用して構成した端末または仮想端末が必要です。 -互換端末をお持ちの場合、テスト用にプレビュー プラットフォームをインストールできます。 -互換端末をお持ちでない場合は、テスト用に仮想端末を構成できます。 -
- -物理端末をセットアップする
- -- Nexus 5、Nexus 6、Nexus 9、Android TV をお持ちの場合は、アプリのテスト用にこれらの端末にプレビュー システム イメージをインストールできます。Android Virtual Device Manager ツールを使用すると、Android Studio 内から仮想端末をプレビュー版のプラットフォームでセットアップできます。 - - - -
- -- 重要: 端末にプレビュー イメージをインストールすると、端末からすべてのデータが削除されます。そのため、プレビュー イメージをインストールする前にすべてのデータをバックアップする必要があります。 - -
- -仮想端末をセットアップする
- -- Android Virtual Device Manager ツールを使用すると、Android Studio 内からプレビュー版のプラットフォームで仮想端末をセットアップできます。 - -
- -AVD マネージャーで AVD を作成するには:
- --
-
- Preview SDK のセットアップの説明に従って、開発環境に Preview SDK をインストールします。 - - -
- Managing AVDs with AVD Manager の手順に従います。
-
-以下の設定を使用します。
-
-
-
- 端末: Nexus 5、Nexus 6、Nexus 9、Android TV -
- 対象: - Android M (Preview) - API Level M -
- ABI: x86 -
-
- テスト用の仮想端末の作成についての詳細は、Managing Virtual Devices をご覧ください。 -
diff --git a/docs/html-intl/intl/ja/preview/testing/guide.jd b/docs/html-intl/intl/ja/preview/testing/guide.jd deleted file mode 100644 index b70e04d91a1b206770eed91d857c3244fc4d97a7..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/ja/preview/testing/guide.jd +++ /dev/null @@ -1,187 +0,0 @@ -page.title=テストガイド -page.image=images/cards/card-build_16x9_2x.png -page.keywords=プレビュー リソース,Android M,テスト,パーミッション - -@jd:body - -本書の内容
- -- Android M Developer Preview を利用すると、次期バージョンのプラットフォームでアプリが動作するか確認できます。 -Android M Developer Preview には、API の概要と動作の変更点に記載されているように、アプリに影響を与える可能性のある多くの API と動作の変更が含まれています。 - -Android M Developer Preview でアプリをテストする時には、アプリの良好な使用感を確保するために、システムのいくつかの変更点に特に注意する必要があります。 - - -
- -- このガイドでは、アプリで Android M Developer Preview の機能の何をどのようにテストすればよいか説明します。以下の機能は、アプリの動作に大きな影響を与える可能性があるので、優先してテストする必要があります。 - - -
- --
-
- パーミッション - -
- Doze と App Standby - -
- 自動バックアップと端末識別子 -
- テスト用のプレビュー システム イメージを使用した端末または仮想端末のセットアップ方法の詳細については、Preview SDK のセットアップをご覧ください。 - -
- - -パーミッションをテストする
- -- パーミッション モデルの変更により、ユーザーがアプリにパーミッションを付与する方法が変わりました。 -アプリでは、インストール時にすべてのパーミッションを要求するのではなく、実行時に個々のパーミッションをユーザーに要求する必要があります。 - -これにより、ユーザーは、各アプリのアクティビティをより細かくコントロールできるようになるだけではなく、アプリが各パーミッションを要求する理由をこれまでよりもよく理解できるようになります。 -ユーザーは、いつでもアプリに個別にパーミッションを付与したり、付与したパーミッションを個別に取り消したりできます。 -この機能は、アプリの動作に大きな影響を与える可能性があり、アプリの一部の機能が動作しなくなったり、限定された機能しか使えなくなったりする可能性もあります。 - - -
- -- この変更は、アプリがこの新しいバージョンを対象にしているかどうかにかかわらず、この新しいプラットフォーム上で実行されるすべてのアプリに影響します。 -このプラットフォームはレガシーアプリに限定的な互換動作を提供しますが、公式版のプラットフォームのリリースに合わせてアップデート版のアプリを公開できるように、新しいパーミッション モデルに対応させるためのアプリの移行を今から計画することを強くお勧めします。 - - -
- - -テストのヒント
- -- 以下のテストのヒントを活用して、アプリでの新しいパーミッション動作のテストを計画し、実行してください。 - -
- --
-
- アプリの現在のパーミッションと関連するコードパスを確認します。 -
- パーミッションで保護されているサービスとデータ間のユーザーフローをテストします。 -
- 付与されたパーミッションと取り消されたパーミッションのさまざまな組み合わせをテストします。 -
- {@code adb} ツールを使用して、コマンドラインからパーミッションを管理します。
-
-
-
- パーミッションとステータスをグループ化して表示します。
-
adb shell pm list permissions -d -g
-
- - 以下の構文を使用して 1 つまたは複数のパーミッションを付与または取り消します。
-adb shell pm [grant|revoke] <permission.name> ...
-
-
- - パーミッションとステータスをグループ化して表示します。
-
- アプリでパーミッションを使用しているサービスを分析します。 -
テスト方針
- -- このパーミッションの変化は、アプリの構造と設計、ユーザーが体験する使用感とフローに影響を与えます。 -アプリの現在のパーミッション利用の状況を調査し、新しいフローの検討を開始する必要があります。 -このプラットフォームの公式リリースは互換動作を提供しますが、互換動作に頼ることなくアプリのアップデートを計画することを強くお勧めします。 - - -
- -- まずアプリが実際に必要とし使用しているパーミッションを特定してから、パーミッションで保護されたサービスを使用している各コードパスを探してください。 -これには、新しいプラットフォーム上でのテストと、コードの解析が必要です。 -テストでは、アプリの {@code targetSdkVersion} をこのプレビュー版に変えて、実行時パーミッションのオプトインに重点的にテストする必要があります。 -詳細については、Preview SDK のセットアップをご覧ください。 - -
- -- パーミッションの取り消しと追加のさまざまな組み合わせをテストし、パーミッションに依存するユーザーフローを確認します。 -パーミッションへの依存性が明白または論理的ではない箇所では、依存性を取り除くため、またはパーミッションが必要な理由を明白にするために、フローのリファクタリングまたはコンパートメント化を検討する必要があります。 - - -
- -- 実行時パーミッションの動作、テスト、ベスト プラクティスについては、Developer Preview ページのパーミッションをご覧ください。 - - -
- - -Doze と App Standby をテストする
- -- 省電力機能である Doze と App Standby により、端末がアイドル状態のときやそのアプリにフォーカスがないときに、アプリが実行できるバックグラウンド処理の量が制限されます。 -システムによってアプリに加えられる可能性のある制限には、ネットワーク アクセスの制限や停止、バックグラウンド タスクの停止、通知の停止、ウェイク リクエストの無視、アラームなどがあります。 - -これらの省電力のための最適化が行われた状態で確実にアプリが適切に動作するように、これらの省電力状態をシミュレートしてアプリをテストする必要があります。 - - -
- -アプリで Doze をテストする
- -アプリで Doze をテストするには:
- --
-
- M Preview のシステム イメージを使用して、ハードウェア端末または仮想端末を構成します。 -
- 端末を開発マシンに接続し、アプリをインストールします。 -
- アプリを実行し、アクティブ状態のままにします。 -
- 以下のコマンドを実行して、端末の Doze モードへの移行をシミュレートします。
-
-
-$ adb shell dumpsys battery unplug -$ adb shell dumpsys deviceidle step -$ adb shell dumpsys deviceidle -h -
- -
- - 端末がアクティブ状態に戻ったときのアプリの動作を観察します。端末が Doze モードから抜けるときに、アプリがスムーズに復帰することを確認します。 - -
アプリで App Standby をテストする
- -アプリで App Standby モードをテストするには:
- --
-
- M Preview のシステム イメージを使用して、ハードウェア端末または仮想端末を構成します。 -
- 端末を開発マシンに接続し、アプリをインストールします。 -
- アプリを実行し、アクティブ状態のままにします。 -
- 以下のコマンドを実行して、アプリのスタンバイ モードへの移行をシミュレートします。
-
-
-$ adb shell am broadcast -a android.os.action.DISCHARGING -$ adb shell am set-idle <packageName> true -
- -
- - 以下のコマンドを使用して、アプリのウェイクをシミュレートします。
-
$ adb shell am set-idle <packageName> false
-
- - アプリがウェイク状態に戻ったときのアプリの動作を観察します。アプリがスタンバイ モードからスムーズに復帰することを確認します。 -特に、アプリの通知とバックグラウンド ジョブが想定通りの動作を続けているかを確認する必要があります。 - -
アプリの自動バックアップと端末固有識別子
- -アプリが、Google Cloud Messaging の登録 ID などの何らかの端末固有の識別子を内部ストレージに保持している場合、アプリの自動バックアップの説明に従って、そのストレージのロケーションを自動バックアップの対象から除外してください。 - - - -
diff --git a/docs/html-intl/intl/ja/preview/testing/performance.jd b/docs/html-intl/intl/ja/preview/testing/performance.jd deleted file mode 100644 index 1c3ae02290f1c48b3d0a8815a3874b3bfdc4a72e..0000000000000000000000000000000000000000 --- a/docs/html-intl/intl/ja/preview/testing/performance.jd +++ /dev/null @@ -1,656 +0,0 @@ -page.title=表示パフォーマンスのテスト -page.image=images/cards/card-test-performance_2x.png -page.keywords=パフォーマンス,fps,ツール - -@jd:body - - -本書の内容
--
-
- UI のパフォーマンスを測定する - - -
- UI パフォーマンス テストを自動化する - - -
- ユーザー インターフェース(UI)のパフォーマンスをテストすることで、アプリが機能面での要件に合うだけでなく、ユーザーがアプリをスムーズに操作でき、毎秒安定して 60 フレーム(why 60fps?)で、フレームのドロップや遅延なしで、言い換えればジャンクなしで実行されるようにします。 - - -このドキュメントでは、UI のパフォーマンスを測定することができるツールについて説明し、UI パフォーマンスの測定値をテストで活用する方法を提示します。 - - -
- - -UI のパフォーマンスを測定する
- -- パフォーマンスを改善するには、まずシステムのパフォーマンスを測定し、次にパイプラインのさまざまな箇所で発生している問題を診断し識別する必要があります。 - - -
- -- dumpsys は端末上で動作し、システム サービスの状態についての情報をダンプする Android ツールです。 - -gfxinfo コマンドを dumpsys に渡すと、記録中に実行されたアニメーションのフレームに関連するパフォーマンス情報が logcat に出力されます。 - - -
- --> adb shell dumpsys gfxinfo <PACKAGE_NAME> -- -
- このコマンドは、フレーム タイミング データの複数の異なるバリアントを生成することがあります。 -
- -フレームのデータを集計する
- -- M Preview では、このコマンドは、プロセスの生存期間全体を通して収集したフレームのデータの集計結果を logcat に出力します。 -次に例を示します。 -
- --Stats since: 752958278148ns -Total frames rendered: 82189 -Janky frames: 35335 (42.99%) -90th percentile: 34ms -95th percentile: 42ms -99th percentile: 69ms -Number Missed Vsync: 4706 -Number High input latency: 142 -Number Slow UI thread: 17270 -Number Slow bitmap uploads: 1542 -Number Slow draw: 23342 -- -
- これらのデータは、アプリのレンダリングのパフォーマンスと多くのフレームの全体での安定性を大まかに示します。 - -
- - -正確なフレーム タイミング情報
- -- M Preview では、gfxinfo のための新しいコマンド、framestats が採用され、最新のフレームのフレーム タイミングのきわめて詳細な情報を提供します。そのため、より正確に問題を追跡しデバッグできるようになります。 - - -
- -->adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats -- -
- このコマンドは、アプリによって生成された最新 120 フレームのフレーム タイミング情報を、ナノ秒の精度を持つタイムスタンプを使用して出力します。以下は、adb dumpsys gfxinfo - <PACKAGE_NAME> framestats による未加工の出力例です。 - -
- --0,49762224585003,49762241251670,9223372036854775807,0,49762257627204,49762257646058,49762257969704,49762258002100,49762265541631,49762273951162,49762300914808,49762303675954, -0,49762445152142,49762445152142,9223372036854775807,0,49762446678818,49762446705589,49762447268818,49762447388037,49762453551527,49762457134131,49762474889027,49762476150120, -0,49762462118845,49762462118845,9223372036854775807,0,49762462595381,49762462619287,49762462919964,49762462968454,49762476194547,49762476483454,49762480214964,49762480911527, -0,49762479085548,49762479085548,9223372036854775807,0,49762480066370,49762480099339,49762481013089,49762481085850,49762482232152,49762482478350,49762485657620,49762486116683, -- -
- この出力の各行が、アプリによって生成される 1 つのフレームを示します。各ラインは、フレームを生成するパイプラインの各段階で費やされた時間を出力する固定された数の列を持ちます。 -次のセクションでは、各列が何を示しているかも含めて、フォーマットを詳細に説明します。 - -
- - -Framestats データ形式
- -- データは CSV 形式で出力されるため、お好みのスプレッドシート ツールに簡単に貼り付けたり、スクリプトで簡単に集計して解析したりできます。 -以下のリストは、出力データ列のフォーマットを説明しています。 -すべてのタイムスタンプはナノ秒単位で出力されます。 -
- --
-
- FLAGS
-
-
-
- FLAGS 列が「0」の行には、FRAME_COMPLETED 列から INTENDED_VSYNC 列を引いて計算されたフレームの総処理時間が示されます。 - - - -
- FLAGS 列が「0」以外の場合、そのフレームは通常のパフォーマンスからの外れ値であると定められているのでその行は無視する必要があります。この場合、レイアウトと描画に 16 ミリ秒よりも長くかかることが想定されています。
-
-これは、以下の原因で起きることがあります。
-
-
-
- ウィンドウのレイアウトが変更された(アプリケーションの最初のフレームの場合や画面が回転された後など)。 - - - -
- フレームが省略された。この場合、いくつかの値には不適切なタイムスタンプが含まれます。 -たとえば 60 fps よりも速く実行されている場合や、画面上にダーティで終わったものが何もない場合など、フレームは省略することができます。これは必ずしもアプリに問題がある兆候ではありません。 - - - -
-
-
- - INTENDED_VSYNC
-
-
-
- フレームの意図された開始ポイント。この値が VSYNC と異なる場合、vsync 信号にすぐに応答することを阻止する動作が UI スレッド上で発生していたことを意味します。 - - - -
-
- - VSYNC
-
-
-
- すべての vsync リスナーとフレームの描画(Choreographer フレーム コールバック、アニメーション、View.getDrawingTime() など)で使用された時間の値。 - - - -
- VSYNC と VSYNC のアプリケーションへの影響の詳細については、Understanding VSYNC のビデオをご覧ください。 - - - -
-
- - OLDEST_INPUT_EVENT
-
-
-
- 入力キューの最も古い入力イベントのタイムスタンプ。フレームの入力イベントが存在しない場合は、Long.MAX_VALUE。 - - - -
- この値は、主にプラットフォームの動作のパフォーマンスを示すことを意図しており、アプリのデベロッパーが活用できる場面は限定されます。 - - -
-
- - NEWEST_INPUT_EVENT
-
-
-
- 入力キューの最も新しい入力イベントのタイムスタンプ。フレームの入力イベントが存在しない場合は、0。 - - - -
- この値は、主にプラットフォームの動作のパフォーマンスを示すことを意図しており、アプリのデベロッパーが活用できる場面は限定されます。 - - - -
- ただし、FRAME_COMPLETED から NEWEST_INPUT_EVENT を引いた値を確認することによって、そのアプリが増やす待ち時間がどれくらいか大まかに知ることができます。 - - -
-
- - HANDLE_INPUT_START
-
-
-
- 入力イベントがアプリケーションにディスパッチされるときのタイムスタンプ。 - - -
- この値と ANIMATION_START との間の時間を確認することで、アプリケーションが入力イベントを処理するために費やした時間を測定することができます。 - - - -
- この値が大きい(> 2 ミリ秒)の場合、View.onTouchEvent() などの入力イベントを処理するためにアプリが長い時間を費やしていることを意味します。これは、この動作の最適化または別のスレッドへの移行が必要なことを示している場合があります。 - -新しいアクティビティやそれに類するものを起動するクリック イベントなどの一部のシナリオでは、この値が大きいことは想定済みであり許容範囲内です。 - - - -
-
- - ANIMATION_START
-
-
-
- Choreographer を使用して登録されたアニメーションが実行されたときのタイムスタンプ。 - - -
- この値と PERFORM_TRANVERSALS_START の間の時間を確認することで、実行中のすべてのアニメーター(ObjectAnimator、ViewPropertyAnimator、共通の遷移となっている Transitions)を評価するのにかかった時間を確認することができます。 - - - - -
- この値が大きい(> 2 ミリ秒)の場合、アプリがカスタム アニメーターを記述していないか、また ObjectAnimators がアニメーション化しているのがどの項目かを確認して、それらがアニメーションに適しているかどうか確かめてください。 - - - - -
- Choreographer についての詳細は、For Butter or Worse のビデオをご覧ください。 - - -
-
- - PERFORM_TRAVERSALS_START
-
-
-
- この値から DRAW_START を引くと、レイアウトと測定のフェーズが完了するまでにかかる時間を知ることができます(スクロールまたはアニメーションの間は、この時間がゼロに近いことが望ましいことにご注意ください)。 - - - - -
- レンダリング パイプラインのレイアウトと測定のフェーズについての詳細は、Invalidations, Layouts and Performance のビデオをご覧ください。 - - - -
-
- - DRAW_START
-
-
-
- performTraversals の描画のフェーズが開始された時間。これは、無効化されているビューのディスプレイ リストを記録する開始ポイントです。 - - - -
- この値と SYNC_START の間の時間は、ツリー内のすべての無効化されているビュー上で View.draw() を呼び出すのにかかった時間を示します。 - - - -
- 描画モデルに関する詳細は、Hardware Acceleration または Invalidations, Layouts and Performance のビデオをご覧ください。 - - - -
-
- - SYNC_START
-
-
-
- 描画の同期フェーズが開始された時間。 - - -
- この値と ISSUE_DRAW_COMMANDS_START の間の時間が非常に大きい場合(> 0.4 ミリ秒またはこれに近い値)、通常は、GPU にアップロードする必要がある多くの新しい Bitmaps が描画されたこと意味します。 - - - - -
- 同期フェーズについての詳細は、Profile GPU Rendering のビデオをご覧ください。 - - -
-
- - ISSUE_DRAW_COMMANDS_START
-
-
-
- ハードウェア レンダラーが、GPU への描画コマンドの発行を開始した時間。 - - -
- この値と FRAME_COMPLETED の間の時間により、そのアプリがどれくらいの量の GPU 作業を生じさせているのか大まかに知ることができます。 -オーバードローが多すぎたりまたはレンダリング効果が不十分だったりという問題がある場合は、この時間にあらわれます。 - - -
-
- - SWAP_BUFFERS
-
-
-
- eglSwapBuffers が呼び出された時間。プラットフォーム作業関連以外では、あまり重要ではない値です。 - - -
-
- - FRAME_COMPLETED
-
-
-
- すべてが完了した時間です。そのフレームを処理するのにかかった時間の合計は、FRAME_COMPLETED から INTENDED_VSYNC を引くと計算できます。 - - -
-
-
- このデータは、別の方法でも使用できます。たとえば、さまざまな遅延バケットでのフレームの処理にかかった時間(FRAME_COMPLETED - INTENDED_VSYNC)の分布を示す下記のヒストグラムは、単純ですが役に立ちます。 - -このグラフを一目見るだけで、大部分のフレームは 16 ミリ秒の限界線(赤色の線)を大きく下回った良好な状態であるけれども、いくつかのフレームが限界線を著しく上回っていることがわかります。 - -ヒストグラムで時間の経過に伴う変化を確認することで、大規模な変化が起きているのか、新しい外れ値が作成されているのか知ることができます。 -また、データに含まれる多くのタイムスタンプに基づいて、入力待ち時間、レイアウトにかかった時間、その他のこれに類する興味を引く指標をグラフにできます。 - - -
- - - - -簡易フレーム タイミング ダンプ
- -
- [開発者向けオプション] で [GPUレンダリングのプロフィール作成] を [adb shell dumpsys gfxinfo] に設定すると、adb shell dumpsys gfxinfo
コマンドにより、最新の 120 フレームのタイミング情報が、いくつかの異なるカテゴリに分かれて、タブ区切りで出力されます。
-
-
-このデータは、描画パイプラインのどの部分の処理が遅いのかを大まかに知るのに役に立ちます。
-
-
- 上記の framestats と同様に、お好みのスプレッドシート ツールに簡単に貼り付けたり、スクリプトで簡単に集計し解析したりできます。 - -以下のグラフは、アプリによって生成された多くのフレームが時間を費やした箇所の内訳を示しています。 - -
- - - -- このグラフは、gfxinfo を実行し、出力結果をコピーし、スプレッドシート アプリケーションに貼り付け、データを積み上げ棒グラフにしたものです。 - -
- -- 各縦棒は、アニメーションの 1 フレームを示し、その高さはそのフレームを処理するのにかかるミリ秒の数を示しています。 -また、縦棒の色分けされた各部分は、レンダリング パイプラインの各段階を示しています。これにより、ボトルネックを生んでいる可能性があるのはアプリケーションのどの箇所か確認できます。 - -レンダリング パイプラインとその最適化方法に関する詳細は、Invalidations, Layouts and Performance のビデオをご覧ください。 - - -
- - -データ収集用のウィンドウを制御する
- -- Framestats と簡易フレーム タイミングの両方とも、非常に短いウィンドウを通じて、約 2 秒相当のレンダリングについてデータを収集しています。 -たとえば、収集するデータを特定のアニメーションだけに限定したい場合、このタイミング データ収集用ウィンドウを正確にコントロールするには、すべてのカウンタをリセットし収集したデータを集計します。 - - -
- -->adb shell dumpsys gfxinfo <PACKAGE_NAME> reset -- -
- これは、ダンプ コマンドとあわせて使用することもでき、フレームの 2 秒未満のウィンドウを続けてキャプチャしながら、通常の流れで収集しリセットできます。 - - -
- - -パフォーマンスの低下を診断する
- -- パフォーマンスの低下を見つけることは、問題を見つけだし、アプリケーションの状態を良好に維持するための最初のステップです。 -ただし、dumpsys は、ただ問題の存在とその相対的な深刻度を明らかにするだけです。 -さらに、パフォーマンスの問題の具体的な原因を突き止め、解決するための適切な方法を見つける必要があります。 -それには、systrace ツールを利用することをお勧めします。 - -
- - -追加リソース
- -- Android のレンダリング パイプラインの仕組み、一般的な問題、それらの問題の修正方法についての詳細は、以下の資料が役に立ちます。 - - -
- --
-
- Rendering Performance 101 - -
- Why 60fps? - -
- Android UI and the GPU - -
- Invalidations Layouts and performance - -
- Analyzing UI Performance with Systrace - -
UI パフォーマンス テストを自動化する
- -- UI パフォーマンスのテスト手法の 1 つに、対象のアプリ上で一連のユーザー操作を人間のテスターに実行してもらい、目視でジャンクを探すかツール主体の手法を使用して長い時間を費やしてジャンクを見つけるかのいずれかの方法をとるというものがあります。 - -ただし、この人の力による方法は危険を伴います。フレームレートの変化に気付く能力は、人によって大きく異なります。また、この方法は、多くの時間が必要で単調で退屈なものであり、ミスも起こりがちです。 - - -
- -- より効率的な手法は、自動化された UI テストにより主要なパフォーマンス指標のログを取って解析することです。 -Android M Developer Preview には、アプリケーションのアニメーションに対するジャンクの量と深刻度を簡単に確認することができ、現在のパフォーマンスを確認し将来のパフォーマンス目標を実現するための適切なプロセスを構築するために使用できる新しいログ記録機能が含まれています。 - - - -
- -- このドキュメントでは、この新しいログ機能によるデータを使用してパフォーマンス テストを自動化するための手法について紹介します。 - -
- -- この手法には、鍵となるアクションが 2 つあります。何をどのようにテストするかということを明確にすることと、自動化されたテスト環境をセットアップし管理することです。 - - -
- - -UI テストをセットアップする
- -- 自動化されたテストを実行する前に、テストの仕様や必要になる可能性があるものを適切に把握するために、いくつかの大まかな決定をしておくことが重要です。 - -
- -- テストする重要なアニメーションやフローを明確にする -
- -- パフォーマンスの低さがユーザーの目に最も多く触れるのは、アニメーションのスムーズさが失われる場合です。 -そのため、どのタイプの UI アクションをテストするか決めるときに、ユーザーが最もよく見る重要なアニメーションまたはユーザーの使用感にとって最も重要なアニメーションにフォーカスすると効果があります。 - -以下にいくつかの一般的なシナリオをご紹介します。 -
- --
-
- プライマリ ListView または RecyclerView のスクロール - - -
- 非同期処理待ちサイクル中のアニメーション - - -
- ビットマップを読み込んだり操作したりするアニメーション - - -
- アルファブレンドを含むアニメーション - - -
- キャンバスを使用して描画するカスタムビュー - -
- チームのエンジニア、デザイナー、プロダクト マネージャーと連携して、テスト範囲のこれらの重要な製品アニメーションの優先順位を決めてください。 - -
- -- 将来の目標を決め、実現を目指す -
- -- 具体的なパフォーマンス目標を明確にし、その目標に合わせてテストを作成しデータを収集することが重要な場合もあります。 -次に例を示します。 -
- --
-
- 詳細を知るために、初めて UI パフォーマンスの追跡を開始したいだけですか。 - - -
- 将来発生する可能性のあるパフォーマンスの低下を防止したいですか。 - - -
- 現在のフレームのスムーズ度合いは 90% で、今四半期中に 98 % にしたいと考えていますか。 - - -
- 現在のフレームのスムーズ度合い 98% を低下させたくないと考えていますか。 - - -
- ローエンド端末でのパフォーマンスを改善することが目標ですか。 - -
- 上記のすべての場合で、複数のバージョンのアプリケーションでのパフォーマンスを示すヒストリカル トラッキングが必要です。 - -
- -- テストする端末を明確にする -
- -- アプリケーションのパフォーマンスは、そのアプリケーションが実行される端末によって異なります。端末によっては、メモリが少なく、GPU のパワーが低く、CPU チップが遅いものもあります。 -つまり、あるハードウェアでスムーズに実行できるアニメーションが別のハードウェアではうまく実行できなかったり、さらに悪い場合は、パイプラインの別の箇所にボトルネックを生んだりすることになります。 - -そのため、このようなハードウェアの違いに対処するために、最新のハイエンド端末と、ローエンド端末、タブレットなどの幅広い端末を選んでテストを実行する必要があります。 - -さまざまな CPU 性能、RAM、画面密度、サイズ等の端末を用意してください。 -ハイエンド端末でうまくいったテストが、ローエンド端末では失敗することがあります。 - -
- -- UI のテストの基本的なフレームワーク -
- -- UI Automator や Espresso といったツールが、ユーザーがアプリケーション内を移動する動作を自動処理にするために用意されています。 - -これらは、端末でのユーザーの操作を模倣するシンプルなフレームワークです。 -これらのフレームワークを使用するには、一連のユーザー アクションを実行する独自のスクリプトを作成して、端末上で実行します。 - - -
- -
- dumpsys gfxinfo
と、これらの自動化されたテストを組み合わせることで、テストを実行できる再現可能なシステムを簡単に作成して、特定の条件でのパフォーマンス情報を測定できます。
-
-
-
自動化された UI テストをセットアップする
- -- UI テストを実行する機能と、1 つのテストからデータを集めるためのパイプラインを用意したら、次の重要なステップは、複数の端末で、そのテストを複数回実行でき、開発チームの解析用にパフォーマンス データを集計できるフレームワークを用意することです。 - - - -
- -- テスト自動化のためのフレームワーク -
- -- UI テストのフレームワーク(UI Automator など)は、対象の端末やエミュレータ上で直接実行されます。 -dumpsys gfxinfo によるパフォーマンス情報の収集はホストマシンによって行われますが、コマンドの送信は ADB を通じて行われます。 -これらの別々に分かれている処理の自動化を橋渡しするために、MonkeyRunner フレームワークは開発されました。このフレームワークは、ホストマシンで動作するスクリプティング システムで、接続されている端末にコマンドを発行できるとともに、それらの端末からデータを受け取ることもできます。 - - - -
- -- UI パフォーマンス テストの適切な自動化のためのスクリプトを作成することで、少なくとも、以下のタスクを MonkeyRunner を利用して実行することが可能になります。 - -
- --
-
- 対象の端末(1 台または複数台)またはエミュレータに任意の APK をロードして起動する - - -
- UI Automator UI テストを起動して、実行できるようにする - - -
- dumpsys gfxinfoを通じて情報を収集する。 - - -
- 情報を集計し、デベロッパーに役に立つ形で表示する。 - -
見つけた問題を選別し解決する
- -- 問題のパターンまたはパフォーマンスの低下を確認したら、次に必要なことは問題の解決方法を見つけその方法を実行することです。 -その自動化されたテスト フレームワークがフレームの正確なタイミングの内訳を保存している場合、最近行われたコードやレイアウトの疑わしい変更を調べたり(パフォーマンスが低下している場合)、手作業での調査に切り替えたときにシステムのどの箇所を解析するか絞り込んだりするのに役立ちます。 - - -手作業での調査は、まず systrace から開始することをお勧めします。systrace は、システムのレンダリング パイプラインのすべての段階、すべてのスレッド、コア、およびテスト担当者が定義したカスタム イベントについての正確なタイミング情報を表示します。 - - -
- -- 一時的なタイミングを適切にプロファイリングする -
- -- レンダリング パフォーマンスのタイミングを取得し測定することには困難を伴います。 -これらの数値は、その本質として、決定的なものではなく、多くの場合、システムの状態、利用可能なメモリ量、サーマル・スロットリング、その地域に最後に日照があった時間などに応じて変動します。 - -つまり同じテストを 2 度実行した場合、近似するが完全に同じではない、わずかに異なる結果が出ることがあるということです。 - - -
- -- この方法で適切にデータを集めプロファイリングするには、同じテストを複数回実行し、結果を平均値または中間値として集計します(以下では、この処理を「バッチ」と記載します)。これにより、テストのパフォーマンスの大まかな数字を、正確なタイミングを必要とすることなく取得できます。 - - - -
- -- バッチは、コード変更の合間にも、それらの変更がパフォーマンスにもたらす相対的な影響を確認するために使用できます。 -変更前のバッチの平均フレームレートが変更後のバッチよりも大きい場合、通常、WRT パフォーマンスが全面的に改善したと言えます。 - - -
- -- つまり、自動化された UI テストでは、この考え方を取り入れることと、テスト中に発生する可能性のある異常を把握しておくことが必要です。 -たとえば、アプリケーションのパフォーマンスが、そのアプリケーションではなく何らかの端末の問題により突然低下した場合、通常時のタイミングを取得するためにバッチを再度実行した方がよいことがあります。 - - - -
- -- それでは、測定値を意味のあるものにするには、何回テストを実行すればよいでしょうか。少なくとも 10 回は必要であり、50 回や 100 回などのように回数が多いほど正確な結果が得られます(もちろん、時間と正確さはトレードオフの関係にあります)。 - - -
diff --git a/docs/html-intl/intl/ja/sdk/index.jd b/docs/html-intl/intl/ja/sdk/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..f7454c0b8ed62095f80e6998e59e950486fa4a08 --- /dev/null +++ b/docs/html-intl/intl/ja/sdk/index.jd @@ -0,0 +1,432 @@ +page.title=Android Studio と SDK Tools のダウンロード +page.tags=sdk, android studio +page.template=sdk +page.image=images/cards/android-studio_2x.png +header.hide=1 +page.metaDescription=公式 Android IDE とデベロッパー ツールをダウンロードして、Android 版のモバイル端末、タブレット、ウェアラブル端末、TV などの端末向けのアプリをビルドする。 + +@jd:body + + + + + + + +ダウンロード
+ +Android Studio またはスタンドアロンの SDK Tools をインストールする前に、次の利用規約に同意する必要があります。 +
+ +利用規約
+以下は、Android Software Development Kit の使用許諾契約です。 + + +1. Introduction
+1.1 The Android Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK. + +1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time. + +1.3 A "compatible implementation" means any Android device that (i) complies with the Android Compatibility Definition document, which can be found at the Android compatibility website (http://source.android.com/compatibility) and which may be updated from time to time; and (ii) successfully passes the Android Compatibility Test Suite (CTS). + +1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. + + +2. Accepting this License Agreement
+2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License Agreement. + +2.2 By clicking to accept, you hereby agree to the terms of the License Agreement. + +2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. + +2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity. + + +3. SDK License from Google
+3.1 Subject to the terms of the License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable, non-exclusive, and non-sublicensable license to use the SDK solely to develop applications for compatible implementations of Android. + +3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Android) or to develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of Android, provided that this SDK is not used for that purpose. + +3.3 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you. + +3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK. + +3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. + +3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you. + +3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features. + +3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK. + + +4. Use of the SDK by You
+4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. + +4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). + +4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so. + +4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier. + +4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so. + +4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach. + + +5. Your Developer Credentials
+5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials. + + +6. Privacy and Information
+6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected. + +6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy. + + +7. Third Party Applications
+7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources. + +7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners. + +7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. + + +8. Using Android APIs
+8.1 Google Data APIs + +8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service. + +8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so. + + +9. Terminating this License Agreement
+9.1 The License Agreement will continue to apply until terminated by either you or Google as set out below. + +9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials. + +9.3 Google may at any time, terminate the License Agreement with you if: +(A) you have breached any provision of the License Agreement; or +(B) Google is required to do so by law; or +(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or +(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable. + +9.4 When the License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst the License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely. + + +10. DISCLAIMER OF WARRANTIES
+10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. + +10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. + +10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + + +11. LIMITATION OF LIABILITY
+11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. + + +12. Indemnification
+12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with the License Agreement. + + +13. Changes to the License Agreement
+13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available. + + +14. General Legal Terms
+14.1 The License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK. + +14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google. + +14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable. + +14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement. + +14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. + +14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party. + +14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. + +November 20, 2015 +数ステップで、Android 向けアプリのビルドを開始できます。
+まもなく、Installing the Android SDKへリダイレクトします。 +
+ +Android Studio
+ +公式 Android IDE
+ +-
+
- Android Studio IDE +
- Android SDK Tools +
- Android 6.0(Marshmallow)プラットフォーム +
- Google API を使用した Android 6.0 エミュレータのシステム イメージ +
+ + +
+Android Studio または スタンドアロンの SDK Tools を入手するには、developer.android.com/sdk/ へアクセスしてください。 +
+-
+
- システム要件 +
- 他のダウンロード オプション +
- Android Studio への移行 +
- アンケートに回答する +
インテリジェント コード エディタ
+ +Android Studio の中核であるインテリジェント コード エディタは、高度なコード補完機能、リファクタリング機能、解析機能を備えています。 +
+このパワフルなコード エディタは、Android アプリ デベロッパーの生産性を高めます。
+コード テンプレートと GitHub との統合
+ +新しいプロジェクト ウィザードでは、これまで以上に簡単に新規プロジェクトを開始できます。
+ +ナビゲーション ドロワーやビュー ページャーなどのパターンにテンプレート コードを使用してプロジェクトを開始できます。加えて GitHub から Google のコード サンプルをインポートできます。 +
+マルチスクリーン アプリの開発
+ +Android 携帯電話、タブレット、Android Wear、Android TV、Android Auto、Google Glass 向けのアプリをビルドできます。 +
+Android Studio の新しい Android プロジェクト ビューとモジュールのサポートによって、アプリのプロジェクト管理やリソース管理がさらに簡単になります。 + +
あらゆる形状の端末をサポートする仮想デバイス
+ +Android Studio には最適化されたエミュレータ イメージが事前構成されています。
+アップデートされ合理化された仮想デバイス マネージャーには、一般的な Android 端末向けにあらかじめ定義されたプロファイルが用意されています。 +
++Gradle で進化する Android のビルド
+ +1 つのプロジェクトで、Android アプリのための、異なる機能を持つ複数の APK を作成できます。
+Maven を使用してアプリの依存関係を管理します。
+APK は Android Studio でもコマンドラインでもビルドできます。
+Android Studio のその他の特徴
+-
+
- 人気の高い JetBrains の Java IDE である IntelliJ IDEA Community Edition が基盤 +
- Gradle ベースの柔軟なビルドシステム +
- ビルド バリアントと複数の APK 生成機能 +
- Google サービスやさまざまな端末向けのテンプレート サポートの拡充 +
- テーマの編集が可能なレイアウト エディタ +
- パフォーマンス、ユーザビリティ、バージョン互換性、その他の問題を検出する Lint ツール +
- ProGuard とアプリの署名機能 +
- Google Cloud Messaging や App Engine との統合をサポートする Google Cloud プラットフォームの組み込みサポート + +
+Android Studio の機能の詳細については、「Android Studio の基礎」をご覧ください。 +
+Eclipse で ADT を使用している場合、Android Studio が Android の公式 IDE になったため、Android Studio に移行して IDE の最新アップデートを入手する必要があります。 + +プロジェクトの移行については、「Migrating to Android Studio」をご覧ください。 + +
+ + + + + + + +システム要件
+ +Windows の場合
+ +-
+
- Microsoft® Windows® 8/7/Vista/2003(32-bit 版または 64-bit 版) +
- 2 GB 以上のシステム メモリ(RAM)、4 GB 以上を推奨 +
- 400 MB の空き容量のあるハードディスク +
- Android SDK、エミュレータのシステム イメージ、キャッシュ用には少なくとも 1 GB 以上 +
- 1280 x 800 以上の画面解像度 +
- Java Development Kit (JDK) 7 +
- エミュレータ アクセラレータ向け(任意): Intel® VT-x、Intel® EM64T(Intel® 64)、Execute Disable(XD)ビット機能対応の Intel® プロセッサ + +
Mac OS X の場合
+ +-
+
- Mac ®OS X® 10.8.5 以降、10.9(Mavericks)まで +
- 2 GB 以上のシステム メモリ(RAM)、4 GB 以上を推奨 +
- 400 MB の空き容量のあるハードディスク +
- Android SDK、エミュレータのシステム イメージ、キャッシュ用には少なくとも 1 GB 以上 +
- 1280 x 800 以上の画面解像度 +
- Java Runtime Environment (JRE) 6 +
- Java Development Kit (JDK) 7 +
- エミュレータ アクセラレータ向け(任意): Intel® VT-x、Intel® EM64T(Intel® 64)、Execute Disable(XD)ビット機能対応の Intel® プロセッサ + +
Mac OSで最適化されたフォントのレンダリングを使用するには、Android Studio を Java Runtime Environment (JRE) 6 と共に実行する必要があります。 +その後、Java Development Kit(JDK)6 または JDK 7 を使用するようプロジェクトを構成できます。
+ + + +Linux の場合
+ +-
+
- GNOME または KDE デスクトップ +
- GNU C Library (glibc) 2.15 以降 +
- 2 GB 以上のシステム メモリ(RAM)、4 GB 以上を推奨 +
- 400 MB の空き容量のあるハードディスク +
- Android SDK、エミュレータのシステム イメージ、キャッシュ用には少なくとも 1 GB 以上 +
- 1280 x 800 以上の画面解像度 +
- Oracle® Java Development Kit (JDK) 7 +
Ubuntu® 14.04、Trusty Tahr(32-bit 版アプリケーションを実行可能な 64-bit 版)でテスト済み。 +
+ + + + +他のダウンロード オプション
+ + diff --git a/docs/html-intl/intl/ja/sdk/installing/adding-packages.jd b/docs/html-intl/intl/ja/sdk/installing/adding-packages.jd new file mode 100644 index 0000000000000000000000000000000000000000..af5dcd0a49895ccb96c3d3626b951d65e157b653 --- /dev/null +++ b/docs/html-intl/intl/ja/sdk/installing/adding-packages.jd @@ -0,0 +1,227 @@ +page.title=SDK パッケージの追加 + +page.tags=sdk manager +helpoutsWidget=true + +@jd:body + + + + ++Android SDK では、デフォルトの状態で、開発の開始に必要なすべてのものが用意されているわけではありません。 +Android SDK では、ツール、プラットフォーム、その他のコンポーネントがパッケージに分けられており、Android SDK Manager を使って必要に応じてダウンロードできます。 + + +そのため、開始前に、Android SDK にいくつかのパッケージを追加する必要があります。
+ +パッケージの追加を開始するには、次のいずれかの方法で Android SDK Manager を起動します。
+-
+
- Android Studio で、ツールバーの [SDK Manager] をクリックします。 + +
- Android Studio を使用しない場合:
+
-
+
- Windows の場合: Android SDK のルート ディレクトリにある
SDK Manager.exe
ファイルをダブルクリックします。 +
+ - Mac または Linux の場合: ターミナルを開いて Android SDK がインストールされているロケーションの
tools/
ディレクトリに移動し、android sdk
を実行します。 +
+
+ - Windows の場合: Android SDK のルート ディレクトリにある
SDK Manager を初めて開く場合、いくつかのパッケージがデフォルトで選択されています。 +この選択はそのままにしますが、開始に必要なすべてのものが揃っているか、次の手順でご確認ください。 +
+ + +-
+
-
+
最新の SDK Tools を入手する
+ + + +Android SDK をセットアップする場合、少なくとも最新の SDK Tools と Android プラットフォームのダウンロードが必要です。 +
+-
+
- [Tools] ディレクトリを開き、以下のツールを選択します。
+
-
+
- Android SDK Tools +
- Android SDK Platform-tools +
- Android SDK Build-tools(最新バージョンのもの) +
+ - 1 番上の [Android X.X] フォルダ(最新バージョンのフォルダ)を開き、以下を選択します。
+
-
+
- SDK Platform +
- 「ARM EABI v7a System Image」などのエミュレータ用のシステム イメージ
+
+
+
+
+ - [Tools] ディレクトリを開き、以下のツールを選択します。
+
-
+
追加 API 用のサポート ライブラリを取得する
+ +++ +以下を使用するには、サポート ライブラリが必要です。
+-
+
- Android Wear +
- Android TV +
- Google Cast +
サポート ライブラリは、以下の人気の API も提供しています。
+-
+
- ナビゲーション ドロワー + +
- スワイプビュー +
- 下位互換のアクションバー + +
Android サポート ライブラリ は、大部分のバージョンの Android に対応する API の拡張セットを提供しています。 +
+ +[Extras] ディレクトリを開き、以下を選択します。
+-
+
- Android Support Repository +
- Android Support Library +
+
+
+ -
+
その他の API 用の Google Play サービスを入手する
+ ++ ++ +Google Play services API は、Android アプリのための次のようなバラエティに富んだ機能やサービスを提供しています。 +
+-
+
- ユーザー認証 +
- Google マップ +
- Google Cast +
- ゲームの実績とリーダーボード + +
- その他多数の機能 +
Google API を利用して開発を行うには、Google Play サービス パッケージが必要です。
+[Extras] ディレクトリを開き、以下を選択します。
+-
+
- Google Repository +
- Google Play サービス +
注: Google Play services API は、Android が搭載されたすべての端末で利用できるわけではありませんが、Google Play ストアを使用するとすべての端末で利用できます。 +これらの API を Android エミュレータで使用するには、SDK Manager の最新の [Android X.X] ディレクトリから Google API のシステム イメージもインストールする必要があります。 + +
+
+
+
+ -
+
パッケージをインストールする
+必要なパッケージをすべて選択したら、インストールを続行します。
+-
+
- [Install X packages] をクリックします。 +
- 次のウィンドウで、左側のパッケージ名を 1 つずつダブルクリックし、各パッケージの使用許諾契約に同意します。 + +
- [Install] をクリックします。 +
SDK Manager のウィンドウの 1 番下に、ダウンロードの進捗状況が表示されます。 + SDK Manager を終了しないでください。SDK Manager を終了すると、ダウンロードはキャンセルされます。
+
+
+ -
+
アプリを作成する
+ +Android SDK にインストールしたパッケージを使用して、アプリを作成できるようになりました。 +新しいツールとその他の API を入手できるようになった場合は、SDK Manager を起動して SDK に新しいパッケージをダウンロードしてください。 +
+ +必要に応じて以下を参考にしてください。
+ +++ + +++スタートガイド
+Android 開発が初めての場合は、Android アプリの基本を初めてのアプリ作成に関するガイドに従って学習してください。 +
+ +++ウェアラブル端末向けにアプリを作成する
+Android ウェアラブル端末向けにアプリを開発するには、「Android Wear アプリの作成」のガイドをご覧ください。 +
+ +++Google API を使用する
+マップや Play ゲーム サービスなどの Google API の使用を開始するには、「Setting Up Google Play Services」のガイドをご覧ください。 + + +
+ +
+
+
このレッスンでの学習内容
+-
+
- タッチ フィードバックをカスタマイズする +
- 出現エフェクトを使用する +
- アクティビティ遷移をカスタマイズする +
- ビューの状態遷移にアニメーションを付ける +
- ベクター型ドローアブルにアニメーションを付ける +
関連ドキュメント
+ +マテリアル デザインのアニメーションは、ユーザーの操作に応じて反応し、アプリの操作にともない連続した動きを見せます。 +マテリアル テーマでは、ボタンやアクティビティの遷移にデフォルトのアニメーションが用意されており、Android 5.0(API レベル 21)以降では次のようなアニメーションをカスタマイズして新しいアニメーションを作成できます。 + +
+ +-
+
- タッチ フィードバック +
- 円形状の出現 +
- アクティビティ遷移 +
- 曲線モーション +
- ビューの状態遷移 +
タッチ フィードバックをカスタマイズする
+ +マテリアル デザインのタッチ フィードバックは、ユーザーが UI 要素に触れて操作した時点で、視覚的な反応を瞬時に表します。 +ボタンに対するデフォルトのタッチ フィードバック アニメーションでは、新しい {@link android.graphics.drawable.RippleDrawable} クラスを使用して、状態の切り替わりをリップル(波紋)効果で表現しています。 + +
+ +ほとんどの場合、次のようにビューの背景を指定することでビュー XML にこの機能を適用できます。 +
+ +-
+
- 範囲が限定された波紋:
?android:attr/selectableItemBackground
。
+ - ビューの範囲外まで広がる波紋:
?android:attr/selectableItemBackgroundBorderless
。 +これは、背景が null ではない最も近くにある親ビュー上に表示されますが、その外側にはみ出ることはありません。 +
+
注: selectableItemBackgroundBorderless
は API レベル 21 で導入された新しい属性です。
+
または、ripple
要素を使って {@link android.graphics.drawable.RippleDrawable}
+を XML リソースとしても定義できます。
{@link android.graphics.drawable.RippleDrawable} オブジェクトには、色を割り当てることができます。タッチ フィードバックのデフォルトの色を変更するには、テーマの android:colorControlHighlight
+属性を使用します。
+
詳細については、API リファレンスの {@link +android.graphics.drawable.RippleDrawable} クラスをご覧ください。
+ + +出現エフェクトを使用する
+ +Reveal(出現)アニメーションを使用すると、UI 要素のグループを表示したり非表示にしたりするときに連続した印象をユーザーに与えます。 +{@link android.view.ViewAnimationUtils#createCircularReveal +ViewAnimationUtils.createCircularReveal()} メソッドでは、ビューを表示したり非表示にしたりする際に円形のアニメーションを付けることができます。 +
+ +この効果を使って、非表示のビューを表示するには:
+ ++// previously invisible view +View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the final radius for the clipping circle +int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); + +// create the animator for this view (the start radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); + +// make the view visible and start the animation +myView.setVisibility(View.VISIBLE); +anim.start(); ++ +
この効果を使って、表示されているビューを非表示にするには:
+ ++// previously visible view +final View myView = findViewById(R.id.my_view); + +// get the center for the clipping circle +int cx = (myView.getLeft() + myView.getRight()) / 2; +int cy = (myView.getTop() + myView.getBottom()) / 2; + +// get the initial radius for the clipping circle +int initialRadius = myView.getWidth(); + +// create the animation (the final radius is zero) +Animator anim = + ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); + +// make the view invisible when the animation is done +anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + myView.setVisibility(View.INVISIBLE); + } +}); + +// start the animation +anim.start(); ++ + +
アクティビティ遷移をカスタマイズする
+ + +マテリアル デザイン アプリの Activity transitions (アクティビティ遷移)では、共通する要素の間での動作や変化を通じて、状態の切り替えに視覚的なつながりを持たせます。 +Enter と Exit の遷移や、アクティビティ間での Shared elements 遷移にカスタム アニメーションを指定できます。 +
+ +-
+
- Enter(入口)遷移は、アクティビティのビューがどのように画面に入ってくるかを決定します。 +たとえば Explode の Enter 遷移の場合、ビューが画面外から画面の中心に向かって飛び込むように現れます。 + + +
- Exit 遷移は、アクティビティのビューがどのように画面から出ていくかを決定します。同じく Explode の Exit 遷移の場合、画面の中心から外側に向かってビューが出ていきます。 + + + +
- Shared Elements 遷移は、2 つのアクティビティで共有されているビューが、各アクティビティの間でどのように遷移するかを決定します。 +たとえば、2 つのアクティビティで同じ画像を異なる位置とサイズで使用している場合、changeImageTransform 共有要素の遷移によって、2 つのアクティビティの間でスムーズに画像が変換されスケーリングされます。 + + +
Android 5.0(API レベル 21)では、次の Enter 遷移と Exit 遷移がサポートされています。
+ +-
+
- explode (爆発状) - ビューをシーン中心から外側へ移動したり外側から中心へ移動したりします。 +
- slide (スライド) - ビューをシーンの端から移動したり端へ移動したりします。 +
- fade (フェード) - 不透明度を変化させながらビューをシーンに追加したりシーンから削除したりします。 +
{@link android.transition.Visibility} クラスを拡張する Transition はすべて、EnterTransition または ExitTransition としてサポートされます。 +詳細については、API リファレンスの +{@link android.transition.Transition} クラスをご覧ください。
+ +Android 5.0(API レベル 21)では、次の共有要素遷移もサポートしています。
+ +-
+
- changeBounds - 対象ビューのレイアウト範囲での変化にアニメーションを付けます。 +
- changeClipBounds - 対象ビューのクリップ範囲での変化にアニメーションを付けます。 +
- changeTransform - 対象ビューのスケールや向きの変化にアニメーションを付けます。 +
- changeImageTransform - 対象画像のサイズやスケールの変化にアニメーションを付けます。 +
アプリにアクティビティ遷移を適用すると、アクティビティの開始と終了の間でデフォルトのクロス フェーディング遷移が有効になります。 +
+ + + + +カスタム遷移を指定する
+ +まず、マテリアル テーマから継承したスタイルを定義するときに、android:windowContentTransitions
+ 属性で windowContentTransitions を有効にします。また、次のように Enter、Exit、Shared Element の Transitions をスタイルの定義で指定できます。
+
+<style name="BaseAppTheme" parent="android:Theme.Material"> + <!-- enable window content transitions --> + <item name="android:windowContentTransitions">true</item> + + <!-- specify enter and exit transitions --> + <item name="android:windowEnterTransition">@transition/explode</item> + <item name="android:windowExitTransition">@transition/explode</item> + + <!-- specify shared element transitions --> + <item name="android:windowSharedElementEnterTransition"> + @transition/change_image_transform</item> + <item name="android:windowSharedElementExitTransition"> + @transition/change_image_transform</item> +</style> ++ +
この例の change_image_transform
遷移は、次のように定義されています。
+<!-- res/transition/change_image_transform.xml --> +<!-- (see also Shared Transitions below) --> +<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> + <changeImageTransform/> +</transitionSet> ++ +
changeImageTransform
要素は
+{@link android.transition.ChangeImageTransform} クラスに対応します。詳細については、API リファレンスの {@link android.transition.Transition} をご覧ください。
+
代わりに、コードで windowContentTransitions を有効にするには、 +{@link android.view.Window#requestFeature Window.requestFeature()} メソッドを呼び出します。
+ ++// inside your activity (if you did not enable transitions in your theme) +getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + +// set an exit transition +getWindow().setExitTransition(new Explode()); ++ +
コードで遷移を指定するには、{@link +android.transition.Transition} オブジェクトで次のメソッドを呼び出します。
+ +-
+
- {@link android.view.Window#setEnterTransition Window.setEnterTransition()} +
- {@link android.view.Window#setExitTransition Window.setExitTransition()} +
- {@link android.view.Window#setSharedElementEnterTransition + Window.setSharedElementEnterTransition()} +
- {@link android.view.Window#setSharedElementExitTransition + Window.setSharedElementExitTransition()} +
{@link android.view.Window#setExitTransition setExitTransition()} と {@link +android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} メソッドは、呼び出し元のアクティビティの ExitTransition を定義します。 +{@link android.view.Window#setEnterTransition +setEnterTransition()} と {@link android.view.Window#setSharedElementEnterTransition +setSharedElementEnterTransition()} メソッドは、呼び出し先のアクティビティの EnterTransition を定義します。
+ +遷移の効果を完全に表すには、呼び出し元と呼び出し先のアクティビティ双方で windowContentTransitions を有効にする必要があります。 +有効にしていないと、呼び出し元のアクティビティが Exit 遷移を開始したあと、window 遷移(スケールやフェードなど)が起きます。 +
+ +Enter 遷移をできるだけ早く開始するには、呼び出し先のアクティビティで +{@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} + メソッドを使用します。これにより、さらに印象的な Enter 遷移になります。
+ +遷移を使ってアクティビティを開始する
+ +遷移を有効にしてアクティビティで ExitTransition を設定した場合、次のように別のアクティビティを開始したときに Exit 遷移がアクティベートされます。 +
+ ++startActivity(intent, + ActivityOptions.makeSceneTransitionAnimation(this).toBundle()); ++ +
2 つ目のアクティビティに EnterTransition を設定している場合は、そのアクティビティの開始時に Enter 遷移も発生します。
+別のアクティビティ開始時の遷移を無効にするには、null
のオプション バンドルを付与します。
+
共有要素を使ってアクティビティを開始する
+ +共有要素を持つ 2 つのアクティビティの間で画面遷移のアニメーションを作成するには:
+ +-
+
- テーマで windowContentTransitions を有効にします。 +
- スタイルで SharedElementsTransition を指定します。 +
- 遷移を XML リソースとして定義します。 +
-
+
android:transitionName
属性を用いて、双方のレイアウトで共有要素に同じ名前を割り当てます。
+ - {@link android.app.ActivityOptions#makeSceneTransitionAnimation +ActivityOptions.makeSceneTransitionAnimation()} メソッドを使用します。 +
+// get the element that receives the click event +final View imgContainerView = findViewById(R.id.img_container); + +// get the common element for the transition in this activity +final View androidRobotView = findViewById(R.id.image_small); + +// define a click listener +imgContainerView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(this, Activity2.class); + // create the transition animation - the images in the layouts + // of both activities are defined with android:transitionName="robot" + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(this, androidRobotView, "robot"); + // start the new activity + startActivity(intent, options.toBundle()); + } +}); ++ +
コードで生成した共有の動的ビューでは、 +{@link android.view.View#setTransitionName View.setTransitionName()} メソッドを使用して両方のアクティビティに共通の要素名を指定します。 +
+ +2 つ目のアクティビティが終了したときにシーンの切り替えアニメーションを逆回転させるには、{@link android.app.Activity#finish Activity.finish()} の代わりに +{@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} + メソッドを呼び出します。
+ +複数の共有要素を使ってアクティビティを開始する
+ +複数の共有要素を持つ 2 つのアクティビティの間にシーンの切り替えアニメーションを付けるには、双方のレイアウトで android:transitionName
+属性を使用(または双方のアクティビティで {@link android.view.View#setTransitionName View.setTransitionName()} メソッドを使用)して共有要素を定義して、次のように {@link android.app.ActivityOptions} オブジェクトを作成します。
+
+
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, + Pair.create(view1, "agreedName1"), + Pair.create(view2, "agreedName2")); ++ + +
曲線モーションを使用する
+ +マテリアル デザインのアニメーションは、時間的な間を補ったり立体的な動作パターンを表現するために曲線を多く用いています。 +Android 5.0(API レベル 21)以降では、カスタムのタイミングで描かれる曲線や曲線モーションのパターンをアニメーションで定義できます。 +
+ +{@link android.view.animation.PathInterpolator} クラスはベジェ曲線や {@link android.graphics.Path} オブジェクトに基づく新しい Interpolator(補間)です。 +この Interpolator は 1x1 の正方形に動作曲線を指定します。アンカー ポイントは(0,0)と(1,1)、制御点はコンストラクタ引数を使用して指定します。 + +または、PathInterpolator を XML リソースとしても定義できます。
+ ++<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:controlX1="0.4" + android:controlY1="0" + android:controlX2="1" + android:controlY2="1"/> ++ +
マテリアル デザインの仕様では、次の 3 つの基本的な曲線を XML リソースとして提供しています。 +
+ +-
+
@interpolator/fast_out_linear_in.xml
+ @interpolator/fast_out_slow_in.xml
+ @interpolator/linear_out_slow_in.xml
+
{@link android.view.animation.PathInterpolator} オブジェクトは {@link +android.animation.Animator#setInterpolator Animator.setInterpolator()} メソッドに渡すことができます。
+ +{@link android.animation.ObjectAnimator} クラスには新しいコンストラクタがあり、一度に 2 つ以上のプロパティを使用して経路に沿ったアニメーションを作ることができます。 +たとえば、次の animator では {@link android.graphics.Path} オブジェクトを使ってビューの X と Y プロパティを指定しています。 +
+ ++ObjectAnimator mAnimator; +mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); +... +mAnimator.start(); ++ + +
ビューの状態遷移にアニメーションを付ける
+ +{@link android.animation.StateListAnimator} クラスを使って、ビューの状態が変化したときに実行されるアニメーションを定義できます。 +次の例は、{@link +android.animation.StateListAnimator} を XML リソースとして定義する方法を示しています。
+ ++<!-- animate the translationZ property of a view when pressed --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="@android:integer/config_shortAnimTime" + android:valueTo="2dp" + android:valueType="floatType"/> + <!-- you could have other objectAnimator elements + here for "x" and "y", or other properties --> + </set> + </item> + <item android:state_enabled="true" + android:state_pressed="false" + android:state_focused="true"> + <set> + <objectAnimator android:propertyName="translationZ" + android:duration="100" + android:valueTo="0" + android:valueType="floatType"/> + </set> + </item> +</selector> ++ +
ビューの状態についてのカスタム アニメーションをビューに付与するには、この例のように XML リソース ファイルの
+selector
要素を使用して animator を定義し、それを android:stateListAnimator
属性でビューに割り当てます。
+コードで StateListAnimator をビューに割り当てるには、{@link android.animation.AnimatorInflater#loadStateListAnimator
+AnimationInflater.loadStateListAnimator()} メソッドを使用して
+{@link android.view.View#setStateListAnimator View.setStateListAnimator()} メソッドでビューに animator を割り当てます。
+
テーマがマテリアル テーマに拡張されると、ボタンにはデフォルトで Z アニメーションが設定されます。これを避けるためには、android:stateListAnimator
属性を
+@null
に設定します。
+
{@link android.graphics.drawable.AnimatedStateListDrawable} クラスを使用すると、関連するビューの状態遷移にアニメーションを表示するドローアブルを作成できます。 +Android 5.0 の一部のシステム ウィジェットでは、デフォルトでこれらのアニメーションを使用しています。 +次の例は、{@link android.graphics.drawable.AnimatedStateListDrawable} を XML リソースとして定義する方法を示しています。 +
+ ++<!-- res/drawable/myanimstatedrawable.xml --> +<animated-selector + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- provide a different drawable for each state--> + <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" + android:state_pressed="true"/> + <item android:id="@+id/focused" android:drawable="@drawable/drawableF" + android:state_focused="true"/> + <item android:id="@id/default" + android:drawable="@drawable/drawableD"/> + + <!-- specify a transition --> + <transition android:fromId="@+id/default" android:toId="@+id/pressed"> + <animation-list> + <item android:duration="15" android:drawable="@drawable/dt1"/> + <item android:duration="15" android:drawable="@drawable/dt2"/> + ... + </animation-list> + </transition> + ... +</animated-selector> ++ + +
ベクター型ドローアブルにアニメーションを付ける
+ +ベクター型ドローアブルは定義を失わずにスケールできます。 +{@link android.graphics.drawable.AnimatedVectorDrawable} +クラスを使うと、ベクター型ドローアブルのプロパティを指定してアニメーションを付けられます。
+ +通常は、次に示す 3 つの XML ファイルで AnimatedVectorDrawable を定義します。
+ +-
+
res/drawable/
の +<vector>
要素を持つ vectordrawable の xml ファイル
+res/drawable/
の +<animated-vector>
要素を持つ AnimatedVectorDrawable の xml ファイル
+res/anim/
の +<objectAnimator>
要素を持つ 1 つ以上の ObjectAnimator の xml ファイル
+
AnimatedVectorDrawable では、<group>
要素と
+<path>
要素の属性にアニメーションを付けることができます。<group>
要素は一連の経路やサブグループを定義し、<path>
要素は描く経路を定義します。
+
アニメーションを付けたいベクター型ドローアブルを定義するときは、android:name
+属性を使用してグループや経路に一意の名前を割り当てれば animator の定義からそれらを参照できるようになります。
+以下に例を示します。
+<!-- res/drawable/vectordrawable.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600"> + <group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:name="v" + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + </group> +</vector> ++ +
AnimatedVectorDrawable の定義では、次のようにベクター型ドローアブルのグループや経路をその名前で参照します。 +
+ ++<!-- res/drawable/animvectordrawable.xml --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vectordrawable" > + <target + android:name="rotationGroup" + android:animation="@anim/rotation" /> + <target + android:name="v" + android:animation="@anim/path_morph" /> +</animated-vector> ++ +
アニメーションの定義は {@link android.animation.ObjectAnimator} オブジェクトか {@link +android.animation.AnimatorSet} オブジェクトを示します。この例の最初の animator は、次のように対象グループを 360 度回転させています。 +
+ ++<!-- res/anim/rotation.xml --> +<objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360" /> ++ +
この例の 2 つ目の animator は、ベクター型ドローアブルの経路をある形から別の形へと変化させています。 +両方の経路が形の変化に対応できる必要があります。つまり同じ数のコマンドと、各コマンドで同じ数のパラメーターを保持している必要があります。 +
+ ++<!-- res/anim/path_morph.xml --> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="3000" + android:propertyName="pathData" + android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" + android:valueType="pathType" /> +</set> ++ +
詳細については、API リファレンスの {@link +android.graphics.drawable.AnimatedVectorDrawable} をご覧ください。
diff --git a/docs/html-intl/intl/ja/training/material/compatibility.jd b/docs/html-intl/intl/ja/training/material/compatibility.jd new file mode 100644 index 0000000000000000000000000000000000000000..0f8922fec4a306b27653cdf02af2f62265544b24 --- /dev/null +++ b/docs/html-intl/intl/ja/training/material/compatibility.jd @@ -0,0 +1,168 @@ +page.title=互換性の維持 + +@jd:body + +このレッスンでの学習内容
+ +関連ドキュメント
+ +マテリアル テーマやカスタムのアクティビティ遷移など、マテリアル デザインの一部の機能は Android5.0(API レベル21)以降のみで利用できます。 +ただし、マテリアル デザインをサポートし、以前のバージョンの Android を実行している端末と互換性がある端末でこれらの機能が実行されている場合は、機能を使用できるようにアプリを設計することが可能です。 + +
+ + +別のスタイルを定義する
+ +マテリアル テーマをサポートしている端末ではマテリアル テーマを使用するようにアプリを構成できますが、同時に次のようにして以前のバージョンの Android を実行する端末向けに以前のテーマに戻すことができます。 +
+ +-
+
-
+
res/values/styles.xml
で、以前のテーマ(Holo など)から継承するテーマを定義します。
+ -
+
res/values-v21/styles.xml
で、マテリアル テーマから継承するテーマを上記と同じ名前で定義します。
+ - マニフェスト ファイルでこのテーマをアプリのテーマとして設定します。 +
注: この方法で別のテーマを用意せずマテリアル テーマだけを使う場合、そのアプリは 5.0 よりも前のバージョンの Android では実行できません。 + + +
+ + +別のレイアウトを提供する
+ +マテリアル デザインのガイドラインに沿って設計したレイアウトでも、Android 5.0(API レベル 21)で導入された新しい XML 属性を一切使用していない場合は、以前のバージョンの Android でも問題なく表示されます。 + +新しい XML 属性を使用している場合は、別のレイアウトを用意できます。以前のバージョンの Android でアプリが表示される方法をカスタマイズする目的で別のレイアウトを用意することも可能です。 +
+ +Android 5.0(API レベル 21)向けのレイアウト ファイルを res/layout-v21/
に作成し、以前のバージョンの Android 向けの別のレイアウト ファイルを
+res/layout/
に作成します。
+たとえば、res/layout/my_activity.xml
は res/layout-v21/my_activity.xml
の代替レイアウトになります。
+
コードの重複を避けるには、res/values/
でスタイルを定義して res/values-v21/
で新しい API 用にスタイルを修正します。それからスタイル継承を用いて、基本スタイルを res/values/
で定義して、そのスタイルを res/values-v21/
で継承します。
+
+
サポート ライブラリを使用する
+ +v7 サポート ライブラリ r21 以降には、次のマテリアル デザイン機能が含まれています。 +
+ +-
+
Theme.AppCompat
テーマのいずれかを適用した場合の、システム ウィジェット用のマテリアル デザインのスタイル。 +
+Theme.AppCompat
テーマのカラーパレット テーマ属性。 +
+- データ コレクションを表示する {@link android.support.v7.widget.RecyclerView} ウィジェット。 + +
- カードを作成する {@link android.support.v7.widget.CardView} ウィジェット。 +
- 画像から代表色を抽出する {@link android.support.v7.graphics.Palette} クラス。 + +
システム ウィジェット
+ +Theme.AppCompat
テーマでは、次のウィジェット向けにマテリアル デザインのスタイルが提供されています。
-
+
- {@link android.widget.EditText} +
- {@link android.widget.Spinner} +
- {@link android.widget.CheckBox} +
- {@link android.widget.RadioButton} +
- {@link android.support.v7.widget.SwitchCompat} +
- {@link android.widget.CheckedTextView} +
カラーパレット
+ +Android v7 サポート ライブラリでマテリアル デザインのスタイルを入手し、カラーパレットをカスタマイズするには、次のように Theme.AppCompat
テーマのいずれかを適用します。
+
+<!-- extend one of the Theme.AppCompat themes --> +<style name="Theme.MyTheme" parent="Theme.AppCompat.Light"> + <!-- customize the color palette --> + <item name="colorPrimary">@color/material_blue_500</item> + <item name="colorPrimaryDark">@color/material_blue_700</item> + <item name="colorAccent">@color/material_green_A200</item> +</style> ++ +
リストとカード
+ +{@link android.support.v7.widget.RecyclerView} ウィジェットや {@link +android.support.v7.widget.CardView} ウィジェットは Android v7 サポート ライブラリを通じて以前のバージョンの Android でも使用できますが、次のような制限があります。 +
+-
+
- {@link android.support.v7.widget.CardView} は、付加的なパディングを使い、プログラムでシャドウを実装するものになります。 + +
- {@link android.support.v7.widget.CardView} によって、丸い角と交差する子ビューがクリップされることはありません。 + +
依存関係
+ +5.0(API レベル 21)より前のバージョンの Android でこれらの機能を使用するには、Android v7 サポート ライブラリを Gradle 依存関係としてプロジェクトに含めます。 +
+ ++dependencies { + compile 'com.android.support:appcompat-v7:21.0.+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} ++ + +
システム バージョンを確認する
+ +次の機能は、Android 5.0(API レベル 21)以降でのみ使用できます。
+ +-
+
- アクティビティ遷移 +
- タッチ フィードバック +
- 出現アニメーション +
- 経路ベースのアニメーション +
- ベクター型ドローアブル +
- ドローアブルによる着色 +
以前のバージョンの Android との互換性を維持するには、上記の機能に対する API を起動する前に、システム {@link +android.os.Build.VERSION#SDK_INT version} を実行時に確認します。 +
+ ++// Check if we're running on Android 5.0 or higher +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // Call some material design APIs here +} else { + // Implement this feature without material design +} ++ +
注: アプリがサポートする Android のバージョンを指定するには、マニフェスト ファイルで android:minSdkVersion
属性と android:targetSdkVersion
+属性を使用します。
+Android 5.0 でマテリアル デザインの機能を使用するには、android:targetSdkVersion
属性を 21
に設定します。
+詳細については、<uses-sdk> API ガイドをご覧ください。
+
+
このレッスンでの学習内容
+ +関連ドキュメント
+ +アプリにマテリアル デザインを実装する際は、Drawable (ドローアブル)の次の機能を活用できます。
+ +-
+
- ドローアブルによる着色 +
- 代表色の抽出 +
- ベクター型ドローアブル +
このレッスンでは、アプリでのこれらの機能を使用する方法について説明します。
+ + +ドローアブル リソースに色を付ける
+ +Android 5.0(API レベル 21)以降では、アルファ マスクとして定義されたビットマップや 9-patch に色を付けることができます。
+着色には、カラーリソースまたはカラーリソースに変換されるテーマ属性を使用できます(?android:attr/colorPrimary
など)。
+通常は、これらのアセットを一度作成するだけで、テーマに合うように自動的に着色されます。
+
{@code setTint()} メソッドを使用して {@link android.graphics.drawable.BitmapDrawable} オブジェクトか {@link
+android.graphics.drawable.NinePatchDrawable} オブジェクトに色を適用できます。また、android:tint
属性や
+android:tintMode
属性を使ってレイアウトで色やモードを設定できます。
+
画像から代表色を抽出する
+ +Android サポート ライブラリ r21 以降には、画像から代表色を抽出できる {@link +android.support.v7.graphics.Palette} クラスが含まれています。 +
+ +-
+
- Vibrant (鮮やか) +
- Vibrant dark (鮮やかな暗色) +
- Vibrant light (鮮やかな明色) +
- Muted (控えめ) +
- Muted dark (控えめな暗色) +
- Muted light (控えめな明色) +
これらの色を抽出するには、画像を読み込むバックグラウンド スレッドで {@link android.graphics.Bitmap} オブジェクトを +{@link android.support.v7.graphics.Palette#generate Palette.generate()} の静的メソッドに渡します。 +スレッドを使用できない場合は、代わりに +{@link android.support.v7.graphics.Palette#generateAsync Palette.generateAsync()} メソッドを呼び出してリスナーを提供します。 +
+ +
+Palette
クラスで、Palette.getVibrantColor
などの getter メソッドを使って画像から代表色を取得できます。
プロジェクトで {@link android.support.v7.graphics.Palette} クラスを使用するには、アプリのモジュールに次の +Gradle 依存関係を追加します。 +
+ ++dependencies { + ... + compile 'com.android.support:palette-v7:21.0.0' +} ++ +
詳細については、API リファレンスの {@link android.support.v7.graphics.Palette} クラスをご覧ください。 +
+ + +ベクター型ドローアブルを作成する
+ + + +ビデオ
+Android ベクター グラフィック
+Android 5.0(API レベル 21)以降では、ベクター型ドローアブルを定義できます。このドローアブルは定義を失わずに拡張できます。
+ビットマップ画像では画面密度ごとにアセット ファイルが必要ですが、ベクター画像で必要なアセット ファイルは 1 つのみです。
+ベクター画像を作成するには、<vector>
XML 要素で図形の詳細を定義します。
+
次の例では、ハート型のベクター画像を定義しています。
+ ++<!-- res/drawable/heart.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + <!-- intrinsic size of the drawable --> + android:height="256dp" + android:width="256dp" + <!-- size of the virtual canvas --> + android:viewportWidth="32" + android:viewportHeight="32"> + + <!-- draw a path --> + <path android:fillColor="#8fff" + android:pathData="M20.5,9.5 + c-1.955,0,-3.83,1.268,-4.5,3 + c-0.67,-1.732,-2.547,-3,-4.5,-3 + C8.957,9.5,7,11.432,7,14 + c0,3.53,3.793,6.257,9,11.5 + c5.207,-5.242,9,-7.97,9,-11.5 + C25,11.432,23.043,9.5,20.5,9.5z" /> +</vector> ++ +
Android ではベクター画像は {@link android.graphics.drawable.VectorDrawable}
+ オブジェクトとして表示されます。pathData
構文の詳細については、SVG パス リファレンスをご覧ください。ベクター型ドローアブルのアニメーションの詳細については、
+ベクター ドローアブルのアニメーションをご覧ください。
+
このレッスンでの学習内容
+ +関連ドキュメント
+ +マテリアル デザインでアプリを作成するには:
+ +-
+
- + マテリアル デザインの仕様を確認します。 +
- + マテリアル テーマをアプリに適用します。 +
- + マテリアル デザインのガイドラインに沿ってレイアウトを作成します。 +
- + ビューのエレベーションを設定してシャドウを付与します。 +
- + リストやカードにシステムウィジェットを使用します。 +
- + アプリでアニメーションをカスタマイズします。 +
下方互換性を維持する
+ +Android 5.0 より前のバージョンとの互換性を維持しながら、マテリアル デザインのさまざまな機能をアプリに追加できます。 +詳細については、 +互換性の維持をご覧ください。
+ +マテリアル デザインでアプリをアップデートする
+ +既存のアプリをアップデートしてマテリアル デザインを組み込むには、マテリアル デザインのガイドラインに沿ってレイアウトをアップデートします。 +深度、タッチ フィードバック、アニメーションを組み込んでいることも確認してください。 +
+ +マテリアル デザインで新しいアプリを作成する
+ +マテリアル デザインの機能を使って新しいアプリを作成すると、マテリアル デザインのガイドラインから凝縮したデザイン フレームワークが得られます。 +ガイドラインに従い、Android フレームワークの新しい機能を使ってアプリを設計、開発してください。 +
+ + +マテリアル テーマを適用する
+ +アプリでマテリアル テーマを適用するには、次のように
+android:Theme.Material
から継承したスタイルを指定します。
+<!-- res/values/styles.xml --> +<resources> + <!-- your theme inherits from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- theme customizations --> + </style> +</resources> ++ +
マテリアル テーマはアップデートされたシステム ウィジェットを提供しています。これにより、タッチ フィードバックやアクティビティ遷移のためのカラーパレットやデフォルトのアニメーションを指定できます。 +詳細については、 +マテリアル テーマの使用をご覧ください。
+ + +レイアウトを設計する
+ +マテリアル テーマを適用したり、カスタマイズしたりすることに加えて、レイアウトがマテリアル デザインのガイドラインに準拠している必要があります。 +レイアウトを設計するときは、次の項目に特に注意してください。 +
+ +-
+
- ベースライン グリッド +
- キーライン +
- 空白スペース +
- タッチ ターゲット サイズ +
- レイアウト構成 +
ビューでエレベーションを指定する
+ +ビューにはシャドウを付与できます。ビューのエレベーションの値によって、付与されるシャドウのサイズと表示される順序が決まります。
+ビューのエレベーションを設定するには、次のようにレイアウトの
+android:elevation
属性を使用します。
+<TextView + android:id="@+id/my_textview" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/next" + android:background="@color/white" + android:elevation="5dp" /> ++ +
新しい translationZ
プロパティを使用すると、ビューのエレベーションの一時的な変更が反映されるアニメーションを作成できます。
+エレベーションの変更は、
+タッチ操作に応答するときに便利です。
+
詳細については、シャドウとクリッピング ビューの定義をご覧ください。 +
+ + +リストとカードを作成する
+ +{@link android.support.v7.widget.RecyclerView} は {@link +android.widget.ListView} のさらに柔軟なバージョンで、異なるレイアウト タイプをサポートしてパフォーマンスを向上します。 +{@link android.support.v7.widget.CardView} を使用すると、あらゆるアプリで一貫した外観でカードの中に情報を表示できます。 +次のコードは、レイアウトに +{@link android.support.v7.widget.CardView} を含める方法の一例です。
+ ++<android.support.v7.widget.CardView + android:id="@+id/card_view" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="3dp"> + ... +</android.support.v7.widget.CardView> ++ +
詳細については、リストとカードの作成をご覧ください。 +
+ + +アニメーションをカスタマイズする
+ +Android 5.0(API レベル 21)には、アプリでカスタム アニメーションを作成する新たな API が含まれています。 +たとえば次のように、アクティビティ遷移を有効にしてアクティビティ内部で ExitTransition を定義できます。 +
+ ++public class MyActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // enable transitions + getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); + setContentView(R.layout.activity_my); + } + + public void onSomeButtonClicked(View view) { + getWindow().setExitTransition(new Explode()); + Intent intent = new Intent(this, MyOtherActivity.class); + startActivity(intent, + ActivityOptions + .makeSceneTransitionAnimation(this).toBundle()); + } +} ++ +
このアクティビティから別のアクティビティを開始するときに Exit 遷移がアクティベートされます。
+ +新しいアニメーション API の詳細については、カスタム アニメーションの定義をご覧ください。
diff --git a/docs/html-intl/intl/ja/training/material/index.jd b/docs/html-intl/intl/ja/training/material/index.jd new file mode 100644 index 0000000000000000000000000000000000000000..9f6d18701417209cd731402ef426671c52b3d9b7 --- /dev/null +++ b/docs/html-intl/intl/ja/training/material/index.jd @@ -0,0 +1,61 @@ +page.title=デベロッパーのためのマテリアル デザイン +page.type=デザイン +page.image=images/cards/material_2x.png +page.metaDescription=アプリにマテリアル デザインを適用する方法を学習する + + +@jd:body + +必要な知識と前提条件
+-
+
- Android 5.0(API レベル 21) +
マテリアル デザインは、複数のプラットフォームや端末の視覚、モーション、インタラクション デザインの包括的な指針です。 +Android アプリでマテリアル デザインを使うには、 +マテリアル デザインの仕様で説明されているガイドラインに従い、Android 5.0(API レベル 21)の新しいコンポーネントや機能を使用します。 + + +
+ +ここでは、次の要素を用いてマテリアル デザイン アプリを作成する方法について説明します。
+ +-
+
- マテリアル テーマ +
- カードやリストのウィジェット +
- カスタム シャドウとビューのクリッピング +
- ベクター型ドローアブル +
- カスタム アニメーション +
さらに、アプリでマテリアル デザインの機能を使うときに Android 5.0(API レベル 21)より前のバージョンとの互換性を維持する方法についても説明します。 +
+ +レッスン
+ +-
+
- スタートガイド +
- マテリアル デザインの機能でアプリを更新する方法について学習します。 + +
- マテリアル テーマの使用 +
- マテリアル デザインのスタイルをアプリに適用する方法について学習します。 + +
- リストとカードの作成 +
- システム ウィジェットを使って、一貫した外観や使用感のリストやカードを作成する方法について学習します。 + +
- シャドウとクリッピング ビューの定義 +
- ビューのエレベーションを設定してカスタム シャドウを作成する方法やビューをクリップする方法について学習します。 + +
- ドローアブルの使用 +
- ベクター型ドローアブルを作成する方法やドローアブル リソースに色を付ける方法について学習します。 + +
- カスタム アニメーションの定義 +
- ビューのカスタム アニメーションや共有要素とアクティビティ遷移を作成する方法について学習します。 + +
- 互換性の維持 +
- Android 5.0 より前のバージョンのプラットフォームとの互換性を維持する方法について学習します。 +
このレッスンでの学習内容
+ +関連ドキュメント
+ +マテリアル デザインのスタイルを適用した複雑なリストやカードをアプリで作成するには、 +{@link android.support.v7.widget.RecyclerView} ウィジェットや {@link android.support.v7.widget.CardView} + ウィジェットを使用します。
+ + +リストを作成する
+ +{@link android.support.v7.widget.RecyclerView} ウィジェットは、{@link android.widget.ListView} をさらに進化させて柔軟にしたものです。 +このウィジェットは、大きなデータセットを表示するためのコンテナであり、限られたビューを維持することで非常に効率的にスクロールできます。 +ユーザーのアクションやネットワークのイベントに基づいて、実行時に要素が変わるデータ コレクションを持つ場合には、 +{@link android.support.v7.widget.RecyclerView} ウィジェットを使用してください。 +
+ +{@link android.support.v7.widget.RecyclerView} クラスは次の機能を提供することで、簡単に大きなデータセットを表示したり処理したりできます。 +
+ +-
+
- アイテムの位置調整を行うレイアウト マネージャー +
- アイテムの削除や追加のような一般的な操作のデフォルト アニメーション +
また、{@link +android.support.v7.widget.RecyclerView} ウィジェットのカスタム レイアウト マネージャーやアニメーションも柔軟に定義できます。
+ + + + +{@link android.support.v7.widget.RecyclerView} ウィジェットを使用するには、アダプターとレイアウト マネージャーを指定する必要があります。 +アダプターを作成するには、{@link +android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter} クラスを拡張します。具体的な実装方法は、データセットの詳細やビューの種類によって異なります。 +詳細については、下記の例をご覧ください。 +
+ +レイアウト マネージャーは、{@link +android.support.v7.widget.RecyclerView} 内でアイテムビューを位置付けし、ユーザーから見えなくなったアイテムビューを再利用するタイミングを決定します。 +ビューを再利用(またはリサイクル)するために、レイアウト マネージャーからアダプターにデータセットの異なる要素でビューの内容を入れ替えるよう求められることがあります。 +このようにビューをリサイクルすることで、不要なビューを作成したりコストのかかる {@link android.app.Activity#findViewById findViewById()} のルックアップをしたりせずに済み、パフォーマンスが向上します。 + +
+ +{@link android.support.v7.widget.RecyclerView} には、次のレイアウト マネージャーが組み込まれています。
+ +-
+
- {@link android.support.v7.widget.LinearLayoutManager} は、アイテムを縦方向か横方向のスクロール リストに表示します。 + +
- {@link android.support.v7.widget.GridLayoutManager} は、アイテムをグリッドに表示します。 +
- {@link android.support.v7.widget.StaggeredGridLayoutManager} は、アイテムをスタッガード グリッドに表示します。 +
カスタム レイアウト マネージャーを作成するには、{@link +android.support.v7.widget.RecyclerView.LayoutManager RecyclerView.LayoutManager} クラスを拡張します。
+ +アニメーション
+ +{@link +android.support.v7.widget.RecyclerView} では、アイテムの追加や削除のアニメーションがデフォルトで有効になっています。これらのアニメーションをカスタマイズするには、 +{@link android.support.v7.widget.RecyclerView.ItemAnimator RecyclerView.ItemAnimator} クラスを拡張し、{@link android.support.v7.widget.RecyclerView#setItemAnimator RecyclerView.setItemAnimator()} + メソッドを使用します。 +
+ +例
+ +次のコードは、レイアウトに +{@link android.support.v7.widget.RecyclerView} を追加する方法の一例です。
+ ++<!-- A RecyclerView with some commonly used attributes --> +<android.support.v7.widget.RecyclerView + android:id="@+id/my_recycler_view" + android:scrollbars="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"/> ++ +
レイアウトに {@link android.support.v7.widget.RecyclerView} ウィジェットを追加したら、オブジェクトのハンドルを取得してレイアウト マネージャーに接続し、表示するデータのアダプターを添付します。 + +
+ ++public class MyActivity extends Activity { + private RecyclerView mRecyclerView; + private RecyclerView.Adapter mAdapter; + private RecyclerView.LayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.my_activity); + mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); + + // use this setting to improve performance if you know that changes + // in content do not change the layout size of the RecyclerView + mRecyclerView.setHasFixedSize(true); + + // use a linear layout manager + mLayoutManager = new LinearLayoutManager(this); + mRecyclerView.setLayoutManager(mLayoutManager); + + // specify an adapter (see also next example) + mAdapter = new MyAdapter(myDataset); + mRecyclerView.setAdapter(mAdapter); + } + ... +} ++ +
アダプターによって、データセット内の各項目にアクセスしたり、アイテムのビューを作成したり、元のアイテムが見えなくなったときにビューのコンテンツの一部を新しいデータアイテムと入れ替えたりできます。 + +次のコードはデータセットを実装する簡易な例です。このデータセットは、{@link android.widget.TextView} ウィジェットを使用して表示した文字列の配列で構成されています。 +
+ ++public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { + private String[] mDataset; + + // Provide a reference to the views for each data item + // Complex data items may need more than one view per item, and + // you provide access to all the views for a data item in a view holder + public static class ViewHolder extends RecyclerView.ViewHolder { + // each data item is just a string in this case + public TextView mTextView; + public ViewHolder(TextView v) { + super(v); + mTextView = v; + } + } + + // Provide a suitable constructor (depends on the kind of dataset) + public MyAdapter(String[] myDataset) { + mDataset = myDataset; + } + + // Create new views (invoked by the layout manager) + @Override + public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + // create a new view + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.my_text_view, parent, false); + // set the view's size, margins, paddings and layout parameters + ... + ViewHolder vh = new ViewHolder(v); + return vh; + } + + // Replace the contents of a view (invoked by the layout manager) + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + // - get element from your dataset at this position + // - replace the contents of the view with that element + holder.mTextView.setText(mDataset[position]); + + } + + // Return the size of your dataset (invoked by the layout manager) + @Override + public int getItemCount() { + return mDataset.length; + } +} ++ + +
カードを作成する
+ +{@link android.support.v7.widget.CardView} は {@link android.widget.FrameLayout} クラスを拡張して、あらゆるプラットフォームで統一された外観のカード内に情報を表示できます。 +{@link +android.support.v7.widget.CardView} ウィジェットは、シャドウを付けたり角を丸くしたりできます。
+ +シャドウ付きのカードを作成するには、card_view:cardElevation
属性を使用します。
+{@link android.support.v7.widget.CardView} は Android 5.0(API レベル 21)以降ではリアルなエレベーションや動きのあるシャドウを使用し、それより前のバージョンではプログラム的なシャドウを使用します。
+
+詳細については、互換性の維持をご覧ください。
+
+{@link android.support.v7.widget.CardView} ウィジェットの外観をカスタマイズするには、次のプロパティを使用します。
+ +-
+
- レイアウトで角の丸みを設定するには、
card_view:cardCornerRadius
属性を使用します。 +
+ - コードで角の丸みを設定するには、
CardView.setRadius
メソッドを使用します。
+ - カードの背景色を設定するには、
card_view:cardBackgroundColor
属性を使用します。 +
+
次のコードは、レイアウトに {@link android.support.v7.widget.CardView} + ウィジェットを含める方法の一例です。
+ ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:card_view="http://schemas.android.com/apk/res-auto" + ... > + <!-- A CardView that contains a TextView --> + <android.support.v7.widget.CardView + xmlns:card_view="http://schemas.android.com/apk/res-auto" + android:id="@+id/card_view" + android:layout_gravity="center" + android:layout_width="200dp" + android:layout_height="200dp" + card_view:cardCornerRadius="4dp"> + + <TextView + android:id="@+id/info_text" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </android.support.v7.widget.CardView> +</LinearLayout> ++ +
詳細については、API リファレンスの {@link android.support.v7.widget.CardView} をご覧ください。
+ + +依存関係を追加する
+ +{@link android.support.v7.widget.RecyclerView} ウィジェットと {@link android.support.v7.widget.CardView} ウィジェットは、v7 サポート ライブラリの一部です。 + +プロジェクトでこれらのウィジェットを使うには、次のようにアプリのモジュールに +Gradle 依存関係を追加します。 +
+ ++dependencies { + ... + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' +} +diff --git a/docs/html-intl/intl/ja/training/material/shadows-clipping.jd b/docs/html-intl/intl/ja/training/material/shadows-clipping.jd new file mode 100644 index 0000000000000000000000000000000000000000..981a4d1c872a04e6241d649584a2e1aaaa79bfcf --- /dev/null +++ b/docs/html-intl/intl/ja/training/material/shadows-clipping.jd @@ -0,0 +1,133 @@ +page.title=シャドウとクリッピング ビューの定義 + +@jd:body + +
このレッスンでの学習内容
+ +関連ドキュメント
+ +マテリアル デザインでは、UI 要素に Elevation(エレベーション、高度)を導入しています。エレベーションによって、ユーザーは 1 つの要素が他の要素と比べて重要であることを理解でき、目前の作業に集中できるようになります。 +
+ +ビューのエレベーションは Z プロパティで表され、シャドウビューの見た目を決定します。Z 値が高くなればシャドウも大きく、滑らかになります。 +Z 値が高いビューは Z 値が低いビューを覆い隠しますが、Z 値がビューのサイズに影響することはありません。 +
+ +シャドウは、エレベーションが設定された親ビューによって描かれ、標準的なビュー クリッピングの対象になります。デフォルトでは親ビューによってクリップされます。 +
+ +エレベーションは、何らかのアクションでビューの平面上にウィジェットが浮き上がるようなアニメーションを作成する際にも役立ちます。 +
+ +マテリアル デザインのエレベーションの詳細については、 +3D スペースのオブジェクトをご覧ください。 +
+ + +ビューにエレベーションを割り当てる
+ +ビューの Z 値には次の 2 つのコンポーネントがあります。 + +
-
+
- Elevation (エレベーション): 静的なコンポーネントです。 +
- Translation (トランスレーション): アニメーションに使われる動的なコンポーネントです。 +
Z = elevation + translationZ
レイアウトの定義でビューのエレベーションを設定するには、android:elevation
+ 属性を使用します。アクティビティのコードでビューのエレベーションを設定するには、
+{@link android.view.View#setElevation View.setElevation()} メソッドを使用します。
ビューのトランスレーションを設定するには、{@link android.view.View#setTranslationZ +View.setTranslationZ()} メソッドを使用します。
+ +新しい {@link android.view.ViewPropertyAnimator#z ViewPropertyAnimator.z()} メソッドや {@link +android.view.ViewPropertyAnimator#translationZ ViewPropertyAnimator.translationZ()} メソッドを使用すると、ビューのエレベーションに簡単にアニメーションを付けられます。 +詳細については、API リファレンスの +{@link android.view.ViewPropertyAnimator} と、デベロッパー ガイドのプロパティ アニメーションをご覧ください。 +
+ +また、{@link android.animation.StateListAnimator} を使用してアニメーションを宣言的に指定することも可能です。 +これは、ユーザーがボタンを押したときなど、状態の変化によってアニメーションを動作する場合に特に役立ちます。 +詳細については、 +ビューの状態遷移にアニメーションを付けるをご覧ください。
+ +Z 値は dp(密度非依存ピクセル)で測られます。
+ + +ビューシャドウとアウトラインをカスタマイズする
+ +ビュー背景のドローアブルの範囲によってシャドウのデフォルトの形状が決まります。 +Outlines はグラフィック オブジェクトの外形を表し、タッチ フィードバックのリップル(波紋)の領域を定義します。 +
+ +背景ドローアブルで定義されたビューについて考えてみます。
+ ++<TextView + android:id="@+id/myview" + ... + android:elevation="2dp" + android:background="@drawable/myrect" /> ++ +
背景ドローアブルが角が丸い長方形として定義されます。
+ ++<!-- res/drawable/myrect.xml --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#42000000" /> + <corners android:radius="5dp" /> +</shape> ++ +
背景ドローアブルによってビューの外形が定義されるため、このビューは角が丸いシャドウを付与します。 +カスタム アウトラインを使えば、ビューシャドウのデフォルトの形状を更新できます。
+ +コードでビューのカスタム アウトラインを定義するには:
+ +
-
+
- {@link android.view.ViewOutlineProvider} クラスを拡張します。 +
- {@link android.view.ViewOutlineProvider#getOutline getOutline()} メソッドを上書きします。 +
- {@link +android.view.View#setOutlineProvider View.setOutlineProvider()} メソッドで、ビューに新しい OutlineProvider を割り当てます。 +
+{@link android.graphics.Outline} クラスのメソッドを使用して、楕円形や角が丸い長方形のアウトラインを作成できます。ビューのデフォルトの OutlineProvider は、ビューの背景から外形を決定します。
+ビューがシャドウを付与しないようにするには、OutlineProvider を null
に設定します。
+
ビューをクリップする
+ +ビューをクリップすると、ビューの形を簡単に変更できます。ビューをクリップすることで、他のデザイン要素との統一性を保ったり、ユーザーのインプットに応じてビューの形を変えたりできます。
+
+{@link android.view.View#setClipToOutline
+View.setClipToOutline()} メソッドか android:clipToOutline
属性を使用すると、ビューをそのアウトラインの範囲にクリップできます。
+{@link android.graphics.Outline#canClip Outline.canClip()} メソッドで指定されているように、クリップがサポートされるのは長方形、円形、角が丸い長方形のみです。
+
上述のように、ドローアブルの範囲でビューをクリップするには、ドローアブルをビューの背景として設定し、{@link android.view.View#setClipToOutline View.setClipToOutline()} +メソッドを呼び出します。 +
+ +ビューのクリップは負荷の高い操作であるため、ビューのクリップに使用する形状にはアニメーションを付けないでください。 +この効果を発揮させるには、出現エフェクトアニメーションを使用します。
diff --git a/docs/html-intl/intl/ja/training/material/theme.jd b/docs/html-intl/intl/ja/training/material/theme.jd new file mode 100644 index 0000000000000000000000000000000000000000..43e5c6c995d6631cdc3ff97da15aa7f86e7dc838 --- /dev/null +++ b/docs/html-intl/intl/ja/training/material/theme.jd @@ -0,0 +1,131 @@ +page.title=マテリアル テーマの使用 + +@jd:body + +このレッスンでの学習内容
+ +関連ドキュメント
+ +新しいマテリアル テーマでは、次のものが提供されます。
+ +-
+
- カラーパレットを設定できるシステム ウィジェット +
- システム ウィジェットのタッチ フィードバック アニメーション +
- アクティビティ遷移アニメーション +
マテリアル テーマの外観は、ブランド イメージにあわせて自分のカラーパレットでカスタマイズできます。 +図 3 のように、アクションバーやステータスバーにテーマ属性で色を付けることができます。 +
+ +システム ウィジェットには、新しいデザインやタッチ フィードバックがあります。カラーパレット、タッチ フィードバック、アクティビティ遷移は、自分のアプリ向けにカスタマイズできます。 +
+ +マテリアル テーマは次のように定義されます。
+ +-
+
@android:style/Theme.Material
(暗色バージョン)
+ @android:style/Theme.Material.Light
(明色バージョン)
+ @android:style/Theme.Material.Light.DarkActionBar
+
使用できるマテリアル スタイルのリストについては、API リファレンスの +{@link android.R.style R.style} をご覧ください。
+ + +図 1 暗い色のマテリアル テーマ
+図 2 明るい色のマテリアル テーマ
++
+注: マテリアル テーマは、Android 5.0(API レベル 21)以降でのみ使用できます。 +v7 サポート ライブラリは、一部のウィジェットに対してマテリアル デザイン スタイルでテーマを提供し、カラーパレットのカスタマイズをサポートしています。 + +詳細については、 +互換性の維持をご覧ください。 +
+ + +カラーパレットをカスタマイズする
+ +ブランド イメージに合うようにテーマの基本色をカスタマイズするには、次の例に示すようにマテリアル テーマから継承する場合、テーマ属性を使ってカスタムカラーを定義します。 +
+ ++<resources> + <!-- inherit from the material theme --> + <style name="AppTheme" parent="android:Theme.Material"> + <!-- Main theme colors --> + <!-- your app branding color for the app bar --> + <item name="android:colorPrimary">@color/primary</item> + <!-- darker variant for the status bar and contextual app bars --> + <item name="android:colorPrimaryDark">@color/primary_dark</item> + <!-- theme UI controls like checkboxes and text fields --> + <item name="android:colorAccent">@color/accent</item> + </style> +</resources> ++ +
ステータスバーをカスタマイズする
+ +マテリアル テーマを使うと、ステータスバーを簡単にカスタマイズできます。ブランド イメージに合わせて、またコントラストで白色のステータス アイコンを際立たせて色を設定できます。
+ステータスバーのカスタムカラーを設定するには、マテリアル テーマを拡張するときに android:statusBarColor
属性を使用します。
+
+デフォルトでは android:statusBarColor
は android:colorPrimaryDark
の値を継承します。
+
また、ステータスバーの背景を描くこともできます。たとえば、白色のステータス アイコンが見にくくならないように薄い暗色のグラデーションを付けて、ステータスバーを写真の上に透過的に表示したい場合、
+
+android:statusBarColor
属性に
+@android:color/transparent
を指定してウィンドウ フラグを必要に応じて調整します。アニメーションやフェードには、{@link android.view.Window#setStatusBarColor Window.setStatusBarColor()} メソッドも使用できます。
+
+
+注: ステータスバーはメインのツールバーと明確に分かれている必要があります。ただし、背景に画面の端から端まで表示される鮮やかな画像やメディア コンテンツを使用したり、アイコンが見にくくならないようにグラデーションを使用する場合は例外です。 + + +
+ +ナビケーションとステータスバーをカスタマイズするときは、どちらも透過的にするか、ステータスバーだけを変更します。 +その他のケースではナビゲーション バーは黒色のままにする必要があります。
+ + +テーマ個別のビュー + +
XML レイアウト定義の各要素では、テーマのリソースを参照する android:theme
属性を指定できます。
+この属性は、要素や子要素のテーマを変更し、インターフェースの一定の割合を占めるテーマ カラーパレットを変更する場合に役立ちます。
+
+
이러한 디자인 원칙은 사용자의 이익을 가장 염두에 두고 Android -사용자 환경 팀(User Experience Team)에 의해서와 이 팀을 위해 개발되었습니다. Android 개발자 및 디자이너를 +
이 디자인 원칙은 사용자의 이익을 가장 염두에 두고 Android +사용자 환경 팀(User Experience Team)에 의해 이 팀을 위해 개발되었습니다. Android 개발자 및 디자이너를 위해 Android 사용자 환경 팀은 계속해서 여러 유형의 기기를 위한 상세한 디자인 가이드라인의 기저를 이루고 있습니다.
@@ -14,8 +14,8 @@ page.title=Android 디자인 원칙황홀하게 만들기
-놀라운 방식으로 기쁨을 주기
아름다운 표면, 신중하게 위치한 애니메이션 또는 시간적으로 잘 짜여진 소리 효과는 사람들에게 즐거운 @@ -23,7 +23,7 @@ page.title=Android 디자인 원칙 힘을 가지고 있다고 느끼게 해줍니다.
버튼 및 메뉴보다 더 흥미로운 실제 사물
사람들이 직접 앱 내 사물을 터치하고 조작할 수 있게 해보세요. 이는 태스크를 수행할 때 필요한 인지 노력을 줄이는 동시에 정서적인 만족을 가져다 줍니다.
내 것으로 만들게 하기
사람들은 개인적인 취향을 더하고 싶어 하는데, 그렇게 하면 마음이 편안해지고 통제할 수 있다고 느끼게 되기 때문입니다. 합리적이고 @@ -58,7 +58,7 @@ page.title=Android 디자인 원칙 주요 태스크를 저해하지 않는 범위에서 재미있고, 선택 가능한 맞춤 기능을 제공할 것을 고려해 보십시오.
사용자에 대해 파악하기
시간이 지남에 따라 사람들이 선호하는 것을 알아보세요. 똑같은 선택을 매번 하도록 요구하기 보다는 이전 선택을 쉽게 접근할 수 있는 곳에 둡니다.
사용자의 생활을 단순하게 만들기
-간결하게 만들기
간단한 단어로 이루어진 짧은 문구를 사용하세요. 문장이 길면 사람들이 보지 않고 넘길 가능성이 커집니다.