Uvod
Adapter je most između izvora podataka (Array objekat, List objekat…) i korisničkog interfejsa. Uloga adapter objekta (implementira Adapter interfejs) je da čita podatke iz različitih izvora podataka, i na osnovu njih popunjava View objekte članove nekog ViewGroup-a.
ViewGroup: ListView, RecyclerView, GridView, Spinner, Gallery čiji sadržaj se popunjava korišćenjem adaptera se nazivaju zajedničkim imenom “AdapterView”.
Korišćenje adaptera kao medijatora izmedju “model-a” (podataka) i View-a, predstavlja varijaciju MVC patern-a pod nazivom MVA (ModelViewAdapter). To znači da Model i View nikada ne komuniciraju međusobno, već komuniciraju preko Adapter-a (koji je zapravo samo “event-driven Controller”). Prednost ovog patern-a je da View ne mora da zna ništa o modelu, te se na taj način postiže bolje razdvajanje odgovornosti.
Postoji više različitih adaptera, i njihov izbor zavisi od AdapterView-a za koji se koristi. Najjednostavniji adapter je “ArrayAdapter”, koji uzima podatke u vidu “ArrayList” i sa njima popunjava sadržaj View elementa koji su deo kontejner-a (“ListView”, GridView, Spinner). Za “RecyclerView” se koristi njegov specijalizovani “RecyclerView.adapter”, dok se za “ViewPager” koristi “PagerAdapter”.
Postupak kreiranja ArrayAdapter-a
Osnovni defaultni Android Adapter predstavlja “ArrayAdapter” koji koristi neki od default-nih layout-a koji su ugradjeni u Android.
a) Definisanje podataka koji treba da se prikažu
Prvo su nam potrebni podaci koji bi se smeštali u neki View, ArrayAdapter ima različite konstruktore, te stoga može da primi različite tipove podataka:
1 |
String[] nizPodataka = new String[] { "Pera", "Mika", "Zika", "Rada", "Deka", "Marko", "Darko", "Sima", "Mirko"}; |
1 2 3 4 5 6 7 8 9 10 |
listaPodataka = new ArrayList<String>(); listaPodataka.add("Pera"); listaPodataka.add("Mika"); listaPodataka.add("Zika"); listaPodataka.add("Rada"); listaPodataka.add("Deka"); listaPodataka.add("Marko"); listaPodataka.add("Darko"); listaPodataka.add("Sima"); listaPodataka.add("Mirko"); |
ili
1 2 3 4 5 |
String[] nizPodataka = new String[] { "Pera", "Mika", "Zika", "Rada", "Deka", "Marko", "Darko", "Sima", "Mirko"}; final ArrayList<String> listaPodataka = new ArrayList<String>(); for (int i = 0; i < nizPodataka.length; ++i) { listaPodataka.add(nizPodataka[i]); } |
Desni klik na res > values zatim se izabere New > Values resource file nakon čega se izabere ime fajla npr. “imena_ljudi_array”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="imena_ljudi"> <item>Pera</item> <item>Mika</item> <item>Zika</item> <item>Rada</item> <item>Deka</item> <item>Marko</item> <item>Darko</item> <item>Sima</item> <item>Mirko</item> </string-array> </resources> |
Ovome se kasnije možemo pristupiti:
1 |
getResources().getStringArray(R.array.imena_ljudi); |
NAPOMENA:
Kada su podaci statična lista onda nije neophodno koristiti adaptere, možemo povezati podatke (resourse string-array) i View jednostavanije i bez korišćenja adaptera samo koristeći View XML atribut: android:entries.
1 2 3 4 5 |
<ListView android:id="@+id/mojListView" android:layout_width="match_parent" android:layout_height="match_parent" android:entries="@array/imena_ljudi" /> |
b) Kreiranje AdapterView-a koji treba da prihvati podatke
Već je pomenuto da je AdapterView ustvari neki ViewGroup (ListView, RecyclerView…) čiji se sadržaj popunjava podacima uz pomoć adaptera, te je potrebno definisati neki AdapterView u okviru XML-a.
Primer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_orange_dark"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/mojaLista" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </android.support.constraint.ConstraintLayout> |
NAPOMENA:
Ako ekstendujemo aktivnost sa ListActivity (ili kod fragmenata sa ListFragment), i tada ne moramo da definišemo nikakav layout, jer u tom slučaju aktivnost (fragment) već sadrži podrazumevano kao root view jedan ListView koji može da primi podatke. Pored toga ListActivity i ListFragment nam takođe dozvoljavaju da “pregazimo” (override) metodu onListItemClick() i tako definišemo akciju koja će da se izvrši klikom na neki od članova liste. Pogledajte objedinjen kod iz primera ovde.
c) Kreiranje instance adaptera
Postoji više “ArrayAdapter” konstruktora koji mogu da prihvate različite tipove podataka, mada generalizovani konstruktor bi mogao ovako da izgleda:
1 |
ArrayAdapter(Context context, int resource, nekaVrstaPodataka) |
Legenda:
- Context
- Neki predefinisani layout koji dolazi sa androidom (npr. “R.layout.simple_list_item_1” pogledaj sliku) ili neki custom layout. Listu predefinisanih layout-a možete da pogledate ovde.
- Podaci koji se ubacuju da (lista, niz….)
Primer
ArrayAdapter zahteva da se tip elementa niza deklariše kao View (u ovom primeru kao String).
1 |
ArrayAdapter<String> mojAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, myStringArray); |
NAPOMENA:
ArrayAdapter po default-u u pozadini za svaku stavku niza poziva metodu “toString()” i tako generiše TextView u koji stavlja sadržaj člana niza. Ako želimo komplikovaniji layout koji ima više elemenata (npr. ImageView), onda je potrebno da napravimo custom ArrayAdapter što će biti objašnjeno u nekom drugom članku.
Pored ovog načina za kreiranje adaptera gde se koristi konstruktor metoda, za kreiranje adaptera možemo da koristimo i njegovu
metodu createFromResource(). Pogledajte sve metode ArrayAdapter-a i RecyclerView.adapter-a ovde.
d) Povezivanje adapter instance sa AdapterView-om
Povezivanje adaptera sa odgovarajućim View-om se vrši metodom setAdapter() (setListAdapter() kod “ListActivity”).
1 2 |
ListView nekiListView = (ListView) findViewById(R.id.nekiListview); nekiListView.setAdapter(mojAdapter); |
Sa ovim smo omogućili da adapter pokupljene podatke iz nekog resursa i ubaci kao String u svaki element AdapterView-a koji je stilizovan sa izabranim predefinisanim android layoutom (u primeru: “android.R.layout.simple_list_item_1”)
f) Definisanje click listener-a
Da bi se aktivirala akcija nakon klika na neki od elemenata liste je potrebno implementirati interfejs AdapterView.OnItemClickListener i override-ovati onItemClick() callback metodu. Metoda prihvata četri parametra od kojih prvi predstavlja parent view (u ovom primeru ListView).
1 2 3 4 5 6 7 |
mojListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String poruka = "Kliknut je redni broj #" + i + " sa imenom " + parent.getItemAtPosition(position).toString(); Toast.makeText(MainActivity.this, poruka, Toast.LENGTH_SHORT).show(); } }); |
Pogledajte objedinjen kod iz primera ovde.
Lista predefinisanih layout-a u sklopu androida.
- activity_list_item
- browser_link_context_header
- expandable_list_content
- list_content
- preference_category
- select_dialog_item
- select_dialog_multichoice
- select_dialog_singlechoice
- simple_dropdown_item_1line
- simple_expandable_list_item_1
- simple_expandable_list_item_2
- simple_gallery_item
- simple_list_item_1
- simple_list_item_2
- simple_list_item_activated_1
- simple_list_item_activated_2
- simple_list_item_checked
- simple_list_item_multiple_choice
- simple_list_item_single_choice
- simple_selectable_list_item
- simple_spinner_dropdown_item
- simple_spinner_item
- test_list_item
- two_line_list_item
Ovim layoutima se pristupa sa R.layout.nazivLayouta a njihov XML može da se pogleda ovde.
Metode ArrayAdapter-a
Metode RecyclerView.Adapter-a
- bindViewHolder
- createViewHolder
- getItemCount
- getItemId
- getItemViewType
- hasObservers
- hasStableIds
- notifyDataSetChanged
- notifyItemChanged
- notifyItemChanged
- notifyItemInserted
- notifyItemMoved
- notifyItemRangeChanged
- notifyItemRangeChanged
- notifyItemRangeInserted
- notifyItemRangeRemoved
- notifyItemRemoved
- onAttachedToRecyclerView
- onBindViewHolder
- onBindViewHolder
- onCreateViewHolder
- onDetachedFromRecyclerView
- onFailedToRecycleView
- onViewAttachedToWindow
- onViewDetachedFromWindow
- onViewRecycled
- registerAdapterDataObserver
- setHasStableIds
- unregisterAdapterDataObserver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class MainActivity extends AppCompatActivity { ListView mojListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mojListView = findViewById(R.id.mojListView); ArrayAdapter mojAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.imena_ljudi)); mojListView.setAdapter(mojAdapter); mojListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { String poruka = "Kliknut je redni broj #" + i + " sa imenom " + adapterView.getItemAtPosition(i).toString(); Toast.makeText(MainActivity.this, poruka, Toast.LENGTH_SHORT).show(); } }); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class MyListFragment extends ListFragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // NEMA ovog dela // setContentView(R.layout.activity_main); // mojListView = findViewById(R.id.mojListView); ArrayAdapter mojAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.imena_ljudi)); mojListView.setAdapter(mojAdapter); } @Override public void onListItemClick(ListView l, View v, int position, long id) { // Akcija na klik } } |