Servicios de la plataforma Android Sesión 1: Librerías de compatibilidad y servicios 2012-2013 Depto. Ciencia de la Computación e IA
Puntos a tratar Compatibilidad de versiones Fragmentos Loaders Librería de compatibilidad Librería de servicios de Google Play 2
Compatibilidad de versiones A mayor versión utilizada por nuestras aplicaciones Mayores funcionalidades y facilidades Menor compatibilidad Se especifican dos versiones <uses- sdk android:minsdkversion="4" android:targetsdkversion="17" /> Podemos utilizar de forma opcional funcionalidades avanzadas if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Utilizar características de Android 3.0 (Honeycomb) Algunas características no pueden ser utilizadas opcionalmente Por ejemplo los fragmentos 3
Fragmentos Característica introducida en Android 3.0 (Honeycomb) Orientada a la introducción de tablets Forma recomendada de estructurar la interfaz Nos permiten construir la interfaz de forma modular Una actividad puede mostrar varios fragmentos Según el tipo de dispositivo se puede variar la disposición 4
Creación de fragmentos Se crean heredando de Fragment Debemos definir el método oncreateview donde contruimos la interfaz Normalmente la construimos a partir de un layout XML public class DetalleFragment extends Fragment { @Override public View oncreateview(layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { return inflater.inflate(r.layout.fragmento, container, false); No es una actividad, pero puede que necesitemos tener acceso a la actividad contenedora Button boton = (Button)getActivity().findViewById(R.id.boton); Existen fragmentos especializados ListFragment, DialogFragment, PreferencesFragment 5
Ciclo de vida de los fragmentos 6
Añadir el fragmento a la actividad Los fragmentos siempre deben estar dentro de una actividad Existen dos formas de añadirlos: Estática Se añaden en el layout XML No pueden ser modificados en tiempo de ejecución Varios fragmentos al mismo tiempo en pantalla (tablets) Dinámica Se añaden desde el código de la actividad Podemos hacer transiciones entre fragmentos Útil para dispositivos en los que no se pueden mostrar todos en la misma pantalla 7
Fragments estáticos Se definen en el layout XML de la actividad <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="es.ua.jtech.fragments.principalfragment" android:id="@+id/principal_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="es.ua.jtech.fragments.detallefragment" android:id="@+id/detalle_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout> 8
Fragments dinámicos Definimos en el layout de la actividad un marco vacío Si el marco existe, añadimos el fragmento al crear la actividad Si venimos de una instancia anterior no hace falta volver a construir <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" /> public class MainActivity extends Activity { public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.news_articles); if (findviewbyid(r.id.fragment_container)!= null) { if (savedinstancestate!= null) { return; PrincipalFragment ppalfragment = new PrincipalFragment(); ppalfragment.setarguments(getintent().getextras()); getfragmentmanager().begintransaction().add(r.id.fragment_container, ppalfragment).commit(); Comprobamos si existe el contenedor Mostramos el fragmento con FragmentManager 9
Transiciones entre fragmentos En caso de haber añadido el fragmento de forma dinámica, podemos hacer transiciones a otro fragmento DetalleFragment detallefragment = new DetalleFragment(); // Pasamos parametros al nuevo fragmento Bundle args = new Bundle(); args.putint(param_posicion, posicionseleccionada); detallefragment.setarguments(args); FragmentTransaction transaction = getfragmentmanager().begintransaction(); transaction.replace(r.id.fragment_container, detallefragment); transaction.addtobackstack(null); transaction.commit(); 10
Comunicación entre fragmentos Siempre se hará a través de la actividad contenedora Definimos un callback en uno de los fragmentos public class PrincipalFragment extends ListFragment { OnItemSelectedListener mcallback; public interface OnItemSelectedListener { public void onitemselected(int position); @Override public void onattach(activity activity) { super.onattach(activity); try { mcallback = (OnItemSelectedListener) activity; catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " debe implementar OnItemSelectedListener");... La actividad debe implementar esta interfaz Comprueba que la actividad implemente la interfaz 11
Gestión de la comunicación En la actividad implementamos la comunicación en el listener public static class MainActivity extends Activity implements PrincipalFragment.OnItemSelectedListener {... public void onitemselected(int position) { DetalleFragment detallefragment = (DetalleFragment) getfragmentmanager().findfragmentbyid(r.id.detalle_fragment); Comprobamos si el fragmento está en pantalla if (detallefragment!= null) { detallefragment.setdetalleitem(position); else { detallefragment = new DetalleFragment(); Bundle args = new Bundle(); args.putint(param_posicion, position); detallefragment.setarguments(args); Tipo estático Tipo dinámico FragmentTransaction transaction = getfragmentmanager().begintransaction(); transaction.replace(r.id.fragment_container, detallefragment); transaction.addtobackstack(null); transaction.commit(); 12
Creación de diálogos La forma recomendada de crear diálogos es con fragmentos Se crean mediante fragmentos de tipo DialogFragment Se puede especificar el título de la ventana del diálogo public View oncreateview(layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { View view = inflater.inflate(r.layout.dialog, container); getdialog().settitle("título"); return view; Tiene un método show para mostrarlos FragmentManager manager = getfragmentmanager(); MiDialogFragment dialog = new MiDialogFragment(); dialog.setarguments(bundle); dialog.show(manager, "fragment_dialog"); 13
Loaders Se trata de otra característica introducida en Android 3.0 Gestiona la carga de datos por parte de actividades/fragmentos Normalmente carga datos de proveedores de contenidos o servicios web Inicia el proceso de carga si no está ya en marcha Si detecta un cambio en los datos, los vuelve a recuperar Lo iniciamos normalmente en oncreate getloadermanager().initloader(0, null, this); También podemos solicitar reiniciar la carga getloadermanager().restartloader(0, null, this); Nuestra clase debe implementar LoaderManager.LoaderCallbacks para gestionar los datos proporcionados por el loader 14
Métodos a definir en el callback Al implementar el callback se debe especificar el tipo de datos a utilizar Utilizamos genéricos Los métodos que debemos definir son los siguientes public class MiListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Tipo> {... public Loader<Tipo> oncreateloader(int id, Bundle args) {... public void onloadfinished(loader<tipo> loader, Cursor data) {... public void onloaderreset(loader<tipo> loader) {... 15
Callback del loader Debemos indicar cómo construir el objeto Loader public Loader<Cursor> oncreateloader(int id, Bundle args) { return new CursorLoader(getActivity(), baseuri, proyeccion, seleccion, args, orden); También debemos definir qué hacer cuando obtengamos datos public void onloadfinished(loader<cursor> loader, Cursor data) { madapter.swapcursor(data); Y por último, la forma de reiniciar el contenido public void onloaderreset(loader<cursor> loader) { madapter.swapcursor(null); 16
Loader personalizado Podemos crear nuestro propio tipo de loader Normalmente lo hacemos con una subclase de AsyncTaskLoader Debemos implementar el proceso de carga de forma similar a una async task static class MiLoader extends AsyncTaskLoader<Tipo> { Tipo mdatos = null; public MiLoader(Context context) { super(context); Especificamos el tipo de los datos a obtener @Override public Tipo loadinbackground() { return cargardatos(); Descarga los datos en background... 17
Otros métodos de AsyncTaskLoader Comprobamos si tenemos los datos ya descargados o si hay que cargarlos Entregamos los datos, y los retenemos Cancelamos la descarga Borramos los datos descargados static class MiLoader extends AsyncTaskLoader<Tipo> { Tipo mdatos = null;... @Override protected void onstartloading() { super.onstartloading(); if(mdatos!= null) { deliverresult(mdatos); else { forceload(); @Override public void deliverresult(tipo data) { mdatos = data; super.deliverresult(data); @Override protected void onstoploading() { super.onstoploading(); cancelload(); @Override protected void onreset() { super.onreset(); onstoploading(); mdatos = null; 18
Uso del loader Podemos utilizar el loader definido desde nuestro callback public class MiFragmento implements LoaderManager.LoaderCallbacks {... public Loader<Tipo> oncreateloader(int id, Bundle args) { return new MiLoader(getActivity()); public void onloadfinished(loader<tipo> loader, Tipo data) { madapter.clear(); for(item item: data) { madapter.add(item); public void onloaderreset(loader<tipo> loader) { madapter.clear(); Introduce los datos cargados en el adaptador 19
Librería de compatibilidad Fragmentos y loaders son características importantes Es importante seguir dando soporte a dispositivos antiguos Existen librerías de compatibilidad Incorporan estas características a dispositivos a partir de 1.6 20
Uso de la librería de compatibilidad Copiamos la librería de compatibilidad al directorio libs $ANDROID_SDK/extras/android/support/v4/android- support- v4.jar Utilizamos los imports de la librería de compatibilidad import android.support.v4.app.fragment; import android.support.v4.app.fragmentmanager; import android.support.v4.app.fragmenttransaction; import android.support.v4.app.loadermanager; La actividad debe heredar de FragmentActivity public class MainActivity extends FragmentActivity {... Usamos métodos alternativos para obtener los managers FragmentManager manager = getsupportfragmentmanager(); LoaderManager manager = getsupportloadermanager(); 21
Librerías de servicios Podemos también añadir librerías para acceso a servicios Los servicios de Google se añaden mediante librería externa Aporta mayor flexibilidad para suministrar actualizaciones Debemos descargar la librería desde Google Play Soporta Android 2.2 y superiores Para desarrollar un proyecto con ella debemos Descargar la librería de servicios Google Play con SDK Manager Importar la librería (Existing Android Code into Workspace) $ANDROID_SDK/extras/google/google_play_services/ Añadir como dependencia de nuestro proyecto Properties > Android > Library > Add... 22
Configuración de los permisos Añadir permisos para los servicios <uses- permission android:name="android.permission.internet"/> <uses- permission android:name= "android.permission.write_external_storage"/> <uses- permission android:name= "com.google.android.providers.gsf.permission.read_gservices"/> <uses- permission android:name= "android.permission.access_coarse_location"/> <uses- permission android:name= "android.permission.access_fine_location"/> Sustituimos es.ua.jtech por el paquete de nuestra aplicación <permission android:name="es.ua.jtech.permission.maps_receive" android:protectionlevel="signature"/> <uses- permission android:name="es.ua.jtech.permission.maps_receive"/> 23
Clave de desarrollador y OpenGLES 2.0 Google Maps v2 necesita OpenGLES 2.0 Se debe indicar en el manifest <uses- feature android:glesversion="0x00020000" android:required="true"/> También debemos indicar nuestra clave de desarrollador <meta- data android:name="com.google.android.maps.v2.api_key" android:value="pon_aqui_tu_clave"/> La obtendremos de la siguiente dirección https://developers.google.com/maps/documentation/android/start#the_google_maps_api_key 24
Integración del mapa Podemos añadirlo al layout como fragmento <?xml version="1.0" encoding="utf- 8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.mapfragment"/> También podemos utilizar la librería de compatibilidad <?xml version="1.0" encoding="utf- 8"?> <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.supportmapfragment"/> 25
Preguntas...? 26