AQuery – šikovná knihovna pro Android

V dnešním článku si představíme knihovnu Android Query, která se po vzoru jQuery snaží zjednodušit některé úkoly na Androidu. Podíváme se na její koncepci a pak si naprogramujeme prohlížeč obrázků z Flickru.
Nálepky:
Android Query (dále AQuery) je šikovná knihovna pro Android. Jak lze vidět už z názvu, AQuery se inspirovalo jQuery. Snaží se mít podobnou úspornou syntaxi a přináší do Androidu jednoduché a přímočaré „ajax“ requesty (vím, že je to termín nepřesný, přesto ho však budu používat, neboť to tak dělá i knihovna). A to samozřejmě není všechno.
Jak AQuery přidat
V Eclipse (jinými prostředími se zabývat nebudu) jako jakoukoli jinou knihovnu. Nejprve si stáhněte příslušný .jar soubor ze stránek AQuery (v tuto chvíli je to soubor android-query-0.21.7.jar
) a uložte ho do složky libs
ve vašem projektu (pokud složka libs
neexistuje, vytvořte ji). Potom klikněte pravým tlačítkem na váš projekt v Eclipse, zvolte Build Path → Configure Build Path...
, v okně, které vyskočilo, vyberte záložku Libraries
, klikněte na Add JARs...
, proklikejte se ke složce libs
v příslušném projektu, vyberte .jar soubor AQuery, stiskněte OK a pak ještě jednou OK.
Základní koncepce
Nejdůležitější třídou v AQuery je (překvapivě) AQuery
, která umí manipulovat s View
objekty, provádět ajax požadavky i stahovat obrázky z internetu do nějakého ImageView
. Odteď bude AQuery znamenat knihovnu, zatímco AQuery
bude značit třídu AQuery
nebo její instanci.
Abychom pochopili, jak AQuery
funguje, musíme se na chvilku podívat dovnitř. AQuery
má čtyři konstruktory, každý z nich se hodí v jiné situaci:
AQuery aq; aq = new AQuery(Activity act); // Uvnitř Activity aq = new AQuery(Activity act, View root); // Uvnitř Fragmentu aq = new AQuery(Context context); // Například v BroadcastReceiveru, lze použít pouze ajax aq = new AQuery(View root); // Třeba v nějakém Adapteru
Aby mohlo AQuery používat internet, musí být v manifestu <uses-permission android:name="android.permission.INTERNET" />
.
AQuery
si také udržuje odkazy na dvě View
, a to View root
, což je View
předané v konstruktoru (případně null) a aktivní View view
– to View
, na němž se budou provádět všechny operace. Předáme-li nějaké View
konstruktoru, hned ze začátku bude i aktivní. Pokud ne (tzn. konstruktor AQuery(Activity act)
, musíme nějaké vybrat, například pomocí metody AQuery.id(int id)
(detailněji níže). AQuery
si udržuje odkaz na aktivní View
do té doby, než vybereme jiné.
Samotné AQuery
je velmi levné vytvořit a nezabere prakticky žádné místo, ale udržuje si odkazy na poměrně veliké objekty. Proto pokud chcete předejít problémům s pamětí, neuchovávejte AQuery
globálně (jako nějakou static složku)!
AQuery se občas nechová příliš javovsky. Jedním z takových případů (ale tady si myslím, že je to šikovné) je volání metod na AQuery
. Zavolám-li například aq.text("Text")
a aktivní View
žádný text zobrazit neumí, AQuery
takové volání ignoruje. Ignoruje ho dokonce i tehdy, je-li aktivní View
null
. To hodně zkrátí kód, neboť člověk nemusí ošetřovat, zda View
, s nímž pracuje, vlastně existuje. Ale zase na druhou stranu to přidá trochu práce, když člověk potřebuje, aby program zahlásil chybu v případě, že požadované View
neexistuje. (Na stránkách AQuery tvrdí, že je to výborné pro tabletové layouty, ale dle mého je to špatný přístup a takové layouty by se měly řešit pomocí Fragmentů
, které spolu komunikují skrze vlastní API, viz můj předchozí článek na Zdrojáku.)
// Z takového kódu TextView nameView = (TextView) view.findViewById(R.id.name); if (nameView != null) { nameView.setText(content.getPname()); } // se s AQuery stane takovýto. aq.id(R.id.name).text(content.getPname()); // (převzato ze stránek AQuery)
A jak tedy AQuery používat?
Využití si rozdělíme na čtyři skupiny: základ, ajax, stahování obrázků a ostatní.
Základ
API AQuery
je poměrně malé a názvy metod jsou ve většině případů samovysvětlující. (Asi jste si všimli, že odkazuji na Javadoc třídy AbstractAQuery
. Samotná třída AQuery
od ní dědí a nic vlastního nepřidává.)
Jak AQuery
objekt vytvoříme, jsme si řekli už dříve. Pokud jsme mu předali nějaké View
, můžeme metody, jež s ním pracují, používat ihned. Pokud ne, anebo pokud chceme manipulovat s jiným než kořenovým View
, musíme ho najít. K tomu slouží metody id
a find
. Metoda find(int id)
jako argument přebírá id požadovaného View
a vrací nový AQuery
objekt s oním View
nastaveným jako root (a i jako aktivní).
Metoda id
má dvě varianty. Poněkud nelogická id(View view)
, jež nastaví view jako aktivní a potom id(int... id)
, která se postupně prochází předané pole id a vždy na předtím nalezeném View
zavolá findViewById
a poslední nalezené nastaví jako aktivní. Je to tedy obdoba jQuery CSS selektoru. Nenapadá mě, kdy bych předal více než jedno id. Na rozdíl od find
upraví id
aktuální instanci. Většinou to není problém, pokud člověk nepotřebuje pracovat s více View
naráz.
Jak metoda id
, tak metoda find
volají findViewById
na View root
popřípadě v Activity act
, nikoli na View view
(aktivní)!
Když máme AQuery
s nastaveným aktivním View
, můžeme s ním provádět různé věci. Můžeme mu nastavovat některé běžné vlastnosti, posluchače událostí atd. Syntaxe je poměrně intuitivní a podobná jQuery (v tom, že nastavovací metody nemají prefix set
– gettery prefix get
však mají, neboť settery podporují tzv. chaining, což znamená, že vrací this
– AQuery
objekt –, aby se mohla rovnou zavolat jiná metoda, a v Javě není možné, aby se lišil návratový typ metody v závislosti na počtu nebo typu argumentů). K dispozici jsou například metody adapter
pro nastavení Adapteru
nějakému ListView
nebo GridView
, backgroundColor
pro nastavení barvy pozadí, clear
které u TextView
odstraní text, u ImageView
odstraní obrázek a u WebView
„otevře prázdnou stránku“ a dále třeba metody enabled
, gone
, height
, margin
, text
, textColor
, visible
nebo width
, jejichž názvy mluví za vše. Pro popis parametrů a další metody se podívejte na Javadoc třídy AbstractAQuery
. A dovolím si znovu upozornit na to, že nepodporuje-li aktivní View
(nebo není-li žádné) volanou metodu, v tichosti je ignorována.
Trochu zvláštně pojmenovaná, ale užitečná je metoda isExist
, která zjistí, existuje-li aktivní View
.
Neumí-li AQuery
nějakou operaci s aktuálním View
, lze to View
získat. Buď pomocí metody getView
, která vrátí aktuální View
nebo null, není-li žádné, anebo (šikovněji) pomocí metod typu getEditText
, getListView
, getSpinner
atd. (pro kompletní seznam viz dokumentaci). Vězte však, že zatímco jinde AQuery
možná až nevhodně zamlčuje problémy, u těchto metod jednoduše hloupě vezme aktuální View
a pokusí se ho přetypovat na instanci požadované třídy. Nelze-li přetypovat anebo je aktuální View
null
, skončí to výjimkou. (A zrovna tady si myslím, že vrátit null
by bylo šikovnější.)
Poslední základní manipulací, o které jsme ještě nemluvili, je práce s událostmi. AQuery
má metody pro většinu nejčastěji používaných událostí. Metody mají vždy tvar minulého času (koncovka -ed) a každá má dvě varianty: fooed(View.OnFooListener listener)
a fooed(Object handler, String method)
. První varianta je klasicky androidí, druhá se mi osvědčila jako velmi šikovná – jako listener se zavolá metoda method
objektu handler
, která přebírá stejné argumenty jako posluchačská metoda ve speciálním posluchačském rozhraní ( View.OnFooListener
). Problém je ale ten, že se název metody předává jako řetězec, a IDE tudíž může tvrdit, že daná metoda je nevyužitá. U větších projektů bych se tomu z tohoto důvodu vyhl. Nepodporuje-li aktuální View
danou událost, jíž chceme přiřadit posluchače, vše se samozřejmě v tichosti ignoruje.
AQuery aq = new AQuery(this); // Uvnitř nějaké Activity // Následující dvě přiřazení posluchače jsou ekvivalentní. aq.id(R.id.button).clicked(new View.OnClickListener() { public void onClick(View v) { // ... } }); aq.id(R.id.button).clicked(this, "onButtonClicked"); // ... public void onButtonClicked(View v) { // ... }
Ajax
Ajax v AQuery neuvěřitelně zjednoduší stahování dat z internetu a umožní soustředit se jen na samotné zpracování dat. A má jednu záludnost, o níž si řekneme později.
Než se ale vrhneme o ajaxu, představíme si jinou šikovnou metodu, která se však ajaxu týká, a to metodu progress
. Tato metoda (musí být zavolána před voláním ajaxu) přijímá tři typy argumentů. progress(Dialog dialog)
při startu ajaxu zobrazí a po skončení zase skryje předaný Dialog
(většinou asi ProgressDialog
). progress(View view)
respektive progress(int id)
zobrazí a po skončení skryjí určité View
(většinou asi ProgressBar
). O pro mě důležitou variantu, a to vestavěný progressbar v titulkové liště jsem si zažádal a bude v příští verzi (mimochodem, rychlost reakce ukazuje na to, že AQuery je stále vyvíjené, podporované a má aktivní vývojáře).
Možnosti ajaxu v AQuery jsou poměrně rozsáhlé, že by vydaly na vlastní článek, a my si tudíž ukážeme jen něco. Velmi obšírně je vše napsané v dokumentaci ajaxu na stránkáh AQuery.
Metodu ajax
můžeme volat na jakékoli instanci AQuery
za předpokladu, že má aplikace permission android.permission.INTERNET
. Předáme-li konstruktoru AQuery
nějakou Activity
, která bude při dokončení ajaxu už stopnutá, callback se nezavolá, aby se předešlo chybám (jako například zobrazení dialogu v neaktivní Activity
). Je-li to nechtěné chování, musíme vytvořit AQuery
objekt, kterému předáme Context
( new AQuery(getApplicationContext())
). A jak metoda ajax
vypadá? Jako první argument přebírá url, jako druhý třídu výsledku, aby věděla, jak odpověď serveru zpracovat a jako třetí přebírá callback. A jak je u metod nastavujících callback v AQuery zvykem, lze jako callback předat jak callbackový objekt, tak libovolný objekt a název jeho metody, která se jako callback zavolá.
String url = //... q.ajax(url, JSONObject.class, new AjaxCallback<JSONObject>() { @Override public void callback(String url, JSONObject json, AjaxStatus status) { if (json != null) { // Úspěch } else { // Chyba int errorCode = status.getCode(); } } }); q.ajax(url, JSONObject.class, this, "onDataFetched"); //... public void onDataFetched(String url, JSONObject json, AjaxStatus status) { if (json != null) { // Úspěch } else { // Chyba int errorCode = status.getCode(); } }
Tato dvě volání ajaxu jsou ekvivalentní.
Místo JSONObject.class
lze předat například String.class
pro surový řetězec navrácených dat, XmlDom.class
a mnoho dalšího.
Cachováním, POST požadavky, stahováním souborů, vlastními hlavičkami, cookies ani ničím dalším se tu zabývat nebudeme a já vás místo toho odkážu na dokumentaci. Ajax v AQuery toho každopádně ale umí hodně a v mnoha situacích dokáže být velmi šikovným pomocníkem.
Všechno má své ale…
…a to má i ajax. Ale možná není přesný výraz, třeba je to tak správně, ale mně se to rozhodně nelíbí a přijde mi to neintuitivní. Řeč je o zachytávání chyb v ajaxových callbacích. AQuery zastává názor, že v různých listenerech může nastat nečekaná běhová chyba (což je pravda) a že uživatel by o tom neměl vědět (s čímž já nesouhlasím), a tak všechny nezachycené chyby, které se vyskytnou v ajaxových callbacích i event listenerech, zachytává. Přesněji řečeno, zachytává je tehdy, předali-li jsme callback, resp. listener jako Object handler, String method
. A jediné, co my s tím můžeme udělat, je zavolat metodu AQUtility.setExceptionHandler(UncaughtExceptionHandler handler)
a vytvořit funkci, která se při chybě zavolá. Popsané to je v dokumentaci zachytávání chyb. Pokud použijeme callbackovou třídu, je všechno v pořádku.
Na tuhle vlastnost každopádně dávejte obrovský pozor, komplikuje to debugování. Já například řešil, proč se mi nespouští ShowPhotosActivity
po kliknutí na tlačítko a stažení JSON souboru. Pořád jsem zjišťoval, proč se JSON nestáhne nebo proč obslužná funkce končí v polovině a teprve pak jsem zjistil, že jsem zase zapomněl přidat ShowPhotosActivity
do manifestu. Určitě zavolejte funkci AQUtility.setDebug(true)
, díky které se chyba alespoň vypíše do LogCatu, když už tedy nezabije aplikaci. Ale nezapomeňte řádek s tímto příkazem před zabalením aplikace a rozšířením mezi uživatele odstranit.
Stahování obrázků
Potřebujete do ImageView
umístit obrázek z internetu? Nebo snad potřebujete zobrazit obrázek tak, aby šel přibližovat? Tohle a mnohem více AQuery
vyřeší. Navíc k tomu nabídne šikovnou podporu zobrazení progressbaru, cachování, změnu velikosti obrázku, fallback obrázek, callback po stažení obrázku a ještě více. Opět se budeme věnovat jen tomu základnímu a pro větší detaily vás odkážu na dokumentaci.
Stažení obrázku do ImageView
Není nic jednoduššího.
aq.id(R.id.imageView).progress(R.id.progressBar).image("https://www.google.com/images/srpr/logo3w.png");
Funkce image
samozřejmě přijímá i další argumenty, viz dokumentace. Předat ji lze i objekt Bitmap
, Drawable
nebo File
a tehdy nic nestahuje a použije lokální obrázek.
Chci stáhnout obrázek a aby se dal zvětšovat a zmenšovat.
Není problém, jen místo ImageView
potřebujeme prázdné WebView
aq.id(R.id.webView).progress(R.id.progressBar).webImage("https://www.google.com/images/srpr/logo3w.png");
Metoda webImage
nemá zdaleka tolik možností jako image
, kromě url lze nastavit už jen, bude-li obrázek zoomovatelný, jestli bude zobrazeno zoomovací ovládání a barva pozadí.
Ostatní
Kromě výše zmíněných věcí má AQuery plno dalších šikovných (maličkostí), které programátorovi usnadní žívot.
Nastavení dostupná až ve vyšších API
Některé volby jsou dostupné až od vyšších API. Například hardwarová akcelerace lze zapnout až od API 11. Místo toho, aby člověk musel zjišťovat verzi API a podle toho volat nebo nevolat funkci, nabízí AQuery
zkratku. V případě hardwarové akcelerace se zkratka jmenuje hardwareAccelerated11()
. Metody mají vždy na konci číslo značící, od kterého API fungují. Je-li API nižší, nestane se nic. Dalšími takovými metodami jsou třeba overridePendingTransition5(int enterAnim, int exitAnim)
nebo setOverScrollMode9(int mode)
. Všechny najdete v Javadocu třídy AbstractAQuery
.
Kontrola nové verze na Marketu Play Store
AQuery tvrdí, že umí zkontrolovat, je-li na Play Store dostupná nová verze aplikace, a pokud ano, zobrazí uživateli dialog nabízející update (podporují plno jazyků včetně češtiny). Mně se to zatím nepodařilo rozchodit. Ale jejich server, na němž služba běží, vrací správné výsledky, takže tam problém nebude.
Autentizace
AQuery zjednoduší autentizaci přes Facebook, Twitter a snad i Google. Nikdy jsem to nepoužil a ani moc nestudoval, jen odkážu na dokumentaci.
A jdeme programovat!
Vytvoříme si jednoduchý „zobrazovač obrázků z Flickru“ (budeme mu říkat Zobrázkovač). Ten se bude skládat ze tří Activit
. V první ( ZobrazkovacActivity
) bude EditText
, do něhož uživatel napíše jméno nějakého Flickrového uživatele, a Button
, jímž odešle požadavek. Ta Activity
zašle požadavek na Flickrové API (konkrétně na flickr.people.findByUsername
), zjistí id onoho uživatele a spustí druhou, ShowPhotosActivity
. Ta si na Flickru zažádá o flickr.people.getPublicPhotos
pro daného uživatele a zobrazí GridView
s thumbnaily těch fotek. Po kliknutí na některý z thumbnailů se spustí SinglePhotoActivity
, která stáhne a zobrazí fotku v plné velikosti s možností přibližování. Kompletní zdrojové kódy (kromě API klíče Flickru) jsou ke stáhnutí na konci článku, zkompilovaná, zabalená a podepsaná aplikace tamtéž.
V layoutu třídy ZobrazkovacActivity
je EditText
s id nick
, do nějž uživatel vepíše jméno Flickr uživatele. Dále je tam ještě Button
s id submit
, jímž se odešle požadavek na Flickr API, a ProgressBar
s id progressbar
.
Samotný kód ZobrazkovacActivity
je poměrně jednoduchý. V onCreate
zapneme debug režim v AQuery ( AQUtility.setDebug(true)
), vytvoříme AQuery
objekt a tlačítku nastavíme OnClickListener
. Pro něj jsem použil anonymní třídu, neboť chci, aby případné výjimky nebyly zachyceny. Při klepnutí na tlačítko se zjistí obsah EditText
u, vytvoří se url požadavku na Flickr API a odešle se. Jako ajaxový callback jsem sice zase použil anonymní třídu, aby výjimky zabily aplikaci, ale jediné, co se v callbacku děje, je zavolání metody onUserFetched
(protože je už hodně odsazený).
public void onCreate(Bundle savedInstanceState) { AQUtility.setDebug(true); // !! ODSTRANIT PŘED ZABALENÍM A PODEPSÁNÍM !! super.onCreate(savedInstanceState); setContentView(R.layout.main); aq = new AQuery(this); // Přidáme tlačítku OnClickListener aq.id(R.id.submit).clicked(new View.OnClickListener() { public void onClick(View v) { // Zjistíme obsah EditTextu String nick = aq.id(R.id.nick).getText().toString(); try { // Url už musí být zakódované a v nicku mohou být nepovolené // znaky, proto musíme url vytvořít takhle URI url = new URI("http", "api.flickr.com", "/services/rest", "method=flickr.people.findByUsername&api_key=" + API_KEY + "&format=json&nojsoncallback=1&username=" + nick, null); // Místo ajax(url.toString(), this, "onUserFetched") jsem // použil toto řešení, neboť v případě výjimky vyskočí // oznámení a zabije to aplikaci. Pro mě je to chtěné // chování. // Pozor ovšem na to, že AQuery stejně odchytává chyby ve // své ajaxové funkci (například // org.apache.http.conn.ConnectTimeoutException) aq.progress(R.id.progressbar).ajax(url.toString(), JSONObject.class, new AjaxCallback() { @Override public void callback(String url, JSONObject json, AjaxStatus status) { onUserFetched(url, json, status); } }); } catch (URISyntaxException e) { Toast.makeText(ZobrazkovacActivity.this, "Nepovedlo se vytvořit URI", Toast.LENGTH_LONG); } } }); }
onUserFetched
potom zjistí, byl-li požadavek úspěšný a existuje-li uživatel s požadovaným jménem, a pokud ano, zjistí jeho id a spustí ShowPhotosActivity
, jejímuž Intentu
toto id předá jako extra data.
public void onUserFetched(String url, JSONObject json, AjaxStatus status) { if (json != null) { try { // Pro dokumentaci JSON tříd viz // http://www.json.org/javadoc/org/json/JSONObject.html String stat = json.getString("stat"); if (!stat.equals(STATUS_OK)) { // Chyba při volání API - špatný API klíč, neexistující // uživatel, ... signalizeError(); return; } JSONObject user = json.getJSONObject("user"); String id = user.getString("nsid"); Intent i = new Intent(this, ShowPhotosActivity.class); i.putExtra(ShowPhotosActivity.EXTRA_USER_ID, id); startActivity(i); } catch (JSONException e) { signalizeError(); } } else { signalizeError(); } }
V layoutu ShowPhotosActivity
je ProgressBar
s id progressbar
a GridView
s id grid
, v němž budou zobrazeny thumbnaily obrázků.
V metodě onCreate
ShowPhotosActivity
hlavně stáhne seznam obrázků a nastaví OnItemClickListener
svému GridView
. Tentokrát jsem v obou případech použil callbacky objekt-metoda, takže musím počítat s odchytávanými výjimkami.
public void onCreate(Bundle savedInstanceState) { // ... URI url = new URI("http", "api.flickr.com", "/services/rest", "method=flickr.people.getPublicPhotos&api_key=" + API_KEY + "&user_id=" + getIntent().getStringExtra(EXTRA_USER_ID) + "&format=json&nojsoncallback=1", null); // Zde si musím dát pozor na to, že nezachycené výjimky v // onPhotosFetched jsou odchytávány aq.progress(R.id.progressbar).ajax(url.toString(), JSONObject.class, this, "onPhotosFetched"); // ... // Nastavení posluchače při kliknutí na jednotlivé thumbnaily. Opět si // musím dát pozor, že nezachycené výjimky jsou odchytávány. aq.id(R.id.grid).itemClicked(this, "onPhotoClick"); }
Metoda onPhotosFetched
zjistí, je-li vrácené JSON správné, a pokud ano, vytáhne z něj pole informací o fotografiích, které předá nově vytvořenému AsyncImageAdapter
u (vlastní třída, podíváme se na ni za chvíli). Ten si jednak uloží jako instanční proměnnou a jednak ho nastaví GridView
jako adaptér.
public void onPhotosFetched(String url, JSONObject json, AjaxStatus status) { // ... String stat = json.getString("stat"); if (!stat.equals(STATUS_OK)) { // ... } // Vrácený JSON vypadá zhruba takto: // { "photos": { "photo": [{...}, ...], ... }} JSONObject photosObj = json.getJSONObject("photos"); JSONArray photos = photosObj.getJSONArray("photo"); adapter = new AsyncImageAdapter(this, photos); // Po úspěšném stažení seznamu obrázků nastavíme GridView // Adapter. aq.id(R.id.grid).adapter(adapter); // ... }
A metoda onPhotoClick
získá z AsyncImageAdapter
u url velkého obrázku (viz níže) a tu předá jako Intent-extra spouštěné SinglePhotoActivity
.
public void onPhotoClick(AdapterView parent, View v, int position, long id) { Intent i = new Intent(this, SinglePhotoActivity.class); // Neřešíme NullPointerException, kdyby adapter.getItem(position) // vrátilo null i.putExtra(SinglePhotoActivity.PHOTO_URL, AsyncImageAdapter.getLargeImgUrl(adapter.getItem(position))); startActivity(i); }
AsyncImageAdapter
v konstruktoru přebírá Context
a JSONArray
obsahující informace o jednotlivých fotkách. Kvůli dědění od BaseAdapteru
musí implementovat několik důležitých metod, které ale nejsou z hlediska AQuery tak zajímavé, takže vás odkážu na zdrojové kódy. Zde si ukážeme metodu getView
, která vytvoří ImageView
a pomocí AQuery
do něj stáhne příslušný Flickr obrázek. Dále se ještě hodí vědět, že getItem(int position)
vrátí JSONObject
z příslušné pozice, anebo null
, pokud objekt neexistuje. getThumbUrl(JSONObject photo)
vrátí řetězec s url adresou thumbnailu obrázku a getLargeImgUrl(JSONObject photo)
vrátí url velkého obrázku. Obě posledně jmenované metody jsou statické.
public View getView(int position, View convertView, ViewGroup parent) { try { JSONObject photo = photos.getJSONObject(position); ImageView imageView; // Tady buď zkonvertujeme convertView nebo vytvoříme nové ImageView // Díky šikovnému AQuery (mimochodem konstruktor // new AQuery(View root);) do ImageView stáhneme obrázek jednoduše. // Z počátku to bude jen prázdné ImageView, obrázek se tam stáhne // asynchronně. new AQuery(imageView).image(getThumbUrl(photo)); return imageView; } catch (JSONException e) { return null; } }
SinglePhotoActivity
nemá žádný XML layout, pouze v onCreate
vytvoříme WebView
, které předáme do setContentView
, vytvoříme ProgressDialog
, abychom uživatele informovali o stahování (a jinak než už ohraným ProgressBar
em) a nakonec použijeme AQuery
.
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WebView webview = new WebView(this); setContentView(webview); // Pro změnu použijeme ProgressDialog ProgressDialog dialog = new ProgressDialog(this); dialog.setIndeterminate(true); dialog.setCancelable(true); dialog.setInverseBackgroundForced(false); dialog.setCanceledOnTouchOutside(false); dialog.setTitle("Loading..."); // Ve webview zobrazí obrázek, jehož url získá z Intentu (new AQuery(webview)).progress(dialog).webImage( getIntent().getStringExtra(PHOTO_URL)); }
A to je vše. Pokud je v pořádku Manifest (zaregistrované všechny Activity
a požádáno o android.permission.INTERNET
a pokud jste nezapomněli přidat AQuery .jar soubor, máte funkční Flickr zobrázkovač. S Android Query brnkačka, ne?
Ke stažení
Stáhnout si můžete zdrojové kódy aplikace a zkompilovanou, zabalenou a podepsanou aplikaci.
Závěr
Dnes jsme si představili knihovnu AQuery, která se snaží do Androidu přinést stručnost jQuery. Na mnoho věcí je opravdu velmi šikovná a značně usnadní práci. Někteří javovští puristé tvrdí, že taková syntaxe do Javy nepatří a že navíc už z názvu plyne, že je stejně o dž horší než jQuery, ale já bych se tím moc netrápil a klidně ji použil.
Diky za skvely clanek, doufam, ze v tom budete pokracovat ;-)
Clanku takovehle kvality posledni dobou spise ubyva nez pribyva. Ode mne palec nahoru za skvelou praci ;-) Diky
My děkujeme za chválu! Ale bereme to s odstupem, ono „kvalitních článků ubývá“ se říká minimálně 10 let a možná i déle. A kdyby to byla opravdu, do puntíku a celou dobu pravda, tak bychom dnes už asi neměli nic 8-)
Chtěl bych se zeptat jak je to s podporou nativních funkcí androidu, usnadňuje to např. focení obrázků nativním foťákem nebo přístup do fotogalerie v androidu nebo je to jen pro jakési „android-webaplikace“ (za použití ajaxu)?
Nic takového AQuery neumí. Co se foťáku týče, myslím si, že to ani není potřeba. Ve většině případů stačí (a je to pro uživatele IMHO mnohem příjemnější) zaslat Intent uživatelově výchozí foto-aplikaci (android.provider.MediaStore.ACTION_IMAGE_CAPTURE). A když to nestačí, práce s foťákem, API Camera není tak složité ani zdlouhavé, aby na to byla potřeba knihovna.
AQuery je knihovna usnadňující obecné, často používané úkony. To, co jste vyjmenoval je velmi konkrétní.