Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00543 012487 16998125 na godz. na dobę w sumie
Optymalizacja wydajności aplikacji na Android - książka
Optymalizacja wydajności aplikacji na Android - książka
Autor: Liczba stron: 256
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5555-7 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie mobilne >> android
Porównaj ceny (książka, ebook (-25%), audiobook).

Twórz stabilne, wydajne i szybkie aplikacje!

Platforma Android wciąż się rozwija, a użytkownicy oczekują coraz bardziej zaawansowanych aplikacji. Istotne jest to, że muszą one działać perfekcyjnie - nie ma tu miejsca na zacięcia, spowolnienia lub brak odpowiedzi. Programiści często muszą dopracowywać, poprawiać i optymalizować wydajność tworzonych programów. Ponieważ aplikacje stają się coraz bardziej złożone, zagadnienia te zyskują na znaczeniu. Wydajniejsze programy pozwalają uzyskać wyższe oceny i ostatecznie odnieść większy sukces programiście aplikacji na Android. Jak to osiągnąć? Jest to zadanie trudne, ale wykonalne!

Z tego podręcznika dowiesz się, jak dopracować aplikacje na Android; zapewnić ich stabilność, wydajność i szybkość działania. Zobaczysz, jak pisać aplikacje w Javie, C i obu tych językach z użyciem pakietów SDK i NDK Androida. W trakcie lektury odkryjesz, jak optymalizować kod oparty o OpenGL, jak zmniejszyć zużycie pamięci oraz zużycie baterii przez Twoją aplikację. Ponadto nauczysz się testować wydajność aplikacji oraz korzystać z nowości, jaką jest RenderScript. Po zapoznaniu się z tą książką staniesz się lepszym programistą i wzrośnie jakość Twoich aplikacji!

Sięgnij po tę książkę i:

Wydajność to jedna z najważniejszych cech aplikacji - zadbaj o nią!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Pro Android Apps Performance Optimization Tłumaczenie: Tomasz Walczak ISBN: 978-83-246-5555-7 Original edition copyright © 2012 by Hervé Guihot. All rights reserved. Polish edition copyright © 2013 by HELION SA. All rights reserved. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/optwyd.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/optwyd Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treĂci O autorze.......................................................................................................9 Redaktorzy techniczni .................................................................................11 PodziÚkowania ...........................................................................................13 Wprowadzenie ...........................................................................................15 Rozdziaï 1 Optymalizowanie kodu w Javie ..................................................................17 W jaki sposób Android wykonuje kod? ............................................................................. 18 Optymalizowanie obliczania ciągu Fibonacciego ............................................................. 20 Od rekurencji do iteracji ................................................................................................ 20 Typ BigInteger ................................................................................................................. 21 Zapisywanie wyników w pamięci podręcznej ................................................................... 25 Klasa android.util.LruCache K, V ............................................................................ 27 Wersje interfejsu API ............................................................................................................ 28 Fragmentacja rynku ........................................................................................................ 30 Struktury danych ................................................................................................................... 30 Reagowanie ............................................................................................................................. 33 Leniwe inicjowanie ......................................................................................................... 35 Klasa StrictMode ............................................................................................................. 35 SQLite ...................................................................................................................................... 37 Instrukcje bazy SQLite ................................................................................................... 37 Transakcje ........................................................................................................................ 40 Zapytania .......................................................................................................................... 41 Podsumowanie ....................................................................................................................... 42 SPIS TRE¥CI Rozdziaï 2 Wprowadzenie do pakietu NDK ..................................................................43 Co znajduje się w pakiecie NDK? ........................................................................................ 44 Łączenie Javy oraz C i C++ ................................................................................................... 46 Deklarowanie metody natywnej ................................................................................... 47 Implementowanie warstwy łączącej JNI ..................................................................... 47 Tworzenie plików makefile ........................................................................................... 49 Implementowanie funkcji natywnej ............................................................................ 50 Kompilowanie biblioteki natywnej .............................................................................. 52 Wczytywanie biblioteki natywnej ................................................................................ 52 Plik Application.mk ............................................................................................................... 53 Optymalizowanie pod kątem (prawie) wszystkich urządzeń ................................... 54 Obsługa wszystkich urządzeń ....................................................................................... 56 Plik Android.mk .................................................................................................................... 58 Usprawnianie wydajności za pomocą kodu w językach C lub C++ ............................... 60 Więcej o JNI ..................................................................................................................... 64 Klasa NativeActivity .............................................................................................................. 68 Budowanie brakującej biblioteki .................................................................................. 70 Inne podejście .................................................................................................................. 76 Podsumowanie ....................................................................................................................... 77 Rozdziaï 3 Zaawansowane mechanizmy pakietu NDK .................................................79 Asembler ................................................................................................................................. 79 Największy wspólny dzielnik ........................................................................................ 80 Przekształcanie zapisu kolorów .................................................................................... 84 Równoległe obliczanie średniej ..................................................................................... 88 Instrukcje architektury ARM ........................................................................................ 91 Rozszerzenie NEON ....................................................................................................... 98 Mechanizmy procesora .................................................................................................. 98 Rozszerzenia języka C ......................................................................................................... 100 Funkcje wbudowane ..................................................................................................... 100 Instrukcje dla wektorów .............................................................................................. 101 Wskazówki ............................................................................................................................ 105 Rozwijanie funkcji ........................................................................................................ 105 Rozwijanie pętli ............................................................................................................. 105 Wstępne wczytywanie do pamięci ............................................................................. 106 Stosowanie instrukcji LDM i STM zamiast LDR i STD .......................................... 107 Podsumowanie ..................................................................................................................... 107 Rozdziaï 4 Wydajne korzystanie z pamiÚci ................................................................109 Krótko o pamięci ................................................................................................................. 109 Typy danych ......................................................................................................................... 110 Porównywanie wartości ............................................................................................... 112 Inne algorytmy .............................................................................................................. 114 Sortowanie tablic ........................................................................................................... 115 Tworzenie własnych klas ............................................................................................. 116 4 SPIS TRE¥CI Dostęp do pamięci ............................................................................................................... 117 Długość wiersza w pamięci podręcznej ..................................................................... 118 Określanie struktury danych .............................................................................................. 118 Przywracanie pamięci ......................................................................................................... 123 Wyciekanie pamięci ..................................................................................................... 123 Referencje ....................................................................................................................... 124 Interfejsy API ....................................................................................................................... 128 Mała ilość pamięci ............................................................................................................... 128 Podsumowanie ..................................................................................................................... 129 Rozdziaï 5 WielowÈtkowoĂÊ i synchronizacja ............................................................131 Wątki ..................................................................................................................................... 132 Klasa AsyncTask .................................................................................................................. 134 Klasy Handler i Looper ....................................................................................................... 137 Obiekty Handler ........................................................................................................... 137 Obiekty Looper ............................................................................................................. 139 Typy danych ......................................................................................................................... 139 Model pamięci a słowa kluczowe synchronized i volatile ...................................... 140 Współbieżność ..................................................................................................................... 143 Architektury wielordzeniowe ............................................................................................ 144 Modyfikowanie algorytmu pod kątem architektury wielordzeniowej ........................ 145 Stosowanie współbieżnej pamięci podręcznej .......................................................... 148 Cykl życia aktywności ......................................................................................................... 150 Przekazywanie informacji ............................................................................................ 151 Zapamiętywanie stanu ................................................................................................. 153 Podsumowanie ..................................................................................................................... 156 Rozdziaï 6 Testy szybkoĂci i profilowanie ..................................................................157 Pomiar czasu ......................................................................................................................... 157 System.nanoTime() ...................................................................................................... 158 Debug.threadCpuTimeNanos() ................................................................................. 159 Śledzenie ................................................................................................................................ 160 Debug.startMethodTracing() ...................................................................................... 160 Korzystanie z narzędzia Traceview ............................................................................ 161 Narzędzie Traceview w perspektywie DDMS .......................................................... 163 Śledzenie kodu natywnego .......................................................................................... 164 Rejestrowanie komunikatów .............................................................................................. 166 Podsumowanie ..................................................................................................................... 168 Rozdziaï 7 Maksymalizowanie czasu pracy na baterii ................................................169 Baterie .................................................................................................................................... 169 Pomiar zużycia baterii .................................................................................................. 171 Wyłączanie odbiorników rozgłoszeniowych ................................................................... 174 Wyłączanie i włączanie odbiornika rozgłoszeniowego ........................................... 176 Sieć ......................................................................................................................................... 178 Pobieranie danych w tle ............................................................................................... 178 Transfer danych ............................................................................................................ 179 5 Lokalizacja ............................................................................................................................. 181 Wyrejestrowywanie odbiornika .................................................................................. 182 Częstotliwość aktualizacji ............................................................................................ 183 Wielu dostawców .......................................................................................................... 184 Filtrowanie dostawców ................................................................................................ 185 Ostatnia znana lokalizacja ........................................................................................... 187 Czujniki ................................................................................................................................. 188 Grafika ................................................................................................................................... 189 Alarmy ................................................................................................................................... 190 Planowanie zgłaszania alarmów ................................................................................. 191 Blokady WakeLock .............................................................................................................. 192 Zapobieganie problemom ........................................................................................... 193 Podsumowanie ..................................................................................................................... 194 Grafika ......................................................................................................195 Optymalizowanie układów ................................................................................................. 195 Układ RelativeLayout ................................................................................................... 197 Scalanie układów ........................................................................................................... 200 Ponowne wykorzystanie układów .............................................................................. 201 Namiastki widoków ...................................................................................................... 203 Narzędzia wspomagające tworzenie układów ................................................................. 204 Przeglądarka hierarchii ................................................................................................ 205 Narzędzie layoutopt ...................................................................................................... 205 Standard OpenGL ES .......................................................................................................... 205 Rozszerzenia .................................................................................................................. 206 Kompresja tekstur ......................................................................................................... 207 Mipmapy ........................................................................................................................ 212 Różne pliki APK ............................................................................................................ 213 Programy cieniowania ................................................................................................. 213 Złożoność sceny ............................................................................................................ 214 Odrzucanie ..................................................................................................................... 214 Tryb renderowania ....................................................................................................... 214 Zużycie energii .............................................................................................................. 214 Podsumowanie ..................................................................................................................... 215 RenderScript .............................................................................................217 Wprowadzenie ..................................................................................................................... 217 Witaj, świecie ........................................................................................................................ 219 Witaj, renderingu ................................................................................................................. 222 Tworzenie skryptu renderującego .............................................................................. 222 Tworzenie kontekstu (obiektu RenderScriptGL) ..................................................... 223 Rozszerzanie klasy RSSurfaceView ............................................................................ 224 Ustawianie widoku zawartości .................................................................................... 224 Stosowanie zmiennych w skrypcie .................................................................................... 225 SPIS TRE¥CI Rozdziaï 8 Rozdziaï 9 6 SPIS TRE¥CI Aplikacja HelloCompute .................................................................................................... 228 Obiekty Allocation ........................................................................................................ 229 Funkcja rsForEach ........................................................................................................ 229 Wydajność ..................................................................................................................... 233 Natywne interfejsy API dla RenderScriptu ...................................................................... 234 Plik rs_types.rsh ............................................................................................................ 234 Plik rs_core.rsh .............................................................................................................. 237 Plik rs_cl.rsh .................................................................................................................. 238 Plik rs_math.rsh ............................................................................................................ 241 Plik rs_graphics.rsh ...................................................................................................... 242 Plik rs_time.rsh ............................................................................................................. 243 Plik rs_atomic.rsh ......................................................................................................... 244 RenderScript a NDK ............................................................................................................ 244 Podsumowanie ..................................................................................................................... 245 Skorowidz .................................................................................................247 7 SPIS TRE¥CI 8 R O Z D Z I A ’ 8 „ „ „ Grafika Często trzeba poświęcić dużo czasu na projektowanie wyglądu aplikacji. Niezależnie od tego, czy jest nią klient pocztowy oparty na standardowych kontrolkach Androida, czy gra wykorzystująca standard OpenGL ES, wygląd programu jest jedną z pierwszych rzeczy, na jakie użytkownicy zwracają uwagę w trakcie przeglądania sklepów Android Market lub Amazon Appstore. Jednak aplikacja, która wprawdzie świetnie wygląda, ale jest wolno wyświetlana lub aktualizowana, prawdopodobnie nie stanie się hitem. Podobnie gra z wysokiej jakości renderingiem, ale niską liczbą klatek, pewnie nie spodoba się użytkownikom. Sukces aplikacji zależy od jej ocen, dlatego ważne jest, aby nie skupiać się tylko na pierwszym wrażeniu. W tym rozdziale poznasz podstawowe metody optymalizowania układów za pomocą różnych technik i narzędzi. Dowiesz się też, jak optymalizować rendering z wykorzystaniem standardu OpenGL ES, aby zwiększyć liczbę klatek lub obniżyć zużycie energii. Optymalizowanie ukïadów Prawdopodobnie znasz już układy w formacie XML i metodę setContentView(). Na listingu 8.1 pokazano typowy sposób korzystania z tej metody. Choć zdaniem wielu programistów definiowanie układów jest proste (zwłaszcza za pomocą graficznego interfejsu układów, dostępnego w środowisku Eclipse), łatwo można utworzyć wysoce nieoptymalny układ. W tym podrozdziale poznasz kilka podstawowych sposobów na upraszczanie układów i przyspieszanie rozwijania układów do klas. Listing 8.1. Typowy sposób wywoływania metody setContentView() public class MyActivity extends Activity { private static final String TAG = MyActivity ; /** Wywoływana, gdy aktywność jest tworzona po raz pierwszy */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Wywołanie metody setContentView() w celu rozwinięcia // i skonfigurowania układu (zdefiniowanego w pliku main.xml) setContentView(R.layout.main); ... ROZDZIA’ 8. „ GRAFIKA } ... } Choć wywołanie jest tu bardzo proste, uruchomienie metody setContentView() prowadzi do wykonania na zapleczu kilku operacji. Oto one: x Android wczytuje dane zasobów aplikacji (z pliku APK, zapisanego albo w pamięci wewnętrznej, albo na karcie SD). x Ma miejsce przetwarzanie danych zasobów i rozwijanie układu do klasy. x Rozwinięty układ staje się widokiem najwyższego poziomu w aktywności. Czas wykonywania tej metody zależy od złożoności układu. Im więcej jest danych zasobów, tym dłużej trwa przetwarzanie. Im więcej egzemplarzy klas trzeba utworzyć, tym dłuższe jest rozwijanie układu. W trakcie tworzenia androidowego projektu w środowisku Eclipse w pliku main.xml generowany jest układ domyślny, przedstawiony na listingu 8.2. Tekst widoku TextView jest zdefiniowany w pliku strings.xml. Listing 8.2. Układ domyślny ?xml version= 1.0 encoding= utf-8 ? LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical TextView android:layout_width= fill_parent android:layout_height= wrap_content android:text= @string/hello / /LinearLayout W tablecie Samsung Galaxy Tab 10.1 wywołanie metody setContentView() z listingu 8.1 dla przedstawionego tu układu zajmuje około 17 milisekund. To szybko, jednak warto zauważyć, że układ jest niezwykle prosty. W typowych aplikacjach na Androida zwykle układy są inne. Tu trzeba utworzyć egzemplarze tylko dwóch klas (LinearLayout i TextView), a w pliku XML ustawione są nieliczne właściwości. „ Uwaga Ukïady moĝna tworzyÊ takĝe programowo, jednak zaleca siÚ stosowanie formatu XML. Po dodaniu do układu domyślnego innych kontrolek (na przykład ScrollView, EditText i ProgressBar), tak że ich łączna liczba wynosi 30, wywołanie metody setContentView() zajmuje ponad 163 milisekundy. Jak widać, czas rozwijania układu rośnie niemal liniowo wraz z liczbą kontrolek. Ponadto wykonywanie metody setContentView() zajmuje prawie 99 czasu od początku działania metody onCreate() do końca działania metody onResume(). Możesz przeprowadzić własne pomiary po dodaniu kontrolek do układu lub ich usunięciu. Modyfikowanie układu za pomocą graficznego widoku plików XML w środowisku Eclipse jest bardzo łatwe. Jeśli już zdefiniowałeś układ aplikacji, powinieneś przede wszystkim zmierzyć czas jego rozwijania. Ponieważ rozwijanie układu zwykle odbywa się w metodzie onCreate() aktywności, czas rozwijania ma bezpośredni wpływ na czas uruchamiania aktywności, a także całej aplikacji. Dlatego zaleca się minimalizowanie czasu rozwijania układów. 196 OPTYMALIZOWANIE UK’ADÓW Aby uzyskać pożądane skutki, można zastosować kilka technik. Większość z nich oparta jest na jednej zasadzie — zmniejszaniu liczby tworzonych obiektów. Można to zrobić przez zastosowanie różnych układów dających ostatecznie ten sam efekt wizualny, przez wyeliminowanie zbędnych obiektów lub przez odroczenie momentu tworzenia obiektów. Układ RelativeLayout Programiści aplikacji zwykle najpierw poznają układy liniowe (LinearLayout). Układ tego rodzaju jest częścią układu domyślnego z listingu 8.1, dlatego jest jednym z pierwszych, z jakimi stykają się programiści widoków ViewGroup. Łatwo też go zrozumieć, ponieważ układ liniowy jest kontenerem na kontrolki ułożone obok siebie lub jedna nad drugą. Większość programistów poznających Android zaczyna od zagnieżdżania układów liniowych w celu uzyskania pożądanych efektów. Na listingu 8.3 przedstawiono przykładowe zagnieżdżone układy liniowe. Listing 8.3. Zagnieżdżony układ liniowy ?xml version= 1.0 encoding= utf-8 ? LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= wrap_content android:orientation= horizontal TextView android:id= @+id/text1 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str1 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text2 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str2 android:textAppearance= ?android:attr/textAppearanceLarge / /LinearLayout LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= wrap_content android:orientation= horizontal TextView android:id= @+id/text3 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str3 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text4 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str4 android:textAppearance= ?android:attr/textAppearanceLarge / /LinearLayout LinearLayout xmlns:android= http://schemas.android.com/apk/res/android 197 ROZDZIA’ 8. „ GRAFIKA android:layout_width= fill_parent android:layout_height= wrap_content android:orientation= horizontal TextView android:id= @+id/text5 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str5 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text6 android:layout_width= wrap_content android:layout_height= wrap_content android:text= str6 android:textAppearance= ?android:attr/textAppearanceLarge / /LinearLayout /LinearLayout Podstawowe widoki w tym układzie to sześć widoków tekstowych. Cztery układy liniowe służą tu do określenia pozycji elementów. W przedstawionym układzie występują dwa problemy. Oto one: x Ponieważ układy liniowe są tu zagnieżdżone, hierarchia układów ma więcej poziomów, co spowalnia obsługę układu i kluczy. x Cztery z dziesięciu obiektów służą tylko do wyznaczania pozycji. Oba problemy można łatwo rozwiązać przez zastąpienie układów liniowych jednym układem względnym (RelativeLayout), co pokazano na listingu 8.4. Listing 8.4. Układ względny ?xml version= 1.0 encoding= utf-8 ? RelativeLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical TextView android:id= @+id/text1 android:layout_width= wrap_content android:layout_height= wrap_content android:layout_alignParentLeft= true android:layout_alignParentTop= true android:text= @string/str1 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text2 android:layout_width= wrap_content android:layout_height= wrap_content android:layout_toRightOf= @id/text1 android:layout_alignParentTop= true android:text= @string/str2 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text3 android:layout_alignParentLeft= true android:layout_below= @id/text1 android:layout_width= wrap_content android:layout_height= wrap_content android:text= @string/str3 android:textAppearance= ?android:attr/textAppearanceLarge / TextView 198 OPTYMALIZOWANIE UK’ADÓW android:id= @+id/text4 android:layout_width= wrap_content android:layout_height= wrap_content android:layout_toRightOf= @id/text3 android:layout_below= @id/text2 android:text= @string/str4 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text5 android:layout_alignParentLeft= true android:layout_below= @id/text3 android:layout_width= wrap_content android:layout_height= wrap_content android:text= @string/str5 android:textAppearance= ?android:attr/textAppearanceLarge / TextView android:id= @+id/text6 android:layout_width= wrap_content android:layout_height= wrap_content android:layout_toRightOf= @id/text5 android:layout_below= @id/text4 android:text= @string/str6 android:textAppearance= ?android:attr/textAppearanceLarge / /RelativeLayout Jak widać, wszystkie sześć układów tekstowych umieszczono teraz w jednym układzie względnym. Dlatego wystarczy utworzyć siedem obiektów zamiast dziesięciu. Ponadto układ nie ma tylu poziomów co wcześniej — widoki tekstowe znajdują się teraz na drugim poziomie. Do określenia pozycji kontrolek służą atrybuty layout_***. W Androidzie zdefiniowanych jest wiele atrybutów tego typu, które można wykorzystać do określania pozycji różnych elementów układu. Oto przykładowe atrybuty tego rodzaju: x layout_above, x layout_alignBaseline, x layout_alignBottom, x layout_alignLeft, x layout_alignRight, x layout_alignTop, x layout_alignParentBottom, x layout_alignParentLeft, x layout_alignParentRight, x layout_alignParentTop, x layout_alignWithParentIfMissing, x layout_below, x layout_centerHorizontal, x layout_centerInParent, x layout_centerVertical, x layout_column, x layout_columnSpan, x layout_gravity, x layout_height, 199 ROZDZIA’ 8. „ GRAFIKA x layout_margin, x layout_marginBottom, x layout_marginLeft, x layout_marginRight, x layout_marginTop, x layout_row, x layout_rowSpan, x layout_scale, x layout_span, x layout_toLeftOf, x layout_toRightOf, x layout_weight, x layout_width, x layout_x, x layout_y. „ Uwaga Niektóre atrybuty sÈ charakterystyczne dla ukïadów okreĂlonego rodzaju. Na przykïad atrybuty layout_column, layout_columnSpan, layout_row i layout_rowSpan sÈ przeznaczone do stosowania w ukïadach opartych na siatce. Układy względne są ważne zwłaszcza przy wyświetlaniu elementów list, ponieważ aplikacje nieraz pokazują na ekranie jednocześnie dziesięć, a nawet więcej takich elementów. Scalanie układów Inny sposób na zmniejszenie liczby poziomów w hierarchii układów to scalanie układów za pomocą znacznika merge/ . Stosunkowo często głównym elementem układu jest układ ramowy (FrameLayout). Tak właśnie jest na listingu 8.5. Listing 8.5. Układ ramowy ?xml version= 1.0 encoding= utf-8 ? FrameLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:id= @+id/my_top_layout ImageView android:layout_width= fill_parent android:layout_height= fill_parent / TextView android:layout_width= fill_parent android:layout_height= wrap_content android:text= @string/hello / /FrameLayout 200 OPTYMALIZOWANIE UK’ADÓW Ponieważ elementem nadrzędnym widoku zawartości aktywności jest także układ FrameLayout, ostatecznie w układzie znajdują się dwa obiekty FrameLayout. Oto one: x obiekt FrameLayout dodany przez programistę, x element nadrzędny widoku zawartości aktywności, czyli drugi obiekt FrameLayout (ma on tylko jeden element podrzędny — pierwszy obiekt FrameLayout). Na rysunku 8.1 pokazano układ, który powstanie, jeśli układ FrameLayout zdefiniowany przez programistę ma dwa elementy podrzędne — ImageView i TextView. Rysunek 8.1. Układ FrameLayout będący układem podrzędnym innego układu FrameLayout Występuje tu jeden nadmiarowy układ FrameLayout. Liczbę poziomów układu można zmniejszyć przez zastąpienie własnego układu FrameLayout znacznikiem merge / . Wtedy Android dołącza elementy podrzędne znacznika merge / do nadrzędnego układu FrameLayout. Na listingu 8.6 pokazano nowy układ w formacie XML. Listing 8.6. Znacznik merge / ?xml version= 1.0 encoding= utf-8 ? merge xmlns:android= http://schemas.android.com/apk/res/android ImageView android:layout_width= fill_parent android:layout_height= fill_parent / TextView android:layout_width= fill_parent android:layout_height= wrap_content android:text= @string/hello / /merge Jak widać, wystarczy zastąpić znacznik FrameLayout / znacznikiem merge / . Na rysunku 8.2 pokazano uzyskany układ. Ponowne wykorzystanie układów Android udostępnia znacznik include / , który można stosować w układach w formacie XML w podobny sposób jak dyrektywę #include w kodzie w językach C i C++. Znacznik include / powoduje dołączenie innego układu w formacie XML, co pokazano na listingu 8.7. Znacznik include / stosuje się w dwóch sytuacjach: x gdy programista chce wielokrotnie wykorzystać ten sam układ; x jeśli układ ma powtarzalne elementy, a oprócz nich części zależne od konfiguracji urządzenia (np. od orientacji ekranu — poziomej lub pionowej). 201 ROZDZIA’ 8. „ GRAFIKA Rysunek 8.2. Hierarchia po zastąpieniu znacznika FrameLayout / znacznikiem merge / Na listingu 8.7 pokazano, że układ można dołączyć wielokrotnie, a przy tym zmienić niektóre jego parametry. Listing 8.7. Wielokrotne dołączanie układu LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical include android:id= @+id/myid1 android:layout= @layout/mylayout android:layout_margin= 9dip / include android:id= @+id/myid2 android:layout= @layout/mylayout android:layout_margin= 3dip / include android:id= @+id/myid3 android:layout= @layout/mylayout / /LinearLayout Na listingu 8.8 pokazano, w jaki sposób dołączyć układ tylko raz. Jednak w zależności od orientacji ekranu dołączany jest układ layout-land/mylayout.xml lub layout-port/mylayout.xml. Przyjęto tu, że istnieją dwie wersje pliku mylayout.xml — jedna z katalogu res/layout-land i druga z katalogu res/layout-port. Listing 8.8. Dołączanie układu w zależności od orientacji ekranu LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical include android:id= @+id/myid android:layout= @layout/mylayout / /LinearLayout Gdy układ jest dołączany, można zmienić niektóre jego parametry, takie jak: x identyfikator widoku głównego (android:id), x parametry układu (android:layout_*). „ Uwaga Nie trzeba zmieniaÊ parametrów ukïadu. W znaczniku include / trzeba podaÊ tylko atrybut android:layout. Jak pokazano na listingu 8.8 dołączanie układu odbywa się dynamicznie w momencie jego rozwijania. Gdyby dołączanie odbywało się w czasie kompilacji, Android nie wiedziałby, który 202 z dwóch układów powinien dołączyć (layout-land/mylayout.xml czy layout-port/mylayout.xml). Dyrektywa #include w językach C i C++ działa inaczej, ponieważ jest obsługiwana przez preprocesor w czasie kompilacji. OPTYMALIZOWANIE UK’ADÓW Namiastki widoków W rozdziale 1. wyjaśniono, że leniwe inicjowanie to wygodna technika służąca do odraczania tworzenia obiektów, zwiększania wydajności i potencjalnie zmniejszania zużycia pamięci (gdy okazuje się, że dane obiekty nigdy nie są potrzebne). W Androidzie leniwe inicjowanie jest możliwe dzięki namiastce widoków — klasie ViewStub. Reprezentuje ona prosty, ukryty widok, który można zastosować w układzie, aby umożliwić leniwe rozwijanie zasobów układu, wtedy gdy są potrzebne. Listing 8.9 to zmodyfikowana wersja listingu 8.8. Pokazano tu, jak zastosować klasę ViewStub w układzie w formacie XML. Listing 8.9. Klasa ViewStub w XML-owym układzie LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical ViewStub android:id= @+id/mystubid android:inflatedId= @+id/myid android:layout= @layout/mylayout / /LinearLayout Przedstawiony tu układ LinearLayout w trakcie rozwijania obejmuje tylko jeden element podrzędny — ViewStub. Układ powiązany z obiektem ViewStub, @layout/mylayout, może być bardzo skomplikowany. Jego rozwinięcie może więc zająć dużo czasu (na razie układ ten jednak nie jest rozwijany). Układ z pliku mylayout.xml można rozwinąć w kodzie na dwa sposoby, przedstawione na listingach 8.10 i 8.11. Listing 8.10. Rozwijanie układu w kodzie ViewStub stub = (ViewStub) findViewById(R.id.mystubid); // inflatedView będzie układem zdefiniowanym w pliku mylayout.xml View inflatedView = stub.inflate(); Listing 8.11. Rozwijanie układu w kodzie za pomocą metody setVisibility() View view = findViewById(R.id.mystubid); view.setVisibility(View.VISIBLE); // Namiastka widoku zastępowana rozwiniętym układem view = findViewById(R.id.myid); // W tym miejscu trzeba pobrać rozwinięty widok Wprawdzie pierwszy sposób rozwijania układu (listing 8.10) wydaje się wygodniejszy, jednak zdaniem niektórych programistów występuje w nim drobna wada. W kodzie wiadomo, że widok jest namiastką, dlatego trzeba bezpośrednio rozwinąć układ. W większości sytuacji nie stanowi to problemu, dlatego zaleca się stosowanie tej techniki do rozwijania układu, jeśli w układzie aplikacji używana jest klasa ViewStub. Druga metoda rozwijania układu (listing 8.11) jest bardziej uniwersalna, ponieważ nie trzeba używać tu klasy ViewStub. Jednak w przedstawionym tu rozwiązaniu nadal wiadomo, że stosowana jest klasa ViewStub (ponieważ w kodzie występują różne identyfikatory — R.id.mystubid i R.id.myid). Aby kod był w pełni uniwersalny, układ trzeba zdefiniować w sposób pokazany na listingu 8.12, a rozwijanie układu powinno wyglądać tak jak na listingu 8.13. Listing 8.12 jest prawie identyczny z listingiem 8.9. Różnica polega na tym, że tworzony jest tylko jeden identyfikator (R.id.myid) 203 ROZDZIA’ 8. „ GRAFIKA zamiast dwóch. Podobnie listing 8.13 jest bardzo podobny do listingu 8.11 — zastąpiono jedynie identyfikator R.id.mystubid identyfikatorem R.id.myid. Listing 8.12. Klasa ViewStub w XML-owym układzie bez zmiany identyfikatora LinearLayout xmlns:android= http://schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= fill_parent android:orientation= vertical ViewStub android:id= @+id/myid android:layout= @layout/mylayout / /LinearLayout Listing 8.13. Rozwijanie układu w kodzie za pomocą metody setVisibility() View view = findViewById(R.id.myid); view.setVisibility(View.VISIBLE); // Namiastka widoku zastępowana rozwiniętym układem view = findViewById(R.id.myid); // W tym miejscu trzeba pobrać rozwinięty widok Kod z listingu 8.13 jest prawidłowy niezależnie od tego, czy w układzie występuje klasa ViewStub. Jeśli kod ma być uniwersalny i działać poprawnie niezależnie od stosowania klasy ViewStub, zaleca się używanie opisanego podejścia. Jednak dwa wywołania metody findViewById() są niewydajne. Aby częściowo rozwiązać problem, warto wykorzystać fakt, że obiekt ViewStub jest usuwany z rodzica w momencie wywołania metody setVisibility(View.VISIBLE). Dlatego można najpierw (przed ponownym wywołaniem metody findViewById()) sprawdzić, czy widok nadal ma rodzica. Choć nie jest to idealne rozwiązanie (ponieważ jeśli klasa ViewStub występuje w układzie, to i tak trzeba dwukrotnie wywołać metodę findViewById()), uzyskano przynajmniej to, że metoda jest wywoływana jednokrotnie, jeśli programista nie używa klasy ViewStub. Nowa wersja kodu znajduje się na listingu 8.14. Listing 8.14. Jednokrotne wywołanie metody findViewById() (jeśli jest to możliwe) View view = findViewById(R.id.myid); // Namiastka jest zastępowana rozwiniętym układem (jeśli w układzie występuje namiastka) view.setVisibility(View.VISIBLE); if (view.getParent() == null) { // Użyto namiastki, dlatego trzeba znaleźć zastępujący ją rozwinięty widok view = findViewById(R.id.myid); } else { // Nie trzeba nic robić. Odpowiedni jest widok znaleziony za pierwszym razem } Kod z listingów 8.13 i 8.14 jest niestandardowy i zwykle nie trzeba stosować przedstawionego tu podejścia. Przeważnie dopuszczalne jest uwzględnianie w kodzie tego, że w układach używana jest klasa ViewStubs, dlatego można zastosować prosty sposób rozwijania namiastek, pokazany na listingu 8.10. NarzÚdzia wspomagajÈce tworzenie ukïadów W pakiecie SDK dostępne są dwa łatwe w użyciu narzędzia, mianowicie hierarchyviewer i layoutopt, które wspomagają tworzenie optymalnych układów. Te i inne narzędzia znajdują się w katalogu tools pakietu SDK. 204 STANDARD OPENGL ES Przeglądarka hierarchii W pakiecie SDK Androida znajduje się bardzo przydatne narzędzie do wyświetlania i analizowania układu aplikacji. To narzędzie to hierarchyviewer. Rysunki 8.1 i 8.2 wygenerowano właśnie przy użyciu tego narzędzia. Nie tylko wyświetla ono szczegółowy układ aplikacji, ale też określa, ile czasu potrzeba na wymierzenie, rozmieszczenie i wyświetlenie każdej kontrolki. Wykrywa też, dla których kontrolek ten czas jest długi. Narzędzie hierarchyviewer można stosować niezależnie lub bezpośrednio w środowisku Eclipse (w perspektywie Hierarchy View). Narzędzie layoutopt Innym narzędziem z pakietu SDK pomocnym przy tworzeniu układów jest layoutopt. Narzędzie to analizuje pliki układu i zaleca zmiany zwiększające jego wydajność. Uruchomienie narzędzia layoutopt dla układu z listingu 8.5 pozwala uzyskać następujące informacje: The root-level FrameLayout/ can be replaced with merge/ (czyli: element główny FrameLayout/ można zastąpić elementem merge/ ). Okazuje się, że właśnie taką zmianę wprowadzono na listingu 8.6. Uruchomienie narzędzia layoutopt dla kodu z listingu 8.6 nie prowadzi do uzyskania żadnych zaleceń. „ Wskazówka Aby uzyskaÊ najlepsze efekty, naleĝy zastosowaÊ najnowszÈ wersjÚ narzÚdzia layoutopt. Przed udostępnieniem aplikacji popraw wszelkie problemy wykryte przez narzędzie layoutopt. Niezoptymalizowane układy mogą spowalniać działanie aplikacji, a rozwiązanie wskazanych usterek jest zwykle proste. Standard OpenGL ES Renderowanie grafiki trójwymiarowej staje się coraz ważniejszą funkcją współczesnych urządzeń i aplikacji androidowych. Choć potrzeba sporo czasu, aby zostać ekspertem do renderowania grafiki trójwymiarowej, w najbliższych punktach poznasz łatwe w stosowaniu techniki, a także podstawowe zagadnienia, o których należy wiedzieć przed rozpoczęciem pisania kodu związanego z grafiką trójwymiarową. Jeśli chcesz dowiedzieć się czegoś więcej o korzystaniu ze standardu OpenGL ES w Androidzie, zajrzyj do książki Pro OpenGL ES for Android Mike’a Smithwicka i Mayanka Vermy. Większość nowych urządzeń z Androidem obsługuje zarówno standard OpenGL ES 1.1, jak i OpenGL ES 2.0, natomiast starsze urządzenia są zgodne tylko z tym pierwszym. W grudniu 2011 roku około 90 urządzeń łączących się ze sklepem Android Market obsługiwało standard OpenGL ES 2.0. Choć OpenGL ES to standard opracowany przez organizację Khronos Group, istnieje kilka jego implementacji. Oto zgodne ze standardem OpenGL ES procesory graficzne najczęściej spotykane w urządzeniach z Androidem: x ARM Mali (np. Mali 400-MP4), x Imagination Technologies PowerVR (np. PowerVR SGX543), x Nvidia GeForce (Nvidia Tegra), x Qualcomm Adreno (kupiony od AMD; wcześniej nosił nazwę ATI Imageon; jest zintegrowany z układami Qualcomm Snapdragon). 205 ROZDZIA’ 8. „ GRAFIKA Rozszerzenia Standard OpenGL obsługuje rozszerzenia, co pozwala na wbudowanie w niektóre procesory graficzne nowych funkcji. Na przykład w tabletach Samsung Galaxy Tab 10.1 (z procesorem graficznym Nvidia Tegra 2) obsługiwane są następujące rozszerzenia: x GL_NV_platform_binary, x GL_OES_rgb8_rgba8, x GL_OES_EGL_sync, x GL_OES_fbo_render_mipmap, x GL_NV_depth_nonlinear, x GL_NV_draw_path, x GL_NV_texture_npot_2D_mipmap, x GL_OES_EGL_image, x GL_OES_EGL_image_external, x GL_OES_vertex_half_float, x GL_NV_framebuffer_vertex_attrib_array, x GL_NV_coverage_sample, x GL_OES_mapbuffer, x GL_ARB_draw_buffers, x GL_EXT_Cg_shaders, x GL_EXT_packed_float, x GL_OES_texture_half_float, x GL_OES_texture_ float, x GL_EXT_texture_array, x GL_OES_compressed_ETC1_RGB8_texture, x GL_EXT_texture_compression_latc, x GL_EXT_texture_compression_dxt1, x GL_EXT_texture_compression_s3tc, x GL_EXT_texture_filter_anisotropic, x GL_NV_get_text_image, x GL_NV_read_buffer, x GL_NV_shader_framebuffer_fetch, x GL_NV_fbo_color_attachements, x GL_EXT_bgra, x GL_EXT_texture_format_BGRA8888, x GL_EXT_unpack_subimage, x GL_NV_texture_compression_st3c_update. Na listingu 8.15 pokazano, jak pobrać listę rozszerzeń obsługiwanych przez urządzenie. Ponieważ standard OpenGL ES 2.0 obecnie nie jest obsługiwany przez emulator Androida, kod należy uruchomić na urządzeniu. 206 STANDARD OPENGL ES Listing 8.15. Rozszerzenia standardu OpenGL ES // Lista rozszerzeń zwracana jako jeden łańcuch znaków (można znaleźć w nim konkretne rozszerzenie) String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS); Log.d(TAG, Rozszerzenia: + extensions); Aby z powodzeniem wykonać kod z listingu 8.15 i pobrać listę rozszerzeń, potrzebny jest kontekst związany ze standardem OpenGL. Kod ten można uruchomić na przykład w metodzie onSurfaceChanged() klasy GLSurfaceView.Renderer. Wywołanie kodu poza odpowiednim kontekstem spowoduje wyświetlenie w narzędziu LogCat komunikatu call to OpenGL ES API with no current context. Przedstawione wcześniej rozszerzenia można podzielić na kilka grup: x GL_OES_*, x GL_ARB_*, x GL_EXT_*, x GL_NV_*. Rozszerzenia z rodziny GL_OES_* zostały zatwierdzone przez grupę roboczą odpowiedzialną za OpenGL ES w operacji Khronos. Choć rozszerzenia te nie są wymagane w standardzie OpenGL, są powszechnie dostępne. Rozszerzenia GL_ARB_* zostały zatwierdzone przez jednostkę OpenGL Architecture Review Board. Rozszerzenia GL_EXT_* są obsługiwane przez dużą część producentów, a rozszerzenia GL_NV_* są charakterystyczne dla sprzętu Nvidii. Na podstawie obsługiwanych rozszerzeń można zwykle stwierdzić, która firma jest producentem procesora graficznego zastosowanego w urządzeniu. x Rozszerzenia procesorów ARM mają przedrostek GL_ARM. x Rozszerzenia procesorów firmy Imagination Technologies mają przedrostek GL_IMG. x Rozszerzenia procesorów Nvidii mają przedrostek GL_NV. x Rozszerzenia procesorów firmy Qualcomm mają przedrostki GL_QUALCOMM, GL_AMD i GL_ATI. „ Uwaga WiÚcej informacji znajdziesz na stronach http://www.khronos.org/registry/gles i http://www.opengl.org/registry. Ponieważ nie wszystkie urządzenia obsługują te same rozszerzenia (warto przypomnieć tu o fragmentacji rynku), trzeba zachować dużą ostrożność przy optymalizowaniu kodu pod kątem konkretnego urządzenia. Czasem kod, który działa w jednym urządzeniu, nie będzie działał w innym. Typowymi przykładami technik obsługiwanych tylko w niektórych urządzeniach są tekstury typu NPOT (ang. Non-Power-Of-Two) i format kompresji tekstur. Jeśli chcesz, aby kod był zgodny także z urządzeniami bez Androida, zwróć uwagę na rozszerzenia obsługiwane przez docelowe urządzenia. Obecnie urządzenia Apple’a (iPhone, iPod i iPad) są oparte na procesorze PowerVR firmy Imagination Technologies, jednak w przyszłych urządzeniach Apple’a mogą pojawić się inne procesory. Kompresja tekstur Od tekstur zależy wygląd aplikacji wykorzystujących OpenGL ES. Choć korzystanie z nieskompresowanych tekstur jest proste, tekstury tego rodzaju powodują szybki wzrost wielkości aplikacji. Na przykład nieskompresowana tekstura o wymiarach 256×256 w formacie RGBA8888 może zajmować 256 kilobajtów pamięci. 207 ROZDZIA’ 8. „ GRAFIKA Nieskompresowane tekstury negatywnie wpływają na wydajność, ponieważ trudniej jest je zapisać w pamięci podręcznej niż tekstury skompresowane (z uwagi na wielkość). Ponadto wymagają dłuższego dostępu do pamięci, co wpływa także na zużycie energii. Aplikacje z nieskompresowanymi teksturami są również większe, dlatego dłużej trwa ich pobieranie i instalowanie. Oprócz tego ilość pamięci w urządzeniach z Androidem jest zwykle ograniczona, dlatego w aplikacjach należy zajmować jej jak najmniej. Na poniższej liście wymieniono formaty kompresji tekstur obsługiwane w urządzeniu Samsung Galaxy Tab 10.1: x GL_OES_compressed_ETC1_RGB8_texture, x GL_EXT_texture_compression_latc, x GL_EXT_texture_compression_dxt1, x GL_EXT_texture_compression_s3tc. Format kompresji ETC1 został opracowany w firmie Ericsson (ETC to akronim nazwy Ericsson Texture Compression) i jest obsługiwany przez większość urządzeń z Androidem, w tym przez wszystkie takie urządzenia zgodne ze standardem OpenGL ES 2.0. Dlatego jest to najbezpieczniejszy format ze względu na liczbę obsługiwanych urządzeń. Używa się w nim 4 bitów na piksel zamiast 24 (format ETC1 nie obsługuje kanału alfa), co zapewnia sześciokrotny poziom kompresji. Jeśli dodać 16-bajtowy nagłówek, tekstura o wymiarach 256×256 w formacie ETC1 zajmuje 32 784 bajty. Istnieje wiele narzędzi do tworzenia tekstur w formacie ETC1. W pakiecie SDK Androida znajduje się uruchamiane z wiersza poleceń narzędzie etc1tool. Służy ono do przekształcania obrazów w formacie PNG na skompresowane obrazy w formacie ETC1. Poniższa instrukcja kompresuje plik lassen.png (183 kilobajty) i pokazuje różnicę między pierwotnym a skompresowanym plikiem: etc1tool lassen.png --encode --showDifference lassen_diff.png Jeśli programista nie podał pliku wynikowego, nazwa pliku jest generowana na podstawie pliku wejściowego. Tu plik wynikowy to lassen.pkm (zajmuje 33 kilobajty). Na rysunku 8.3 pokazano różnicę między skompresowaną grafiką a oryginałem. Rysunek 8.3. Pierwotny rysunek (po lewej) i różnica w stosunku do skompresowanej wersji (po prawej) „ Uwaga Za pomocÈ narzÚdzia etc1tool moĝna teĝ przeksztaïciÊ plik w formacie ETC1 na obraz w formacie PNG. WiÚcej informacji o tym narzÚdziu znajdziesz na stronie http://d.android.com/guide/developing/tools/etc1tool.html. Niestety, narzędzie etc1tool z pakietu SDK Androida udostępnia niewiele opcji. Dlatego programiści, którzy chcą zachować kontrolę nad kompresją i jakością grafiki, powinni stosować inne narzędzie — etcpack. Można je pobrać z witryny firmy Ericsson (http://devtools.ericsson.com/etc). Pozwala ono ustawić następujące opcje: 208 STANDARD OPENGL ES x szybkość kompresji (mniejsza szybkość to wyższa jakość), x miarę błędu (percepcyjna lub niepercepcyjna), x orientację. Jeśli tekstury są generowane „stacjonarnie” (czyli nie na samym urządzeniu z Androidem), zawsze należy zastosować jak najwyższą jakość kompresji. Ponieważ ludzkie oko jest wrażliwsze na kolor zielony niż na czerwony lub niebieski, należy ponadto wybrać tryb percepcyjny dla miary błędu (algorytm zapewnia wtedy większą wierność koloru zielonego względem oryginału kosztem kolorów czerwonego i niebieskiego, co zmniejsza maksymalny stosunek sygnału do szumu). Choć różnice nie zawsze są widoczne, nie ma powodu, aby udostępniać aplikację z teksturami niższej jakości. W formacie ETC1 tekstury wyższej jakości mają ten sam rozmiar jak te o niższej jakości. Choć generowanie tekstur wyższej jakości trwa dłużej (dlatego na etapie programowania wielu programistów decyduje się korzystać z tekstur niższej jakości), przed udostępnieniem aplikacji zawsze należy pamiętać o zastosowaniu tekstur wyższej jakości. Jeszcze inna możliwość to narzędzie ARM Mali GPU Compression Tool. Można je pobrać bezpłatnie ze strony http://www.malideveloper.com/developer-resources/tools. Narzędzie to udostępnia podobne opcje jak etcpack, jednak ma interfejs graficzny (przy czym dostępna jest też wersja uruchamiana z wiersza poleceń). Na rysunku 8.4 pokazano narzędzie ARM Mali GPU Compression Tool modyfikujące opisywany już wcześniej plik. Rysunek 8.4. Narzędzie ARM Mali GPU, przeznaczone do kompresji grafiki Na rysunku 8.5 pokazano różnicę w jakości dla kompresji wysokiej jakości (powolnej) i niskiej jakości (szybkiej). Widać, że różnice między grafikami w różnych trybach nie są wyraźne. 209 ROZDZIA’ 8. „ GRAFIKA Rysunek 8.5. Wysoka jakość (po lewej), średnia jakość (pośrodku) i niska jakość (po prawej) W witrynie dla programistów oprogramowania na procesory ARM Mali dostępnych jest wiele narzędzi. Liczne narzędzia do tworzenia i debugowania kodu można znaleźć w witrynach firm ARM, Imagination Technologies, Nvidia i Qualcomm: x http://www.malideveloper.com/developer-resources/tools, x http://www.imgtec.com/powervr/insider/sdkdownloads, x http://developer.nvidia.com/tegra-android-development-pack, x http://developer.qualcomm.com/develop/mobile-technologies/graphics-optimization-adreno. Na przykład firma Imagination Technologies także udostępnia narzędzie do tworzenia skompresowanych tekstur, PVRTexTool, a w witrynie Nvidii znajduje się kompletny pakiet SDK (obejmujący pakiet SDK Androida, pakiet NDK, środowisko Eclipse i przykładowy kod). „ Uwaga W niektórych z wymienionych witryn trzeba siÚ zarejestrowaÊ, aby uzyskaÊ dostÚp do narzÚdzi i dokumentów. Począwszy od Androida 2.2 (poziom 8. interfejsu API) dostępne są następujące klasy pomagające w korzystaniu z tekstur w formacie ETC1: x android.opengl.ETC1, x android.opengl.ETC1Util, x android.opengl.ETC1Util.ETC1Texture. Aplikacja może kompresować grafikę do formatu ETC1 dynamicznie. Służą do tego metody ETC1.encodeImage() i ETC1Util.compressTexture(). Dynamiczna kompresja jest przydatna, jeśli tekstur ETC1 nie można wygenerować w trybie „stacjonarnym”, na przykład gdy tekstury są oparte na plikach graficznych zapisanych w urządzeniu (np. zdjęcie jednej z osób z listy kontaktów). „ Wskazówka ChoÊ format ETC1 nie obsïuguje przezroczystoĂci (w skompresowanej teksturze nie ma kanaïu alfa), moĝna wykorzystaÊ innÈ, jednokanaïowÈ teksturÚ obejmujÈcÈ tylko informacje o przezroczystoĂci i poïÈczyÊ obie tekstury w programie cieniowania. Inne formaty kompresji tekstur Choć ETC1 to najpopularniejszy format kompresji tekstur, istnieją też inne, obsługiwane przez niektóre urządzenia. Oto wybrane formaty: x PowerVR Texture Compression (PVRTC), 210 STANDARD OPENGL ES x ATI Texture Compression (ATC lub ATITC), x S3 Texture Compression (S3TC) z wersjami od DXT1 do DXT5. Warto wypróbować różne formaty w zależności od urządzeń docelowych. Ponieważ dany procesor graficzny może być zoptymalizowany pod kątem powiązanego z nim formatu kompresji (np. procesor graficzny PowerVR jest zoptymalizowany na potrzeby formatu PVRTC), lepsze efekty można uzyskać za pomocą specyficznych formatów kompresji niż przy stosowaniu bardziej standardowego formatu ETC1. „ Uwaga Do generowania tekstur w formacie PVRTC moĝna teĝ stosowaÊ narzÚdzie texturetool z systemu iOS Apple’a. Manifest W manifeście aplikacji wykorzystującej OpenGL należy określić dwie rzeczy: x którą wersję standardu OpenGL urządzenie ma obsługiwać, x które formaty kompresji wykorzystano w aplikacji. Na listingu 8.16 pokazano, jak określić, że urządzenie ma być zgodne ze standardem OpenGL ES 2.0, a aplikacja obsługuje tylko dwa formaty kompresji: ETC1 i PVRTC. Listing 8.16. Manifest aplikacji korzystającej z OpenGL ?xml version= 1.0 encoding= utf-8 ? manifest xmlns:android= http://schemas.android.com/apk/res/android package= com.apress.proandroid.opengl android:versionCode= 1 android:versionName= 1.0 uses-sdk android:minSdkVersion= 8 / uses-feature android:glEsVersion= 0x00020000 / supports-gl-texture android:name= GL_OES_compressed_ETC1_RGB8_texture / supports-gl-texture android:name= GL_IMG_texture_compression_pvrtc / ... /manifest „ Uwaga Wersja standardu OpenGL ES jest zapisywana w formacie 16.16, dlatego OpenGL ES 2.0 to 0x0002000. W sklepie Android Market opisane informacje są używane do filtrowania aplikacji dostępnych dla łączących się urządzeń. Na przykład w urządzeniu zgodnym tylko ze standardem OpenGL ES 1.1 nie są widoczne aplikacje wymagające OpenGL ES 2.0. Podobnie w urządzeniach obsługujących tylko format ETC1 nie pojawiają się aplikacje korzystające tylko z formatów PVRTC i ATC. Jeśli w manifeście aplikacji nie określono żadnego formatu kompresji tekstur, sklep Android Market nie stosuje filtrów dotyczących takiego formatu (z uwagi na założenie, że program obsługuje wszystkie możliwe formaty). Dlatego może się okazać, że użytkownik zainstaluje aplikację, która nie będzie działać. Może to prowadzić do przyznawania niskich ocen programowi. 211 ROZDZIA’ 8. „ GRAFIKA Mipmapy Obiekty w trójwymiarowej scenie często pojawiają się w tle i nie zajmują dużo przestrzeni na ekranie. Dlatego stosowanie tekstury o wymiarach 256×256 dla obiektu zajmującego na ekranie obszar 10×10 pikseli prowadzi do marnotrawienia zasobów (pamięci i przepustowości łącza). Mipmapy pozwalają rozwiązać ten problem przez określenie różnych poziomów szczegółowości w teksturach, co pokazano na rysunku 8.6. Rysunek 8.6. Mipmapy o wymiarach od 256×256 do 1×1 Choć zestaw bitmap zajmuje zwykle około 33 więcej pamięci niż pojedynczy pierwotny rysunek, pozwala nie tylko poprawić wydajność, ale też jakość grafiki. Na rysunku 8.6 widać, że każdy rysunek to wersja pierwotnej grafiki, ale na różnym poziomie szczegółowości. Oczywiście trudno jest dostrzec kwiat w wersji o wymiarach 1×1. Do generowania mipmap można zastosować narzędzie ARM Mali GPU Texture Compression Tool. Zamiast tworzyć jeden plik .pkm, narzędzie to generuje obrazy na wszystkich poziomach szczegółowości (aż do grafiki o wymiarach 1×1) i dla każdego poziomu tworzy odrębny plik .pkm. W aplikacji trzeba następnie wczytywać te poziomy jeden po drugim — wywołując na przykład metodę ETC1Util.loadTexture() lub GLES20.glTexImage2D(). Ponieważ nie wszystkie urządzenia są identyczne, nie każde wymaga tego samego poziomu szczegółowości. Na przykład urządzenia Google TV o rozdzielczości HD 1920×1080 wymagają bardziej szczegółowego obrazu niż Samsung Nexus S o rozdzielczości WVGA 800×480. Dlatego dla urządzenia Google TV potrzebna może być tekstura o wymiarach 256×256, natomiast dla urządzenia Nexus S wystarczająca jest tekstura o wymiarach 128×128. „ Uwaga Przy wyborze tekstury, którÈ aplikacja ma zastosowaÊ, nie naleĝy uwzglÚdniaÊ tylko rozdzielczoĂci ekranu. Na przykïad w telewizorach Google TV firmy Sony (rozdzielczoĂÊ 1920×1080) uĝywany jest procesor PowerVR SGX535 o szybkoĂci 400MHz, który jest mniej wydajny niĝ procesor PowerVR SGX540 o szybkoĂci 384MHz z nowszego urzÈdzenia Samsung Galaxy Nexus (rozdzielczoĂÊ 1280×720). Sposób renderowania tekstur zależy też od parametrów ust
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Optymalizacja wydajności aplikacji na Android
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: