Strona 1 Co to jest usługa w systemie Android? Usługi HTTP Obsługa wywołania HTTP GET Obsługa wywołania HTTP POST Obsługa wieloczęściowego wywołania HTTP POST Usługi lokalne Usługi zdalne Tworzenie usługi lokalnej Tworzenie usługi zdalnej
Strona 2 Usługa w systemie Android Usługa (service) to jeden z możliwych składników aplikacji systemu Android. Charakterystyka usługi: proces działający w tle przez dłuższy czas nie posiada interfejsu użytkownika posiada cykl życia Zadania przetwarzane w tle Komunikacja międzyprocesowa w urządzeniu usługa lokalna (dostępna tylko w aplikacji, której składnikiem jest usługa) usługa zdalna (łączą się z nią zdalnie inne aplikacje w urządzeniu, umożliwia komunikację między aplikacjami, definiowana w języku AIDL) dostępne są usługi zdalne systemowe (składniki innych aplikacji) możliwość tworzenia własnych usług (dziedziczenie po klasie Service) możliwość wykorzystania usług zewnętrznych (np. usługi HTTP)
Strona 3 Usługi HTTP Do obsługi usług zewnętrznych wykorzystywany jest protokół HTTP. W systemie Android dostępny jest moduł HttpClient, który bazuje na module znanym z Java EE. Jest to klient protokołu HTTP, który umożliwia pełną obsługę protokołu, jednak najczęściej wykorzystywane czynności to: obsługa wywołania HTTP GET obsługa wywołania HTTP POST Schemat obsługi wywołań GET i POST za pomocą modułu HttpClient : 1. utworzenie obiektu modułu HttpClient, 2. utworzenie obiektu żądania HTTP (abstrakcja HttpGet lub HttpPost), 3. konfiguracja ewentualnych nazw i wartości parametrów protokołu HTTP, 4. wykonanie wywołania GET lub POST, 5. przetworzenie uzyskanej odpowiedzi protokołu HTTP.
Strona 4 Obsługa wywołania HTTP GET BufferedReader we = null; // bufor try obiekt klienta HTTP 1 2 4 HttpClient klient = new DefaultHttpClient(); 3 obiekt żądania GET (bez parametrów) HttpGet request = new HttpGet(); request.seturi(new URI( http://www.xyz.com )); metoda execute HttpResponse odp = klient.execute(request); wykonuje żądanie we = new BufferedReader(new InputStreamReader(odp.getEntity().getContent())); StringBuffer sb = new StringBuffer( ); String linia = ; String NL = System.getProperty( line.separator ); while ( (linia = we.readline())!= null ) sb.append(linia + NL); pętla odczytu odpowiedzi HTTP we.close(); String wynik = sb.tostring(); System.out.println(wynik); //... parametry żądania GET możliwe jako część adresu URL, np. http://www.xyz.com/upload.aspx?a=10) zawartość pobrana ze strony www Kod wymaga nadania w deskryptorze aplikacji uprawnienia INTERNET (dostęp do Internetu). 5
Strona 5 Obsługa wywołania HTTP GET (c.d.) //... finally if (we!= null) try we.close(); catch (IOException e) e.printstacktrace(); zamknięcie bufora, a tym samym zamknięcie połączenia HTTP Kod wymaga nadania w deskryptorze aplikacji uprawnienia INTERNET (dostęp do Internetu).
Strona 6 Obsługa wywołania HTTP POST BufferedReader we = null; // bufor try obiekt klienta HTTP obiekt żądania POST (jeden parametr jako część treści żądania) 1 2 HttpClient klient = new DefaultHttpClient(); HttpPost request = new HttpPost( http://www.xyz.com/upload.aspx ); 3 lista parametrów żądania: pary nazwa parametru, wartość List<NameValuePair> param = new ArrayList<NameValuePair>(); param.add(new BasicNameValuePair( a, 10 )); UrlEncodedFormEntity fe = new UrlEncodedFormEntity(param); request.setentity(fe); dodanie parametru do listy 4 5 HttpResponse odp = klient.execute(request); wykonanie żądania we = new BufferedReader(new InputStreamReader(odp.getEntity().getContent())); // odczyt i przetworzenie odpowiedzi jak na str.6 finally // jak na str.7 Kod wymaga nadania w deskryptorze aplikacji uprawnienia INTERNET (dostęp do Internetu).
Strona 7 Wieloczęściowe wywołanie HTTP POST Żądanie POST pozwala również przekazywać parametry w postaci złożonej, jako pary nazwa-wartość i pliki (tzw. multipart POST). W systemie Android obsługa wieloczęściowych żądań POST wymaga pobrania i dodania do projektu aplikacji następujących bibliotek w formacie JAR: Commons IO http://commons.apache.org/io/ Mime4j http://james.apache.org/mime4j/ HttpMime http://hc.apache.org/httpcomponents/-client/httpmime/index.html W środowisku Eclipse, biblioteki należy dodać do projektu aplikacji: należy kliknąć prawym przyciskiem myszy nazwę projektu, w rozwijanym menu wybrać kolejno: Properties Java Class Path zakładka Libraries opcja Add External JARs.
Strona 8 try 1 2 Obsługa wieloczęściowego wywołania HTTP POST obiekt klienta HTTP obiekt żądania POST InputStream is = this.getassets().open( dane.xml ); HttpClient klient = new DefaultHttpClient(); HttpPost request = new HttpPost( http://www.xyz.com/upload.aspx ); 3 byte[] dane = IOUtils.toByteArray(is); InputStreamBody isb; isb = new InputStreamBody(new ByteArrayInputStream(dane), plik ); StringBody sb1 = new StringBody( część 1 ); StringBody sb2 = new StringBody( część 2 ); MultiPartEntity mp = new MultiPartEntity(); treść żądania mp.addpart( plik, isb); mp.addpart( jeden, sb1); mp.addpart( dwa, sb2); request.setentity(mp); // plik XML // String // String parametry żądania jako części treści żądania 4 HttpResponse odp = klient.execute(request); odp.getentity().getcontent().close(); catch (Throwable e) /* obsługa wyjątków*/ wykonanie żądania Kod wymaga nadania w deskryptorze aplikacji uprawnienia INTERNET (dostęp do Internetu).
Strona 9 Problem wyjątków w usługach HTTP Korzystanie z usług HTTP w szczególnych przypadkach może powodować występowanie wyjątków: wyjątki transportowe np. niska jakość połączenia sieciowego, wyjątki protokołowe np. błędy uwierzytelniania, niewłaściwe pliki ciasteczek cookie, wyjątki wynikające z przekroczenia limitu czasu: przekroczenie czasu połączenia (niepoprawny adres URL, brak odpowiedzi serwera, niemożność ustanowienia połączenia), przekroczenie czasu gniazda (brak odpowiedzi serwera w określonym czasie). Najprostszą metodą obsługi przekroczeń limitu czasu jest ponawianie wywołań HTTP i umieszczenie metody execute wykonującej żądanie w klauzulach try-catch.
Strona 10 Obsługa przekroczenia limitu czasu int liczba_prob = 3; // liczba ponawianych prób wywołań HTTP int licznik = 0; while (licznik < liczba_prob) licznik++; try // tutaj kod wywołania, np. GET ze str.6 catch (Exception e) Przykładowy schemat obsługi przekroczenia limitu czasu. if (licznik < liczba_prob) // nie wyczerpano limitu powtórzeń System.out.println(e.getMessage()); else System.out.println( próba zakończona niepowodzeniem ); throw e;
Strona 11 Usługi lokalne Usługa lokalna jest wykorzystywana w obrębie jednego procesu. Przeznaczona jest do uruchamiania zadań wykonywanych w tle, na potrzeby aplikacji która uruchomiła usługę. Jest wywoływana wyłącznie przez aplikację, która nią zarządza. Przykłady usług lokalnych: okresowe łączenie się z Internetem w celu pobrania lub wysłania danych, kolejkowanie zadań i ich zgłaszanie do wykonania przez aktywności w tej samej aplikacji. Obsługa usługi lokalnej: uruchamianie metoda Context.startService() Wywołanie metody Context.startService powoduje utworzenie usługi i uruchomienie jej metody onstart(). Ponowne wywołanie metody Context.startService nie tworzy nowej instancji usługi przywołuje jedynie metodę onstart istniejącej już usługi. zatrzymywanie przez klienta metoda Context.stopService() zatrzymywanie przez usługę metoda stopself().
Strona 12 Usługi zdalne Usługa zdalna (zewnętrzna) obsługuje metodę onbind(). Przeznaczona jest do komunikacji międzyprocesowej (między aplikacjami). Obsługuje mechanizm wywołania RPC (Remote Procedure Call) zdalne wywołanie procedury (usługa RPC). Umożliwia zewnętrznym aplikacjom (klientom), działającym na tym samym urządzeniu, uzyskanie dostępu do usługi (podłączenie do usługi) i korzystanie z jej funkcji. Usługa zdalna to usługa obsługująca język AIDL, usługa AIDL (Android Interface Definition Language język definicji interfejsu systemu Android). Klienci komunikują się z usługą zdalną za pomocą języka AIDL. Usługi są definiowane wobec klientów przy użyciu języka AIDL. Obsługa usługi zdalnej: uruchamianie (klient łączy się z usługą) metoda Context.bindService() rozłączenie klienta z usługą metoda Context.unbindService().
Strona 13 Wybrane metody publiczne klasy android.app.service IBinder onbind(intent intent); void onconfigurationchanged(configuration newconfig); void oncreate(); void ondestroy(); void onlowmemory(); void onrebind(intent intent); void onstart(intent intent, int startid); boolean onunbind(intent intent); Application getapplication(); final void stopself(); final void stopself(int startid); final boolean stopselfresult(int startid); zwraca interfejs umożliwiający aplikacjom komunikację z usługą zmienia konfigurację usługi po zmianie konfiguracji urządzenia pierwsze utworzenie usługi (inicjalizacja), przed onstart zamknięcie usługi wołana przy małej ilości pamięci wołana, gdy nowy klient jest podłączany do usługi wołana po startservice wołana, gdy wszyscy klienci zostaną odłączeni od usługi zwraca obiekt aplikacji usługi zatrzymanie usługi przez nią samą (zatrzymanie usługi przez klienta: Context.stopService)
Strona 14 Tworzenie usługi lokalnej definicja usługi import android.app.service; utworzenie klasy dziedziczącej po public class NaszService extends Service abstrakcyjnej klasie Service private static final String TAG = NaszService ; @Override public void oncreate() super.oncreate(); Log.d(TAG, oncreate ); Thread t = new Thread(null, new Zadanie(), NaszService ); t.start(); wątek dla usługi @Override public IBinder onbind(intent intent) Log.d(TAG, onbind ); return null; usługa lokalna nie obsługuje metody onbind wynik to null informacje wyświetlane w oknie narzędzia do usuwania błędów LogCat class Zadanie implements Runnable public void run() // zadanie wykonywane w tle... // zatrzymanie usługi przez nią // samą: metoda // NaszService.this.stopSelf()
Strona 15 Tworzenie usługi lokalnej rejestracja i uruchamianie Rejestrowanie usługi w pliku AndroidManifest.xml Usługę należy zarejestrować w deskryptorze aplikacji w węźle service. <application <service android:name="naszservice"> </service> </application> nazwa klasy usługi Uruchamianie i zatrzymywanie usługi przez klienta aktywność bieżąca nazwa klasy usługi startservice(new Intent(aktywnosc.this, NaszService.class)); stopservice(new Intent(aktywnosc.this, NaszService.class));
Strona 16 Tworzenie usługi zdalnej Usługa zdalna to usługa obsługująca język AIDL, usługa AIDL (Android Interface Definition Language język definicji interfejsu systemu Android). Klienci komunikują się z usługą zdalną za pomocą języka AIDL. Usługi są definiowane wobec klientów również przy użyciu języka AIDL. Definiowanie usługi zdalnej: 1. utworzenie pliku AIDL definiującego interfejs usługi dla klienta, 2. dodanie pliku AIDL do katalog src projektu aplikacji (w czasie kopiowania pliku/kompilacji projektu, na podstawie pliku AIDL zostanie wygenerowany interfejs Java w katalogu gen projektu), 3. zaimplementowanie usługi i zwrócenie interfejsu IBinder w metodzie onbind, 4. zarejestrowanie usługi w pliku deskryptora aplikacji.
Strona 17 KROK 1 Tworzenie usługi zdalnej plik AIDL Plik AIDL to plik źródłowy o rozszerzeniu *.aidl, zawierający kod Java. Przykład pliku AIDL: // plik INaszService.aidl package com.przyklad.pakiet; interface INaszService double wynik(string arg); nazwa pakietu taka sama jak nazwa pakietu w projekcie aplikacji definicja interfejsu usługi INaszService
Strona 18 KROK 3 Tworzenie usługi zdalnej definicja usługi public class NaszService extends Service private static final String TAG = NaszService ; utworzenie klasy dziedziczącej po interfejsie INaszService public class NaszServiceImp extends INaszService.Stub @Override public double wynik(string arg) throws RemoteException Log.v(TAG, Metoda wynik wywołana dla + arg); return 20.0; // tutaj to co realizuje usługa, zwraca wynik 20.0 @Override public IBinder onbind(intent intent) Log.v(TAG, onbind ); return new NaszSerwiceImpl; //... utworzenie klasy dziedziczącej po abstrakcyjnej klasie Service klasa abstrakcyjna Stub wygenerowana automatycznie dla interfejsu informacje wyświetlane w oknie narzędzia do usuwania błędów LogCat usługa zdalna obsługuje metodę onbind - zwraca instancję implementowanej klasy-usługi
Strona 19 KROK 3 Tworzenie usługi zdalnej definicja usługi (c.d.) //... @Override Metody zostały przedefiniowane jedynie public void oncreate() w celu wyświetlania informacji w oknie narzędzia do usuwania błędów LogCat. super.oncreate(); Log.v(TAG, wywołana metoda oncreate ); @Override public void ondestroy() super.ondestroy(); Log.v(TAG, wywołana metoda ondestroy ); @Override public void onstart(intent intent, int startid) super.onstart(intent, startid); Log.v(TAG, wywołana metoda onstart );
Strona 20 Tworzenie usługi zdalnej rejestrowanie usługi KROK 4 Usługę należy zarejestrować w deskryptorze aplikacji w węźle service. Fragment pliku AndroidManifest.xml: <application <service android:name="naszservice"> <intent-filter> <action android:name="com.przyklad.pakiet.inaszservice" /> </intent-filter> </service> filtr intencji dla usługi </application>
Strona 21 Tworzenie usługi zdalnej czynności po stronie klienta INaszService usluga = null; obiekt usługi obiekt implementujący interfejs ServiceConnection ServiceConnection sc = new ServiceConnection() @Override metoda uruchamiana po połączeniu z usługą public void onserviceconnected(componentname name, IBinder service) Log.v(TAG, wywołana metoda onserviceconnected ); usluga = INaszService.Stub.asInterface(service); double x = usluga.wynik( abcd ); // i inne czynności związane z usługą... ; metoda uruchamiana po przerwaniu połączenia z usługą @Override public void onservicedisconnected(componentname name) Log.v(TAG, wywołana metoda onservicedisconnected ); usluga = null; nazwa usługi AIDL instancja obiektu ServiceConnection flaga (automatyczne tworzenie usługi) // przyłączenie klienta do usługi: bindservice(new Intent(INaszService.class.getName()),sc,Context.BIND_AUTO_CREATE); // wywołanie usługi przez klienta: double x = usluga.wynik( abcd ); // i inne czynności związane z usługą... // odłączenie klienta od usługi: unbindservice(sc);