Narzędzia użytkownika

Narzędzia witryny


java:java11

Aplikacje mobilne - Android

Wprowadzenie

Tematem modułu jest wykorzystanie domyślnego zintegrowanego środowiska rozwoju aplikacji dla platformy Android – Android Studio, oraz języka Java do projektowania graficznego interfejsu użytkownika oraz do programowania logiki aplikacji. Do wykonania ćwiczeń potrzebne będą następujące narzędzia: Java Development Kit (JDK) w wersji 1.7 lub wyższej oraz środowisko Android Studio, w skład którego wchodzi zintegrowane środowisko rozwoju aplikacji (IDE), narzędzia dla programistów Android Software Development Kit (SDK), platforma Android (maszyna wirtualna i biblioteki) oraz emulator służący do testowania aplikacji. Zarówno pakiet JDK, jak i środowisko Android Studio są dostępne bezpłatnie i można je pobrać odpowiednio z serwisu internetowego firmy Oracle oraz ze strony http://developer.android.com.

Utworzymy aplikację mobilną demonstrującą wykorzystanie elementów interfejsu graficznego systemu Android oraz obsługę zdarzeń generowanych przez ten interfejs.

Przykład I

Przykład ilustruje projektowanie interfejsu użytkownika oraz obsługę zdarzeń tego interfejsu.

Utworzenie projektu

Uruchom Android Studio i rozpocznij nowy projekt.

Wprowadź odpowiednio nazwę Twojej aplikacji, domenę oraz lokalizację nowo tworzonego projektu (katalogu zawierającego pliki projektu) w systemie plików.

W języku Java klasy zorganizowane są w pakiety. Pakiety deklaruje się w pierwszej (niezakomentowanej) linii każdego pliku źródłowego. Przynależność do pakietu decyduje na przykład o znaczeniu modyfikatorów dostępu do składowych obiektów (zob. poprzedni moduł). Zgodnie z powszechnie przyjętą konwencją nazwa pakietu składa się z odwróconej domeny internetowej (co zapewnia unikalność nazw) instytucji lub osoby firmującej dany pakiet oraz członu opisującego zawartość pakietu. Pełna nazwa każdej klasy w języku Java składa się z nazwy pakietu oraz nazwy klasy (zob. poprzedni moduł).

W kolejnym oknie dialogowym wybieramy szablon aplikacji, możemy także wybrać szablon nie zawierający żadnego predefiniowanego elementu Activity (Add No Activity). W naszym przypadku wybieramy Blank Activity.

W kolejnym kroku musimy jeszcze zdefiniować nazwy dla elementów Activity (obsługa zdarzeń generowanych przez interfejs - logika aplikacji) oraz Layout (graficzny interfejs użytkownika – komponenty interfejsu, ich rozmieszczenie, wygląd, kolory, reakcje). W naszym przypadkuanalizujemy zaproponowane nazwy domyślne oraz konwencję dotyczącą nazewnictwa (wielkie i małe litery, znaki podkreślenia) i akceptujemy.

Tworzenie projektu może potrwać około kilkudziesięciu sekund. Po utworzeniu projektu możemy go zbudować i uruchomić za pomocą emulatora (Run/Run ’app’, albo ikonka zielonej strzałki w głównym pasku narzędzi). Zanim emulator zostanie uruchomiony, musimy jeszcze wybrać urządzenie które ma być emulowane i na którym chcemy testować naszą aplikację.

W naszym przypadku wybierzmy Nexus 5 i Android API w wersji 22. Urządzenia wirtualne możemy dodawać za pomocą Android Virtual Devices Manager (/Tools/Android/AVD Manager).

Uruchomienie emulatora trwa dość długo (od kilkunastu sekund do kilku minut, w zależności od szybkości komputera). Po uruchomieniu otworzy się okno emulatora z widokiem emulowanego urządzenia, na którym będziemy mogli przetestować naszą aplikację.

W oknie Android Studio możemy teraz przejrzeć najważniejsze pliki naszego projektu. Layout aplikacji jest opisany w formacie xml i znajduje się w pliku /app/src/main/res/layout/activity_main.xml (res jest skrótem od resources, nazwę activity_main dla tego elementu Layout wybraliśmy podczas tworzenia projektu). Warto zauważyć, że Android Studio prezentuje zawartość tego pliku zarówno w postaci tekstu xml (zakładka Text)jak i w postaci graficznej (zakładka Design).

Element Activity naszej aplikacji jest napisany w języku Java i znajduje się w pliku /app/src/main/ java/com.delta.tango.mod2/MainActivity.java.

Projekt interfejsu graficznego (Layout)

Projekt aplikacji jest opisywany w formacie xml. Przeanalizuj poniższy fragment pliku xml i określ znaczenie poszczególnych znaczników. RelativeLayout jest jednym z menadżerów rozkładu elementów interfejsu graficznego, jego nazwa wiąże się z faktem że określa położenia poszczególnych elementów interfejsu względem siebie (relative).

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
 
  <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
 
</RelativeLayout>

Możemy go tworzyć zarówno w sposób wizualny (zakładka Design), jak i w sposób programistyczny (xml). Wszystkie zmiany dokonywane w jednym z tych widoków są automatycznie odzwierciedlane w drugim. Możemy teraz usunąć etykietę (Label) z przykładowym tekstem, żeby zobaczyć że zmiana ta zostanie uwzględniona zarówno w widoku Design, jak i w widoku Text, zawierającym plik xml opisujący ten Layout.

Kolejnym krokiem będzie dodanie dodanie i rozmieszczenie elementów interfejsu graficznego, a także wybór takich cech jak odstępy, obramowania, kolory, czy reakcje na zdarzenia. Możemy zrobić to zarówno bezpośrednio w pliku xml (zakładka Text), jak i wizualnie (zakładka Design). Dodajmy jeden przycisk (Button) i jedno pole tekstowe (TextView).

Wybierz odpowiednie rozmieszczenie tych komponentów i przeanalizujmy opisujący to rozmieszczenie plik xml. Odpowiedz na pytania dotyczące znaczenia poszczególnych atrybutów menadżera RelativeLayout. W celu zapewnienia wygodnej możliwości zmiany języka interfejsu (internacjonalizacji), powszechnie przyjętym standardem jest definiowanie wszystkich tekstów interfejsu graficznego w postaci zmiennych tekstowych definiowanych w pliku xml w postaci @string/nazwa_zmiennej. Wartości tak zdefiniowanych zmiennych są przechowywane w pliku /app/src/main/res/values/strings.xml.

<resources>
  <string name="app_name">Mod2</string>
 
  <string name="b1_text">Aforyzm dnia</string>
  <string name="eracism">Greatest failure is not to try</string>
  <string name="action_settings">Settings</string>
</resources>

Stworzenie innej wersji językowej aplikacji polega na przygotowaniu alternatywnego pliku, na przykład o nazwie strings-pl.xml, zawierającego wszystkie teksty mogące pojawić się na komponentach interfejsu graficznego. Po zapisaniu tekstów w postaci zmiennych, zawartość pliku main_activity.xml, opisującego Layout naszego pierwszego elementu Activity, wygląda w następujący sposób

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop=„@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin"
  tools:context=".MainActivity">
 
  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/b1_text"
    android:id="@+id/b1"
    android:layout_marginTop="49dp"
    android:layout_alignParentTop="true" />
 
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/eracism"
    android:id="@+id/tv1"
    android:layout_marginTop="45dp"
    android:layout_below="@+id/b1"
    android:layout_alignParentStart="true" />
 
</RelativeLayout>
</xml>

Obsługa zdarzeń i logika aplikacji (Activity)

Żeby obsłużyć zdarzenie polegające na naciśnięciu przycisku, musimy do opisu xml elementu Layout dodać odpowiedni znacznik wskazujący która funkacja ma zostać wywołana w celu obsłużenia zdarzenia polegającego na naciśnięciu tego przycisku. W naszym przypadku, do opisu przycisku b1 dodajemy atrybut android:onClick, któremu nadajemy wartość b1_pressed, która wskazuje że w celu obsłużenia zdarzenia należy wywołać funkcję składową b1_pressed klasy opisującej Activity powiązaną z tym obiektem Layout.

<Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/b1_text"
  android:id="@+id/b1"
  android:layout_marginTop="49dp"
  android:layout_alignParentTop="true"
  android:onClick="b1_pressed"/>

Definicję Klasy opisującej Activity znajdziemy w pliku /app/src/main/java/com/delta/tango mod2. W chwili tworzenia obiektu Layout, automatycznie wywoływana jest metoda protected void onCreate(Bundle savedInstanceState) skojarzonego z nim obiektu Activity. Do metody tej jest automatycznie przekazywany obiekt klasy Bundle, zawierający informację o zapisanym stanie obiektu.

@Override
protected void onCreate(Bundle savedInstanceState)
{
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
}

Łącznikiem pomiędzy opisem interfejsu (xml) a działaniami aplikacji (Java) jest automatycznie generowana przez Android SDK klasa R, którą można znaleźć w pliku /app/build/generated/source/r/debug/com/delta/tango/mod2/R.java. Klasa ta definiuje szereg pól statycznych, które zawierają referencje do odpowiadających im elementów interfejsu graficznego (Layout).

public final class R
{
  ...
 
  public static final class layout
  {
    ...
    public static final int activity_main=0x7f040019;
    ...
  }
 
  ...
}

Utworzona przez kreator metoda onCreate() składa się z wywołania metody onCreate() z nadklasy i przekazaniu do niej otrzymanego jako parametr obiektu savedInstanceState

super.onCreate(savedInstanceState)

oraz z wywołania metody

setContentView(R.layout.activity_main)

ustawiającej Layout opisany w formie xml w activity_main.xml. Przeanalizuj definicję klasy R i narysuj na kartce jej strukturę. Zastanów się jakiego typu elementy składowe posiada i jakie elementy interfejsu graficznego reprezentuje.

Komponenty naszego interfejsu graficznego możemy teraz obsłużyć na przykład za pomocą metody findViewById(), która przyjmuje jako parametr identyfikator komponentu i zwraca reprezentujący go obiekt android.view.View. W tym celu w activity_main.xml usuń atrybut android:text w opisie pola tekstowego tv1 (pole tekstowe po uruchomieniu nie będzie posiadać żadnego tekstu). Następnie w klasie MainActivity zaimplementujmy metodę b1_pressed()

public void b1_pressed(android.view.View v)
{
  android.widget.TextView obj=(android.widget.TextView)findViewById(R.id.tv1);
  obj.setText("Greatest failure is not to try");
}

Pełne nazwy klas (android.view.View i android.widget.Widget), złożone z nazwy pakietu i nazwy klasy, możemy oczywiście zastąpić krótkimi nazwami klas. W tym celu, w pliku Main Activity.java, po deklaracji pakietu a przed definicjami klas musimy dodać odpowiednie dyrektywy import (zob. poprzedni moduł). Przetestuj aplikację.

Ćw. 11.1
Wykorzystując wiadomości dotyczące programowania w języku Java, rozwiń aplikację w ten sposób żeby po każdym naciśnięciu przycisku „Aforyzm dnia” wypisywała na ekranie aforyzm losowo wybrany spośród tekstów przechowywanych w pliku strings.xml (w odpowiedniej wersji językowej)

<?xml version="1.0" encoding="utf-8"?>
<resources>
 
  <string name="app_name">cw1</string>
  <string name="menu_settings">Settings</string>
  <string name="b1text">Aforyzm dnia</string>
  <string name="tv1text">Greatest failure is not to try</string>
 
  <string name="eracism">The greatest failure is not to try</string>
  <string name="latin">To err is human, but being right is nice too</string>
  <string name="latin2">Lex retro not agit</string>
 
</resources>

Będziesz musiał także zdefiniować w formacie xml odpowiednią tablicę tekstów. W tym celu dodaj plik res/values/arrays.xml i dodaj do niego definicję

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array
    name="tab_aforyzmy">
    <item>@string/eracism</item>
    <item>@string/latin</item>
    <item>@string/latin2</item>
  </string-array>
</resources>

Losowy wybór tekstu do wypisania na ekranie musisz zaimplementować w języku Java, wykorzystaj do tego klasę Random z pakietu java.util (generator liczb pseudolosowych).

java.util.Random gen=new java.util.Random();
int i=gen.nextInt(tab.length);
String[] tab=getResources().getStringArray(R.array.tab_aforyzmy);
TextView obj=(TextView)findViewById(R.id.tv1);
obj.setText(tab[i]);
Potrzebne informacje znajdziesz w module dotyczącym podstaw programowania w języku Java.

Ćw. 11.2
W oparciu o wiadomości z tego modułu oraz z modułu dotyczącego programowania w języku Java napisz implementacje kalkulatora dla platformy Android. Twój kalkulator powinien posiadać przyciski z cyframi oraz odpowiednimi działaniami. W tym celu będziesz potrzebował konwersji Będziesz potrzebował konwersji informacji tekstowych z obiektu klasy CharSequence to obiektu klasy String oraz parsowania tekstu do zmiennopozycyjnego typu danych (na przykład double) oraz z typu liczbowego to tekstowego (w drugą stronę).

TextView obj=(TextView)findViewById(R.id.tv1);
 
CharSequence cs=obj.getText();
String s=cs.toString();
double x=Double.parseDouble(s);
x=x*x;
String s2=Double.toString(x);
tv.setText(s2);

Zaimplementuj podstawowe działania arytmetyczne, potęgowanie, pierwiastkowanie, procenty, silnię, logarytmy, funkcje trygonometryczne, pamięć (lub grupowanie działań za pomocą nawiasów).

Przykład II

Przykład ilustruje programowanie grafiki 2D dla platformy Android. Utworzymy aplikację mobilną demonstrującą generowanie obiektów graficznych w odpowiedzi na zdarzenia interfejsu użytkownika.

Utworzenie projektu

Uruchom Android Studio, rozpocznij nowy projekt. Wybierz szablon aplikacji Blank Activity. W kolejnym kroku musisz jeszcze zdefiniować nazwy dla elementów Activity (obsługa zdarzeń generowanych przez interfejs - logika aplikacji) oraz Layout (graficzny interfejs użytkownika – komponenty interfejsu, ich rozmieszczenie, wygląd, kolory, reakcje). Tworzenie projektu może potrwać około kilkudziesięciu sekund. Po utworzeniu projektu możemy go zbudować i uruchomić za pomocą emulatora (Run/Run ’app’, albo ikonka zielonej strzałki w głównym pasku narzędzi). Zanim emulator zostanie uruchomiony, musimy jeszcze wybrać urządzenie które ma być emulowane i na którym chcemy testować naszą aplikację. W naszym przypadku wybierzmy Nexus 5 i Android API w wersji 22. Urządzenia wirtualne możemy dodawać za pomocą Android Virtual Devices Manager (/Tools/Android/AVD Manager). Uruchomienie emulatora trwa dość długo (od kilkunastu sekund do kilku minut, w zależności od szybkości komputera). Po uruchomieniu otworzy się okno emulatora z widokiem emulowanego urządzenia, na którym będziemy mogli przetestować naszą aplikację.

Projekt interfejsu graficznego (Layout)

Layout aplikacji jest opisany w formacie xml i znajduje się w pliku /app/src/main/res/layout/activity_main.xml (res jest skrótem od resources, nazwę activity_main dla tego elementu Layout wybraliśmy podczas tworzenia projektu). Layout możemy tworzyć zarówno w sposób wizualny (zakładka Design), jak i w sposób programistyczny (xml). Wszystkie zmiany dokonywane w jednym z tych widoków są automatycznie odzwierciedlane w drugim. Pierwszym krokiem będzie dodanie i rozmieszczenie elementów interfejsu graficznego, a także wybór takich cech jak odstępy, obramowania, kolory, czy reakcje na zdarzenia.

W poprzednim module do projektu aplikacji dodawaliśmy predefinowane komponenty graficzne, takie jak przycisk (Button), czy pole tekstowe (TextView). W tym przypadku Dodajmy jeden przycisk (Button) i jedno pole tekstowe (TextView). W tym przypadku zdefiniujemy klasę rozszerzającą (dziedziczenie) klasę android.view.View. Obiekt takiej klasy, jako obiekt klasy View (podobnie jak poprzednio użyte obiekty Button, czy TextView), będzie mógł być być dodany do obiektu Layout naszej aplikacji.

Napisz definicję klasy, która dziedziczy po klasie android.view.View i dodaj ją do Twojego projektu. Możesz w tym celu posłużyć się kreatorem dodawania plików klas, który można uruchomić po kliknięciu prawym przyciskiem myszy w odpowiedniej lokalizacji w panelu nawigacyjnym po lewej stronie. Żeby posłużyć się nią do zaprojektowania interfejsu graficznego za pomocą xml, Twoja klasa powinna posiadać konstruktor z dwoma parametrami (Context, AttributeSet). Jeżeli chcesz utworzyć interfejs graficzny bezpośrednio w Javie, będziesz potrzebował konstruktora jednoparametrowego (Context). Przykład zawiera definicje obydwu konstruktorów. Tworzenie grafiki odbywa się w metodzie onDraw(), do której przekazywany jest obiekt typu Canvas, podobnie jak w przypadku metody paintComponent() w przypadku komponentów graficznego interfejsu użytkownika biblioteki Swing używanej do programowania aplikacji desktopowych w języku Java. Metody tej nie wywołujemy jawnie, jest ona wywoływana przez maszynę wirtualną, w celu wyrenderowania grafiki.

package com.tango.tmp2;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
 
public class A extends View
{
   Paint paint = new Paint();
   float cx=0,cy=0,radius=0;
 
   public A(Context context)
   {
      super(context);
      paint.setColor(Color.BLACK);
   }
 
 
   public A(Context context,AttributeSet attrs)
   {
      super(context,attrs);
      paint.setColor(Color.BLACK);
   }
   public void setCircle(float cx,float cy,float radius)
   {
      this.cx=cx;
      this.cy=cy;
      this.radius=radius;
   }
   @Override
   public void onDraw(Canvas canvas)
   {
      paint.setColor(Color.BLACK);
      canvas.drawCircle(cx, cy, radius, paint);
   }
}

Kolejnym krokiem będzie dodanie obiektu widoku (w tym przypadku obiekt klasy A) do pliku opisującego Layout (activity_main.xml).

<com.tango.tmp2.A
   android:id="@+id/v1"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignParentTop="true"
   android:layout_centerHorizontal="true"
   android:layout_marginTop="100dp"
   android:background="#ff0000"
/>

Jeżeli chcesz użyć klasy widoku jako klasy wewnętrznej (w klasie Activity), odpowiedni wpis w pliku xml będzie miał następującą postać.

<view
   class="com.tango.tmp2.A"
   android:id="@+id/v1"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignParentTop="true"
   android:layout_centerHorizontal="true"
   android:layout_marginTop="100dp"
   android:background="#ff0000"
/>

Obsługa zdarzeń i logika aplikacji

W pliku opisującym Layout aplikacji (xml) dodaj definicję przycisku Plot i ustaw odpowiednie atrybuty oraz funkcję obsługi zdarzenia polegającego na naciśnięciu przycisku. Activity naszej aplikacji jest napisany w języku Java i znajduje się w pliku /app/src/main/java/com.delta.tango.mod3/MainActivity.java.

package com.tango.tmp2;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
 
public class MainActivity extends Activity
{
   A obj;
   float cx=50,cy=400,radius=0;
 
   @Override
   protected void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      obj=(A)findViewById(R.id.v1);
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu)
   {
      getMenuInflater().inflate(R.menu.activity_main, menu);
      return true;
   }
 
   public void fdraw(View v)
   {
      cx+=5;
      cy-=5;
      radius=5;   obj.setCircle(cx, cy, radius);
      obj.invalidate();
   }
}

Ćw. 11.3
Dodaj do widoku układ współrzędnych. Żeby to zrobić, do metody onDraw() klasy A powinieneś dodać wywołania odpowiednich metod na rzecz obiektu Paint.

public void onDraw(Canvas canvas)
{
   paint.setColor(Color.BLACK);
   canvas.drawLine(50, 50, 50, 400, paint);
   canvas.drawLine(50, 400, 400, 400, paint);
   canvas.drawCircle(cx, cy, radius, paint);
}

Ćw. 11.4
Dodaj odpowiednie przyciski, pola tekstowe i napisz implementację prostego kalkulatora graficznego pozwalającego wykonywać operacje arytmetyczne i wykreślać wykresy funkcji. Do tej ostatniej funkcjonalności będziesz potrzebował parser wyrażeń arytmetycznych. Jeżeli napotkasz na trudności z implementacją takiego parsera, to ogranicz się do jakiejś wybranej kategorii funkcji (na przykład do wielomianów).



Z. Dendzik, 2016

java/java11.txt · ostatnio zmienione: 2017/12/21 23:48 (edycja zewnętrzna)