Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(1/35)
Zagadnienia wykładu
Interfejs użytkownika
●
Activity
●
Views
●
ArrayAdapter
●
Resources
Cykl życia aktywności
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(2/35)
Aplikacja RestaurantFinder
Aplikacja wyszukiwania opinii o restauracji na podstawie jej lokalizacji i ro-
dzaju kuchni.
Ekran wprowadzania parametrów
do wyszukania opinii restauracji
(lokalizacja, rodzaj kuchni)
Lista opinii odpowiadających pa-
rametrom
Szczegóły wybranej opinii
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(3/35)
Wsparcie dla Androida
public class ReviewCriteria extends Activity
{
private static final int MENU_GET_REVIEWS = Menu.FIRST;
private Spinner cuisine;
private Button grabReviews;
private EditText location;
zmienne wiązane z odpowiednimi kon-
trolkami widoku
identyfikator menu
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(4/35)
Acitivity i layout
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.
review_criteria
);
this.location = (EditText) findViewById(R.id.
location
);
this.cuisine = (Spinner) findViewById(R.id.
cuisine
);
this.grabReviews = (Button) findViewById(R.id.
get_reviews_button
);
}
plik review_criteria.xml opisuje layout
powiązanie zmiennych z kontrolkami layoutu
{
layout może być
budowany także
dynamicznie
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(5/35)
Acitivity i layout
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this. setContentView(R.layout.
review_criteria
);
this.location = (EditText) findViewById(R.id.
location
);
this.cuisine = (Spinner) findViewById(R.id.
cuisine
);
this.grabReviews = (Button) findViewById(R.id.
get_reviews_button
);
}
plik review_criteria.xml opisuje layout
powiązanie zmiennych z kontrolkami layoutu
{
layout może być
budowany także
dynamicznie
Pliki layout
●
definiują obiekty View (kontrolki/widgety)
w strukturę drzewiastą
●
wygodnie tworzyć plik layoutu dla każdej Activity
●
dla widoków dynamicznych posiadających odwołania w kodzie
wygodnie utworzyć zmienne klasy Activity
●
widoki statyczne (nie posiadających odwołań, jak etykiety) nie
muszą być wiązane ze zmiennymi klasy
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(6/35)
Spinner – widok listy wyboru
Klasa Spinner jest wiązana z Adapterem, który umożliwia prezento-
wanie elementów Spinera jako widoków.
@Override
public void onCreate(Bundle savedInstanceState) {
...........
...........
ArrayAdapter<String> cuisines =
...........
...........
...........
...........
...........
this.cuisine.setAdapter(cuisines);
........
}
adapter dla elementów spinnera
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(7/35)
Wzorzec projektowy - adapter
Adapter przekształca interfejs jednej z klas na interfejs drugiej klasy.
Innym zadaniem wzorca jest opakowanie istniejącego interfejsu w
nowy.
W Androidzie Adapter jest klasą obsługi kolekcji, która zwraca każdy
element kolekcji w postaci widoku – View. Android posiada wiele
podstawowych adapterów.
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(8/35)
Adapter
Obiekt klasy Adaptera jest wiązany w konstruktorze z
●
Context (naszą Activity, która jest typu Context)
●
layoutem prezentacji wybranego elementu
●
tablicą zawierającą dane
@Override
public void onCreate(Bundle savedInstanceState) {
...........
...........
ArrayAdapter<String> cuisines =
new ArrayAdapter<String>(
this
,
R.layout.
spinner_view
,
getResources().getStringArray(R.array.
cuisines
));
cuisines.setDropDownViewResource(R.layout.
spinner_view_dropdown
);
this.cuisine.setAdapter(cuisines);
...........
}
nasza aktywność
plik spinner_view.xml – layout elementu wybra-
nego z listy
plik arrays.xml
plik spinner_view_dropdown.xml – layout każ-
dego z elementów listy (na rozwiniętej liście)
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(9/35)
Obsługa zdarzenia przycisku
@Override
public void onCreate(Bundle savedInstanceState) {
.................
this.grabReviews.
setOnClickListener
(new
OnClickListener
() {
@Override
public void
onClick
(View v) {
handleGetReviews();
}
});
}
metoda ustawiająca Listenera zdarzenia
wciśnięcia przycisku
anonimowy obiekt ob-
sługujący zdarzenie
metoda obsługująca zdarzenie
metoda pobierająca listę opinii
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(10/35)
Menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.
add
(
0
,
ReviewCriteria.
MENU_GET_REVIEWS
,
0
,
R.string.
menu_get_reviews
)
.setIcon(android.R.drawable.
ic_menu_more
);
return true;
}
dodaj element menu
identyfikator grupy
ikona menu
zasób tekstowy
identyfikator elementu
numer w sekwencji
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(11/35)
Obsługa zdarzenia wyboru menu
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case MENU_GET_REVIEWS:
handleGetReviews();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
sprawdzenie wybranego
elementu menu
metoda pobierająca listę opinii
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(12/35)
Metoda pobierająca listę opinii
private void handleGetReviews() {
if (!validate()) {
return;
}
...........
}
sprawdzenie poprawności danych
w kontrolce
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(13/35)
Sprawdzenie poprawności danych w kontrolce
private boolean validate() {
boolean valid = true;
StringBuilder validationText = new StringBuilder();
if ((this.location.getText() == null) || this.location.getText().toString().equals(""))
{
validationText.append(getResources().
getString(R.string.
location_not_supplied_message
));
valid = false;
}
.......
}
zakładamy poprawność danych
sprawdź poprawność danych
„Location must be specified \n(City, State [Country]).”
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(14/35)
Dialog komunikatu
private boolean validate() {
.........
if (!valid)
{
new
AlertDialog.Builder
(this)
.setTitle(getResources().getString(R.string.
alert_label
))
.setMessage( validationText.toString()).setPositiveButton(
"Continue",
new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int arg1) {
/* nie rób nic */
}
})
.show();
validationText = null;
}
return valid;
}
budujemy dialog komunikatu
„Sorry!”
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(15/35)
Wzorzec projektowy - budowniczy
Celem budowniczego jest rozdzielenie sposobu tworzenia obiektów
od ich reprezentacji. Innymi słowy proces tworzenia obiektu podzie-
lony jest na kilka mniejszych etapów a każdy z tych etapów może
być implementowany na wiele sposobów. Dzięki takiemu rozwiąza-
niu możliwe jest tworzenie różnych reprezentacji obiektów w tym
samym procesie konstrukcyjnym.
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(16/35)
Wzorzec projektowy - budowniczy
Sekwencja budowy obiektu.
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(17/35)
Metoda pobierająca listę opinii cd
private void handleGetReviews() {
if (!validate()) {
return;
}
RestaurantFinderApplication application = (RestaurantFinderApplication) getApplication();
application.
setReviewCriteriaCuisine
(this.cuisine.getSelectedItem().toString());
application.
setReviewCriteriaLocation
(this.location.getText().toString());
// wywołaj następną aktywność
Intent intent = new Intent(Constants.INTENT_ACTION_VIEW_LIST);
startActivity(intent);
}
zapamiętaj zawartość kontrolek w obiekcie aplikacji
wywołaj następną aktywność
AndroidManifest.xml
<application
android:icon="@drawable/restaurant_icon_trans"
android:label="@string/app_short_name"
android:name="
RestaurantFinderApplication
"
.....>
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(18/35)
Cykl życia aktywności
●
Procesy umieszczane są na stosie.
●
Procesy są związane z aktywnościami.
●
Proces aktywności na pierwszym planie umieszczany jest na
szczycie stosu.
●
W momencie zmniejszania zasobów Android decyduje o tym, któ-
ry proces zabić:
•
każdy proces nie obsługujący żadnej aktywności (ani usługi ani
BroadcastReceiver) jest nazywany pustym procesem i jest
pierwszym do usunięcia
•
każdy proces obsługujący aktywność działającą w tle jest na-
stępny w kolejce
•
każdy proces obsługujący widoczną aktywność, ale niebędącą
na pierwszym planie, jest następny w kolejce
•
proces obsługujący widoczną aktywność działającą na pierw-
szym planie jest najważniejszy
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(19/35)
Cykl życia aktywności
●
W momencie tworzenia aktywności, przełączania na pierwszy
plan, w tło i wyłączenia wywoływane są przez Androida odpo-
wiednie metody Aktywności
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(20/35)
Metody Activity cyklu życia
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(21/35)
Widoki
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(22/35)
Widoki
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(23/35)
Wybrane metody View
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(24/35)
Wybrane metody TextView
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(25/35)
Korzystanie z ListActivity
public class ReviewList extends
ListActivity
{
private static final String CLASSTAG = ReviewList.class.getSimpleName();
private static final int MENU_CHANGE_CRITERIA = Menu.FIRST + 1;
private static final int MENU_GET_NEXT_PAGE = Menu.FIRST;
private static final int NUM_RESULTS_PER_PAGE = 8;
private TextView empty;
private ProgressDialog progressDialog;
private
ReviewAdapter reviewAdapter
;
private List<Review> reviews;
.......
}
Wykorzystywany będzie w aktywności własny Ad-
apter
Dziedziczenie po ListActivity
●
ListActivity posiada ListView
●
Domyślnym layoutem dla ListView jest pełnoekranowa, wyśrod-
kowana lista elementów do wyboru
widok używany, gdy lista opinii jest pusta
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(26/35)
Handler w ReviewList
public class ReviewList extends ListActivity {
...........
private final
Handler handler
= new Handler() {
@Override
public void handleMessage(final Message msg) {
progressDialog.dismiss();
if ((reviews == null) || (reviews.size() == 0))
{
empty.setText("No Data");
}
else
{
reviewAdapter = new ReviewAdapter(ReviewList.this, reviews);
setListAdapter(reviewAdapter);
}
}
};
..........
Gdy nie otrzymano danych
Zamknij dialog postępu
●
wykonuje zadania w osobnym wątku
●
odpowiedzialny za wysyłanie zadań do innego wątku
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(27/35)
onCreate w ReviewList
public class ReviewList extends ListActivity {
...........
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.
review_list
);
this.empty
= (TextView) findViewById(R.id.empty);
final ListView
listView
= getListView();
listView.setItemsCanFocus(false);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setEmptyView(
this.empty
);
}
..........
widget ListView aktywności
plik
review_list
.xml opisuje layout
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(28/35)
onResume w ReviewList
public class ReviewList extends ListActivity {
...........
@Override
protected void onResume() {
super.onResume();
RestaurantFinderApplication application = (RestaurantFinderApplication) getApplication();
String criteriaCuisine = application.getReviewCriteriaCuisine();
String criteriaLocation = application.getReviewCriteriaLocation();
int startFrom = getIntent().getIntExtra(Constants.STARTFROM_EXTRA, 1);
loadReviews(criteriaLocation, criteriaCuisine, startFrom);
}
..........
pobierz numer elementu startowego z intencji
pobierz kryteria z obiektu aplikacji
wywołaj metodę ładującą ciąg dalszy listy
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(29/35)
menu w ReviewList
public class ReviewList extends ListActivity {
...........
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0,
ReviewList.MENU_GET_NEXT_PAGE,
0,
R.string.menu_get_next_page)
.setIcon(android.R.drawable.ic_menu_more);
menu.add(0,
ReviewList.MENU_CHANGE_CRITERIA,
0,
R.string.menu_change_criteria)
.setIcon(android.R.drawable.ic_menu_edit);
return true;
}
..........
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(30/35)
onMenuItemSelected w ReviewList
public class ReviewList extends ListActivity {
...........
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
Intent intent = null;
switch (item.getItemId())
{
case MENU_GET_NEXT_PAGE:
intent = new Intent(Constants.INTENT_ACTION_VIEW_LIST);
intent.putExtra(Constants.STARTFROM_EXTRA,
getIntent().getIntExtra(Constants.STARTFROM_EXTRA, 1)
+ ReviewList.NUM_RESULTS_PER_PAGE);
startActivity(intent);
return true;
case MENU_CHANGE_CRITERIA:
intent = new Intent(this, ReviewCriteria.class);
startActivity(intent);
return true;
}
return super.onMenuItemSelected(featureId, item);
}
..........
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(31/35)
onListItemClick w ReviewList
public class ReviewList extends ListActivity {
...........
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
RestaurantFinderApplication application = (RestaurantFinderApplication) getApplication();
application.setCurrentReview(this.reviews.get(position));
Intent intent = new Intent(Constants.INTENT_ACTION_VIEW_DETAIL);
intent.putExtra(Constants.STARTFROM_EXTRA,
getIntent().getIntExtra(Constants.STARTFROM_EXTRA,1));
startActivity(intent);
}
..........
zapamiętaj wybraną opinię w obiekcie aplikacji
Przejdź do aktywności szczegółów
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(32/35)
onListItemClick w ReviewList
public class ReviewList extends ListActivity {
...........
private void loadReviews(String location, String cuisine, int startFrom) {
final ReviewFetcher
rf
= new ReviewFetcher(location, cuisine, "ALL", startFrom,
ReviewList.NUM_RESULTS_PER_PAGE);
this.
progressDialog
= ProgressDialog.show(this,
" Working...", " Retrieving reviews", true, false);
new Thread() {
@Override
public void run() {
reviews = rf.getReviews();
handler.sendEmptyMessage(0);
}
}.start();
}
..........
dialog postępu
wątek pobierający dane
z wykorzystaniem API Google Base
Obiekt pobierający dane z wykorzy-
staniem API Google Base
prześlij wiadomość do Loopera
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(33/35)
HandlerThread, Handler, Looper
●
Android monitoruje czas odpowiedzi aplikacji i usuwa te, które wg
niego przestały działać
●
Zdarzenie „aplikacja nie odpowiada” (ANR) jest generowane, gdy
interfejs użytkownika nie otrzyma odpowiedzi przez 5 sekund
●
Zatem długotrwałe operacje powinny być wykonywane poza wąt-
kiem interfejsu użytkownika.
●
Wątek UI jest typu HandlerThread (specjalizacja Thread)
●
HandlerThread posiada obiekt typu Looper, który odbiera wiado-
mości (Message) od handlera
●
Handler jest kojarzony z obiektem Looper bieżącego wątku pod-
czas tworzenia handlera bezargumetowym konstruktorem
●
Looper przetwarza wiadomości handlera umieszczając je w Mes-
sageQueue
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(34/35)
HandlerThread, Handler, Looper
Katedra Mikroelektroniki i Technik Informatycznych Politechniki Łódzkiej
(35/35)
Typy zasobów
●
res/anim
— reprezenacja XML animacji 'ramka po ramce'
●
res/drawable
— .png, .png, i .jpg obrazy
●
res/layout
— reprezenacja XML obiektów widoków
●
res/values
— reprezenacja XML napisów, kolorów, styli, rozmia-
rów i tablic
●
res/xml
— zdefiniowane przez użytkownika pliki XML aplikacji
kompilowane do postaci binarnej
●
res/raw
— pliki niekompilowane dodawane do aplikacji