ANTIK ANTIK ANTIK

Programujeme pre Android /7.časť

0

V tejto časti seriálu sa zameriame na implementáciu tzv. poskytovateľov, resp. vyhodnocovačov obsahu (content providers, resolvers) a takisto komponentov (tried), ktoré s nimi určitým spôsobom súvisia. Pretože používanie výrazov poskytovateľ, resp. vyhodnocovač môže viesť k istým nejasnostiam, v našich článkoch budeme používať ich anglické ekvivalenty. Provider a ďalšie nevyhnutné triedy zahrnieme do vzorovej aplikácie planovac_v2.

planovac_v2

Na obr. 1 je zobrazený grafický výstup aplikácie planovac_v2 v porovnaní s výstupom predchádzajúcej verzie. Aj napriek tomu, že rozdiely grafických výstupov sú zanedbateľné, štruktúra zdrojového kódu oboch aplikácií sa v mnohom odlišuje (obr. 2). Hlavným dôvodom zmien bola implementácia providera na prístup k databáze. Táto zmena si následne vynútila zmeny ostatných častí pôvodného kódu vrátane reštrukturalizácie a umiestnenia kódu jednotlivých tried do nových balíčkov contentprovider a database.

Grafický výstup aplikácií planovac_v1 a planovac_v2 (jediný viditeľný rozdiel je označený červenou)

dB_helper.java - SQLiteOpenHelper - contract classes

Jedna z čŕt objektovo orientovaného programovania je aj tzv. zapuzdrenie členských konštánt, resp. premenných = vlastností tried (properties) a takisto členských funkcií = metód tried do ich „vnútra" (local space). Triedy následne poskytujú prístup k svojmu vnútornému priestoru, resp. k údajom, ktoré spravujú (vrátane údajov uložených v databázach), cestou verejne prístupných vlastnostní a metód (public). Tým vytvárajú vzťahy čiže kontrakty medzi svojím vnútorným a okolitým prostredím (global space). Vznikajú tak tzv. kontraktné, resp. pomocné triedy (contract, helper classes).

Jedna z nich je aj abstraktná trieda SQLiteOpenHelper, ktorá je vzorom (pattern) na implementáciu tried a ich metód určených na vytvorenie, otvorenie a upgrade databáz. V rámci našej aplikácie sme kontraktnú triedu rozširujúcu SQLiteOpenHelper implementovali pomocou triedy dB_helper. Podľa odporúčaní sme kód zodpovedný za vytvorenie (onCreate) a upgrade (onUpgrade) konkrétnej tabuľky s názvom ulohy umiestnili do samostatnej triedy tbl_ulohy. Tu je definovaný aj výraz SQL na vytvorenie novej databázy (tabuľky). Otvorenie (vytvorenie, resp. upgrade) databázy s možnosťou zápisu sa realizuje neskôr v rámci providera, konkrétne jeho metódy onCreate(), a to vykonaním metódy getWritableDatabase().

Content Providers

Patria medzi štyri základné typy aplikácií písaných pre OS Android. Majú rovnaké postavenie ako aktivity, služby a prijímače oznámení. Ich existenciu uvádzame priamo do manifestu, kde súčasne definujeme bezpečnostné pravidlá na ich používanie.

Každý provider sám seba identifikuje pomocou tzv. autority (authority). Autorita je základná časť tzv. jednotného identifikátora zdroja (URI - Uniform Resource Identifier) daného providera. URI sa používa ako náhrada adresy zdroja, ktorý chceme použiť. Autorita providera musí byť rovnako ako názov programového balíčka našej aplikácie jedinečná (unique). Preto je vhodné, ak je táto základná časť URI rovnaká ako názov balíčka aplikácie.

Úlohou providerov je vytvárať rozhranie medzi vrstvou údajov (uložených najčastejšie v databáze = data layer) a aplikačnou vrstvou (application layer). Štruktúra providerov predstavuje abstrakciu štruktúry údajov (databáz). Providery sa teda navonok javia ako databázy. Jedna z ich hlavných úloh je sprístupniť inak neprístupné interné údaje (databázy) ostatným aplikáciám. Rovnakú úlohu plnia aj tzv. natívne providery, ktoré poskytujú prístup k „systémovým" údajom (napr. hovorom, kontaktom, multimédiám, kalendáru...) nielen pre systémové, ale aj pre všetky ostatné aplikácie.

Implementácia providera v aplikácii planovac_v2

Aplikácie žiadajú providery o prístup k údajom spravovaným nimi pomocou resolverov, ktoré sú priradené ku kontextu každej aktivity. Náš resolver sme získali v rámci triedy MainActivity, a to vykonaním metódy getContentResolver().

Programový kód providera sme umiestnili do triedy dB_contentprovider. Na jeho začiatku sme definovali „povinnú" konštantu CONTENT_URI. Následne sme využili služby triedy UriMatcher, ktorá je určená na analýzu URI a determináciu formátu požiadavky zaslanej resolverom. Definovali sme tak formát URI dvoch základných požiadaviek týkajúcich sa:

  1. všetkých riadkov, resp. záznamov (records) tabuľky,
  2. konkrétneho riadka tabuľky.

V ďalšom sme implementovali metódy query() a getType(). Prvá z nich využíva služby triedy SQLiteQueryBuilder určené na vytvorenie výrazu SQL v závislosti od konkrétnej formy URI. Druhá z nich vracia MIME (Multipurpose Internet Mail Extensions) typ údajov, ktoré ponúka náš provider. Rovnako ako v prípade dvoch odlišných formátov URI treba rozlíšiť MIME typ údajov pre prípad požiadavky týkajúcej sa všetkých riadkov a konkrétneho riadka tabuľky.

V neposlednom rade sme v rámci kódu nášho providera definovali transakčné metódy na vloženie (insert), zmazanie (delete) a zmenu (update) údajov uložených v databáze. Vo všetkých prípadoch sme o vykonaných zmenách informovali resolver pomocou metódy notifyChange().

Android-obr1.jpg

Štruktúra zdrojového kódu aplikácií planovac_v1 a planovac_v2 (zmenené časti sú označené červenou)

CursorLoader

Na prácu s údajmi uloženými v databázach slúži trieda Cursor. Tá je ukazovateľom (pointer) na množinu údajov (result set), ktorá je výsledkom riešenia zaslanej požiadavky. Kurzor je zároveň manažérom danej množiny údajov.

Pretože operácie (transakcie) vykonávané s údajmi uloženými v databázach sú časovo náročné, je vhodné, aby sa vykonávali mimo hlavného programového vlákna (main thread), resp. používateľského rozhrania (UI - User Interface) aplikácie. Na zjednodušenie procesu synchronizácie práce kurzorov s UI aplikácií boli do Android 3.0 (API level 11) a takisto do Android Support Library doplnené tzv. nahrávače (loaders).

Loadery sú určené na asynchrónnu prácu so zdrojmi údajov a ich monitorovanie. V rámci aktivít a fragmentov sú dostupné prostredníctvom triedy LoaderManager, a to vykonaním metódy getLoaderManager(), resp. getSupportLoaderManager(). LoaderManager spravuje životný cyklus loaderov, medzi ktoré patrí aj CursorLoader.

CursorLoader poskytuje asynchrónny manažment kurzora, prostredníctvom ktorého sú riešené požiadavky zaslané danému provideru. Na to, aby implementácia takéhoto loadera pracovala správne, musíme definovať obsah nasledujúcich troch abstraktných metód rozhrania LoaderManager.LoaderCallbacks:

  1. onCreateLoader() - inicializácia loadera, špecifikácia parametrov požiadaviek zasielaných resolverom,
  2. onLoadFinished() - ukončenie asynchrónneho riešenia požiadavky (kurzor ukazuje na údaje),
  3. onLoaderReset() - reštart loadera (údaje nie sú viac k dispozícii).
Zobrazit Galériu

Marek Sopko

Všetky autorove články
programovanie Android seriál

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať