Laborator 4 - Liste

In aplicatiile realizate, un element important pe care il vom utiliza il reprezinta listele. Sub platforma Android, acestea sunt implementate folosind modelul MVC (Model View Controller). Modelul este reprezentat de datele ce trebuie afisate, View-ul este lista propriu-zisa si Controller-ul este programul care controleaza modul de afisare.

ListView

Un este un View care contine o lista de elemente, care poate fi parcursa. Un View de tip poate fi plasat pe orice tip de activitate. In mod normal, descriem ListView-ul in fisierul xml atasat activitatii, ii dam un id si in codul java luam un pointer catre el.

ListActivity

Exista un mod mai simplu decat folosirea unui . In general, pe o activitate exista o singura lista, astfel ca Android ne pune la dispozitie un tip special de activitate, numit , care rezolva automat preluarea pointer-ului listei. In XML, trebuie declarat obligatoriu un cu id-ul . De asemenea, ListActivity pune la dispozitie urmatoarele functii: // seteaza adaptorul pentru lista de pe fereastra void setListAdapter (ListAdapter adapter);

// intoarce adaptorul listei de pe fereastra ListAdapter getListAdapter ();

// intoarce un pointer catre lista din fereastra ListView getListView ();

O alta functie oferita de catre ListActivity este onListItemClick(). Acesta este apelata automat de fiecare data cand se executa un click asupra unui element din lista. Initial functia este vida, in alte cuvinte, nu face nimic. Pentru a-i adauga o actiune, programatorul trebuie sa suprascrie acesta functie. @Override

   public void onListItemClick (ListView list, View v, int position, long id)
   {
       // list - este lista de pe fereastra
       // v - este elementul din lista pe care s-a dat click
       // position - este pozitia pe care s-a dat click (de fapt pozitia la care se afla elementul v in lista)
       // id - este id-ul elementului (obtinut prin functia getItemId () a adaptorului)
   }

ListAdapter

In Android, lista este de fapt un vertical. Sarcina programatorului este de fapt crearea componentelor View pentru fiecare linie din acest , adica crearea unui element pe ecran pentru fiecare element pe care dorim sa il introducem in lista. In alte cuvinte, daca ne uitam la poza de mai sus, ceea ce trebuie noi sa facem este sa scriem componenta . Din punct de vedere ar programarii, asta inseamna crearea unui obiect care sa implementeze interfata . Biblioteciile Android ne pun la dispozitie mai multe variante de a implementa .

ArrayAdapter

Pentru liste simple, ce contin elemente cu o singura linie de text se poate folosi o clasa mult simplificata, si anume . Acesta presupune ca toate elementele sunt stocate intr-un sir (ex: Object[]) sau o lista (orice obiect ce implementeaza interfata ). Deoarece fiecare element din lista este o linie de text si in sir sau lista noi pastram obiecte, adaptorul va apela functia pe fiecare obiect. Un exemplu de folosire este urmatorul: class Personaj {

   public String nume;
   public String desen;

   @Override
   public String toString ()
   {
       // acesta functie este apelata de catre ArrayAdapter pentru a transforma obiectul intr-un String ce
       // sa fie afisat in lista
       return nume+" din desenul animat "+desen;
   } 

}

public class ListaDeseneAnimate extends ListActivity {

   ArrayList personaje;
   ArrayAdapter adapter;

   @Override
   public void onCreate (Bundle savedInstanceBundle)
   {
       super.onCreate (savedInstanceBundle);
       personaje = new ArrayList();
       adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, personaje);
       setContentView (R.layout.main);
       setListAdapter (adapter);

       // adaugam cateva personaje in lista
       adaugaFunnyGuy("Bugs Bunny", "Looney Toons");
       adaugaFunnyGuy("Fred Flinstone", "The Flinstones");
       adaugaFunnyGuy("Betty Rubble", "The Flinstones");
   }

   @Override
   public void onListItemClick (ListView list, View v, int position, long id)
   {
       // afisam numele personajului pe care s-a dat click folosind un Toast
       Toast.makeText(ListaDeseneAnimate.this, personaje.get(position).nume, Toast.LENGTH_LONG).show();
   }

   private void adaugaFunnyGuy (String nume, String desen)
   {
       Personaj p = new Personaj ();
       p.nume = nume;
       p.desen = desen;
       personaje.add (p);
       // acesta functie determina adaptorul sa ceara listei sa reafiseze continutul
       adapter.notifyDataSetChanged();
   }

}

Exercitii

  1. Realizati o lista (editabila) cu personaje din desene animate. Pe activitate veti avea posibilitatea de a adauga un personaj in lista. Stergerea se va face prin apasarea lunga ( sau ) pe un element din lista.

BaseAdapter

Pentru o lista ce trebuie sa afiseze informatii mai complexe decat un rand de text, trebuie sa scriem un adaptor (o clasa ce implmenteaza interfata ). Pentru ca interfata are foarte multe metode, un mod mai simplu este sa extindem clasa . De fapt trebuie sa implementam urmatoarele patru functii: class MyAdapter extends BaseAdapter {

   @Override
   public View getView (int position, View convertView, ViewGroup list) 
   {
       // functia trebuie sa intoarca view-ul de pe pozitia position din lista
       // convertView este un element din lista ce nu mai este vizibil si poate fi convertit
   }

   @Override
       public int getCount ()
       {
       // intoarce nr de elemente din lista
   }

   @Override
   public Object getItem(int position) 
   {
       // intoarce elementul de pe pozitia position din model
   }

   @Override
   public long getItemId(int position) 
   {
       // fiecare element din lista poate avea un id, nu este insa obligatoriu
   }

} Pentru a exemplifica mai bine, vom modifica exemplul de mai sus, astfel incat sa afisam doua linii de text. Clasa Personaj ramane aceeasi ca in exemplul precedent. Primul pas este sa realizam un nou fisier XML (separat) ce va descrie cum arata fiecare element grafic (View) din lista. Il vom plasa in . personaj.xml

   

   

Urmeaza sa realizam fisierul cu codul sursa. Acesta va contine o clasa ce extinde si clasa activitatii (). class Personaj {

   public String nume;
   public String desen;

   @Override
   public String toString ()
   {
       // acesta functie este apelata de catre ArrayAdapter pentru a transforma obiectul intr-un String ce
       // sa fie afisat in lista
       return nume+" din desenul animat "+desen;
   } 

}

class PersonajeAdapter extends BaseAdapter {

   private Activity context;
   ArrayList personaje;

   public PersonajeAdapter (Activity _context)
   {
       this.context = _context;
       personaje = new ArrayList();
   }

   @Override
   public View getView (int position, View convertView, ViewGroup list) 
   {
       // functia trebuie sa intoarca view-ul de pe pozitia position din lista
       // convertView este un element din lista ce nu mai este vizibil si poate fi convertit
       View element;
       LayoutInflater inflater = context.getLayoutInflater();
       element = inflater.inflate(R.layout.personaj, null);

       TextView nume = (TextView)element.findViewById(R.id.personaj_nume);
       TextView desen = (TextView)element.findViewById(R.id.personaj_desen);

       nume.setText(personaje.get(position).nume);
       desen.setText(personaje.get(position).desen);

       return element;
   }

   @Override
       public int getCount ()
       {
       // intoarce nr de elemente din lista
               return personaje.size ();
   }

   @Override
   public Object getItem(int position) 
   {
       // intoarce elementul de pe pozitia position din model
       return personaje.get(position);
   }

   @Override
   public long getItemId(int position) 
   {
       // fiecare element din lista poate avea un id, nu este insa obligatoriu
       return 0;
   }

       public void adaugaFunnyGuy (String nume, String desen)
       {
             Personaj p = new Personaj ();
             p.nume = nume;
             p.desen = desen;
             personaje.add (p);
             // acesta functie determina adaptorul sa ceara listei sa reafiseze continutul
             this.notifyDataSetChanged();
       }

}

public class ListaDeseneAnimate extends ListActivity {

   // ArrayList personaje; -> mutat in PersonajeAdapter
   PersonajeAdapter adapter;

   @Override
   public void onCreate (Bundle savedInstanceBundle)
   {
       super.onCreate (savedInstanceBundle);
       // personaje = new ArrayList(); -> mutat in Personaje Adapter
       adapter = new PersonajeAdapter (this);
       setContentView (R.layout.main);
       setListAdapter (adapter);

       // adaugam cateva personaje in lista
       adapter.adaugaFunnyGuy("Bugs Bunny", "Looney Toons");
       adapter.adaugaFunnyGuy("Fred Flinstone", "The Flinstones");
       adapter.adaugaFunnyGuy("Betty Rubble", "The Flinstones");

       // pentru a seta actiunea click lung
       getListView().setOnItemLongClickListener(new OnItemLongClickListener() 
       {

           public boolean onItemLongClick(AdapterView<?> listAdapter, View view,
                   int position, long id) 
           {
                               Personaj p = (Personaj)adapter.getItem (position);
                               Toast.makeText(this, "click lung pe "+p.nume, Toast.LENGTH_LONG).show();
               return true;
           }
       });
   }

   @Override
   public void onListItemClick (ListView list, View v, int position, long id)
   {
       // afisam numele personajului pe care s-a dat click folosind un Toast
       Personaj p = (Personaj)adapter.getItem (position);
       Toast.makeText(this, p.nume, Toast.LENGTH_LONG).show();
   }

} Sunt importante urmatoarele observatii:

  • modelul () a fost mutat in adaptor. Acesta este de fapt legatura intre lista si date, deci el este cel care trebuie sa cunoasca datele, si nu fereastra
  • implementarea functiei nu este eficienta, nu este folosit parametrul .
  • setarea actiunii pentru click-ul lung se face direct pe lista, nu exista o functie in ce sa poata fi suprascrisa

Implementarea eficienta presupune folosirea parametrului . Acesta este fie , caz in care trebuie ignorat, fie un obiect intors aterior de catre , insa obiect care nu mai este vizibil. Ideea este ca, in loc de a crea un nou View de fiecare data, sa se refoloseasca View-urile create anterior si care nu mai sunt vizibile. @Override

   public View getView (int position, View convertView, ViewGroup list) 
   {
       // functia trebuie sa intoarca view-ul de pe pozitia position din lista
       // convertView este un element din lista ce nu mai este vizibil si poate fi convertit
       View element;
               if (convertView == null)
               {
                LayoutInflater inflater = context.getLayoutInflater();
                element = inflater.inflate(R.layout.personaj, null);
               }
               else element = convertView;

       TextView nume = (TextView)element.findViewById(R.id.personaj_nume);
       TextView desen = (TextView)element.findViewById(R.id.personaj_desen);

       nume.setText(personaje.get(position).nume);
       desen.setText(personaje.get(position).desen);

       return element;
   }

Exercitii

  1. Realizati o lista mai complexa pentru afisarea personajelor din desene animate. Pe fereastra veti avea posibilitatea de a introduce un nou personaj. Nu folositi parametrul ! Fiecare personaj contine:
    • Nume
    • Desenul animat din care face parte
    • O poza (poza va fi aleasa in functie de butonul de adaugare apasat)
  2. Modificati problema precedenta, folosind , insa setati valorile View-urilor doar la creare. (In alte cuvinte, daca , pur si simplu il intoarceti, fara sa il modificati.) Observati ce se intampla.
  3. Modificati problema precedenta, folosind corespunzator .
  4. Optimizati lista de la exercitiul precedent, folosind tag-ul View-urilor.
pdm/laboratoare/04.txt · Last modified: 2016/03/20 23:56 by alexandru.radovici
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0