Android Kotlin Fundamentals 01.3: zasoby graficzne i zgodność

Te ćwiczenia są częścią kursu Android Kotlin Fundamentals. Skorzystaj z tego kursu, jeśli będziesz wykonywać kolejno kilka ćwiczeń z programowania. Wszystkie ćwiczenia z kursu są wymienione na stronie docelowej ćwiczeń z programowania na temat Kotlin.

Wprowadzenie

Dzięki nim dowiesz się, jak ulepszyć aplikację DiceRoller z ostatniego ćwiczenia z programowania, a także jak dodawać zasoby graficzne i jak z nich korzystać. Poznasz również zgodność aplikacji z różnymi wersjami Androida oraz dowiesz się, jak może Ci w tym pomóc pakiet Jetpack dla Androida.

Co warto wiedzieć

  • Jak utworzyć nowy projekt aplikacji i uruchomić ją w emulatorze lub na urządzeniu fizycznym.
  • Podstawowe komponenty projektu aplikacji, w tym katalog (res) i pliki kompilacji Gradle.
  • Jak edytować plik układu aplikacji.
  • Znajdowanie i modyfikowanie obiektów widoku w kodzie aplikacji.

Czego się nauczysz:

  • Jak dodać pliki do zasobów aplikacji.
  • Jak używać obrazów w układzie aplikacji.
  • Jak skuteczniej znaleźć wyświetlenia w kodzie aplikacji.
  • Jak używać zastępczych obrazów w projekcie aplikacji z przestrzenią nazw XML.
  • Informacje o poziomach interfejsu API Androida i o tym, jak sprawdzić minimalny, docelowy i skompilowany poziom interfejsu API.
  • Jak korzystać z bibliotek Jetpacka w swojej aplikacji do obsługi starszych wersji Androida.

Co chcesz

  • Zmodyfikuj aplikację DiceRoller z ostatniego ćwiczenia z programowania, tak by uwzględnić liczbę obrazów, a nie liczbę.
  • Dodaj pliki graficzne do zasobów aplikacji.
  • Zaktualizuj układ i kod aplikacji tak, aby zamiast wartości liczbowej używał obrazów.
  • Zaktualizuj swój kod, aby efektywniej znajdować wyświetlenia.
  • Zaktualizuj kod, aby po uruchomieniu aplikacji używać pustego obrazu.
  • Zaktualizuj aplikację, aby korzystać z bibliotek Android Jetpack do zapewnienia zgodności wstecznej ze starszymi wersjami Androida.

W tym ćwiczeniu tworzysz aplikację DiceRoller rozpoczętą w poprzednim ćwiczeniach z ćwiczenia i dodajesz kości do zmiany, gdy rzucisz kostką. Ostateczna wersja aplikacji DiceRoller wygląda tak:

Jeśli nie przeprowadzono ostatniego ćwiczenia z programowania, aplikację startową możesz pobrać tutaj: DiceRoller.

Na koniec ostatniego ćwiczenia z programowania masz aplikację, która za każdym razem, gdy użytkownik kliknie przycisk, aktualizuje widok tekstowy o liczbie od 1 do 6. Ta aplikacja nazywa się DiceRoller, a nie 1–6 generatorów liczb, więc lepiej byłoby, gdyby kości były do niej podobne. W tym zadaniu dodasz obrazy do kości. Potem zamiast aktualizować tekst po naciśnięciu przycisku, wymieniasz inny obraz dla każdego wyniku.

Krok 1. Dodaj obrazy

  1. Otwórz projekt aplikacji DiceRoller w Android Studio, jeśli nie jest jeszcze otwarty. Jeśli nie udało Ci się ukończyć ostatniego ćwiczenia z programowania, możesz pobrać aplikację tutaj: DiceRoller.
  2. W widoku projektu w Androidzie rozwiń folder res i rozwiń folder draw.



    Twoja aplikacja używa wielu różnych zasobów, w tym obrazów i ikon, kolorów, ciągów tekstowych oraz układów XML. Wszystkie te zasoby są przechowywane w folderze res. W folderze drawable musisz umieścić wszystkie zasoby graficzne aplikacji. W folderze drawable znajdziesz zasoby programu uruchamiającego aplikację.
  3. Kliknij dwukrotnie plik ic_launch_background.xml. Są to pliki XML, które opisują ikonę jako obraz wektorowy. Wektory umożliwiają rysowanie obrazów w różnych rozmiarach i rozdzielczości. Obrazy bitmap, takie jak PNG lub GIF, mogą wymagać skalowania na różnych urządzeniach, co może spowodować utratę jakości.
  4. Kliknij Podgląd w prawej kolumnie edytora XML, aby wyświetlić wektorowy rysunek.


  5. Pobierz zdjęcia kości do swojej aplikacji z DiceImages.zip. Rozpakuj archiwum. Zbiór folderów XML powinien wyglądać tak:

  1. W Android Studio kliknij menu u góry widoku projektu, które obecnie wyświetla Android, i wybierz Projekt. Zrzut ekranu poniżej przedstawia, jak wygląda aplikacja w systemie plików.


  2. Rozwiń sekcję giceRoller > app > src > main > res > pull.
  3. Przeciągnij wszystkie pliki XML z folderu DiceImages do folderu Android Studio i do rysunkowego folderu. Kliknij OK.
  1. Przełącz projekt z powrotem na widok Android. Zwróć uwagę, że pliki XML obrazu z kością znajdują się w rysunkowym folderze.
  2. Kliknij dwukrotnie dice_1.xml. Zwróć uwagę na kod XML tego obrazu. Kliknij przycisk Podgląd, aby zobaczyć, jak wygląda wektorowy obiekt rysowalny.

Krok 2. Zaktualizuj układ, aby używać obrazów

Teraz, gdy masz w folderze res/drawables pliki obrazów kości, możesz uzyskać do nich dostęp za pomocą układu i kodu aplikacji. W tym kroku zastępujesz TextView wartościami, które wyświetlają obrazy, wartością ImageView.

  1. Otwórz plik z układem activity_main.xml, jeśli nie jest jeszcze otwarty. Kliknij kartę Tekst, aby wyświetlić kod XML układu.
  2. Usuń element <TextView>.
  3. Dodaj element <ImageView> o tych atrybutach:
<ImageView
   android:id="@+id/dice_image"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center_horizontal"
   android:src="@drawable/dice_1" />

Użyj ImageView, by wyświetlić obraz w układzie. Jedyny nowy atrybut tego elementu to android:src, który wskazuje zasób źródłowy obrazu. W tym przypadku źródło obrazu @drawable/dice_1 oznacza, że Android powinien poszukać w rysunkach zasobów (res/drawable) obrazu o nazwie dice_1.

  1. Kliknij przycisk Podgląd, aby wyświetlić podgląd układu. Powinno to wyglądać tak:

Krok 3. Zaktualizuj kod

  1. Otwórz aplikację MainActivity. Jak do tej pory działała funkcja rollDice():
private fun rollDice() {
   val randomInt = Random().nextInt(6) + 1

   val resultText: TextView = findViewById(R.id.result_text)
   resultText.text = randomInt.toString()
}

Zauważ, że odwołanie do R.id.result_text może być zaznaczone na czerwono, czyli że fragment TextView został usunięty z układu i ten identyfikator już nie istnieje.

  1. Usuń dwa wiersze na końcu funkcji, która określa zmienną resultText, i ustaw jej właściwość tekstową. Nie korzystasz już z układu TextView w układzie, więc nie potrzebujesz żadnego z tych wierszy.
  2. Użyj atrybutu findViewByID(), aby uzyskać odniesienie do nowego elementu ImageView w układzie według identyfikatora (R.id.dice_image), i przypisz ten widok do nowej zmiennej diceImage:
val diceImage: ImageView = findViewById(R.id.dice_image)
  1. Dodaj blok when, aby wybrać konkretny obraz na podstawie wartości randomInteger:
val drawableResource = when (randomInt) {
   1 -> R.drawable.dice_1
   2 -> R.drawable.dice_2
   3 -> R.drawable.dice_3
   4 -> R.drawable.dice_4
   5 -> R.drawable.dice_5
   else -> R.drawable.dice_6
}

Podobnie jak w przypadku identyfikatorów, możesz odwoływać się do obrazów w rysunku w rysunku z wartościami w klasie R. R.drawable dotyczy folderu rysunkowego aplikacji, a dice_1 to konkretny zasób obrazu w tym folderze.

  1. Zaktualizuj źródło ImageView za pomocą metody setImageResource() i odwołania do znalezionego właśnie obrazu kostki.
diceImage.setImageResource(drawableResource)
  1. Skompiluj i uruchom aplikację. Gdy klikniesz przycisk Rolka, obraz powinien się zaktualizować, dodając odpowiedni obraz.

Wszystko w Twojej aplikacji działa, ale kodowanie to coś więcej niż kod, który będzie działał. Rozumiesz też, jak pisać skuteczne i działające aplikacje. Oznacza to, że aplikacje powinny działać prawidłowo, nawet jeśli użytkownik nie ma najdroższego urządzenia z Androidem lub najlepszej sieci. W miarę dodawania kolejnych funkcji aplikacje powinny nadal działać płynnie, a kod powinien być czytelny i dobrze zorganizowany.

W tym zadaniu poznasz jeden ze sposobów na zwiększenie wydajności aplikacji.

  1. Otwórz aplikację MainActivity, jeśli jeszcze nie jest otwarta. W metodzie rollDice() zwróć uwagę na deklarację zmiennej diceImage:
val diceImage : ImageView = findViewById(R.id.dice_image)

rollDice() jest modułem obsługi kliknięć przycisku Rolka, więc za każdym razem, gdy użytkownik kliknie ten przycisk, aplikacja wywoła polecenie findViewById() i odwoła się do tego elementu ImageView. Najlepiej, aby liczba połączeń z adresem findViewById() była jak najmniejsza, ponieważ system Android za każdym razem przeszukuje całą hierarchię widoków danych, co jest drogim procesem.

W małej aplikacji, takiej jak ta, nie jest to wielki problem. Jeśli korzystasz z bardziej złożonej aplikacji na wolniejszym telefonie, ciągłe wywoływanie findViewById() może spowodować jej opóźnienie. Zamiast tego najlepiej wywołać raz element findViewById() i zapisać obiekt View w polu. Pozostawienie odniesienia do ImageView w polu umożliwia systemowi bezpośredni dostęp do View w dowolnym momencie, co zwiększa wydajność.

  1. U góry klasy przed onCreate() utwórz pole do przechowywania danych ImageView.
var diceImage : ImageView? = null

Najlepiej jest zainicjować tę zmienną tutaj, gdy jest ona deklarowana lub w konstruktorze, ale aktywności na Androidzie nie używają konstruktorów. Widoki w układzie są w ogóle niedostępne dla obiektów, dopóki nie zostaną zawyżone w metodzie onCreate() przez wywołanie metody setContentView(). Dopóki to się nie stanie, nie możesz inicjować zmiennej diceImage.

Jedną z możliwości jest zdefiniowanie zmiennej diceImage jako wartość null. Tak jak w tym przykładzie, Ustaw wartość null, gdy zostanie zadeklarowana, a potem przypisz ją do rzeczywistego elementu ImageView w onCreate() za pomocą findViewById(). Skomplikuje to Twój kod, bo teraz musisz sprawdzić wartość null za każdym razem, gdy chcesz użyć diceImage. Istnieje lepsze rozwiązanie.

  1. Zmień deklarację diceImage, by użyć słowa kluczowego lateinit, i usuń przypisanie null:
lateinit var diceImage : ImageView

Słowo kluczowe lateinit obiecuje kompilator w Kotlin, że zmienna jest inicjowana przed wywołaniem kodu w dowolnych operacjach. W związku z tym nie musimy tutaj inicjować zmiennej na poziomie null i możemy jej używać jako zmiennej niedopuszczającej wartości pustych. Sprawdzoną metodą jest użycie lateinit z polami, które mają właśnie takie widoki.

  1. W onCreate() po metodzie setContentView() użyj findViewById(), by uzyskać ImageView.
diceImage = findViewById(R.id.dice_image)
  1. Usuń stary wiersz rollDice() w deklaracji i pobierz ImageView. Ten wiersz został wcześniej zastąpiony deklaracją pola.
val diceImage : ImageView = findViewById(R.id.dice_image)
  1. Ponownie uruchom aplikację, aby sprawdzić, czy nadal działa.

W tej chwili używasz dice_1 jako początkowego obrazu kości. Zamiast tego chcesz po prostu nie wyświetlać obrazu, dopóki kostka nie zostanie rzucona po raz pierwszy. Możesz to zrobić na kilka sposobów.

  1. Otwórz kartę activity_layout.xml na karcie Tekst.
  2. W elemencie <ImageView> ustaw atrybut android:src na "@drawable/empty_dice":
android:src="@drawable/empty_dice" 

Obraz empty_dice to jeden z obrazów pobranych i dodanych do folderu drawable. Ma taki sam rozmiar jak inne kości, ale tylko ta jest pusta. To obraz, który wyświetli się po uruchomieniu aplikacji.

  1. Kliknij kartę Projekt. Obraz Dieda jest teraz pusty, ale w podglądzie też nie jest widoczny.



    Powszechnie zdarza się, że zawartość projektu jest definiowana dynamicznie w czasie działania – na przykład w przypadku aplikacji pobierających dane z internetu prawdopodobnie zaczyna się pusty ekran. Podczas projektowania aplikacji warto mieć jednak coś w tym formacie, aby wiedzieć, co zamierzasz umieścić.
  2. W systemie activity_layout.xml skopiuj wiersz android:src i wklej drugą kopię. Zmień słowo "android" na "narzędzia", aby oba atrybuty wyglądały następująco:
android:src="@drawable/empty_dice" 
tools:src="@drawable/empty_dice" />

Tutaj zmieniono przestrzeń nazw XML tego atrybutu z domyślnej przestrzeni nazw android na przestrzeń nazw tools. Przestrzeń nazw tools jest używana, gdy chcesz określić treść zastępczą, która ma być używana tylko na podglądzie lub w edytorze projektu w Android Studio. Atrybuty korzystające z przestrzeni nazw tools są usuwane podczas kompilacji aplikacji.

Przestrzenie nazw służą do rozwiązywania niejasności w odniesieniu do atrybutów o tej samej nazwie. Na przykład oba te atrybuty w tagu <ImageView> mają tę samą nazwę (src), ale przestrzeń nazw jest inna.

  1. Przyjrzyj się elementowi <LinearLayout> w katalogu głównym pliku układu i zwróć uwagę na dwie zdefiniowane tutaj przestrzenie nazw.
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   ...
  1. Zmień atrybut tools:src w tagu ImageView na dice_1 zamiast empty_dice:
android:src="@drawable/empty_dice" 
tools:src="@drawable/dice_1" />

Zwróć uwagę, że obraz dice_1 znajduje się teraz na podglądzie.

  1. Skompiluj i uruchom aplikację. Zauważ, że obraz kostki w aplikacji jest pusty, dopóki nie klikniesz Rzuć.

Jedną z wielkich zalet tworzenia aplikacji na Androida jest ogromna liczba urządzeń, na których działa Twój kod – od Nexus One po Pixel, tworząc urządzenia takie jak tablety, Pixelbooki, zegarki, telewizory czy samochody.

Podczas pisania na urządzeniu z Androidem nie musisz tworzyć osobnych aplikacji dla każdego z tych urządzeń – nawet te, które korzystają z bardzo różnych urządzeń, np. zegarków i telewizorów, i mogą współdzielić ten sam kod. Istnieją jednak pewne ograniczenia i strategie zgodności, o których musisz wiedzieć, aby stosować się do tych wymagań.

W tym zadaniu dowiesz się, jak kierować aplikację na określone poziomy interfejsu API Androida i jak używać bibliotek Android Jetpack do obsługi starszych urządzeń.

Krok 1. Poznaj poziomy interfejsu API

Podczas poprzedniego ćwiczenia z programowania dowiesz się, jaki poziom obsługi powinien obsługiwać Twoja aplikacja na Androida API. System operacyjny Android ma różne numery wersji, które wywodzą się z pysznych przysmaków uporządkowane w kolejności alfabetycznej. Każda wersja systemu operacyjnego ma nowe funkcje. Na przykład Android Oreo obsługuje aplikacje w obrazie w obrazie, a w Androidzie – wycinki. Poziomy interfejsu API odpowiadają wersjiom Androida. Na przykład interfejs API 19 odpowiada Androidowi 4.4 (KitKat).

Ze względu na wiele czynników, między innymi to, co obsługuje sprzęt, czy użytkownicy zdecydują się zaktualizować urządzenia i czy producenci obsługują różne poziomy systemu operacyjnego, użytkownicy nieuchronnie trafiają na urządzenia z różnymi wersjami systemu operacyjnego.

Podczas tworzenia projektu aplikacji określasz minimalny poziom interfejsu API, który obsługuje Twoja aplikacja. To znaczy, że określasz najstarszą wersję Androida obsługiwaną przez aplikację. Twoja aplikacja ma również poziom, na którym jest skompilowana, i na wymagany poziom. Każdy z tych poziomów jest parametrem konfiguracji w plikach kompilacji Gradle.

  1. Rozwiń folder Gradle Scripts i otwórz plik build.gradle (Module: app).

    Ten plik definiuje parametry kompilacji i zależności konkretnej aplikacji. Plik build.gradle (Project: DiceRoller) określa parametry kompilacji dla całego projektu. W wielu przypadkach moduł aplikacji jest jedynym modułem w projekcie, więc ten segment może wyglądać na dowolny. Jeśli jednak Twoja aplikacja stanie się bardziej złożona i podzielisz ją na kilka części lub jeśli aplikacja obsługuje platformy takie jak zegarek z Androidem, w tym samym projekcie mogą pojawić się różne moduły.
  2. Sprawdź sekcję android u góry pliku build.gradle. (przedstawiony poniżej przykład nie jest częścią całej sekcji, ale zawiera tematy, które najbardziej Cię interesują w tym ćwiczeniu z programowania).
android {
   compileSdkVersion 28
   defaultConfig {
       applicationId "com.example.android.diceroller"
       minSdkVersion 19
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"
   }
  1. Sprawdź parametr compileSdkVersion.
compileSdkVersion 28

Ten parametr określa poziom interfejsu API Androida, którego Gradle ma używać do kompilowania aplikacji. To najnowsza wersja Androida, którą obsługuje Twoja aplikacja. Oznacza to, że Twoja aplikacja może korzystać z funkcji interfejsu API uwzględnionych na tym poziomie interfejsu API i niższych. Aplikacja obsługuje interfejs API 28, który odpowiada Androidowi 9 (Pie).

  1. Sprawdź parametr targetSdkVersion w sekcji defaultConfig:
targetSdkVersion 28

Ta wartość to najnowsza wersja interfejsu API, który został przez Ciebie przetestowany. W wielu przypadkach jest to ta sama wartość co w przypadku compileSdkVersion.

  1. Sprawdź parametr minSdkVersion.
minSdkVersion 19

Ten parametr jest najważniejszy z trzech, ponieważ określa najstarszą wersję Androida, na której będzie działać aplikacja. Na urządzeniach z systemem Android starszym niż ten poziom interfejsu API w ogóle nie można uruchomić aplikacji.

Wybór minimalnego poziomu API dla aplikacji może być trudnym zadaniem. Ustaw zbyt niski poziom interfejsu API i przegapisz nowsze funkcje systemu operacyjnego Android. Jeśli ustawisz ją na zbyt wysokim poziomie, aplikacja będzie mogła działać tylko na nowszych urządzeniach.

Gdy skonfigurujesz projekt i przejdziesz do miejsca, w którym możesz określić minimalny poziom interfejsu API aplikacji, kliknij Pomóż mi wybrać. Pojawi się okno Rozpowszechnianie wersji interfejsu API. To okno zawiera informacje o liczbie urządzeń z różnymi poziomami systemu operacyjnego oraz o funkcjach dodanych lub zmienionych na poziomie systemu. Możesz też zapoznać się z informacjami o wersji Androida i panelem, gdzie znajdziesz więcej informacji o wpływie obsługi poszczególnych poziomów interfejsu API.

Krok 2. Sprawdź zgodność

Projektowanie aplikacji na Androida o różnych poziomach zaawansowania jest typowym wyzwaniem dla deweloperów aplikacji. Dlatego zespół zajmujący się tworzeniem aplikacji na Androida dołożył wielu starań, aby Ci pomóc.

W 2011 roku zespół opublikował pierwszą bibliotekę pomocy, czyli bibliotekę opracowaną przez Google, która oferuje kompatybilne zajęcia i przydatne funkcje. W 2018 r. ogłosiliśmy wprowadzenie Androida Jetpack, czyli zbioru bibliotek obejmujących wiele wcześniejszych zajęć i funkcji dostępnych w bibliotece pomocy. Teraz udostępniamy ją także w bibliotece pomocy.

  1. Otwórz aplikację MainActivity.
  2. Klasa MainActivity wykracza poza samą właściwość Activity, ale od AppCompatActivity.
class MainActivity : AppCompatActivity() { 
...

AppCompatActivity to klasa zgodności, która zapewnia taka samą aktywność na różnych poziomach systemu operacyjnego.

  1. Kliknij symbol + obok wiersza, który zaczyna się od import, aby rozwinąć importowanie zajęć. Klasa AppCompatActivity została zaimportowana z pakietu androidx.appcompat.app. Przestrzeń nazw bibliotek Android Jetpack to androidx.
  2. Otwórz build.gradle (Moduł: aplikacja) i przewiń w dół do sekcji zależności.
dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
   implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
   implementation 'androidx.core:core-ktx:1.0.1'
   implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
   testImplementation 'junit:junit:4.12'
   androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
   androidTestImplementation 
        'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}

Zwróć uwagę na zależność od biblioteki appcompat, która jest częścią androidx i zawiera klasę AppCompatActivity.

Krok 3. Dodaj zgodność dla obiektów rysowalnych wektorowych

Wykorzystasz nową wiedzę dotyczącą przestrzeni nazw, Gradle i zgodności, aby wprowadzić ostateczne poprawki w swojej aplikacji, co pozwoli zoptymalizować jej rozmiar na starszych platformach.

  1. Rozwiń folder res i rozwiń folder draw. Kliknij dwukrotnie jeden z kostek.

    Jak wcześniej wiesz, wszystkie obrazy kości to w rzeczywistości pliki XML, które określają kolor i kształt kości. Pliki tego typu są nazywane rysunkami wektorowymi. W pozycji rysunkowej wektora wygodniejsze jest stosowanie formatów map bitowych (takich jak PNG), które można skalować wektorowo, nie tracąc jakości. Rysowanie wektorowe jest też zwykle znacznie mniejsze niż w przypadku tego samego obrazu w formacie bitmap.

    Ważne jest, aby zaznaczyć, że element rysowalny wektorowo jest obsługiwany w interfejsie API 21 i kolejnych. Minimalny pakiet SDK Twojej aplikacji jest ustawiony na interfejs API 19. Jeśli aplikacja została wypróbowana na urządzeniu lub w emulatorze API 19, wygląda na to, że aplikacja kompiluje się i działa normalnie. Jak to działa?

    Gdy tworzysz aplikację, proces tworzenia Gradle tworzy plik PNG z każdego z plików wektorowych. Te pliki PNG są używane na każdym urządzeniu z Androidem w wersji starszej niż 21. Te dodatkowe pliki PNG zwiększają rozmiar aplikacji. Niepotrzebne aplikacje są świetne – spowalniają pobieranie plików i zajmują więcej urządzeń oraz ograniczone miejsce. Duże aplikacje mają większą szansę na odinstalowanie, a użytkownicy nie mogą pobrać ani anulować pobierania tych aplikacji.

    Dobra wiadomość jest taka, że dostępna jest biblioteka zgodności Androida X do tworzenia obiektów wektorowych aż do poziomu API 7.
  2. Otwórz build.gradle (Moduł: aplikacja). Dodaj ten wiersz do sekcji defaultConfig:
vectorDrawables.useSupportLibrary = true
  1. Kliknij przycisk Sync Now (Synchronizuj teraz). Za każdym razem, gdy plik build.gradle jest modyfikowany, musisz zsynchronizować pliki kompilacji z projektem.
  2. Otwórz plik z układem main_activity.xml. Dodaj tę przestrzeń nazw do głównego tagu <LinearLayout>, pod przestrzenią nazw tools:
xmlns:app="http://schemas.android.com/apk/res-auto"

Przestrzeń nazw app jest przeznaczona dla atrybutów pochodzących z niestandardowego kodu lub z bibliotek, a nie z podstawowej platformy Android.

  1. Zmień atrybut android:src elementu <ImageView> na app:srcCompat.
app:srcCompat="@drawable/empty_dice"


Atrybut app:srcCompat korzysta z biblioteki Androida X do obsługi obiektów wektorowych w starszych wersjach Androida – nawet na poziomie API 7.

  1. Utwórz i uruchom aplikację. Na ekranie nie będzie widać żadnych innych zmian, ale teraz aplikacja nie będzie musiała generować wygenerowanych plików PNG dla kości, niezależnie od tego, gdzie będą biegać, co oznacza mniejszy plik aplikacji.

Projekt na Android Studio: DiceRollerFinal

Wyzwanie: zmodyfikuj aplikację DiceRoller tak, aby zawierała 2 kości. Gdy użytkownik kliknie przycisk Rzut, każda kostka powinna mieć inną wartość.

Wskazówka: utwórz nową funkcję prywatną, aby uzyskać losowy obraz rysowalny i zwrócić liczbę całkowitą zasobu rysunkowego. Użyj tej funkcji w przypadku każdego obrazu matrycy.

private fun getRandomDiceImage() : Int { ... }

Kod rozwiązania testu zabezpieczającego

Projekt na Android Studio: DiceRollerFinal-challenge

Zasoby aplikacji

  • Zasoby aplikacji mogą zawierać obrazy i ikony, standardowe kolory używane w aplikacji, ciągi tekstowe i układy XML. Wszystkie te zasoby są przechowywane w folderze res.
  • W folderze zasobów drawable umieść wszystkie zasoby graficzne w aplikacji.

Używanie elementów graficznych wektorowych w widokach obrazów:

  • Rysunki wektorowe to obrazy opisane w formacie XML. Obrazy rysunkowe wektorowe są bardziej elastyczne niż obrazy bitmap (np. pliki PNG), ponieważ można je skalować do dowolnego rozmiaru i rozdzielczości.
  • Aby dodać rysunek do układu aplikacji, użyj elementu <ImageView>. Źródło obrazu znajduje się w atrybucie android:src. Aby odwołać się do folderu zasobów, które można rysować, użyj @drawable, na przykład "@drawable/image_name".
  • Użyj widoku ImageView w kodzie MainActivity obrazu. Za pomocą setImageResource() możesz zmienić obraz widoku na inny zasób. Używaj znaczników R.drawable do odwoływania się do określonych elementów rysowalnych, na przykład setImageResource(R.drawable.image_name).

Słowo kluczowe lateinit:

  • Zminimalizuj wywołania funkcji findViewById() w kodzie, deklarując pola do przechowywania tych widoków i inicjując pola w onCreate(). Użyj w tym polu słowa kluczowego lateinit, aby uniknąć deklarowania jego wartości unieważniającej.

Przestrzeń nazw tools dla atrybutów czas-projektu:

  • Użyj atrybutu tools:src w elemencie <ImageView> w układzie, aby wyświetlać obraz tylko w podglądzie lub edytorze projektu w Android Studio. Następnie możesz użyć pustego obrazu dla aplikacji android:src w ostatecznym interfejsie.
  • Użyj przestrzeni nazw tools w pliku układu Androida, by utworzyć zastępcze treści lub wskazówki dotyczące układu w Android Studio. Dane zadeklarowane przez atrybuty tools nie są używane w aplikacji końcowej.

Poziomy interfejsu API:

  • Każdy system operacyjny Android ma oficjalną nazwę i wersję wersji (np. Android 9.0, &Pie") oraz poziom API (API 28). Użyj poziomów interfejsu API w plikach Gradle aplikacji, aby wskazać wersje Androida obsługiwane przez Twoją aplikację.
  • Parametr compileSdkVersion w pliku build.gradle określa poziom interfejsu API Androida, którego Gradle ma używać do kompilowania aplikacji.
  • Parametr targetSdkVersion określa najnowszy poziom interfejsu API, na którym przetestowano aplikację. W wielu przypadkach ten parametr ma taką samą wartość jak compileSdkVersion.
  • Parametr minSdkVersion określa najstarszy poziom interfejsu API, na którym może działać Twoja aplikacja.

Jetpack dla Androida:

  • Android Jetpack to zbiór bibliotek stworzonych przez Google. Można w nim znaleźć kursy zgodne z wcześniejszymi wersjami oraz przydatne funkcje obsługujące starsze wersje Androida. Jetpack zastępuje i rozszerza zestaw bibliotek nazywanych wcześniej Biblioteką pomocy Androida.
  • Klasy zaimportowane z pakietu androidx odnoszą się do bibliotek Jetpack. Zależności Jetpacka z pliku build.gradle również zaczynają się od androidx.

Zgodność wsteczna z rysunkami wektorowymi:

  • Rysunki wektorowe są obsługiwane natywnie tylko w wersjach Androida wyższych niż API 21. W starszych wersjach Gradle generuje obrazy PNG dla tych obiektów rysowanych podczas tworzenia aplikacji.
  • Możesz określić, że Biblioteka pomocy Androida ma być używana w przypadku obiektów wektorowych w starszych wersjach interfejsu API z parametrem konfiguracji vectorDrawables.useSupportLibrary = true w pliku build.gradle.
  • Gdy włączysz bibliotekę pomocy dla obiektów rysowalnych wektorowych, użyj atrybutu app:srcCompat w elemencie <ImageView> (zamiast android:src), aby określić źródło rysowania wektorowego dla tego obrazu.

Przestrzeń nazw app:

  • Przestrzeń nazw app w pliku układu XML jest przeznaczona na atrybuty pochodzące z niestandardowego kodu lub z bibliotek, a nie z podstawowej platformy Android.

Kurs Udacity:

Dokumentacja dla programistów Androida:

Inne:

Ta sekcja zawiera listę możliwych zadań domowych dla uczniów, którzy pracują w ramach tego ćwiczenia w ramach kursu prowadzonego przez nauczyciela. To nauczyciel może wykonać te czynności:

  • W razie potrzeby przypisz zadanie domowe.
  • Poinformuj uczniów, jak przesyłać zadania domowe.
  • Oceń projekty domowe.

Nauczyciele mogą wykorzystać te sugestie tak długo, jak chcą lub chcą, i mogą przypisać dowolne zadanie domowe.

Jeśli samodzielnie wykonujesz te ćwiczenia z programowania, możesz sprawdzić swoją wiedzę w tych zadaniach domowych.

Zmienianie aplikacji

W aplikacji DiceRoller dodaj przycisk Wyczyść, który ustawia obraz z powrotem na pusty obraz.

Odpowiedz na te pytania

Pytanie 1

Który atrybut <ImageView> wskazuje obraz źródłowy, którego należy używać tylko w Android Studio?

  • android:srcCompat
  • app:src
  • tools:src
  • tools:sourceImage

Pytanie 2

Która metoda zmienia zasób graficzny ImageView w kodzie Kotlin? xmx

  • setImageResource()
  • setImageURI()
  • setImage()
  • setImageRes()

Pytanie 3

Co oznacza słowo kluczowe lateinit w deklaracji zmiennej w kotlinie?

  • Zmienna nigdy nie jest inicjowana.
  • Zmienna jest inicjowana tylko w czasie działania aplikacji.
  • Zmienna jest automatycznie inicjowana w postaci null.
  • Zmienna zostanie zainicjowana później. Obiecuję.

Pytanie 4

Która konfiguracja Gradle wskazuje najnowszy poziom interfejsu API, na którym przetestowano aplikację?

  • minSdkVersion
  • compileSdkVersion
  • targetSdkVersion
  • testSdkVersion

Pytanie 5

W kodzie znajduje się wiersz importowania zaczynający się od androidx. Co to oznacza?

  • Klasa jest częścią bibliotek Android Jetpack.
  • Klasa jest w bibliotece zewnętrznej, która będzie dynamicznie ładowana, gdy aplikacja zostanie uruchomiona.
  • Klasa to „extra"” – opcjonalnie.
  • Klasa jest częścią obsługi języka XML w Androidzie&#39.

Przesyłanie aplikacji do oceny

Upewnij się, że aplikacja zawiera:

  • Układ aplikacji powinien zawierać jeden widok obrazu i dwa przyciski.
  • Kod aplikacji powinien ustawić dwa moduły obsługi kliknięć – po jednym dla każdego przycisku.
  • Moduł obsługi kliknięcia przycisku Wyczyść powinien ustawić obraz układu na R.drawable.empty_dice.

Rozpocznij następną lekcję: 1.4 Naucz się pomagać sobie

Linki do innych ćwiczeń z programowania w tym kursie znajdziesz na stronie docelowej z ćwiczeniami z podstaw Androida Kotlin.