12 марта 2014 г.

Жизненный цикл Activity в Android (часть 4)

Чтобы еще лучше понять жизненный цикл Активности, я набросал программку, которая состоит из трех активностей: A, B и C. Активность A вызывает Активность B, Активность B вызывает C, а C вызывает снова A. Кратно можно показать так A->B->C->A.

Рассматривая этот пример мы уже в плотную подходим к теме задач и стеков активностей или если правильней назвать обратных стеков (Tasks and Back Stack).

И так на каждой Активити у меня есть кнопка которая вызывает следующую Активность.

Кроме того для большей наглядности и анализа использованы возможности отладки приложений Eclipse и Android SDK.

В написании проги помогли и эти статьи
http://startandroid.ru/ru/uroki/vse-uroki-spiskom/19-urok-12-logi-i-vsplyvajuschie-soobschenija.html
http://developer.alexanderklimov.ru/android/activity.php

А изначальную идею к написанию дала эта статья
http://habrahabr.ru/post/201214/

но там нет представленного кода. Хотя он конечно простой, но когда только начинаешь все изучать, все не просто.

Приложение назвал AP0003. Очень говорящее название. Раскрасил его тоже дико, как светофор. A – красный, B – желтый и C – зеленый. На зато сразу видно какая активность на экране. На каждой Активности есть кнопка, которая вызывает следующую Активность.
Вот так выглядит приложение в работающем виде:

AL0001

AL0002

AL0003

Теперь приведу код активностей и разметок

Код ActivityA.java

package com.example.ap0003;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.util.Log;

public class ActivityA extends Activity {

 final String TAG = "States";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.layout_a);
  Log.d(TAG, "ActivityA: onCreate()");
 }

 @Override
 protected void onStart() {
  super.onStart();
  Log.d(TAG, "ActivityA: onStart()");
 }

 @Override
 protected void onResume() {
  super.onResume();
  Log.d(TAG, "ActivityA: onResume()");
 }

 @Override
 protected void onPause() {
  super.onPause();
  Log.d(TAG, "ActivityA: oPause()");
 }

 @Override
 protected void onStop() {
  super.onStop();
  Log.d(TAG, "ActivityA: onStop()");
 }

 @Override
 protected void onRestart() {
  super.onRestart();
  Log.d(TAG, "ActivityA: onRestart()");
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  Log.d(TAG, "ActivityA: onDestroy()");
 }

 public void onClickStartB(View v) {
  Intent intent = new Intent(ActivityA.this, ActivityB.class);
  startActivity(intent);

 }

}

Две другие Активности подобны этой только есть изменения в соотвтествующих строках выведения сообщений отладки.

В строке 11 задается значение ярлыка отладки, чтобы сообщения с ним было легче находить в журналах отладки. В строке 17 выводится этот ярлык а так же дополнительное сообщение отладки.

Код layout_a.xml
<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:background="#f20808"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".ActivityA" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/strA" />

    <Button
        android:id="@+id/buttonStartB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView1"
        android:onClick="onClickStartB"
        android:text="Start Activity B" />

</RelativeLayout>

В строке 24 определен метод вызова нажатия кнопки запускающей следующую Активность.

Теперь об отладке. Просто приведу скрин и небольшое объяснение.

AL0004

Теперь запускаем приложение и смотрим что показывает отладка по фильтру State.

AL0005

Теперь сделаем интересную и важную вещь. В окне AVD нажмем комбинацию Ctrl+F11 – смена ориентации экрана.

AL0006

и что же мы видим в логах

AL0007



Вот что надо знать и учитывать, что при смене ориентации экрана текущая активность уничтожается и запускается заново. Это раз.

вернем ориентацию обратно и запустим активность B

AL0008

Как видим Активность А перешла в остановленное состояние но не уничтожена, то есть остается в памяти, а верней в стеке активностей.

Теперь запустим Активность C

AL0009

Теперь и Активность B у нас остановлена, но не уничтожена и находится в стеке, на вершине которого сейчас Активность C.

Теперь нажмем кнопку на Активности С и запустим Активность А

AL0010

Активность С была остановлена, и была запущена НОВАЯ Активность А. То есть запущен не старый экземпляр окна который мы видели в начале, а это совершенно новый экземпляр Активности А, так как вызван был метод onCreate, а не onRestart. Из этого вывод, что в стандартном варианте запуска одна Активность может быть запущена несколько раз и находится в стеке сколько угодно раз (но это поведение можно поменять).

Теперь нажмем кнопку обратно (возврат)

AL0011

Сейчас мы видим что Активность С была вызвана заново, то есть не создана заново, а восстановлена из состояния Stop методом onRestart(). А Активность А была уничтожена, но уничтожена самая последняя Активность А, которую мы запускали. Если нажать последовательно еще два раза кнопку back (возврат).

То тогда сперва будет восстановлена и показана Активность B, затем она будет уничтожена и будет показана (восстановлена) наша первая Активность А методом onRestart.

AL0012

И так этот пример уже совсем в плотную пододвинул нас к следующей важной теме Tasks and Back Stack.

Что еще хотелось бы сказать, в данной теме, так то, что если сейчас принудительно завершить приложение AP003, нажав кнопку Home и перейдя в Настройки-> Приложения –> Управление приложениями, затем выбрать приложение AP003 и нажать кнопочку Принудительная остановка (Force Stop)

AL0013

То приложение будет принудительно остановлено, но метод onDestroy вызван не будет! Это надо учитывать при разработке приложений. Так же метод onDestroy не вызывается, если приложение уходит в фон и затем завершается системой для высвобождения необходимых ресурсов.

AL0014

Так же по этой теме можно почитать еще тут:

http://startandroid.ru/ru/uroki/vse-uroki-spiskom/58-urok-21-sozdanie-i-vyzov-activity.html

http://startandroid.ru/ru/uroki/vse-uroki-spiskom/60-urok-23-activity-lifecycle-v-kakih-sostojanijah-mozhet-byt-activity.html

http://startandroid.ru/ru/uroki/vse-uroki-spiskom/61-urok-24-activity-lifecycle-primer-smeny-sostojanij-s-dvumja-activity.html

Хотя в приведенных ссылках вызов Активностей осуществляется несколько по другому, но сути вещей это не меняет.

На этом пока закончим с жизненными циклами Активностей.

Комментариев нет:

Отправить комментарий