Programació de dispositius mòbils

La programació de dispositius mòbils en Android té unes característiques particulars que la diferencien de la programació tradicional en equips de taula. La majoria d’aquestes característiques vénen donades pel fet que els dispositius mòbils tenen unes prestacions inferiors als equips de taula, i per tant el sistema operatiu ha hagut d’implementar unes solucions enginyoses per resoldre-les. D’altra banda, el sistema operatiu i l’API que es fan servir per a les aplicacions del sistema són únics. Aquestes aplicacions (a més a més) tendeixen a estar molt relacionades entre si. Per aquest motiu, és important veure en detall la forma de realitzar una aplicació i entendre els conceptes bàsics de la programació de dispositius mòbils.

Conceptes previs

Existeixen tota una sèrie de conceptes que és interessant veure abans de començar directament amb la programació del dispositiu i l’explicació de les diferents classes que constitueixen l’API d’Android.

Parts d'una aplicació Android

Abans de res, si ja heu fet una aplicació bàsica amb Android (“Hola món!”), podeu mirar en el seu interior i examinar-ne cadascuna de les parts. En cas contrari, obriu el projecte “01 HolaAndroid” que trobareu als Annexos de la unitat. Quan obriu el projecte amb l’Android Studio veureu a la pestanya Project una sèrie de fitxers i carpetes com els que es mostren a la figura.

Figura Vista Android del projecte. Podem canviar-la a Project i a Packages

La carpeta Java conté els fitxers Java amb el codi del projecte, en aquest cas “HolaAndroidActivity”. Aquest fitxer conté el codi de l’activitat, i és aquí on escriureu el codi de la vostra aplicació.

El directori /res conté tots els recursos que es fan servir a l’aplicació. Dins hi ha altres subdirectoris (diferents carpetes drawable per a diferents resolucions, layout, values). Les carpetes drawable, en aquest moment només contenen les icones de l’aplicació en diferents resolucions. La carpeta layout conté el fitxer activity_hola_android.xml. Si l’obriu amb l’editor de text pla obtindreu un codi com el següent:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  4. android:paddingRight="@dimen/activity_horizontal_margin"
  5. android:paddingTop="@dimen/activity_vertical_margin"
  6. android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".HolaAndroidActivity">
  7.  
  8. <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
  9. android:layout_height="wrap_content" />
  10. </RelativeLayout>

Fixeu-vos en el camp “android:text=”@string/hello_world””. La variable “@string/hello_world” fa referència al camp “hello_world” que es troba al fitxer strings.xml dins de la carpeta res/values. El fitxer strings.xml conté les diferents cadenes de text que es fan servir al vostre projecte. Si l’obriu amb l’editor de text trobareu un codi semblant a aquest:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.  
  4. <string name="app_name">Hola Android</string>
  5. <string name="hello_world">Hello world!</string>
  6. <string name="action_settings">Settings</string>
  7.  
  8. </resources>

Tot i que podeu ficar els camps de text com cadenes de caràcters constants, és recomanable que deseu totes les constants de text (els textos que apareixeran al vostre programa) dins del fitxer string.xml i que feu referència a aquests textos a partir de l’identificador ”@string”. D’aquesta manera, si heu de traduir la vostra aplicació a un altre idioma, tot el que necessitareu és traduir els textos del fitxer strings.xml amb l’idioma desitjat i tornar a compilar el projecte.

El directori /assets conté altres recursos que es fan servir en l’aplicació, com ara fitxers de text, bases de dades… En aquest cas no el tenim disponible i l’haurem de crear manualment a la carpeta /res en cas de voler fer-lo servir.

El fitxer AndroidManifest.xml del directori manifests és el fitxer de manifest de l’aplicació Android. Aquí hi ha especificats els permisos i altres característiques de l’aplicació.

Components bàsics d'una aplicació Android

Els blocs principals per construir les vostres aplicacions són els components que fareu servir per programar les aplicacions Android. Són elements conceptuals que ficareu junts per construir una aplicació en conjunt:

  • Activitats
  • Fragments
  • Serveis
  • Proveïdors de continguts
  • Receptors de broadcast

Activitats

Podríem entendre l’activity (activitat) de manera aproximada com cada una de les “pantalles” d’una aplicació. Una definició més precisa establiria que les activitats són cada un dels components de l’aplicació que proveeixen a l’usuari una pantalla amb la que aquest pugui interactuar.

Per exemple, una aplicació de missatgeria pot tenir una activitat que mostri la llista de contactes, una altra per enviar missatges i una altra per llegir missatges rebuts. Tot i que aquestes activitats treballen juntes dins de l’aplicació de missatgeria, cadascuna és independent de les altres.

A més a més, en Android, les aplicacions poden activar activitats (pantalles) d’altres aplicacions. Per exemple, l’aplicació de missatgeria a la que ens referíem podria obrir una activitat de l’aplicació de fotografia per enviar una foto juntament amb un missatge. De la mateixa manera, l’aplicació de fotografia podria obrir l’activitat d’una aplicació de correu electrònic per enviar la foto com a adjunt d’un correu.

Una activitat està implementada com una subclasse de la classe “Activity”.

Podeu trobar més informació sobre la classe Activity a la Guia del desenvolupador d’Android:

developer.android.com/guide/topics/fundamentals/activities.html.

'Fragments'

A la versió d’Android 3.0 (Honeycomb, una versió d’Android exclusiva per a tauletes) Google va incorporar el concepte de fragments. Les majors dimensions de les pantalles en les tauletes permeten mostrar més informació que en un telèfon mòbil i per tant s’havia de trobar la manera de poder combinar diverses pantalles d’informació en una sola.

Un fragment és una porció d’una activitat. Podrem tenir diversos fragments i modificar-los durant l’execució de l’aplicació per tal de combinar-los segons les necessitats.

Figura Exemple de fragments a Android

A la figura podem veure com a la vista del telèfon mòbil una activitat disposa d’un sol fragment mentre que a la tauleta podem afegir dos fragments en cada activitat. Aquesta manera de treballar ens facilita la feina als desenvolupadors ja que, al tractar els fragments de manera modular, podem afegir i treure elements de l’activitat segons la quantitat d’espai lliure de què disposem i simplificar la programació per a dispositius amb diferents mides de pantalla.

Serveis

Un ”Service” (servei) és un component que s’executa en el background (en el fons, que no es veu) per realitzar tasques per a treballs remots.

Els serveis s’executen, com dèiem, en el background i no tenen components d’interfície d’usuari. Poden fer les mateixes coses que una activitat, però no tenen interfície. Són útils per realitzar tasques durant un temps determinat, independentment de la pantalla. Per exemple, podeu voler agafar dades del receptor GPS del telèfon o reproduir música mentre esteu canviant a altres aplicacions. Aquests serveis poden haver estat iniciats per un altre component, com per exemple una activitat, i podran continuar en execució independentment del component que hagi fet la crida.

Els serveis d’Android no són el mateix que els serveis de Linux (també anomenats daemons), que representen un component del sistema operatiu de més baix nivell.

Els serveis tenen un cicle de vida molt més senzill que les activitats, com podreu veure si compareu la figura amb la figura que es mostra més endavant.

Figura Cicle de vida d’un servei

Els serveis, o s’engeguen o s’aturen. A més a més, en general, el seu cicle de vida està més controlat pel programador, i no tant pel sistema.

Els serveis s’implementen com a classes derivades de la classe “Service”. Podeu trobar més informació a la Guia del desenvolupador d’Android sobre aquesta classe, a developer.android.com/guide/topics/fundamentals/services.html.

Proveïdors de continguts

'Intent'

Un intent (en el sistema Android) és un mecanisme que permet als usuaris coordinar funcions de diferents aplicacions per tal de realitzar una tasca. Podeu trobar-ne més informació en l’enllaç http://developer.android.com/ reference/android/content/ Intent.html.

Els content providers (proveïdors de continguts) són interfícies destinades a compartir dades entre les aplicacions. Per defecte, Android executa les aplicacions de forma independent, de manera que les dades de l’aplicació estan aïllades de la resta d’aplicacions del sistema. Encara que es poden traspassar petites quantitats d’informació entre les aplicacions a través dels intents, els proveïdors de continguts són més adequats per compartir conjunts de dades entre aplicacions.

La informació es pot inserir, actualitzar, esborrar i consultar a un proveïdor de continguts. Android fa servir aquest mecanisme tota l’estona. Per exemple, els proveïdors de continguts de contactes (contacts provider) proporcionen la informació dels contactes del telèfon a diferents aplicacions. Així, una aplicació amb els permisos adequats pot consultar el content provider (ContactsContract.Data) per llegir i escriure informació sobre una persona en concret. Un altre exemple: el Media Store (Magatzem de mitjans), emmagatzema i serveix diferents tipus de dades per compartir, com fotos i música, entre les diferents aplicacions.

Els content providers també són útils per llegir i escriure dades que són privades a la vostra aplicació i no estan compartides. Per exemple, una aplicació de bloc de notes pot fer servir un content provider per desar notes.

La separació entre el magatzem de dades i la interfície d’usuari proporciona molta flexibilitat a Android. Per exemple, es podria instal·lar una aplicació alternativa per visualitzar els contactes, o una aplicació podria accedir des de l’escriptori a algunes de les dades de configuració del sistema (que també estan emmagatzemades en un proveïdor de continguts) per modificar-ne algunes en concret, com la d’activar i desactivar el Wi-Fi.

Els proveïdors de continguts tenen interfícies relativament senzilles amb mètodes estàndard per inserir, actualitzar, esborrar i consultar la informació, de manera molt semblant als mètodes d’accés a bases de dades.

Un content provider està implementat com una subclasse de “ContentProvider” i ha d’implementar una sèrie d’APIs que permeten a altres aplicacions fer transaccions. Per a més informació podeu consultar la secció de content providers de la Guia del desenvolupador d’Android: developer.android.com/guide/topics/providers/content-providers.html.

Receptors de 'broadcast'

'Broadcasting'

El terme broadcasting, popularitzat en els dècades de 1920 i 1930 per la implantació de la ràdio i la televisió, es fa servir en l’actualitat per referir-se a qualsevol emissió massiva de continguts d’un únic emissor a múltiples receptors.

Els broadcast Rreceivers (receptors de broadcast) són un tipus de components que responen a anuncis de sistema dirigits a totes les aplicacions del dispositiu (broadcast). En certa manera, és una implementació d’Android d’un sistema de subscripció d’esdeveniments. El receptor simplement es queda en estat latent esperant a activar-se quan s’esdevingui un esdeveniment al qual està subscrit.

El sistema està enviant missatges de broadcast tota l’estona. Per exemple, quan es rep una trucada, s’apaga la pantalla o la bateria té un nivell de càrrega baix, aquests esdeveniments són anunciats pel sistema. Un altre exemple: si voleu que un servei quedi engegat una vegada el sistema ha arrancat, podeu subscriure’l al broadcast que diu que el sistema ha acabat d’engegar-se.

Les aplicacions també poden enviar missatges de broadcast. Per exemple, una aplicació pot anunciar que s’han acabat de descarregar algunes dades i que aquestes ja estan disponibles per usar-se.

Els receptors de broadcast no tenen una representació visual, però quan es llancen executen una part de codi (com engegar una activitat o servei) i poden crear una notificació a la barra d’estat per alertar l’usuari quan ha ocorregut un esdeveniment de broadcast.

Un broadcast receiver està implementat com una subclasse de “BroadcastReceiver” i cada missatge de broadcast s’envia com un objecte Intent. Podeu trobar més informació a la Guia del desenvolupador d’Android a l’apartat de BroadcastReceiver, a developer.android.com/reference/android/content/BroadcastReceiver.html.

Activant els components

Tres dels cinc tipus de components (activitats, serveis i receptors de broadcast) s’activen per missatges asíncrons anomenats intents (intencions). Els intents lliguen els components individuals entre si durant l’execució, tant si els components pertanyen a la mateixa aplicació com si no. Podeu pensar en els intents com missatges que s’envien entre si els diferents components de les aplicacions (i que, de fet, poden servir per activar-ne alguns d’ells).

Un intent es crea amb un objecte de la classe Intent, que defineix un missatge per activar un component específic (intent explícit) o un tipus de component (intent implícit).

URI

Un URI (Universal Resource Identifier, identificador de recursos universal) és una cadena de caràcters que serveix per referenciar recursos en el sistema. Aquesta identificació permet la interacció amb representacions del recurs en el sistema. El mètode Uri.parse(String) serveix per analitzar i codificar un String en forma d’URI.

Per activitats i serveis, un intent defineix una acció que s’ha de realitzar (per exemple, “veure” o “enviar” alguna cosa) i pot especificar l’URI de les dades sobre les quals s’ha d’actuar. Per exemple, un intent pot enviar una petició d’obrir una pàgina web i especificar l’adreça de la web, per tal que l’activitat corresponent pugui obrir la pàgina correctament.

En altres casos es pot començar una activitat i esperar rebre un resultat. Per exemple, es podria iniciar una activitat per seleccionar una persona de l’agenda de contactes, i l’activitat retornaria el resultat en un intent (aquest inclouria l’URI apuntant al contacte seleccionat).

Per als Receptors de broadcast, un intent simplement defineix l’anunci que s’està transmetent; per exemple, un missatge a tot el dispositiu per indicar que el nivell bateria del dispositiu és baix inclouria únicament un String indicant aquest anunci.

Els proveïdors de continguts no s’activen per intents, sinó amb peticions d’un ContentResolver (Resolutor de continguts). El Resolutor de continguts tracta totes les transaccions directes amb el proveïdor de continguts, per tal que no ho hagi de fer directament el component que el fa servir. Això proporciona una capa d’abstracció entre el proveïdor de continguts i el component que sol·licita la informació (per seguretat).

Existeixen mètodes diferents per activar cada tipus de component:

  • Les activitats es poden invocar creant un objecte de la classe Intent i passant-lo als mètodes startActivity(Intent i) o a startActivityForResult (Intent i, int requestCode) si voleu que l’activitat us retorni un resultat.
  • Es pot iniciar un servei passant un intent a startService(Intent service). Podeu enllaçar a un servei passant un intent a bindService (Intent service, ServiceConnection conn, int flags).
  • És possible iniciar un missatge de broadcast passant un intent als mètodes sendBroadcast (Intent i), sendOrderedBroadcast (Intent intent, String receiverPermission) o sendStickyBroadcast (Intent i).
  • Es pot realitzar una consulta a un proveïdor de continguts amb una crida a query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) d’un ContentResolver.

Podeu consultar informació sobre tots aquests mètodes a la Guia del desenvolupador d’Android: developer.android.com/reference/packages.html.

El fitxer AndroidManifest.xml

Abans que el sistema Android iniciï un component de l’aplicació, el sistema ha de saber que aquest component existeix. Per anunciar al sistema els components que farà servir l’aplicació existeix el fitxer AndroidManifest.xml (el fitxer de manifest de l’aplicació). L’aplicació ha de declarar tots els components en aquest fitxer, que ha d’estar a l’arrel del directori del projecte.

A més de declarar els components de l’aplicació, el fitxer de manifest fa les següents funcions, entre d’altres:

  • Identifica els permisos que necessita l’aplicació (com ara permisos per accedir a Internet).
  • Declara les característiques de maquinari i programari necessàries per executar correctament l’aplicació, com poden ser, entre d’altres:
    • La càmera.
    • La resolució mínima de la pantalla per poder funcionar.
    • Els dispositius d’entrada necessaris per executar l’aplicació (com el pad de quatre direccions).
    • Bluetooth.
    • Pantalla multitàctil.
  • Declara les llibreries d’aplicació, a banda de les API d’Android, que s’han d’enllaçar (link) a l’aplicació, per exemple com la llibreria de Google Maps.

El fitxer XML del projecte d’Hola Món és el següent:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.exemple.holaandroid" >
  4.  
  5. <application
  6. android:allowBackup="true"
  7. android:icon="@drawable/ic_launcher"
  8. android:label="@string/app_name"
  9. android:theme="@style/AppTheme" >
  10. <activity
  11. android:name=".HolaAndroidActivity"
  12. android:label="@string/app_name" >
  13. <intent-filter>
  14. <action android:name="android.intent.action.MAIN" />
  15.  
  16. <category android:name="android.intent.category.LAUNCHER" />
  17. </intent-filter>
  18. </activity>
  19. </application>
  20. </manifest>

El fitxer manifest el podeu trobar a la carpeta manifests de qualsevol projecte, tal i com podeu veure a la figura.

Figura Carpeta manifests d’un projecte

En l’element <application> hi podeu trobar altres atributs específics de l’aplicació, per exemple android:icon apunta al recurs de la icona que identifica l’aplicació i android:label apunta al recurs (dins del fitxer string.xml) amb el nom de l’aplicació.

L’element <activity> serveix per declarar una activitat. Així, l’atribut android:name especifica el nom de la subclasse (que hereta de la classe Activity) que tindrà el codi de l’activitat. Aquesta classe ha d’estar implementada i aparèixer al projecte. Els components de l’aplicació han d’estar declarats fent servir les etiquetes: <activity>, <service>, <receiver> i <provider>.

Aquells components que programeu i incloeu al projecte però no estiguin declarats al fitxer AndroidManifest.xml no es podran executar, atès que no són visibles pel sistema. Els receptors de broadcast, però, es poden declarar al manifest o bé crear-se dinàmicament amb codi i registrar-se al sistema tot cridant a registerReceiver().

Gradle

Gradle és una eina per automatitzar la construcció de projectes. Podrem configurar fàcilment distintes versions de la nostra aplicació, per exemple: generar una versió demo o lite de la nostra aplicació, la versió “completa”, per fer “debug”, etc. A més, disposem d’una gran quantitat de plugins i la gestió de dependències millora respecte ant, l’antic sistema de construcció utilitzat a Android. Per més informació podeu consultar el següent enllaç: https://developer.android.com/tools/building/configuring-gradle.html.

La tasca principal del manifest és informar el sistema sobre els components de l’aplicació. Actualment, algunes de les característiques que abans trobàvem al fitxer de manifest han passat a formar part del fitxer build.gradle (Module: app), que trobem dins de Gradle Scripts, els quals pengen a la vegada de l’arrel del projecte; és el cas de la declaració de la versió de la plataforma, el nivell mínim d’API o la versió de la nostra aplicació.

Aquest és el fitxer build.gradle d’HolaAndroid:

  1. apply plugin: 'com.android.application'
  2.  
  3. android {
  4. compileSdkVersion 21
  5. buildToolsVersion "21.1.2"
  6.  
  7. defaultConfig {
  8. applicationId "com.exemple.holaandroid"
  9. minSdkVersion 10
  10. targetSdkVersion 21
  11. versionCode 1
  12. versionName "1.0"
  13. }
  14. buildTypes {
  15. release {
  16. minifyEnabled false
  17. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  18. }
  19. }
  20. }
  21.  
  22. dependencies {
  23. compile fileTree(dir: 'libs', include: ['*.jar'])
  24. compile 'com.android.support:appcompat-v7:21.0.3'
  25. }

Per a més informació sobre el contingut i l’estructura del fitxer AndroidManifest.xml, podeu consultar la documentació de la Guia del desenvolupador d’Android: developer.android.com/guide/topics/manifest/manifest-intro.html.

Declarant les capacitats del component

Es pot fer servir un intent per activar activitats, serveis i receptors de broadcast. Per fer-ho es pot especificar a l’intent el nom del component que es vol activar (fent servir el nom de la classe de l’activitat que voleu activar, per exemple). Però existeix una altra forma d’activar activitats, a través del que es coneix com a intent actions (intents d’acció).

Un intent d’acció descriu el tipus d’acció que es vol realitzar (i, opcionalment, les dades sobre les quals es vol realitzar) i delega al sistema la tasca de trobar un component en el dispositiu que pugui realitzar aquesta acció, i activar-lo. Per exemple, es pot llançar un intent on s’especifica que es vol visitar una pàgina web o fer una foto, i deixar que el sistema trobi l’activitat (de l’aplicació que sigui) que pugui realitzar aquesta acció. En el cas que hi hagi múltiples components que puguin realitzar l’acció, es demana a l’usuari quina d’elles vol fer servir.

Com pot saber el sistema quins components són apropiats per fer la tasca que es demana des de l’intent? Els components poden definir uns filtres d’intents (intent filters) al fitxer de manifest que seran comparats pel sistema amb l’acció que s’ha demanat fer. Podeu, opcionalment, definir aquests filtres d’intents al manifest de la vostra aplicació per tal que el vostre component pugui respondre a intents d’altres aplicacions. Per fer-ho, heu d’afegir un element <intent-filter> com un fill de l’element de la declaració de component al fitxer XML.

Podeu trobar més informació sobre els filtres d’intents a la Guia del desenvolupador d’Android: developer.android.com/guide/topics/intents/intents-filters.html.

Activitats

A Android, una Activity (activitat) és un component d’aplicació que proporciona una finestra amb una interfície d’usuari de la vostra aplicació. Una aplicació també pot no tenir cap activitat.

Generalment, les aplicacions tenen més d’una activitat i el seu principal propòsit és el d’interactuar amb l’usuari. Des del moment que una activitat es mostra en pantalla fins al moment que es tanca, l’activitat passa per una sèrie de fases, conegudes com el cicle de vida de l’activitat. És molt important que entengueu el cicle de vida de l’activitat per tal que la vostra aplicació funcioni correctament.

Una Activity (activitat) és un component que proporciona una interfície gràfica amb la qual interactua l’usuari.

Podeu trobar la darrera informació oficial de Google sobre activitats a developer.android.com/guide/topics/fundamentals/activities.html.

Una aplicació consisteix en múltiples activitats que estan relacionades entre si. En general, existeix una activitat considerada l’activitat principal (o main) de l’aplicació, que és la que es mostra quan es llança l’aplicació per primera vegada. Aquesta activitat principal pot iniciar altres activitats per realitzar diferents accions. Cada vegada que es llança una activitat, l’activitat prèvia s’atura, però el sistema guarda l’activitat a la pila (anomenada back stack). Quan s’inicia una activitat, aquesta concentra el focus de l’aplicació.

Quan una activitat s’atura perquè una altra comença, la primera queda notificada a través dels mètodes de callback, que són mètodes de l’activitat que són cridats quan aquesta canvia d’estat (si es crea, s’atura, es destrueix…) i que li permeten realitzar tasques en relació a aquest canvi d’estat. Per exemple, quan l’activitat s’atura aquesta hauria d’alliberar els recursos reservats i tancar les comunicacions de xarxa. Quan una activitat es llança, podria activar aquestes mateixes connexions de xarxa.

Callback

Una funció de callback (retrotrucada o devolució de trucada) és una referència a una porció de codi executable (“funció A”) que es passa com a argument en la crida a un altre codi (“funció B”). D’aquesta manera, el codi (la “funció B”) pot cridar la funció que se li passa com a argument (“funció A”) quan ho necessiti. Per exemple, imagineu que voleu cridar una funció que realitza una cerca a una llista (“B”), i que quan trobi un element en concret voleu que cridi una funció vostra per mostrar-ho per pantalla (“A”). En aquest cas, es passaria a la crida de la funció B una referència a A. Quan B trobi l’element, farà una crida a A.

Treballant amb activitats

Per crear una activitat heu de crear una classe derivada de la classe Activity(o una subclasse d’aquesta). En la classe que heu creat heu d’implementar els mètodes de callback que el sistema cridarà en les transicions dels diferents estats del cicle de vida de l’activitat (quan es crea, es destrueix, etc.). Els dos mètodes més importants són:

  • onCreate(): el sistema crida aquest mètode quan es crea l’activitat. Dins, heu d’inicialitzar els components inicials de la vostra aplicació. Aquí s’ha de cridar setContentView() per definir la distribució de la interfície d’usuari de l’activitat (coneguda com a layout).
  • onPause(): el sistema crida aquest mètode, en primer lloc, per indicar que l’usuari està sortint de la vostra activitat. Encara que això no signifiqui necessàriament que l’activitat es destrueixi, cal que deseu tots els canvis que voleu conservar de l’Aplicació, ja que és possible que l’usuari no torni a l’activitat.

La interfície d’usuari d’una activitat està formada per una jerarquia de vistes (objectes derivats de la classe View). Cada vista (view) controla un espai rectangular dins de l’espai de l’activitat i pot respondre a la interacció de l’usuari. Per exemple, una vista podria ser un botó que inicia una acció quan és premut per l’usuari.

A Android disposeu d’una sèrie de vistes que ja estan fetes que podeu fer servir per dissenyar la vostra activitat. Els widgets són vistes que proporcionen elements visuals i interactius en pantalla com un botó, un camp de text, un checkbox o una imatge. Els layouts (distribucions) també són vistes que deriven de la classe ViewGroup. Contenen altres vistes i proporcionen un tipus de distribució específica per a elles. Per exemple, un layout linear pot contenir altres botons (vistes) que es mostraran en forma de vista en la pantalla. Podeu crear subclasses derivades de View i ViewGroup (o les seves subclasses) per crear els vostres widgets i layouts i aplicar-los a les vostres activitats.

Els layouts de les diferents activitats de l’aplicació estan definits a una sèrie de fitxers XML que es troben a la carpeta /res/layout del projecte. Existeix un fitxer XML per cada layout, sent el fitxer main.xml el que es crea per defecte per a la primera activitat de l’aplicació. Podeu carregar els layouts com la interfície gràfica de la vostra activitat amb una crida a la funció setContentView (int layoutResID) que té un únic argument, l’identificador del layout que es vol carregar.

A més de les activitats, els intents són un altre concepte únic d’Android. Aquests, bàsicament, permeten a diferents activitats de diferents aplicacions treballar conjuntament com si totes pertanyessin a la mateixa aplicació.

Cicle de vida d'una activitat

Podeu descarregar el codi corresponent a aquesta activitat en l’annex anomenat “Cicle de vida” de la secció “Annexos”.

Per crear una activitat primer heu de crear una classe de Java que sigui descendent de la classe base Activity. Per seguir l’explicació, creeu un nou projecte.

Fixeu-vos en la definició de la classe que trobeu quan creeu un nou projecte:

  1. public class ActivitatPrincipal extends ActionBarActivity {
  2.  
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. }
  8. }

La classe ActivitatPrincipal hereta d‘ActionBarActivity que a la vegada és un descendent d‘Activity. La classe Activity defineix una sèrie d’events que defineixen el cicle de vida de l’aplicació:

  • onCreate(): es crida quan l’activitat s’ha creat per primera vegada.
  • onStart(): es crida quan l’activitat és visible per a l’usuari.
  • onResume(): es crida quan l’activitat comença a interaccionar amb l’usuari.
  • onPause(): es crida quan l’activitat actual es pausa i l’activitat anterior és represa.
  • onStop(): es crida quan l’activitat ja no és visible per a l’usuari.
  • onDestroy(): es crida abans que l’activitat sigui destruïda pel sistema (manualment o pel sistema per estalviar memòria).
  • onRestart(): es crida quan l’activitat s’ha aturat i s’ha tornat a iniciar.

Un handler (controlador) és un mètode o funció que s’executa per tractar un esdeveniment ocorregut al sistema.

Per defecte, l’activitat que es crea al nou projecte conté l’event onCreate(). Dins d’aquest mètode (és un handler de l’event) hi ha el codi que serveix per mostrar els elements de la UI (user interface, interfície d’usuari) en pantalla. El cicle de vida d’una activitat i les diferents fases per les quals passa són les següents:

  • Estat inicial
  • Estat en execució
  • Estat pausat
  • Estat aturat (stop)
  • Estat destruïda

Estat inicial

Quan una activitat s’està engegant passa a través de tota una sèrie de crides a mètodes de callback on podeu introduïr codi. Tot seguit, passarà a l’estat d’execució. Aquest procés de creació de l’activitat (la transició entre l’estat inicial i l’estat en execució) és una de les operacions més costoses en temps de computació i, per tant, afecta la vida de la bateria del dispositiu. Aquest és el motiu pel qual les activitats no es destrueixen automàticament quan es deixen de mostrar, ja que l’usuari pot voler tornar-hi aviat.

Estat en execució

Una activitat en execució és la que està actualment en pantalla i oferint interacció a l’usuari. També diem que l’activitat està en focus, és a dir, que totes les interaccions de l’usuari (com tocar la pantalla, escriure al teclat, pressionar els diferents botons del telèfon) són tractades per aquesta activitat. Per aquest motiu, hi ha una única activitat en estat d’execució en cada moment. L’activitat en execució és la que té prioritat en termes de memòria i recursos, per tal d’oferir a l’usuari un temps de resposta reduït.

Estat pausat

Quan una activitat no té el focus (l’usuari no hi està interactuant) però encara està visible en pantalla, diem que està en estat de pausa. No és una situació freqüent, ja que la pantalla del dispositiu sol ser petita i l’activitat, generalment, o bé la fa servir tota o bé no la fa servir en absolut. Però de vegades es mostra un diàleg en pantalla,fent que l’activitat que estava en execució quedi en pausa. A més, totes les activitats que es tancaran (estat stop) passen abans per l’estat de pausa. Les activitats en estat de pausa encara tenen una prioritat alta en termes de memòria i altres recursos, perquè romanen visibles i no es poden amagar.

Estat aturat ('stop')

Una activitat està en estat aturat quan no és visible però encara està en memòria. Una activitat aturada es pot tornar a mostrar (i, per tant, tornaria a ser una activitat en execució) o es pot destruir definitivament alliberant l’espai que ocupava a la memòria. El sistema desa les activitats en estat aturat, ja que és probable que l’usuari les vulgui tornar a executar aviat, i reiniciar una activitat aturada és més ràpid que engegar-la des de zero. Això és així perquè els objectes ja estan carregats en memòria i és més fàcil portar-los al capdavant de la pantalla. Les activitats aturades es poden treure de memòria en qualsevol moment (ja que el sistema pot necessitar la memòria que estan ocupant).

Estat destruïda

Una activitat destruïda és aquella que ja no està en memòria. L’activity manager ha decidit que aquesta activitat ja no és necessària i ha alliberat l’espai de memòria que estava ocupant. Abans que es destrueixi es poden fer certes accions, com salvar informació important de l’activitat.

Cicle de vida de l'activitat

La figura mostra les etapes del cicle de vida de l’activitat.

Figura Cicle de vida d’una activitat
Imatge reproduïda a partir del treball creat i compartit pel projecte Android Open Source Project i publicada a partir dels termes descrits a la llicència Creative Commons 2.5.

En execució i aturada

El fet que una activitat estigui en execució no vol dir necessàriament que estigui fent moltes coses. Podria estar senzillament esperant interacció per part de l’usuari. Igualment, una activitat en estat aturat no vol dir que necessàriament no estigui fent res. Els noms dels estats fan referència a com d’activa està l’activitat respecte a l’entrada de l’usuari. En altres paraules, si l’activitat està visible, si té el focus o si no és visible en absolut.

Què fa l’activitat en cada estat? Per veure i entendre les diferents fases del cicle de vida d’una activitat, el millor és crear un projecte i interactuar-hi, i veure quan ocorren els diferents esdeveniments.

Una vegada creat el nou projecte, el fitxer ActivitatPrincipal quedarà:

  1. package cat.xtec.ioc.cicledevida;
  2.  
  3. import android.support.v7.app.ActionBarActivity;
  4. import android.os.Bundle;
  5. import android.util.Log;
  6.  
  7.  
  8. public class ActivitatPrincipal extends ActionBarActivity {
  9.  
  10. String tag = "Events";
  11.  
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main);
  16.  
  17. Log.d(tag, "A l'event onCreate()");
  18. }
  19.  
  20. @Override
  21. public void onStart() {
  22. super.onStart();
  23. Log.d(tag, "A l'event onStart");
  24. }
  25.  
  26. public void onRestart() {
  27. super.onRestart();
  28. Log.d(tag, "A l'event onRestart()");
  29. }
  30.  
  31. public void onResume() {
  32. super.onResume();
  33. Log.d(tag, "A l'event onResume()");
  34. }
  35.  
  36. public void onPause() {
  37. super.onPause();
  38. Log.d(tag, "A l'event onPause()");
  39. }
  40.  
  41. public void onStop() {
  42. super.onStop();
  43. Log.d(tag, "A l'event onStop()");
  44. }
  45.  
  46. public void onDestroy() {
  47. super.onDestroy();
  48. Log.d(tag, "A l'event onDestroy()");
  49. }
  50.  
  51. }

Abans d’executar el projecte feu clic al menú Run/Edit Configurations i a l’opció Target device assegureu-vos que està marcada l’opció Show chooser dialog. Això farà que cada vegada que executeu el programa se us demani on s’executarà d’entre les diferents opcions possibles del sistema (màquines virtuals o dispositius físics connectats a l’ordinador). Feu clic a Run per executar el projecte. Veureu una pantalla com la de la figura. En aquest cas en concret, no disposem de cap dispositiu ni emulador en funcionament, i se’ns proposa executar una màquina virtual d’un Nexus 5.

Figura Selecció de dispositiu on s’executarà l’aplicació

Una vegada fet això, podeu executar el projecte per depurar amb el botó dret el projecte al Package Explorer i l’opció Debug As/Android Application. Seguiu aquests events amb el gràfic de la figura (“Cicle de vida d’una activitat”). Podeu veure també els esdeveniments de log a la finestra LogCat de l’Android Studio, tal com podeu veure a la figura.

Figura Log d’‘events’

Podeu provar d’afegir filtres fent clic al desplegable de la part superior dreta i escollint Edit filter configuration.

Així, quan es carrega l’aplicació per primera vegada es mostrarà al logcat el següent:

D/Events: A l'event onCreate()
D/Events: A l'event onStart()
D/Events: A l'event onResume()

Les inicialitzacions de les variables de la vostra aplicació les podeu fer a l’event onCreate, que com vèiem al codi anterior és el primer en executar-se. Quan premeu el botó de tornar enrere al simulador, els events que es mostren al log seràn aquests:

D/Events: A l'event onPause()
D/Events: A l'event onStop()
D/Events: A l'event onDestroy()

Podeu observar com quan premem la tecla enrere l’aplicació es destrueix (crida el mètode onDestoy()) de manera que si tornem a executar-la, ja sigui des del menú o des de la tecla recents (prement durant una estona el botó home en aquells telèfons on no existeixi aquesta tecla), es tornaran a produir els següents esdeveniments:

D/Events: A l'event onCreate()
D/Events: A l'event onStart()
D/Events: A l'event onResume()

Si mentre estem a l’aplicació premem el botó home i tornem a executar-la, la seqüència d’esdeveniments serà la següent:

D/Events: A l'event onPause()
D/Events: A l'event onStop()
D/Events: a l'event onRestart()
D/Events: A l'event onStart()
D/Events: A l'event onResume()

En aquest cas no es fa cap crida a onDestroy() i per tant, al tornar a tenir l’aplicació en primer pla no s’executa el mètode onCreate(). Quan una aplicació està pausada o aturada i tornem a ella, executarà el mètode onRestart(), seguits d‘onStart() i onResume().

Hem vist com l’activitat es destrueix quan es prem el botó de tornar enrere (Back button). És molt important aquest punt, ja que l’estat de l’activitat es perd. Per tant, heu d’afegir codi addicional per preservar l’estat de l’activitat abans no es destrueixi (en qualsevol dels events que s’executen abans de destruir l’aplicació) i tornar a restituir l’estat quan es torni a obrir. Per exemple, les dades que voleu desar quan l’aplicació deixa d’estar en execució les podríeu desar a onPause() i tornar a carregar-les des d‘onResume(). </newcontent>

L’event onPause() és cridat als dos escenaris, quan l’activitat s’envia al fons (background) i quan és eliminada amb el botó Back. Quan l’activitat es torna a engegar sempre es crida onStart() i onResume(), independentment de si ha tornat del fons (background) o si s’ha creat de nou.

'Intents'

Els intents són missatges enviats entre els diferents elements que conformen les aplicacions d’Android. Les activitats, serveis i broadcast receivers (receptors de broadcast) són activats a través d’aquests missatges. Els intents li indiquen a una activitat que s’iniciï, o a un servei que comenci o s’aturi, o són simplement missatges de broadcast (dirigits a totes les aplicacions del dispositiu). En definitiva, serveixen per comunicar components de la mateixa aplicació o d’altres.

Els intents serveixen per comunicar diferents components de la mateixa aplicació o d’aplicacions diferents. Generalment fan referència a una acció que s’ha de realitzar i van acompanyats de dos elements: l’acció que s’executarà i la informació que aquesta necessita.

L’intent és un objecte de la classe Intent, i conté la informació de l’operació que es vol realitzar o, en el cas dels broadcasts, la descripció d’algun esdeveniment que ha tingut lloc en el sistema. Existeixen diferents maneres d’enviar els intents en funció del tipus de component al qual van dirigits.

Per adreçar un intent a una activitat, podeu fer servir els mètodes Context.startActivity (Intent intent) o Activity.startActivityForResult (Intent intent, int requestCode), depenent de si espereu que l’activitat us retorni alguna informació o no.

Per iniciar un servei o enviar informació a un servei podeu fer servir el mètode Context.startService (Intent service). Es pot fer servir Context.bindService (…) per establir una connexió entre el servei i el component que l’està cridant.

Per adreçar un intent a tots els receptors de broadcast podeu fer servir Context.sendBroadcast (Intent intent), Context.sendOrderedBroadcast (…) o Context.sendStickBroadcast (Intent intent).

En cada cas, el sistema Android troba l’activitat, servei o receptor de broadcast que respondrà a l’intent, instanciant-lo si cal.

Objecte ''Intent''

Un Intent és un objecte que conté informació d’interès per al component que el rep (com l’acció que ha de realitzar i les dades sobre les quals l’ha de realitzar). També conté informació per al sistema Android (com la categoria del component que ha de tractar l’intent i les instruccions sobre com llançar el component). Conté la següent informació:

  • Nom del component
  • Acció
  • Dades
  • Categoria
  • Extres
  • Flags

Nom del component

El nom del component que ha de tractar l’intent és un objecte ComponentName. El nom del component és opcional. Si s’especifica, l’intent és enviat a la instància de la classe especificada. Si no s’especifica, el sistema trobarà un component per tractar l’intent (en base a una altra informació especificada a l’objecte Intent).

El component s’especifica amb setComponent(), setClass() o setClassName().

Acció

L’acció és un string que especifica l’acció a realitzar o, en el cas dels intents broadcast, una acció que ha tingut lloc i que s’està anunciant. La classe Intent defineix alguns tipus d’accions estàndards, com les que es poden veure a la taula. Podeu veure tots els tipus de constants d’acció a la Guia del desenvolupador d’Android, a la pàgina de la classe Intent.

Taula: Diferents tipus d’accions
Constant Component al qual va dirigit l’intent Acció
ACTION_CALL Activitat Realitza una trucada.
ACTION_EDIT Activitat Mostra dades a l’usuari per a edició.
ACTION_MAIN Activitat Inicia com a activitat principal d’una aplicació. No s’espera valor de retorn.
ACTION_SYNC Activitat Sincronitza dades des del dispositiu al servidor.
ACTION_VIEW Activitat Mostra dades a l’usuari.
ACTION_BATTERY_LOW Receptor de broadcast Advertència de que la bateria del dispositiu està baixa.
ACTION_HEADSET_PLUG Receptor de broadcast S’han connectat o desconnectat els auriculars del dispositiu.
ACTION_SCREEN_ON Receptor de broadcast S’ha encès la pantalla.
ACTION_AIRPLANE_MODE_CHANGED Receptor de broadcast S’ha modificat el mode avió del dispositiu.

Podeu definir i llegir l’acció d’un objecte Intent amb els mètodes setAction() i getAction().

Dades

MIME

MIME (Multipurpose Internet Mail Extensions, extensions de correu d’Internet multipropòsit) és un estàndard d’Internet que es va dissenyar originalment per especificar el tipus de les dades adjuntes a un correu electrònic, però que actualment serveix per especificar el tipus de dades en general.

Es tracta de la informació relativa a les dades sobre les quals s’ha de realitzar l’acció (especificant l’URI) i el tipus MIME d’aquestes dades.

Depenent del tipus d’acció, l’URI especificarà unes dades o altres. Per exemple, quan l’acció és ACTION_CALL el camp de dades serà de tipus “tel:” i anirà acompanyat d’un URI amb el número de telèfon al que s’ha de trucar. O si l’acció és ACTION_VIEW, el camp de dades pot ser del tipus “http:” i s’aportarà l’adreça del lloc web que es vol visitar.

Moltes vegades, el tipus de dades es pot deduir de l’URI, per exemple mirant si és la URL d’un web o una imatge del dispositiu. Però es pot definir específicament el tipus de les dades a l’objecte intent.

El mètode setData (Uri data) serveix per especificar l’URI de les dades, i el mètode setType (String type) serveix per especificar el tipus MIME de les dades. També podeu fer servir el mètode setDataAndType (Uri data, String type) per especificar ambdós. Per llegir l’URI i el tipus MIME, podeu fer servir getData() i getType(), respectivament.

Categoria

És una cadena que conté informació addicional sobre el tipus de component que ha de tractar l’intent. La classe Intent defineix algunes categories, entre les quals es troben les de la taula.

Taula: Alguns dels tipus de categories definides a l’‘intent’
Constant Significat
CATEGORY_PREFERENCE L’activitat és un panell de preferències.
CATEGORY_APP_MUSIC L’activitat ha de ser capaç de reproduir o manipular música.
CATEGORY_APP_MESSAGING L’aplicació ha de ser capaç d’enviar i rebre missatges.
CATEGORY_APP_BROWSER L’activitat ha de ser capaç de navegar per Internet.

Podeu comprovar la llista completa de categories de la definició de la classe Intent a la Guia del desenvolupador d’Android.

Podeu fer servir els mètodes addCategory(String category), removeCategory(String category) i getCategories() per afegir, esborrar i obtenir una llista de les categories de l’objecte intent, respectivament.

Extres

Els extres són parells clau-valor que aporten informació addicional que s’ha d’enviar al component perquè tracti l’intent. Així, diferents URI tenen associats alguns extres en particular. Per exemple, l’acció ACTION_HEADSET_PLUG, que correspon a una canvi en l’estat de la connexió dels auriculars del dispositiu, té un camp extra indicant si els auriculars s’han endollat o no. Un altre exemple, l’acció ACTION_TIMEZONE_CHANGED, que correspon al fet que s’ha canviat l’ús horari, té un extra time-zone per especificar l’ús horari que s’ha definit.

La classe Intent té una sèrie de mètodes que es fan servir per afegir extres, els podeu consultar a la Guia del desenvolupador d’Android. També es pot fer servir un objecte del tipus Bundle per afegir extres. Un objecte de la classe Bundle (literalment de l’anglès, ‘paquet’ o ‘feix’) permet emmagatzemar una sèrie de dades (que poden ser de diferent tipus). Les variables es poden afegir al Bundle simplement donant un nom i la variable que es vol guardar. En certa manera, recorda els arrays amb què es passen variables entre els formularis en PHP: un array de tuples [nom, valor]. Podeu fer servir els mètodes putExtras(Bundle extras) i getExtras() per afegir i obtenir extres de l’intent.

'Flags' (banderes)

Es poden especificar flags de diferents tipus que indiquin al sistema com ha de llançar l’activitat i com tractar-la després que s’hagi engegat. Tots aquests flags estan definits a la classe Intent.

Enviament de 'broadcasts'

Les aplicacions fan servir els objectes Intent per enviar broadcasts i activar components del sistema. Per exemple, a la taula teniu alguns exemples d’intents que criden a serveis estàndard del sistema, amb el seu significat.

Taula: Diferents ‘intents’
Aplicació objectiu URI de l’intent Acció de l’intent Resultat
Navegador http://ioc.xtec.cat ACTION_VIEW Obre en un navegador l’adreça especificada.
Navegador “text” ACTION_WEB_SEARCH Es realitza una cerca a Google de la cadena especificada.
Marcador tel:número de telèfon ACTION_CALL Truca al número de telèfon especificat.
Marcador tel:número de telèfon ACTION_DIAL Marca el número de telèfon especificat (però no truca).
GoogleMaps geo:latitud,longitud
geo:latitud,longitud?z=zoom
geo:0,0?q=adreça
geo:0,0?q=pizzeria
ACTION_VIEW Obre GoogleMaps a la localització especificada o fent la cerca demanada.

Filtres d''intents'

Hi ha dos tipus d’intents diferents:

  • Explícits: on s’especifica el component explícitament pel seu nom (el camp nom del component de l'Intent té un valor introduït). Generalment, no podem saber el nom específic dels components d’altres aplicacions, per això els intents explícits generalment es fan servir per cridar components de la nostra pròpia aplicació.
  • Implícits: aquests no tenen definit el nom del component al qual van dirigits. Generalment, es fan servir per activar components d’altres aplicacions.

Els intents explícits s’envien a través del sistema a una instància de la classe definida, únicament es fa servir el nom del component (definit al ComponentName de l’objecte Intent) per determinar quin és el component al qual va dirigit l’intent.

Com els intents implícits no especifiquen quin és el component al qual va dirigit l’intent, el sistema ha de trobar el millor component per tractar l’intent. Per fer-ho, compara els continguts definits a l’objecte Intent amb unes estructures definides als components que serveixen per anunciar al sistema les capacitats del component. Aquestes estructures serveixen per dir al sistema quin tipus d’intents és capaç de tractar el component i s’anomenen intent filters (filtres d’intents).

Els intent filters serveixen per dir al sistema les capacitats del component. El sistema sabrà a quin tipus d’intent pot respondre el component comparant les característiques de l’intent amb el filtre d’intent.

Per exemple, podeu crear una activitat que serveixi per veure pàgines web. Podeu anunciar al sistema que la vostra activitat està oberta a rebre intents per visitar llocs web. La propera vegada que es faci un intent per visitar un web des del vostre dispositiu, la vostra activitat serà una de les candidates per obrir el web (en el cas que hi hagi diversos components per atendre l‘Intent, el sistema demanarà a l’usuari quin vol fer servir).

Els filtres permeten que els components puguin rebre intents implícits. Si un component no té intent filters, únicament pot rebre intents explícits (amb el seu nom). Un component que defineix filtres d’intents pot rebre intents implícits i explícits.

Un component té un filtre diferent per cada treball que pot fer. Per exemple, una aplicació multimèdia pot tenir diferents tipus de filtres per anunciar que pot obrir diferents tipus de fitxers (fotos, àudio, vídeo, etc.).

Un filtre és una instància de la classe IntentFilter. El sistema comprova els components per veure quin pot rebre l’intent implícit, per aquest motiu ha de conèixer les capacitats del component abans d’engegar-lo. Per això els filtres s’han de definir al fitxer AndroidManifest.xml com a elements <intent-filter>. L’única excepció són els filtres per als receptors de broadcast que es registren dinàmicament cridant el mètode Context.registerReceiver().

Un filtre té camps similars als de l’objecte Intent: acció, dades i categoria. Els intents implícits es comparen amb els camps del filtre. Perquè l’intent sigui enviat al component, la comparació amb els tres camps del filtre ha de ser vàlida. Es realitza un test amb cada camp per separat:

  • Acció
  • Categoria
  • Dades (l’URI i el tipus de dades)

Els extres i els flags no es fan servir per determinar quin component rep l'Intent.

Acció

L’element <intent-filter> en el fitxer de manifest mostra les accions del filtre com a subelements <action>. Per exemple:

  1. <intent-filter>
  2. <action android:name="android.settings.SOUND_SETTINGS"/>
  3. <action android:name="android.settings.WIFI_SETTINGS"/>
  4. <action android:name="android.intent.action.CALL"/>
  5. </intent-filter>

Encara que els objectes Intent únicament defineixen una acció, els filtres poden definir-ne més d’una. La llista no pot estar buida, ha de tenir almenys un element <action> o bloquejarà tots els intents. Per tal que l’objecte Intent passi el test del filtre d’acció ha de coincidir una de les accions definides al filtre. Si l’objecte Intent no especifica una acció, passarà el test d’acció automàticament i es comprovaran la resta de camps.

Categoria

L’element <intent-filter> també defineix les categories com a subelements, per exemple:

  1. <intent-filter>
  2. <categoryandroid:name="android.intent.category.DEFAULT"/>
  3. <categoryandroid:name="android.intent.category.BROWSABLE"/>
  4. </intent-filter>

Fixeu-vos que es fan servir les cadenes completes per definir les accions i les categories (a diferència del que hem vist per a la creació de l’objecte Intent). Així, quan a l’objecte Intent definiu la categoria CATEGORY_BROWSABLE, al filtre d’intent s’ha de definir android.intent.category.BROWSABLE.

Perquè l’intent passi la comprovació de categoria, totes les categories definides a l’objecte Intent han d’estar presents al filtre d’intents.

Existeix una petita característica que cal aclarir. Tots els intents implícits que s’envien a startActivity() es tracten pel sistema com si tinguessin la categoria CATEGORY_DEFAULT definida. Per tant, les activitats que volen rebre intents implícits han d’incloure android.intent.category.DEFAULT en el seu filtre d’intents.

Els filtres android.intent.action.MAIN i android.intent.category.LAUNCHER són excepcions. Defineixen activitats que comencen noves tasques i que estan representades a la pantalla llançadora d’aplicacions (la pantalla on l’usuari pot escollir entre totes les aplicacions que vol llançar). Poden incloure android.intent.category.DEFAULT en la llista de categories, encara que no ho necessiten.

Dades

La definició de dades està especificada com un subelement del filtre d’intents.

  1. <intent-filter>
  2. <data android:mimeType="image/*"/>
  3. <data android:scheme="http" android:type="video/*"/>
  4. </intent-filter>

Cada element <data> pot especificar un URI i un tipus de dades (MIME). L’atribut type de l’element <data> especifica un tipus MIME de les dades. En l’exemple, el primer element <data> diu al sistema que el component pot obtenir una imatge i mostrar-la. El segon element és un filtre que defineix un esquema i un tipus de dades, que en aquest cas li diu al sistema Android que el component pot obtenir dades de vídeo de la xarxa i mostrar-les.

Com que la majoria de les dades es proporcionen amb proveïdors de continguts, els filtres que especifiquen tipus de dades no especifiquen URI. Tant l’objecte Intent com el filtre poden usar un comodí “*” per especificar un subtipus. Per exemple, “text/*” o “audio/*” indica que se seleccionarà qualsevol subtipus de text o d'audio respectivament.

Interfície d'usuari d'Android

Les activitats serveixen per interactuar amb l’usuari i mostren la interfície d’usuari (o UI, User Interface) de la vostra aplicació, que pot tenir elements gràfics (widgets, en anglès) com botons, caixes de text, etiquetes… La UI està definida al fitxer activity_*.xml, a la carpeta res/layout del vostre projecte. Si l’obriu a l’editor de l’Android Studio, veureu dues pestanyes: Design i Text, que mostren el contingut del fitxer XML i la interpretació gràfica del mateix, com es pot veure a la figura.

Figura Edició de la UI des d’Android Studio

Quan s’executa l’aplicació es carrega el fitxer XML amb la UI al controlador d’event onCreate() de la vostra classe d’activitat, fent servir el mètode setContentView().

  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.activity_hola_android);
  4. }

En la fase de compilació, cada element del fitxer XML és compilat en una classe d’UI d’Android equivalent amb els seus mètodes i atributs.

Crear la UI

En general, el més senzill és crear la UI mitjançant un fitxer XML, encara que és possible crear la UI mitjançant programació. En alguns casos, com els videojocs, aquesta darrera opció és preferible.

La UI a Android es construeix fent servir objectes View (vistes) i ViewGroup (grups de vistes). Existeixen moltes Views i ViewGroups, tots derivats de la classe View.

Els objectes View són la unitat bàsica de la UI de la plataforma Android. La classe View(android.view.View) serveix de classe base per a totes les subclasses anomenades widgets, que ofereixen objectes UI totalment implementats com a camps de text i botons.

La classe ViewGroup(android.view.ViewGroup) serveix de classe base per a les subclasses anomenades layouts, que proporcionen diferents tipus de disposicions dels elements. Una o més Views es poden agrupar juntes dins d’un ViewGroup. El ViewGroup (que en si mateix és un tipus de View, ja que hereta d’aquesta classe) proporciona una disposició en la qual es mostrarà la seqüència de Views.

A Android, es defineix la UI d’una activitat fent servir una jerarquia de Views i ViewGroups, tal com es pot veure a la figura.

Figura Jerarquia que defineix una UI d’una activitat

Per enllaçar l’arbre jeràrquic de vista a la pantalla, l’activitat ha de cridar setContentView() i passar-li com a referència l’objecte al node arrel de la jerarquia. El node arrel de la jerarquia va cridant els seus nodes fills (els altres Views i ViewGroups) per tal que, finalment, tots es dibuixin en pantalla.

Android té els diferents tipus de ViewGroups:

  • LinearLayout
  • GridLayout
  • TableLayout
  • RelativeLayout
  • FrameLayout
  • ScrollView

El més habitual és combinar els diferents tipus de layout per crear la UI que volem (tal com es mostra a la figura, inserint-ne uns dins dels altres).

'Layout'

La forma més comuna de definir el layout de l’activitat i expressar la jerarquia de Views és a través d’uns fitxers XML de layout, que proporcionen una estructura del layout que resulta fàcil de seguir pel programador. Cada element XML és un objecte View o ViewGroup. Els objectes View serien les fulles de l’arbre i els objectes ViewGroup les branques de l’arbre (fixeu-vos en la figura). Per exemple, el fitxer XML d’un layout lineal vertical amb quatre botons seria el següent:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:orientation="vertical">
  7.  
  8. <Button
  9. android:id="@+id/btnMapa"
  10. android:layout_width="fill_parent"
  11. android:layout_height="wrap_content"
  12. android:text="Mapa"/>
  13.  
  14. <Button
  15. android:id="@+id/btnWeb"
  16. android:layout_width="fill_parent"
  17. android:layout_height="wrap_content"
  18. android:text="Web"/>
  19.  
  20. <Button
  21. android:id="@+id/btnContactes"
  22. android:layout_width="fill_parent"
  23. android:layout_height="wrap_content"
  24. android:text="Contactes"/>
  25.  
  26. <Button
  27. android:id="@+id/btnTrucar"
  28. android:layout_width="fill_parent"
  29. android:layout_height="wrap_content"
  30. android:text="Trucar"/>
  31.  
  32. </LinearLayout>

Fixeu-vos com el LinearLayout conté els elements Button. Es podria niuar un altre LinearLayout (o un altre tipus de ViewGroup) dins seu per afegir complexitat al layout. Si voleu saber més sobre els fitxers de layout XML, podeu consultar la Guia del desenvolupador d’Android a developer.android.com/guide/topics/ui/declaring-layout.html.

Si voleu veure les diferents característiques dels diferents layouts, les podeu trobar a developer.android.com/guide/topics/ui/layout-objects.html.

Creació del 'layout'

Per mostrar els diferents tipus de layout que existeixen es poden crear UI mitjançant l’edició d’un fitxer XML o mitjançant l’editor gràfic que proporciona Android Studio. Per obrir-lo, obriu el fitxer .xml que es troba a la carpeta res/layout del projecte.

Disposem de dues maneres fer de servir els layout existents:

  • Mitjançant l’edició d’un fitxer XML
  • Mitjançant l’editor gràfic que proporciona Android Studio

Per fer servir l’editor gràfic d’Android Studio cal que obriu el fitxer XML que es troba a la carpeta res/layout del projecte.

A la figura podeu veure les diferents parts de l’editor.

Figura Editor de GUI a Android Studio

Les diferents parts són les següents:

  • Visualització de GUI (graphic user interface, interfície gràfica d’usuari): amb aquestes pestanyes podeu escollir si voleu veure la GUI com un fitxer de text de tipus XML (pestanya “Text”) o bé la seva representació gràfica (pestanya “Design”).
  • Opcions generals: inclou algunes opcions per visualitzar el layout, segons:
    • El tipus de dispositiu: mida de pantalla i resolució.
    • El seu format (emmarcat o apaïsat).
    • El seu idioma.
    • La versió de l’SDK.
    • El tema disponible.
  • Jerarquia de Views: a la dreta podeu veure la jerarquia de Views i ViewGroups que formen part de la GUI. Podeu fer clic a cadascuna d’elles per seleccionar-les i així modificar les seves propietats al requadre corresponent. Feu servir aquesta representació per tenir clar com està estructurada la vostra GUI.
  • Representació gràfica: aquí podeu veure com es mostrarà la vostra interfície gràfica. Podeu seleccionar els Views i ViewGroups i desplaçar-los per les diferents parts de la GUI. Igualment, fent clic sobre cada element podreu modificar les seves propietats.
  • Paleta: aquí teniu els diferents Views i ViewGroups que podeu fer servir a la vostra GUI. Per afegir qualsevol d’aquests Views, els podeu arrossegar amb el ratolí a la representació gràfica del GUI o dins de la jerarquia de Views. De vegades és més senzill introduir els Views a la jerarquia a través de la paleta. Feu clic a les diferents carpetes (Widgets, Text Fields, Layouts…) per fer una ullada als diferents elements gràfics amb els quals podeu treballar.
  • Opcions de visualització: us permeten modificar la forma en què es visualitza la representació gràfica de la GUI.
  • Opcions de l’element seleccionat: ofereix diferents opcions que es poden aplicar a l’element seleccionat. Les opcions varien entre els diferents Views; per tant, quan seleccioneu un View cal que us fixeu en quines són les seves opcions.

Android Studio dóna ajuda contextual sobre el cursor del ratolí. Si deixeu el cursor sobre els diferents botons de l’editor, us apareixerà una petita etiqueta explicant què fa aquest botó.

Els Views i ViewGroups tenen una sèrie d’atributs comuns que podeu veure a la taula.

Taula: Atributs comuns de View i ViewGroup
Atribut Descripció.
layout_width Amplada del View.
layout_height Alçada del View.
layout_marginTop Especifica l’espai extra a dalt del View.
layout_marginBottom Especifica l’espai extra a baix del View.
layout_marginLeft Especifica l’espai extra a l’esquerra del View.
layout_marginRight Especifica l’espai extra a la dreta del View.
layout_gravity Especifica com els Views fills es posicionen.
layout_weight Especifica quant de l’espai extra del layout s’hauria de reservar per al View.
layout_x Especifica la coordenada x del View.
layout_y Especifica la coordenada y del View.

Atributs del View

Alguns dels atributs del View únicament són aplicables quan el View està dins d’un ViewGroup. Per exemple, els atributs layout_weight i layout_gravityúnicament s’apliquen quan el View està dins d’un LinearLayout o TableLayout.

Podeu veure els diferents tipus de layouts disponibles a la Guia del desenvolupador d’Android: developer.android.com/resources/tutorials/views/index.html.

Tot seguit veurem el funcionament de LinearLayout; hem triat aquest layout perquè és el més senzill de fer servir. Si feu una ullada a la part de la documentació oficial que parla dels diferents layouts podreu veure altres estils gràfics disponibles.

Un LinearLayout mostra els Views en una única fila o columna, vertical o horitzontalment. Per exemple, a la figura podeu veure un LinearLayout on hem introduït quatre botons.

Figura Amb un ‘Linear Layout’ els components es distribueixen linealment

Clicant el botó dret del ratolí sobre LinearLayout podeu veure i modificar a la jerarquia de Views algunes de les seves propietats. Per exemple, si canvieu l’orientació a Orientation/Horizontal veureu com els botons es disposen de manera horitzontal, tal com es pot veure a la figura.

Figura ‘Linear Layout’ horitzontal

Podeu niuar els layouts els uns dins dels altres per crear disposicions més complexes, tal com es pot veure a la figura.

Figura ‘Linear Layout’ niuats

Podeu modificar les propietats de cada View seleccionant-les en el requadre Properties. Per exemple, podeu canviar el valor de l’ID que identifica el View, o les seves dimensions d’amplada i alçada. En la figura podeu veure tres botons amb amplades diferents. El primer té l’amplada que ve per defecte, al segon li hem assignat el valor Fill Parent (omplir pare) a la propietat Layout Width(amplada del layout), i al tercer li hem assignat per aquesta mateixa propietat el valor de 100 dp (100 punts de pantalla).

Figura Diferents valors de ‘Layout Width’

Finalment, a partir del layout que creeu mitjançant les eines gràfiques es generarà un fitxer XML amb el qual el sistema Android sabrà com crear la interfície gràfica en temps d’execució. Per exemple, el layout de la figura correspon al següent fitxer XML:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@+id/LinearLayout1"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:orientation="vertical">
  7.  
  8. <Button
  9. android:id="@+id/button1"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:text="Button"/>
  13.  
  14. <Button
  15. android:id="@+id/button2"
  16. android:layout_width="fill_parent"
  17. android:layout_height="wrap_content"
  18. android:text="Button"/>
  19.  
  20. <Button
  21. android:id="@+id/button3"
  22. android:layout_width="100dp"
  23. android:layout_height="wrap_content"
  24. android:text="Button"/>
  25.  
  26. </LinearLayout>

Al començament és normal que feu servir l’editor gràfic per crear els vostres layouts, però quan aneu agafant experiència veureu que editar directament el fitxer XML fa molt més ràpida l’edició del layout.

Unitats de mesura

Per especificar la mida d’un element a la interfície gràfica d’Android es poden fer servir les següents unitats de mesura:

  • dp (density-independent pixel, píxel independent de la densitat). És la recomanada per especificar la mida dels Views en el vostre layout.
  • sp (scale-independent pixel, píxel independent de l’escala). Similar a la dp i recomanada per especificar mides en general.
  • pt (point, punt). Un punt està especificat com 1/72 d’una polsada; està basat en la mida física de la pantalla.
  • px (pixel). Correspon als píxels reals en pantalla. Aquesta mida no es recomana, atès que la vostra interfície gràfica es pot mostrar de formes diferents en els diferents dispositius.

'Layouts' XML

El layout defineix la forma en què els elements gràfics de l’activitat es mostren a l’usuari. Es pot declarar el layout de dues maneres diferents:

  • Declarant els elements gràfics a un fitxer XML. Aquest fitxer contindrà les Views i les seves subclasses que definiran l’UI. L’avantatge d’aquest sistema és que permet separar la presentació de l’aplicació del codi que la controla. Així, podeu modificar la UI (o adaptar-la a un altre dispositiu) sense haver de recompilar el projecte. Per exemple, podeu crear diferents layouts XML per a diferents mides de pantalla, diferents orientacions de la pantalla o diferents llenguatges.
  • Instanciant els elements del layout en temps d’execució. Es poden crear els elements gràfics des del mateix programa. Això és útil quan voleu crear una UI en funció d’alguna cosa que no sabeu en el moment de dissenyar l’aplicació (per exemple, en funció d’unes dades que rebeu per Internet).

Podeu fer servir qualsevol dels dos mètodes (tot i que generalment fareu servir el primer), i fins i tot ambdós a la vegada. Podeu dissenyar la UI de l’aplicació i després, en temps d’execució, modificar l’estat dels elements que estan en pantalla.

En general, el vocabulari XML per declarar interfícies d’usuari té una estructura similar als noms corresponents a les classes i mètodes que representen. Així, és fàcil saber a quines classes i atributs corresponen els elements de l’XML (encara que no sempre són idèntiques).

Es poden crear layouts d’UI i els elements que contenen ràpidament, fent servir un fitxer XML de la mateixa manera que es creen les pàgines web amb HTML, amb una sèrie d’element niuats. Cada fitxer layout ha de tenir un element arrel, que ha de ser un objecte View o ViewGroup. Una vegada definit l’element arrel, podeu afegir widgets o objectes de layout com a elements fills de l’arrel per crear a poc a poc la jerarquia de Views que definirà el vostre layout. Per exemple, podeu veure tot seguit el fitxer XML d’un layout que usa un LinearLayout i que inclou a dins un TextView i un Button:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6.  
  7. <TextView
  8. android:id="@+id/text"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="Hola, sóc un TextView"/>
  12.  
  13. <Button
  14. android:id="@+id/button"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:text="Hola, sóc un Button"/>
  18. </LinearLayout>

Carregar el recurs XML

Podeu trobar els fitxers d’android.R a dins del directori app/build/generated/source/ r/debug, accessibles des de la vista Project de l’explorador del projecte.

Els fitxers XML de layout són compilats a la vostra aplicació dins d’un recurs View. Això es produeix quan, en iniciar-se l’aplicació, és cridat el mètode de callback onCreate() de la vostra activitat, mètode a través del qual es carrega el recurs del layout des del codi. Per dur a terme aquest procés, crideu el mètode setContentView (int layoutResID), que té com a argument un identificador de recurs de layout. Aquest ID, el podeu trobar a la classe que conté els recursos android.R. Concretament, els identificadors de layouts es troben dins de R.layout.nom_del_fitxer_layout. Així, si el nostre layout està contingut al fitxer principal.xml, trobareu l’identificador a R.layout.principal. La forma de carregar aquest recurs seria la següent:

  1. public void onCreate(Bundle savedInstanceState)
  2. {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.principal);
  5. }

Atributs

Els objectes de les classes View i ViewGroup tenen els seus propis atributs. Alguns d’ells són comuns a tots els Views, com l’ID, mentre que d’altres són específics de cada tipus de View; per exemple els TextView tenen l’atribut textSize, que no està present en tots els Views.

Tots els objectes View tenen un número d’ID al qual estan associats, i que identifiquen el View de forma unívoca. Aquest ID està present en forma de string al fitxer XML, encara que en compilar l’aplicació és referenciat mitjançant un Integer. Aquest atribut és present a tots els objectes View i derivats d’ell. La sintaxi per definir l’ID al fitxer XML és la següent:

  1. android:id="@+id/el_meu_boto"

El símbol + diu al compilador que es tracta d’un nou recurs i que s’ha de crear i afegir als recursos del projecte (que es troben al fitxer “R.java”). Quan es fa referència a un ID de recurs d’Android, s’ha de fer així:

  1. android:id="@android:id/empty"

Introduint el namespace del paquet, esteu referenciant l’ID de la classe de recursos android.R.

La forma habitual de crear Views i referenciar-los des de l’aplicació és la següent:

En primer lloc, cal definir el View en el fitxer XML de layout i assignar-li un ID únic:

  1. <Button android:id="@+id/botoAcceptar"
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:text="@string/acceptar"/>

Tot seguit creeu la instància de l’objecte View (o classe derivada d’ell) que correspongui i referencieu-lo al del layout (generalment es fa servir la funció de callback onCreate()):

  1. Button Boto =(Button) findViewById(R.id.botoAcceptar);

A partir d’aquest moment ja podeu començar a treballar amb el botó des del codi.

'Widget' i events de teclat

Un widget és un objecte View que serveix d’interfície d’interacció amb l’usuari. Existeixen multitud de widgets ja implementats a Android, com botons, checkboxes, caixes de text, etc. El programador pot crear els seus propis widgets definint una classe que sigui descendent de View o d’un widget ja existent (per exemple, pot heretar les propietats d’una caixa de text).

Una vegada afegits els widgets, caldrà programar la interacció entre el programa i l’usuari. Cal que captureu els events de l’objecte View amb què l’usuari està interactuant i fer que succeeixi quelcom (executar una part de codi).

La classe View (de la qual els widgets hereten les propietats) té una sèrie de mètodes de callback que serveixen per tractar els events de la interfície gràfica. Aquests mètodes són cridats pel sistema quan l’acció corresponent succeeix en aquest objecte. Per exemple, quan es toca un botó, el sistema crida el mètode de callback onTouchEvent().

La classe View té una sèrie d’interfícies anomenades On<quelcom>Listener, cadascuna amb un mètode de callback anomenat on<quelcom>(). Per exemple, OnClickListener (per tractar els clics a un View) defineix el mètode onClick().

Aquestes interfícies, anomenades event listeners (escoltadors d’esdeveniments), us permeten capturar la interacció de l’usuari amb la UI. Si voleu que el vostre View sigui notificat en ser clicat, heu d’implementar l’interfície OnClickListener, definir el mètode onClick(), que establirà l’acció que s’ha de realitzar quan es faci clic, i registrar-lo al View amb setOnClickListener().

Un event listener és una interfície de la classe View que conté un únic mètode de callback. Aquests mètodes seran cridats pel sistema Android quan el View (al qual està registrat l’event listener) s’activa per la interacció de l’usuari.

Per exemple, podeu definir un event listener amb un mètode de callback i registrar-lo a un View de tipus botó. Quan l’usuari premi el botó, el sistema cridarà el mètode de callback definit i podreu executar el codi que vulgueu.

Per això heu de definir un event listener i registrar-lo al View. Un event listener és un mètode que es cridarà pel sistema quan es produeixi un esdeveniment en concret, per exemple quan es premi un botó.

Per registrar un event listener, en primer lloc heu d’obtenir una referència al View sobre el que voleu definir la funció de callback. Per obtenir la referència podeu fer servir el mètode findViewById(int id) de l’objecte de l’activitat. L’argument del mètode (l’identificador) és el que està definit al fitxer AndroidManifest.xml i el podeu obtenir a partir de l’objecte R.id.

Per exemple, per obtenir una referència a un botó anomenat “buttonSi” faríeu el següent:

  1. Button btnSi;
  2.  
  3. //Listener delbotoSi
  4. btnSi = (Button) findViewById(R.id.buttonSi);

Podeu trobar tots els identificadors de widgets de la vostra activitat a la variable R.id. Una vegada tingueu la referència al botó, fareu una crida al mètode setOnClickListener (View.OnClickListener l). Aquest mètode registra el callback que serà invocat quan aquest View sigui clicat. Com a únic argument, se li passa la funció de callback que s’executarà.

Ho podeu fer de dues maneres diferents. A la primera, senzillament, definiu la funció de callback a la mateixa crida a setOnClickListener(). Per exemple:

  1. btnSi.setOnClickListener(
  2.  
  3. new OnClickListener()
  4. {
  5. @Override
  6. publicvoid onClick(View v)
  7. {
  8. //Codi que s'executarà quan es faci clic
  9. Toast.makeText(c, "Boton si", Toast.LENGTH_LONG).show();
  10. }
  11. }
  12. );

En aquest codi es cridasetOnClickListener() i com a argument es fa una implementació de la interfície OnClickListener() que té un únic mètode per definir, onClick(). Dins d’aquest mètode estarà el codi que s’executarà quan es premi aquest botó. En aquest cas, el codi correspon a mostrar un missatge per pantalla amb Toast.

Això s’hauria de fer per cada View que existeixi al layout i amb què es vulgui interactuar.

La segona forma consisteix a implementar OnClickListener com a part de l’activitat. Això evitarà haver de crear totes les implementacions de OnClickListener, simplement diem que la nostra activitat implementa la interfície OnClickListener afegint-ho a la seva definició amb:

  1. public class ProvabotonsActivity extends Activity implements OnClickListener {

Ara, l’activitat ja implementa la interface, i únicament s’ha de sobreescriure el mètode OnClick(View v). En aquest cas es cridarà aquest mètode independentment de quin View hagi estat clicat, per tant el primer que s’haurà de fer és comprovar quin ha sigut l’objecte clicat, com es pot veure al següent codi:

  1. public class ProvabotonsActivity extends Activity implements OnClickListener {
  2.  
  3. Button btnSi, btnNo;
  4.  
  5. @Override
  6. public void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.main);
  9.  
  10. //Definim els listeners
  11. btnSi = (Button)findViewById(R.id.buttonSi);
  12. btnSi.setOnClickListener(this);
  13. btnNo = (Button)findViewById(R.id.buttonNo);
  14. btnNo.setOnClickListener(this);
  15. }
  16.  
  17. public void onClick(View v)
  18. {
  19. // Fer alguna cosa quan s'ha polsat un View.
  20.  
  21. // Comprovem quin ha estat el View clicat.
  22. if(v== btnSi)
  23. {
  24. //Executem el codi
  25. Toast.makeText(this, "Botó si", Toast.LENGTH_LONG).show();
  26. }
  27. else if(v == btnNo)
  28. {
  29. Toast.makeText(this, "Botó no", Toast.LENGTH_LONG).show();
  30. }
  31. }
  32. }

A les interfaces d’event listeners existeixen el següents mètodes de callback:

  • onClick(): de OnClickListener. Es crida quan l’usuari fa clic en l’ítem.
  • onLongClick(): de OnLongClickListener. Es crida quan l’usuari fa una pulsació llarga damunt de l’ítem.
  • onFocusChange(): de OnFocusChangeListener. Es crida quan l’usuari navega en o fora de l’ítem fent servir els cursors o el trackball.
  • onKey(): de OnKeyListener. Es crida quan l’usuari té el focus a l’ítem i prem o solta una tecla del dispositiu.
  • onTouch(): de OnTouchListener. Es crida quan l’usuari fa una acció de tocar l’ítem (inclou prémer, soltar o un gest sobre l’ítem).
  • onCreateContextMenu(): de OnCreateContextMenuListener. Es crida quan un menú contextual es crea sobre l’ítem (resultat d’una pulsació llarga o de la pulsació de la tecla de menú).
Anar a la pàgina anterior:
Exercicis d'autoavaluació
Anar a la pàgina següent:
Activitats