воскресенье, 8 мая 2011 г.

Android: переход между окнами в приложении

Давайте проведём небольшую аналогию. Допустим мы умеем делать сайты, а хотим научиться писать приложения под Android. Казалось бы, мало общего... Но это как посмотреть. Большая часть интерфейсов так или иначе подразумевают переход между окнами (страницами) приложения (сайта). Динамичные web-интерфейсы сводят переход между страницами к минимуму, подменяя отдельные части контента ajax-ом. А там, где это целесообразно, меняем страницу целиком. Есть аналогичный подход в Andriod-приложении? Конечно.
Каждое окно Android-приложения представлено классом, расширяющим Activity. В этом классе изначально нет "контента". Заполняем его методом setContentView(View v), где v - корневой элемент иерархии контейнеров и виджетов, каждый из которых также наследует View. Ничего не  напоминает? Activity похож на Document, а построение иерархии элементов с помощью addView() похоже на appendChild() при построении dom-дерева в javascript. Не правда ли? Теоретически, любое Android-приложение можно построить на базе одного единственного Activity, подменяя в нужный момент его содержимое или часть его с помощью setContentView. Это похоже на чисто ajax-овый сайт из одной страницы. И даже недостатки такого подхода кое-где похожи. На таком сайте бесполезна кнопка "назад" в браузере, а в таком приложении бесполезна аппаратная кнопка "назад" устройства.  Конечно, это поправимо и для сайта и для Android-приложения, но вопрос не в этом. Рассмотрим второй подход. Допустим, мы решили сделать "честное" приложение, где каждому экрану интерфейса соответствует одно Activity. Поступаем примерно так:
Intent intent = new Intent();
intent.setClass(this, NextActivity.class);
startActivity(intent);

Тут NextActivity представляет экран к которому мы переходим. Несколько сложнее, чем в web, конечно. Теперь посмотрим на передачу данных. У каждого Activity своя область видимости переменных, как и у каждой страницы для javascript. Переходя к другому Activity мы теряем возможность использовать поля предыдущего. Данные нужно передавать из одного окна в другое также как и из одной страницы на другую, используя посредника. В случае web, это сервер, который принимает данные из запроса и строит на основании их новую страницу. В случае Android-приложения это среда исполнения, которая по сути делает то же самое.
Тут становится понятна роль Intent. Это что-то вроде запроса. В него мы "вкладываем" команды и данные, и из него потом получаем страницу результата. Происходит это примерно так. В первом Activity:
Intent intent = new Intent();
intent.setClass(this, NextActivity.class);
intent.putExtra(NextActivity.FIELD_NAME, field_value);
startActivity(intent);

А во втором, соответственно, получаем данные из Intent:

  1. public class NextActivity extends Activity {
  2.     public static final String FIELD_NAME = "field_name";
  3.     
  4.     @Override
  5.     public void onCreate(Bundle icicle) {
  6.         super.onCreate(icicle);
  7.         String field_value = getIntent().getExtras().getStirng(FIELD_NAME);
  8.         Toast.makeText(this, "field value is "+field_value, Toast.LENGTH_SHORT).show();
  9.     }
  10. }
Вот так мы передаём строку из первого окна и отображаем её во втором. Первое окно при этом уходит "в фон", а кнопка "назад" в любой момент может вернуть ему управление. При этом данные второго окна останутся недоступными, как и в случае с web-страницами. А чтобы передать данные обратно нужна снова помощь "посредника". В общем, по моему, аналогия есть. Конечно, как и все аналогии она не точна. Но этого и не требуется. Главное в том, что с её помощью легче понять устройство Android-приложений.

5 комментариев:

  1. огромное спасибо) очень в тему объяснено! сравнение в ajax сразу расставило всё на свои места в моей голове)

    ОтветитьУдалить
  2. startActivityForResult можно было бы тоже в статье показать как работает :)

    ОтветитьУдалить
  3. если б он ещё знал как это работает... таких статей в сети полно и все
    по одному шаблону создают блин сайты похожие друг на друга один в один
    программисты хреновы.................

    ОтветитьУдалить
  4. Вот нашлось и про глобальные данные:
    Глобальные данные можно хранить в собственном классе, который наследует класс Application и который прописат на манифесте как класс Application. Этот параметр в манифесте опциональный, так что по умолчанию он пуст.

    ОтветитьУдалить