Lipiec 8, 2011
Activity Podstawowe komponenty Tutoriale
Activity (Aktywność) to jeden z podstawowych komponentów systemu Android. Klasa ta (a raczej jej podklasy) odpowiedzialna jest za interakcję z użytkownikiem, tworzenie okna naszej aplikacji i uruchamianie innych podstawowych komponentów systemowych. Zazwyczaj jedna podklasa Activity reprezentuje jedno okno naszej aplikacji.
W tym artykule zagłębimy się w jej budowę, cykl życia i kilka innych mechanizmów z nią związanych.
Przed przystąpieniem do tego artykuły powinniśmy stworzyć nowy projekt Androidowy w Eclipse. W opisie zakładam, że będzie się on nazywał HelloActivities, a główna Aktywność będzie nosiła nazwę MainActivity.
Pierwszą czynnością, jaką się zajmiemy będzie stworzenie nowej Aktywności w naszym projekcie. Aby się do tego zabrać musimy stworzyć klasę, która dziedziczy po Activity. Klikamy więc prawym przyciskiem myszy na pakiet, w którym umieszczona jest główna Aktywność -> New -> Class.
W tym momencie powinniśmy zobaczyć kreator tworzenia nowej klasy. Wypełniamy pola name (nazwa klasy – ja przyjąłem, że będzie to AnotherActivity) oraz Superclass (klasa, z której dziedziczymy – wybieramy android.app.Activity).
Po zakończeniu edycji powinniśmy zobaczyć pusty szkielet naszej klasy, w którym od razu przeciążymy metodę onCreate():
Kolejną rzeczą, którą należy wykonać jest stworzenie wyglądu naszego Activity. Możemy to zrobić poprzez dodanie nowego pliku .xml do katalogu res/layout/. My jednak wykorzystamy edytor dostarczony wraz z wtyczką ADT. Klikamy prawym przyciskiem myszy na nasz projekt -> New -> Other -> wyszukujemy Android XML File, który zaznaczamy, po czym ukazuje nam się kreator Androidowego pliku XML.
Wypełniamy następujące pola:
Po zatwierdzeniu powinien ukazać nam się plik z layoutem. Aby nie komplikować, dodamy do niego jedynie TextView z jakimś ciągiem znaków.
Teraz pozostało nam już tylko załadowanie layoutu w naszej nowej Aktywności:
Ostatnią czynnością, którą należy wykonać jest zadeklarowanie naszej nowej Aktywności w pliku AndroidManifest.xml. W naszym przypadku sprowadza się to do dodania kolejnego elementu do węzła <application> (dodam, że zwykle jest to trochę więcej niż 1 linijka kodu ).
W tym momencie możemy być pewni, że nasza aplikacja posiada drugą Aktywność czekającą w gotowości na uruchomienie. O tym jak to zrobić napiszę jeszcze w tym artykule.
Zanim zagłębimy się w cykl życia Androidowych okienek, warto uzmysłowić sobie po co w ogóle został on wprowadzony.
Przede wszystkim warto jest wiedzieć, że wszystkie Aktywności (niezależnie od tego do jakiej aplikacji należą) znajdują się na wspólnym stosie. Kiedy nowa Aktywność jest uruchamiana, zostaje ona umieszczona na jego szczycie. I właśnie na podstawie pozycji na stosie ustalana jest „ważność” danego Activity (im niżej znajduje się obiekt Aktywności tym mniejszy ma priorytet).
Priorytety natomiast wykorzystywane są w procesie odzyskiwania zasobów. Kiedy bowiem systemowi zaczyna ich brakować, może zostać podjęta decyzja o usunięciu z pamięci obiektów Aktywności. I jak nietrudno się domyślić, usuwane są te, które znajdują się najniżej na stosie.
Aby taki zabieg nie miał żadnych negatywnych skutków wprowadzono cykl życia Aktywności, który pozwala ustalić jak w danych sytuacjach powinna zachowywać się aktywność.
Źródło: http://developer.android.com/reference/android/app/Activity.html
Jak widać, cykl życia składa się z kilku metod (które wykorzystujemy poprzez ich przeciążanie w naszej klasie):
Aby przekonać się jak cykl życia działa w realnej aplikacji rozbudujemy nasz projekt o kilka metod, które pozwolą przyjrzeć się temu „z bliższa” .
Interfejs naszej aplikacji rozbudujemy o przycisk, który będzie uruchamiał nową aktywność, oraz pole tekstowe, które będzie służyło do wyświetlania listy stanów, przez które przeszła nasza główna aktywność.
Do klasy naszej głównej Aktywności dodamy i zainicializujemy pola layoutu. Dodatkowo do przycisku przypiszemy akcję uruchamiającą nową Aktywność (którą na razie zostawimy bez komentarza).
Teraz pozostało nam tylko przeciążyć każdą z metod cyklu życia Aktywności i sprawić by każda z nich w momencie wywołania wpisywała informacje o tym do pola tekstowego tvLifetime.
Myślę, że powyższy kod nie wymaga komentarzy.
Oto ekran naszej Aktywności zaraz po uruchomieniu aplikacji:
Następnie uruchamiamy naszą drugą aktywność i przyciskiem powrotu wracamy do nasze głównej Aktywności. Jak widać, najpierw wywoływane są metody onPause oraz onStop. Następnie wyświetlana jest druga Aktywność (innymi słowy to ona umieszczona jest na szczycie stosu). Później, gdy druga aktywność jest ze stosu zdejmowana, ponownie główna Aktywność przechodzi na jego szczyt. Skutkuje to wywołaniem kolejno metod onRestart, onStart oraz onResume.
main.xml
another.xml
MainActivity.java
AnotherActivity.java
Cały projekt dostępny jest na naszym githubie – HelloActivities.
[…] Problem jest oczywiście bardziej ogólny. Zacznijmy jednak od wytłumaczenia dlaczego najczęściej mamy z nim do czynienia podczas rotacji. Podczas zmiany orientacji ekranu nasza Aktywność ulega zniszczeniu. Innymi słowy wywoływane są kolejno poniższe metody z jej cyklu życia (opis poszczególnych metod cyklu przedstawiony jest tutaj): […]
[…] Activity – podstawowe informacje, cykl życia […]
[…] powiadomień (Notifications) są jednym z podstawowych komponentów systemu (obok Aktywności, Intencji oraz Dostarczycieli treści). Jest to zbiór elementów, które „zaczepiają” […]
[…] Problem jest oczywiście bardziej ogólny. Zacznijmy jednak od wytłumaczenia dlaczego najczęściej mamy z nim do czynienia podczas rotacji. Podczas zmiany orientacji ekranu nasza Aktywność ulega zniszczeniu. Innymi słowy wywoływane są kolejno poniższe metody z jej cyklu życia (opis poszczególnych metod cyklu przedstawiony jest tutaj): […]
Zaloguj się lub skorzystaj z profilu:
Możesz również zostawić komentarz bez rejestracji, korzystając z poniższego formularza:
Musisz być zalogowany aby móc pisać komentarze.
Activity – podstawowe informacje, cykl życia
Powiązane linki
Przygotowanie
Tworzenie nowego Activity
Cykl życia Activity
Cykl życia w praktyce
Kompletny kod źródłowy aplikacji
Nowa klasa Aktywności
Layout dla nowej Aktywności
Informacja o nowej Aktywności w AndroidManifest.xml
Activity Stack
Opis cyklu życia
UI
Kod źródłowy aplikacji
Prezentacja działania aplikacji
Komentarze (4)
Prześlij komentarz
- File – nazwa pliku (na potrzeby tego wpisy zakładam another.xml)
- Typ – Layout
- Folder – /res/layout
- Root element – LinearLayout
- onCreate() – metoda, która powinna zostać użyta do inicjalizacji Aktywności. To tutaj powinien zostać zbudowany interfejs użytkownika, powiązanane dane z kontrolerami, ewentualnie stworzone Serwisy i/lub wątki.
- onDestroy() – podczas przeciążania tej metody powinniśmy zadbać o to by usunąć wszelkie zasoby stworzone w metodzie onCreate() oraz zamknąć wszelkie połączenia, czy to z bazą danych czy z siecią, jakie nawiązaliśmy przy okazji działania aktywności.
- onStart()/onStop() – czas życia aktywności pomiędzy tymi metodami nazywany jest Widzialnym Czasem Życia (The Visible Lifetime), ponieważ to wtedy Aktywność jest widoczna dla użytkownika.
- onResume()/onPause() – pomiędzy tymi metodami zawiera się Aktywny Czas Życia (The Active Lifetime). Zachodzi on wtedy gdy nasza aktywność jest przez nas używana. To wtedy odbierane/wysyłane są wszelkie działania użytkownika. Pomiędzy tymi metodami powinny znajdować się lekkie i szybkie instrukcje.
- onStop() – powinna zostać użyta do zatrzymania wszelkich animacji, wątków, serwisów i innych, ktore związane są z interfejsem aktywności.
- onStart()/onRestart() – przywracamy lub restartujemy wszystkie czynności/procesy, które zostały zatrzymane przez onStop().
package pl.froger.helloactivities;
import android.app.Activity;
import android.os.Bundle;
public class AnotherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}...
public class AnotherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.another);
}
}<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pl.froger.helloactivities" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".AnotherActivity"></activity>
</application>
</manifest><?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:layout_height="wrap_content" android:id="@+id/btnOpenNewActivity" android:layout_width="fill_parent" android:text="@string/btn_NewActivity"></Button> <TextView android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:text="@string/lifetime" android:gravity="center" android:layout_width="fill_parent"></TextView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tvLifetime"></TextView> </LinearLayout>
...
public class MainActivity extends Activity {
private Button btnOpenNewActivity;
private TextView tvLifetime;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvLifetime = (TextView) findViewById(R.id.tvLifetime);
btnOpenNewActivity = (Button) findViewById(R.id.btnOpenNewActivity);
btnOpenNewActivity.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent startAnotherActivity = new Intent(getApplicationContext(), AnotherActivity.class);
startActivity(startAnotherActivity);
}
});
}
}@Override
public void onCreate(Bundle savedInstanceState) {
...
setCurrentStateInTextView("onCreate");
}
@Override
protected void onRestart() {
super.onRestart();
setCurrentStateInTextView("onRestart");
}
@Override
protected void onStart() {
super.onStart();
setCurrentStateInTextView("onStart");
}
@Override
protected void onResume() {
super.onResume();
setCurrentStateInTextView("onResume");
}
@Override
protected void onPause() {
setCurrentStateInTextView("onPause");
super.onPause();
}
@Override
protected void onStop() {
setCurrentStateInTextView("onStop");
super.onStop();
}
@Override
protected void onDestroy() {
setCurrentStateInTextView("onDestroy");
super.onDestroy();
}
private void setCurrentStateInTextView(String state) {
String text = tvLifetime.getText().toString() + state + " "
+ getNowTime() + "\n";
tvLifetime.setText(text);
}
private String getNowTime() {
DateFormat df = new SimpleDateFormat("H:m:s:S");
Date now = Calendar.getInstance().getTime();
return df.format(now);
}<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:layout_height="wrap_content" android:id="@+id/btnOpenNewActivity" android:layout_width="fill_parent" android:text="@string/btn_NewActivity"></Button> <TextView android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:text="@string/lifetime" android:gravity="center" android:layout_width="fill_parent"></TextView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tvLifetime"></TextView> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Welcome to another activity"></TextView> </LinearLayout>
package pl.froger.helloactivities;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button btnOpenNewActivity;
private TextView tvLifetime;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvLifetime = (TextView) findViewById(R.id.tvLifetime);
btnOpenNewActivity = (Button) findViewById(R.id.btnOpenNewActivity);
btnOpenNewActivity.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent startAnotherActivity = new Intent(getApplicationContext(), AnotherActivity.class);
startActivity(startAnotherActivity);
}
});
setCurrentStateInTextView("onCreate");
}
@Override
protected void onRestart() {
super.onRestart();
setCurrentStateInTextView("onRestart");
}
@Override
protected void onStart() {
super.onStart();
setCurrentStateInTextView("onStart");
}
@Override
protected void onResume() {
super.onResume();
setCurrentStateInTextView("onResume");
}
@Override
protected void onPause() {
setCurrentStateInTextView("onPause");
super.onPause();
}
@Override
protected void onStop() {
setCurrentStateInTextView("onStop");
super.onStop();
}
@Override
protected void onDestroy() {
setCurrentStateInTextView("onDestroy");
super.onDestroy();
}
private void setCurrentStateInTextView(String state) {
String text = tvLifetime.getText().toString() + state + " "
+ getNowTime() + "\n";
tvLifetime.setText(text);
}
private String getNowTime() {
DateFormat df = new SimpleDateFormat("H:m:s:S");
Date now = Calendar.getInstance().getTime();
return df.format(now);
}
}package pl.froger.helloactivities;
import android.app.Activity;
import android.os.Bundle;
public class AnotherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.another);
}
}
25 lipca 2011 o 20:23
28 lipca 2011 o 00:00
1 sierpnia 2011 o 13:49
16 października 2011 o 19:19