IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Menus Android

Els menús són un component d'interfície d'usuari molt comuns en molts tipus d'aplicacions. Android proporciona una API de menús que permet presentar accions d'usuari d'una forma familiar i consistent. Els menús es gestionen principalment a partir de la Vista Android:

 android.view.Menu

Des de la versió Android 3.0 (API level 11), ja no és necessari proveir d'un botó de menú dedicat. Cal tenir en compte que a més s'imposa el paradigma de disseny basat en Action Bar. Ja no és necessari proveir d'un menú amb totes les opcions sinó que es poden destacar les opcions de menú més importants posant-les a l'action bar.

Action bar

La barra d'accions (aka Action bar) és una característica d'Android que identifica l'aplicació i la situació de l'usuari alhora que proveeix d'accions d'usuari i modes de navegació. La barra es pot trobar a la majoria d'activitats a les que és important mostrar als usuaris les accions que es poden dur a terme i les opcions de navegació per l'aplicació.

La barra s'ha convertit en un paradigma de disseny que permet oferir als usuaris interfícies consistents entre diferents aplicacions. A més el sistema adapta de forma automàtica l'apariència de la barra per a diferents configuracions de pantalla.

Existeix una API especifica per a la barra d'accions que es va afegir a la versió 2.0 d'Android (API level 11)

Els objectius principals de la barra de navegació són:

  • Proveir d'un espai dedicat a la pantalla per tal d'identificar la marca de l'aplicació (aka brand) i la localització de l'usuari dins l'aplicació. això s'aconsegueix amb l'icona o logo de l'aplicació que apareix a l'esquerra del titol de l'activitat (tot això es però configurable)
  • Proveïx d'una navegació consistent i un refinament de la vista (View) entre diferents aplicacions. La barra d'acció porta un navegadors de pestanyes (tag navigation) incorporat que permet canviar entre els diferents fragments de l'aplicació de forma ràpida. També ofereix un llista desplegable ( drop-down list) que es pot utilitzar com una alternativa de navegació o per refinar la vista actual.
  • Fa que les accions principals (com cercar, crear, compartir, etc) tinguin un espai prominent i siguin accesibles per a l'usuari d'un forma previsible. Es pot proporcionar accés instantani a les accions d'usuari claus col·locant-les a la barra d'accions com a action items. Els Action items també poden proporcionar una action view, que mostra un widget encastat per tal de mostrar encara més possibles accions. Els items de menú que no són promocionats a la barra d'accions es troben disponibles al overflow menu, que es pot mostrar mitjançant el botó de Menú del dispositiu ( quan es troba disponible) o per un botó que apareix a la barra d'acció (quan el dispositiu no té botó de menú). Vegeu un exemple (per a més informació vegeu Menu guide):
actionbar.png

Recursos:

Estructura

The action bar is a dedicated piece of real estate at the top of each screen that is generally persistent throughout the app.

It provides several key functions:

   Makes important actions prominent and accessible in a predictable way (such as New or Search).
   Supports consistent navigation and view switching within apps.
   Reduces clutter by providing an action overflow for rarely used actions.
   Provides a dedicated space for giving your app an identity.

If you're new to writing Android apps, note that the action bar is one of the most important design elements you can implement. Following the guidelines described here will go a long way toward making your app's interface consistent with the core Android apps.

Tur12.png

L'Action bar té els següents components:

App icon

   The app icon establishes your app's identity. It can be replaced with a different logo or branding if you wish. Important: If the app is currently not displaying the top-level screen, be sure to display the Up caret to the left of the app icon, so the user can navigate up the hierarchy. For more discussion of Up navigation, see the Navigation pattern.
   App icon with and without "up" affordance.
   View control
   If your app displays data in different views, this segment of the action bar allows users to switch views. Examples of view-switching controls are drop-down menus or tab controls.
   If your app doesn't support different views, you can also use this space to display non-interactive content, such as an app title or longer branding information.
   Action buttons
   Show the most important actions of your app in the actions section. Actions that don't fit in the action bar are moved automatically to the action overflow. Long-press on an icon to view the action's name.
   Action overflow
   Move less often 

Afegir una Action bar

Des de la versió Android 3.0 (API level 11), la barra d'acció s'inclou per defecte a totes les activitats que utilitzen el tema:

Theme.Holo

O qualsevol tema que en sigui un descendent. Aquest tema és el tema per defecte quan qualsevol dels atributs:

 targetSdkVersion

o

minSdkVersion

té un valor de 11 o superior al fitxer de manifest.

 <manifest ... >
    <uses-sdk android:minSdkVersion="4"
              android:targetSdkVersion="11" />
    ...
 </manifest>

Eliminar la barra d'accions

Si no es vol utilitzar la barra d'accions per a una activitat en particular, aleshores cal utilitzar el tema:

Theme.Holo.NoActionBar

Per exemple:

 <activity android:theme="@android:style/Theme.Holo.NoActionBar">

En temps d'execució també es pot amagar la barra amb el mètode

hide()

Per exemple:

 ActionBar actionBar = getActionBar();
 actionBar.hide();

Es pot tornar a mostrar amb:

show()

NOTA: Si l'activitat ha de mostrar i amagar molt sovint la barra d'accions es recomana utilitzar el move overlay:

android:windowActionBarOverlay=true

També es pot posar l'estil:

android:windowActionBar=false

Però aleshores no podreu utilitzar en cap moment la barra d'acció a aquesta activitat (getActionBar() retorna null)

Afegir Action items

Els items d'acció de la barra d'acció no són més que ítems del menú que han estat "promocionats" a la barra d'accions. Això es pot fer declarant que el menu item és de tipus:

action item

Un ítem d'acció pot incloure una icona i/o un text. La resta de ítems apareixen al overflow menu que es mostra utilitzant el Menu button (si el dispositiu en té) o amb un botó adicional.

actionbar-item-withtext.png

Quan l'activitat s'inicia per primer com omple la barra d'acció cridant a la funció:

onCreateOptionsMenu()

de l'activitat (vegeu també Menus developer guide). Vegem un exemple:

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_activity, menu);
    return true;
 }

Al fitxer XML es pot demanar a un ítem que aparegui si hi ha espai amb:

android:showAsAction="ifRoom"

Per a l'element:

<item>

Si no hi ha prou espai es mostra al overflow menu.

Si l'ítem proporciona una icona:

android:icon

i una títol:

android:title

Aleshores només es mostra la icona. Si es vol mostrar el text cal utilitzar withText a:

android:showAsAction

Un exemple:

<?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/ic_menu_save"
          android:title="@string/menu_save"
          android:showAsAction="ifRoom|withText" />
</menu>

Quan un usuari selecciona un item aleshores es crida el mètode:

onOptionsItemSelected()

Passant el ID (android:id) del item seleccionat.

IMPORTANT: Cal sempre definir android:title per cada ítem de menú per 3 raons:

  • si no hi ha prou espai per mostra l'acció es mostrarà pel seu nom al overflow menu.
  • Per temes d'accesibilitat ( els Screen readers llegeixen l'ítem)
  • Per mostrar un tip amb la descripció quan es va un long-press sobre l'icona.

NOTA: If you added the menu item from a fragment, via the Fragment class's onCreateOptionsMenu callback, then the system calls the respective onOptionsItemSelected() method for that fragment when the user selects one of the fragment's items. However the activity gets a chance to handle the event first, so the system calls onOptionsItemSelected() on the activity before calling the same callback for the fragment.

També es pot declarar un item per apareixer sempre amb el valor always.

Remaining backward-compatible

If you want to provide an action bar in your application and remain compatible with versions of Android older than 3.0, you need to create the action bar in your activity's layout (because the ActionBar class is not available on older versions).

To help you, the Action Bar Compatibility sample app provides an API layer and action bar layout that allows your app to use some of the ActionBar APIs and also support older versions of Android by replacing the traditional title bar with a custom action bar layout.

Choosing your action items

Menu items vs. other app controls

As a general rule, all items in the options menu (let alone action items) should have a global impact on the app, rather than affect only a small portion of the interface. For example, if you have a multi-pane layout and one pane shows a video while another lists all videos, the video player controls should appear within the pane containing the video (not in the action bar), while the action bar might provide action items to share the video or save the video to a favorites list.

So, even before deciding whether a menu item should appear as an action item, be sure that the item has a global scope for the current activity. If it doesn't, then you should place it as a button in the appropriate context of the activity layout.

You should carefully choose which items from your options menu should appear as action items by assessing a few key traits. In general, each action item should be at least one of the following:

   Frequently used: It's an action that your users need seven out of ten visits or they use it several times in a row.
   Example frequent actions: "New message" in the Messaging app and "Search" on Google Play.
   Important: It's an action that you need users to easily discover or, if it's not frequently used, it's important that it be effortless to perform in the few cases that users do need it.
   Example important actions: "Add network" in Wi-Fi settings and "Switch to camera" in the Gallery app.
   Typical: It's an action that is typically provided in the action bar in similar apps, so your users expect to find it in yours.
   Example typical actions: "Refresh" in an email or social app, and "New contact" in the People app.

If you believe that more than four of your menu items can be justified as action items, then you should carefully consider their relative level of importance and try to set no more than four as action items (and do so using the "ifRoom" value to allow the system to put some back in the overflow menu when space is limited on smaller screens). Even if space is available on a wide screen, you should not create a long stream of action items that clutter the UI and appear like a desktop toolbar, so keep the number of action items to a minimum.

Additionally, the following actions should never appear as action items: Settings, Help, Feedback, or similar. Always keep them in the overflow menu.

Note: Remember that not all devices provide a dedicated hardware button for Search, so if it's an important feature in your app, it should always appear as an action item (and usually as the first item, especially if you offer it with an action view).

Using split action bar

When your application is running on Android 4.0 (API level 14) and higher, there's an extra mode available for the action bar called "split action bar." When you enable split action bar, a separate bar appears at the bottom of the screen to display all action items when the activity is running on a narrow screen (such as a portrait-oriented handset). Splitting the action bar to separate the action items ensures that a reasonable amount of space is available to display all your action items on a narrow screen, while leaving room for navigation and title elements at the top.

To enable split action bar, simply add uiOptions="splitActionBarWhenNarrow" to your <activity> or <application> manifest element.

Be aware that Android adjusts the action bar's appearance in a variety of ways, based on the current screen size. Using split action bar is just one option that you can enable to allow the action bar to further optimize the user experience for different screen sizes. In doing so, you may also allow the action bar to collapse navigation tabs into the main action bar. That is, if you use navigation tabs in your action bar, once the action items are separated on a narrow screen, the navigation tabs may be able to fit into the main action bar rather than be separated into the "stacked action bar." Specifically, if you've disabled the action bar icon and title (with setDisplayShowHomeEnabled(false) and setDisplayShowTitleEnabled(false)), then the navigation tabs collapse into the main action bar, as shown by the second device in figure 3.

Figure 3. Mock-ups of split action bar with navigation tabs on the left; with the app icon and title disabled on the right.

Note: Although the android:uiOptions attribute was added in Android 4.0 (API level 14), you can safely include it in your application even if your minSdkVersion is set to a value lower than "14" to remain compatible with older versions of Android. When running on older versions, the system simply ignores the XML attribute because it doesn't understand it. The only condition to including it in your manifest is that you must compile your application against a platform version that supports API level 14 or higher. Just be sure that you don't openly use other APIs in your application code that aren't supported by the version declared by your minSdkVersion attribute—only XML attributes are safely ignored by older platforms.

Action Bar a mida

TABS: http://fizzylogic.nl/2012/03/05/mono-for-android-by-example-the-action-bar/
Android ActionBar style generator
       http://jgilfelt.github.com/android-actionbarstylegenerator/#name=example&compat=holo&theme=light&actionbarstyle=solid&backColor=E4E4E4%2C100&secondaryColor=D6D6D6%2C100&tertiaryColor=F2F2F2%2C100&accentColor=33B5E5%2C100

Menus

Definir els menus

Fragments

Un fragment representa un comportament o una porció de la interfície d'usuari d'una Activitat Android. Es poden combinar múltiples fragments en una sola activitat per tal de crear una User Interface (aka UI) multi-pane i reutilitzar els fragments en múltiples activitats. Es pot pensar en un fragment com una secció modular d'una activitat.

Els fragments són com activitats anidades dins d'altres Activitats i que tenen el seu propi layout i cicle de vida.

Són com subactivitats que es poden reutilitzar en altres activitats

Un fragment sempre ha de estar dins d'una activitat i el cicle de vida de l'activitat està associat al cicle de vida de l'activitat, per exemple si es destrueix una activitat també es destrueixen tots els fragments que conté. Cal tenir en compte però que quan una activitat esta executant-se, cada fragment es pot manipular de forma independent, com per exemple es pot afegir o eliminar. A aquestes accions les anomenen fragment transactions, per exemple es poden afegir a una back stack.

Quan s'afegeix un fragment al layout d'una activitat, s'ha de fer dins d'un ViewGroup i el fragment defineix el seu propi layout. S'utilitza l'element XML:

<fragment>

NOTA: Es poden utilitzar fragment que no formin part del layout de l'activitat, s'utilitzen com a invisible workers de l'activitat Android

Les qüestions que cal tenir en compte són:

  • Com mantenir l'estat dels fragments al afegir-los al back stack de l'activitat.
  • Com compartir esdeveniments amb l'activitat pare i altres fragments.
  • Com contribuir a l'Action bar de l'activitat pare.

En resum, el que cal tenir en compte dels Fragments és:

  • Descomposen la funcionalitat i el UI de les aplicacions en mòduls
  • s'afegeixen a una pantall per evitar la commutació entre activitats.
  • tenen el seu propi cicle de vida i back stack
  • Requereixen l'API 11 o superior.

Vegeu també Fragments

Recursos:

Filosofia de disseny

Els fragments es van introduir a la versió 3.0 (API level 11), sobretot per donar un millor suport i aplicacions més dinàmiques en pantalles grans, com les de les tablets.

Perquè la pantalla d'una pastilla és molt més gran que que d'un handset, hi ha més habitació per combinar i components d'UI de l'intercanvi. Els fragments permeten tals dissenys sense la necessitat per tu per dirigir canvis complexos a la jerarquia de vista. Per dividir el traçat d'una activitat a fragments, esdevens capaç de modificar l'aspecte de l'activitat a temps d'execució i conservar aquells canvis en un enrere stack allò és dirigit per l'activitat. Per exemple, una aplicació de notícia pot utilitzar un fragment per mostrar una llista d'articles a l'esquerra i un altre fragment per mostrar un article a la dreta—ambdós fragments apareixen dins una activitat, de costat, i cada fragment té el seu conjunt propi de lifecycle callback mètodes i manejar els seus esdeveniments d'entrada d'usuari propis. Així, en comptes d'utilitzar una activitat per seleccionar un article i una altra activitat per llegir l'article, l'usuari pot seleccionar un article i llegit el tot dins de la mateixa activitat, mentre il·lustrat en el traçat de pastilla dins figura 1.

T'Hauria de dissenyar cada fragment com a activitat modular i reutilitzable component. Allò és, perquè cada fragment defineix el seu traçat propi i el seu comportament propi amb el seu propi lifecycle callbacks, pots incloure un fragment en activitats múltiples, així que hauries de dissenyar per reutilització i evitar directament manipulant un fragment d'un altre fragment. Això és especialment important perquè un fragment modular et permet per canviar les vostres combinacions de fragment per mides de pantalla diferent. Quan dissenyant la vostra aplicació per donar suport ambdues pastilles i handsets, pots reutilització els vostres fragments en configuracions de traçat diferent per optimitzar l'experiència d'usuari basada en l'espai de pantalla disponible. Per exemple, en un handset, pugui ser necessari de separar fragments per proporcionar un sol-pane UI quan més d'un pot no cabut dins de la mateixa activitat.

Fragments.png
Figura 1. Un exemple de com dos mòduls d'UI van definir pels fragments poden ser combinats a una activitat per un disseny de pastilla, però separat per un handset disseny.

Per exemple per a continuar amb les noves aplicacions, per exemple la aplicacio pot contenir dos fragments dintre del Activity A, quant funciona en un tablet. Tanmateix, en un handset-sized pantalla, allà ha no prou habitació per ambdós fragments, així que Activitat Un inclou només el fragment per la llista d'articles, i quan l'usuari selecciona un article, comença Activitat B, el qual inclou el segon fragment per llegir l'article. Així, els suports d'aplicació tant pastilles i handsets per reusing fragments en combinacions diferents, mentre il·lustrat dins figura 1.

Per més informació aproximadament dissenyant la vostra aplicació amb combinacions de fragment diferent per configuracions de pantalla diferent, veure la guia a Donar suport Pastilles i Handsets.

Com crear un fragment

Figure 2. The lifecycle of a fragment (while its activity is running)
Fragment lifecycle.png

Per crear un fragment cal crear una classe filla de la classe Fragment:

Fitxer:Fragment.png

Aquesta classe se sembla molt a la classe Activity i té callback methods molt similars com

onCreate(), onStart(), onPause() i onStop(). 

De fet per convertir codi amb només Activitats a codi amb fragments, simplement caldrà moure els mètodes esmentats.

Els mètodes a implementar són:

  • onCreate(): The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
  • onCreateView():The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
  • onPause(): The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back).

Most applications should implement at least these three methods for every fragment, but there are several other callback methods you should also use to handle various stages of the fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section about Handling the Fragment Lifecycle.

Cal tenir en compte que l'API ja ens proporciona Fragments tipus com

Afegir una interfície d'usuari a un fragment

La principal diferència respecte a com s'afegeixen els layous a una activitat, és que no ho farem al mètode onCreate sinó al mètode:

onCreateView()

que és el mètode que el sistema operatiu Android crida quan és el moment de que el fragment sigui dibuixat per pantalla. El mètode ha de tornar una vista (View) que sigui l'arrel del layout del fragment.

Plantilla:Ntoa

Es pot obtenir l'arrel del layout inflant-la a partir d'un layout resource definit en XML. Vegem un exemple de com utilitzar el fitxer example_fragment.xml com a layout d'un fragment.

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);
    }
}
Crear un layout

Vegem com ha de ser el fitxer de layout. De l'exemple anterior el fitxer example_fragment.xml'. El paràmetre container és l'objecte:

ViewGroup

del layout de l'activitat pare, en el qual el fragment s'ha inserit.

El paràmetre savedInstanceState és un Bundle que permet fer persistent les dades de anteriors instàncies del fragment.

En tot cas els layouts es defineixen de forma similar a com es fa amb les activitats.

El mètode inflate() té 3 arguments:

  • El resource ID del layout del fragment
  • El ViewGroup del layout de l'activitat pare.
  • A boolean indicating whether the inflated layout should be attached to the ViewGroup (the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into the container—passing true would create a redundant view group in the final layout.)

Afegint un fragment a una activitat

Hi ha dos formes de fer-ho:

  • Estàtica: Declarar el fragment dins del layout de l'activitat.
  • Dinàmica: per codi afegir el Fragment a un ViewGroup existent.

Estàtica

Vegem un exemple:

    <?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>

On

android:name

indica la classe Fragment.

NOTA: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment: Supply the android:id attribute with a unique ID. Supply the android:tag attribute with a unique string. If you provide neither of the previous two, the system uses the ID of the container view.

Dinàmica

S'utilitza l'API FragmentTransaction:

 FragmentManager fragmentManager = getFragmentManager()
 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Per afegir un fragment.

    ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();

Com realitzar transaccions entre fragments

Una diferència important respecte a les activitats eś que podem utilitzar FragmentManager:

http://developer.android.com/reference/android/app/FragmentManager.html

Per afegir, eliminar o reemplaçar dinàmicament fragments a més d'altres accions en resposta a la interacció amb l'usuari.

Cada conjunt de canvis que es fan a una activitat els anomenem:

transaccions

i es poden realitzar utilitzant l'API FragmentTransaction:

http://developer.android.com/reference/android/app/FragmentTransaction.html

Això permet entre d'altres navegar endarrere entre fragments de la mateixa forma que ho fem amb les activitats.

Per obtenir un gestor de fragments:

 FragmentManager fragmentManager = getFragmentManager();
 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Cada transacció és un conjunt de canvis que es volen aplicar al mateix temps (de forma similar al concepte de transacció en base de dades). S'indiquen els canvis que es volen fer i un cop es volen aplicar de cop es crida a:

commit()

Sovint però abans de cridar commit es voldrà cridar:

 addToBackStack()

Per permetre la navegació endarrere. un exemple:

 // 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();

A l'exemple el fragment newFragment reemplaça el fragment actual.

NOTA: For each fragment transaction, you can apply a transition animation, by calling setTransition() before you commit

Cridant commit() no actua la transacció immediatament. Força, el planifica per córrer en l'activitat és fil d'UI (el "fil" principal) tan aviat com el fil és capaç de fer tan. Si és necessari, tanmateix, pots cridar executePendingTransactions() del vostre fil d'UI a immediatament executar les transaccions van entregar per commit(). Fent així que és normalment no necessari llevat que la transacció és una dependència per feines en altres fils.

Amonestació: pots cometre una transacció que utilitza commit() únic previ a l'activitat que salva el seu estat (quan l'usuari deixa l'activitat). Si intentes per cometre després d'allò punt, una excepció serà tirada. Això és perquè l'estat després del comet pot ser perdut si les necessitats d'activitat per ser restaurat. Per situacions en quin el seu okay que perds el cometre, ús commitAllowingStateLoss().

Afegint ítems al Action Bar

Els fragments poden crear ítems de menú al menú d'opcions ( i conseqüentment a l'Action Bar si s'escau) implementant el mètode:

onCreateOptionsMenu()

De fet igual que fan les activitats. Cal tenir en compte però que per rebre crides cal establir:

setHasOptionsMenu() 

Al:

onCreate()

Del Action Bar

Et També pot registrar una vista en el vostre traçat de fragment per proporcionar una carta de context per cridar registerForContextMenu(). Quan l'usuari obre la carta de context, el fragment rep una trucada a onCreateContextMenu(). Quan l'usuari selecciona un element, el fragment rep una trucada a onContextItemSelected().

Nota: Tot i que el vostre fragment rep un damunt-element-va seleccionar callback per cada element de carta afegeix, l'activitat és primer per rebre el respectiu callback quan l'usuari selecciona un element de carta. Si la implementació de l'activitat del damunt-element-va seleccionar callback no maneja l'element seleccionat, llavors l'esdeveniment és passat al fragment callback. Això és cert per la Carta d'Opcions i cartes de context.

Per més informació sobre menus, veure les Menus i guies de Action Bar developer.

Exemples

Handling the Fragment Lifecycle

Figure 3. The effect of the activity lifecycle on the fragment lifecycle.

Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like an activity, a fragment can exist in three states:

Resumed

   The fragment is visible in the running activity.

Paused

   Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn't cover the entire screen).

Stopped

   The fragment is not visible. Either the host activity has been stopped or the fragment has been removed from the activity but added to the back stack. A stopped fragment is still alive (all state and member information is retained by the system). However, it is no longer visible to the user and will be killed if the activity is killed.

Also like an activity, you can retain the state of a fragment using a Bundle, in case the activity's process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment's onSaveInstanceState() callback and restore it during either onCreate(), onCreateView(), or onActivityCreated(). For more information about saving state, see the Activities document.

The most significant difference in lifecycle between an activity and a fragment is how one is stored in its respective back stack. An activity is placed into a back stack of activities that's managed by the system when it's stopped, by default (so that the user can navigate back to it with the Back button, as discussed in Tasks and Back Stack). However, a fragment is placed into a back stack managed by the host activity only when you explicitly request that the instance be saved by calling addToBackStack() during a transaction that removes the fragment.

Otherwise, managing the fragment lifecycle is very similar to managing the activity lifecycle. So, the same practices for managing the activity lifecycle also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.

Caution: If you need a Context object within your Fragment, you can call getActivity(). However, be careful to call getActivity() only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getActivity() will return null. Coordinating with the activity lifecycle

The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause(), each fragment in the activity receives onPause().

Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment's UI. These additional callback methods are:

onAttach()

   Called when the fragment has been associated with the activity (the Activity is passed in here).

onCreateView()

   Called to create the view hierarchy associated with the fragment.

onActivityCreated()

   Called when the activity's onCreate() method has returned.

onDestroyView()

   Called when the view hierarchy associated with the fragment is being removed.

onDetach()

   Called when the fragment is being disassociated from the activity.

The flow of a fragment's lifecycle, as it is affected by its host activity, is illustrated by figure 3. In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. For example, when the activity has received its onCreate() callback, a fragment in the activity receives no more than the onActivityCreated() callback.

Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.

However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.

Example

To bring everything discussed in this document together, here's an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.

Note: The complete source code for this activity is available in FragmentLayout.java.

The main activity applies a layout in the usual way, during onCreate():

@Override protected void onCreate(Bundle savedInstanceState) {

   super.onCreate(savedInstanceState);
   setContentView(R.layout.fragment_layout);

}

The layout applied is fragment_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

   android:orientation="horizontal"
   android:layout_width="match_parent" android:layout_height="match_parent">
   <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
           android:id="@+id/titles" android:layout_weight="1"
           android:layout_width="0px" android:layout_height="match_parent" />
   <FrameLayout android:id="@+id/details" android:layout_weight="1"
           android:layout_width="0px" android:layout_height="match_parent"
           android:background="?android:attr/detailsElementBackground" />

</LinearLayout>

Using this layout, the system instantiates the TitlesFragment (which lists the play titles) as soon as the activity loads the layout, while the FrameLayout (where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you'll see below, it's not until the user selects an item from the list that a fragment is placed into the FrameLayout.

However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml.

Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved at res/layout/fragment_layout.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

   android:layout_width="match_parent" android:layout_height="match_parent">
   <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
           android:id="@+id/titles"
           android:layout_width="match_parent" android:layout_height="match_parent" />

</FrameLayout>

This layout includes only TitlesFragment. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.

Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment, which shows the list of Shakespeare play titles. This fragment extends ListFragment and relies on it to handle most of the list view work.

As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to the FrameLayout), or start a new activity (where the fragment can be shown).

public static class TitlesFragment extends ListFragment {

   boolean mDualPane;
   int mCurCheckPosition = 0;
   @Override
   public void onActivityCreated(Bundle savedInstanceState) {
       super.onActivityCreated(savedInstanceState);
       // Populate list with our static array of titles.
       setListAdapter(new ArrayAdapter<String>(getActivity(),
               android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
       // Check to see if we have a frame in which to embed the details
       // fragment directly in the containing UI.
       View detailsFrame = getActivity().findViewById(R.id.details);
       mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
       if (savedInstanceState != null) {
           // Restore last state for checked position.
           mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
       }
       if (mDualPane) {
           // In dual-pane mode, the list view highlights the selected item.
           getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
           // Make sure our UI is in the correct state.
           showDetails(mCurCheckPosition);
       }
   }
   @Override
   public void onSaveInstanceState(Bundle outState) {
       super.onSaveInstanceState(outState);
       outState.putInt("curChoice", mCurCheckPosition);
   }
   @Override
   public void onListItemClick(ListView l, View v, int position, long id) {
       showDetails(position);
   }
   /**
    * Helper function to show the details of a selected item, either by
    * displaying a fragment in-place in the current UI, or starting a
    * whole new activity in which it is displayed.
    */
   void showDetails(int index) {
       mCurCheckPosition = index;
       if (mDualPane) {
           // We can display everything in-place with fragments, so update
           // the list to highlight the selected item and show the data.
           getListView().setItemChecked(index, true);
           // Check what fragment is currently shown, replace if needed.
           DetailsFragment details = (DetailsFragment)
                   getFragmentManager().findFragmentById(R.id.details);
           if (details == null || details.getShownIndex() != index) {
               // Make new fragment to show this selection.
               details = DetailsFragment.newInstance(index);
               // Execute a transaction, replacing any existing fragment
               // with this one inside the frame.
               FragmentTransaction ft = getFragmentManager().beginTransaction();
               if (index == 0) {
                   ft.replace(R.id.details, details);
               } else {
                   ft.replace(R.id.a_item, details);
               }
               ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
               ft.commit();
           }
       } else {
           // Otherwise we need to launch a new activity to display
           // the dialog fragment with selected text.
           Intent intent = new Intent();
           intent.setClass(getActivity(), DetailsActivity.class);
           intent.putExtra("index", index);
           startActivity(intent);
       }
   }

}

The second fragment, DetailsFragment shows the play summary for the item selected from the list from TitlesFragment:

public static class DetailsFragment extends Fragment {

   /**
    * Create a new instance of DetailsFragment, initialized to
    * show the text at 'index'.
    */
   public static DetailsFragment newInstance(int index) {
       DetailsFragment f = new DetailsFragment();
       // Supply index input as an argument.
       Bundle args = new Bundle();
       args.putInt("index", index);
       f.setArguments(args);
       return f;
   }
   public int getShownIndex() {
       return getArguments().getInt("index", 0);
   }
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {
       if (container == null) {
           // We have different layouts, and in one of them this
           // fragment's containing frame doesn't exist.  The fragment
           // may still be created from its saved state, but there is
           // no reason to try to create its view hierarchy because it
           // won't be displayed.  Note this is not needed -- we could
           // just run the code below, where we would create and return
           // the view hierarchy; it would just never be used.
           return null;
       }
       ScrollView scroller = new ScrollView(getActivity());
       TextView text = new TextView(getActivity());
       int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
               4, getActivity().getResources().getDisplayMetrics());
       text.setPadding(padding, padding, padding, padding);
       scroller.addView(text);
       text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
       return scroller;
   }

}

Recall from the TitlesFragment class, that, if the user clicks a list item and the current layout does not include the R.id.details view (which is where the DetailsFragment belongs), then the application starts the DetailsActivity activity to display the content of the item.

Here is the DetailsActivity, which simply embeds the DetailsFragment to display the selected play summary when the screen is in portrait orientation:

public static class DetailsActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       if (getResources().getConfiguration().orientation
               == Configuration.ORIENTATION_LANDSCAPE) {
           // If the screen is now in landscape mode, we can show the
           // dialog in-line with the list so we don't need this activity.
           finish();
           return;
       }
       if (savedInstanceState == null) {
           // During initial setup, plug in the details fragment.
           DetailsFragment details = new DetailsFragment();
           details.setArguments(getIntent().getExtras());
           getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
       }
   }

}

Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment alongside the TitlesFragment. This can happen if the user begins the DetailsActivity while in portrait orientation, but then rotates to landscape (which restarts the current activity).

For more samples using fragments (and complete source files for this example), see the API Demos sample app available in ApiDemos (available for download from the Samples SDK component).


Communicating with the Activity

Although a Fragment is implemented as an object that's independent from an Activity and can be used inside multiple activities, a given instance of a fragment is directly tied to the activity that contains it.

Specifically, the fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:

View listView = getActivity().findViewById(R.id.list);

Likewise, your activity can call methods in the fragment by acquiring a reference to the Fragment from FragmentManager, using findFragmentById() or findFragmentByTag(). For example:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

Afegint un fragment sense UI

TODO

The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.

To add a fragment without a UI, add the fragment from the activity using add(Fragment, String) (supplying a unique string "tag" for the fragment, rather than a view ID). This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method.

Supplying a string tag for the fragment isn't strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag().

For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java sample. Managing Fragments

To manage the fragments in your activity, you need to use FragmentManager. To get it, call getFragmentManager() from your activity.

Some things that you can do with FragmentManager include:

   Get fragments that exist in the activity, with findFragmentById() (for fragments that provide a UI in the activity layout) or findFragmentByTag() (for fragments that do or don't provide a UI).
   Pop fragments off the back stack, with popBackStack() (simulating a Back command by the user).
   Register a listener for changes to the back stack, with addOnBackStackChangedListener().

For more information about these methods and others, refer to the FragmentManager class documentation.

As demonstrated in the previous section, you can also use FragmentManager to open a FragmentTransaction, which allows you to perform transactions, such as add and remove fragments.

Creating event callbacks to the activity

In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.

For example, if a news application has two fragments in an activity—one to show a list of articles (fragment A) and another to display an article (fragment B)—then fragment A must tell the activity when a list item is selected so that it can tell fragment B to display the article. In this case, the OnArticleSelectedListener interface is declared inside fragment A:

public static class FragmentA extends ListFragment {

   ...
   // Container Activity must implement this interface
   public interface OnArticleSelectedListener {
       public void onArticleSelected(Uri articleUri);
   }
   ...

}

Then the activity that hosts the fragment implements the OnArticleSelectedListener interface and overrides onArticleSelected() to notify fragment B of the event from fragment A. To ensure that the host activity implements this interface, fragment A's onAttach() callback method (which the system calls when adding the fragment to the activity) instantiates an instance of OnArticleSelectedListener by casting the Activity that is passed into 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");
       }
   }
   ...

}

If the activity has not implemented the interface, then the fragment throws a ClassCastException. On success, the mListener member holds a reference to activity's implementation of OnArticleSelectedListener, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener interface. For example, if fragment A is an extension of ListFragment, each time the user clicks a list item, the system calls onListItemClick() in the fragment, which then calls onArticleSelected() to share the event with the activity:

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.withAppendedId(ArticleColumns.CONTENT_URI, id);
       // Send the event and Uri to the host activity
       mListener.onArticleSelected(noteUri);
   }
   ...

}

The id parameter passed to onListItemClick() is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application's ContentProvider.

More information about using a content provider is available in the Content Providers document.