Переключение между приложениями андроид. Как улучшить многозадачность на Android: обзор приложения Pintasking

Всем привет, в очередной раз решил написать пост и долго не знал о чем написать, а потом залез на несколько форумов и увидел что у народа серьезные траблы с интентами в андроиде, люди не могут перейти с активности на активность или передать данные таким способом.

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


Для начала что такое Intent? Intent — это механизм для описания одной операции — выбрать фотографию, перейти с активности на активность, передать данные с одного окна на другое, отправить письмо, сделать звонок, запустить браузер (или какую либо другую программу) и перейти по указанному адресу.

Сегодня я по порядку расскажу как делается каждый из этих типов интентов, быстро и кратко.

Переход с одной активности на другу


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

Допустим у нас есть два класса — FirstActivity и SecondActivity, нам с первой нада перейти на вторую, для этого на первой активности в лейауте создаем кнопку и вешаем на нее листенера в коде программы. Это выглядит примерно так:

Сперва делаем леяут с разметкой.

main.xml

< RelativeLayout xmlns:android = xmlns:tools = "http://schemas.android.com/tools" android:layout_width = "match_parent" android:layout_height = "match_parent" > < Button android:id = "@+id/button1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "Button" />

FirstActivity.java
protected void onCreate (Bundle savedInstanceState ) { super . onCreate (savedInstanceState ); setContentView (R . layout . activity_main ); //присвоили кнопку к кнопке на леяуте Button btn = (Button ) findViewById (R . id . button1 ); //повесили на него листенера btn . setOnClickListener (new OnClickListener () { @Override public void onClick (View v ) { //переходим с первой на вторую активность Intent intent = new Intent (FirstActivity . this , SecondActivity . class ); startActivity (intent ); } }); }

AndroidManifest.xml
< application android:allowBackup = "true" android:icon = "@drawable/ic_launcher" android:label = "@string/app_name" android:theme = "@style/AppTheme" > < activity android:name = "com.example.intent.FirstActivity" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> < activity android:name = ".SecondActivity" >

Ну вторая а вторая активность у нас пустая, после нажатия на кнопку вы просто перейдете на следующую активность. Для просмотра результата перехода создайте второй лейаут файл в котором добавьте текствью, и напишите что нибудь там. Самое главное что бы SecondActivity наследовался так же от Activity как и первый иначе вы увидите ошибку.

Передача данных между активностями

Передача данных между активностями очень популярная штука, и полезная, что бы не мучаться и не делать все это интентами конечно можно использовать преференсы, сохранять в них и считывать в нужной активности, но это годиться не для разовой передачи, а для записи данных на долгое хранение, так как после 1000 записи в префсы у вас программа начнет уже глючить так как кеш будет забит разного рода данными.

Идея такого интента очень простая, для примера я просто передам с одной активности на другую какое нибудь слово. Пусть это слово будет «ты торт!». Смотрим как это делается.

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

FirstActivity.java
// переходим с первой на вторую активность Intent intent = new Intent (FirstActivity . this , SecondActivity . class ); //Передаем на следующую аквтиность слово в статическую переменную intent . putExtra (SecondActivity . TEXT , "Ты торт!" ); startActivity (intent );

Вот в этом месте мы добавляем putExtra который передает все что ваша душа пожелает, он принимает класс с константой в которую записываем что передавать, и сам текст\символ\цифру которую мы хотим передать.

SecondActivity.java
// статическая перменная public static final String TEXT = "Text" ; @Override protected void onCreate (Bundle savedInstanceState ) { super . onCreate (savedInstanceState ); setContentView (R . layout . second ); //объявляем текствью в который выведем текст TextView text = (TextView ) findViewById (R . id . textView1 ); //принимаем интент посланый из первой активности Bundle extras = getIntent (). getExtras (); //выводим что получили text . setText (extras . getString (TEXT )); }

Ну и теперь нам нужна разметка в которую будем рисовать текст:

second.xml
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" > < TextView android:id = "@+id/textView1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "TextView" />

После перехода с первой активности на другую вы увидите в левом верхнем углу сообщение что вы торт.

Вызов программ через intent

Так же как я уже упоминал ранее при помощи этого класса можно открывать программы разного рода, разные браузеры которые установлены на телефоне\планшете или например приложения для социальных сетей или файловые менеджеры для нахождения файлов.

Это очень удобная штука, я ее использовал в некоторых своих программах, в версиях андроида выше 3 работает отлично, а почему то в 3 версии андроида оно бычит, радует только то что телефонов на третьем андроиде очень мало (:

В общем смотрим на все том же самом примере класса FirstActivity. Сейчас мы откроем список браузеров.

В классе FirstActivity заменим наш старый интент на вот такой:

FirstActivity.java
// задаем адрес на который нада перейти Uri address = Uri . parse ("http://google.com" ); // открываем список браузеров Intent intent = new Intent (Intent . ACTION_VIEW , address ); // запускаем startActivity (intent );

Тут у нас из комментариев понятно что происходит, но помимо константы ACTION_VIEW есть еще очень много других разных констант которые позволяют выполнять разные функций.

Открытие файлов и папок через intent

Например для открытия локального каталога внутри телефона вам нужно сделать вот такой интент:

В FirstActivity заменим старый интент на этот.

FirstActivity.java
//создаем в шапке класса переменную которая будет сохранять id выбранного файла private static final int FILE_SELECT_CODE = 0 ;

//а дальше в том же onClickListener"ре заменяем старый интент на этот // задаем константу для захвата данных Intent intent = new Intent (Intent . ACTION_GET_CONTENT ); //какую папку открываем intent . setType ("file/*" ); //запускаем всю красоту startActivityForResult (intent , FILE_SELECT_CODE );

FirstActivity.java
//Выше или ниже метода onCreate() public void onActivityResult (int requestCode , int resultCode , Intent data ) { switch (requestCode ) { case FILE_SELECT_CODE : { Uri uri = data . getData (); try { //тут передаем uri в тот метод в котором вы ходите вывести содержимое файла } catch (IOException e ) { e . printStackTrace (); } catch (URISyntaxException e ) { e . printStackTrace (); } } break ; } super . onActivityResult (requestCode , resultCode , data ); }

Так же в андроиде есть куча других констант, их всех я описать не буду потому что их много, например вот несколько:

  • ACTION_ANSWER — Открывает активность, которая связана с входящими звонками. Это действие обрабатывается стандартным экраном для приема звонков;
  • ACTION_CALL — инициализирует обращение по телефону;
  • ACTION_DELETE — Запускает активность, с помощью которой можно удалить данные, указанные в пути URI внутри намерения;
  • ACTION_EDIT — Отображает данные для редактирования пользователем;
  • ACTION_INSERT — Открывает активность для вставки в Курсор (Cursor) нового элемента, указанного с помощью пути URI. Дочерняя активность, вызванная с этим действием, должна вернуть URI, ссылающийся на вставленный элемент;
  • ACTION_HEADSET_PLUG — Подключение наушников;
  • ACTION_MAIN — Запускается как начальная активность задания;
  • ACTION_PICK — Загружает дочернюю Активность, позволяющую выбрать элемент из источника данных, указанный с помощью пути URI. При закрытии должен возвращаться URI, ссылающийся на выбранный элемент. Активность, которая будет запущена, зависит от типа выбранных данных, например при передаче пути content://contacts/people вызовется системный список контактов;
  • ACTION_SEARCH — Запускает активность для выполнения поиска. Поисковый запрос хранится в виде строки в дополнительном параметре намерения по ключу SearchManager.QUERY;
  • ACTION_SEND — Загружает экран для отправки данных, указанных в намерении. Контакт-получатель должен быть выбран с помощью полученной активности. Используйте метод setType, чтобы указать тип MIME для передаваемых данных. Эти данные должны храниться в параметре намерения extras с ключами EXTRA_TEXT или EXTRA_STREAM, в зависимости от типа. В случае с электронной почтой стандартное приложение в Android также принимает дополнительные параметры по ключам EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC и EXTRA_SUBJECT. Используйте действие ACTION_SEND только в тех случаях, когда данные нужно передать удаленному адресату (а не другой программе на том же устройстве);
  • ACTION_SENDTO — Открывает активность для отправки сообщений контакту, указанному в пути URI, который передаётся через намерение;
  • ACTION_SYNC — Синхронизирует данные сервера с данными мобильного устройства;
  • ACTION_TIMEZONE_CHANGED — Смена часового пояса;
  • ACTION_VIEW — Наиболее распространенное общее действие. Для данных, передаваемых с помощью пути URI в намерении, ищется наиболее подходящий способ вывода. Выбор приложения зависит от схемы (протокола) данных. Стандартные адреса http: будут открываться в браузере, адреса tel: — в приложении для дозвона, geo: — в программе Google Maps, а данные о контакте — отображатся в приложении для управления контактной информацией;
  • ACTION_WEB_SEARCH — Открывает активность, которая ведет поиск в интернете, основываясь на тексте, переданном с помощью пути URI (как правило, при этом запускается браузер);

  • Сегодня мы рассмотрели только основные самые используемые виды intent"ов, спасибо за внимание.

    Исходников не будет так как мне кажется что материал довольно простой.

    Приложение не всегда состоит из одного экрана. Например, мы создали очень полезную программу и пользователю хочется узнать, кто же её автор. Он нажимает на кнопку «О программе» и попадает на новый экран, где находится полезная информация о версии программы, авторе, адресе сайта, сколько у автора котов и т.д. Воспринимайте экран активности как веб-страницу с ссылкой на другую страницу. Если вы посмотрите на код в файле MainActivity.java из прошлых уроков, то увидите, что наш класс MainActivity тоже относится к Activity (или его наследникам) или, если говорить точнее, наследуется от него.

    Public class MainActivity extends AppCompatActivity

    Как нетрудно догадаться, нам следует создать новый класс, который может быть похож на MainActivity и затем как-то переключиться на него при нажатии кнопки.

    Для эксперимента мы возьмем программу из первого урока и будем использовать для опытов кнопку (или создайте новый проект с одной кнопкой на экране). Далее создадим новую форму для отображения полезной информации. Например, покажем пользователю, что делает кот, когда идёт налево и направо. Согласитесь, это очень важная информация, дающая ключ к разгадке Вселенной.

    Создавать новую активность будем вручную, хотя в студии есть готовые шаблоны. Но там ничего сложного и для лучшего понимания полезно всё делать руками.

    Создадим новый XML-файл разметки activity_about.xml в папке res/layout . Щёлкните правой кнопкой мыши на папке layout и выберите из контекстного меню New | Layout resource file . Появится диалоговое окно. В первом поле вводим имя файла activity_about . Во втором нужно ввести корневой элемент. По умолчанию там стоит ConstraintLayout . Стираем текст и вводим ScrollView . Ввода нескольких символов достаточно, чтобы студия подсказала готовые варианты, можно сразу нажать Enter, не дожидаясь полного ввода слова:

    Получится соответствующая заготовка, в которую вставим элемент TextView .

    Информация будет извлекаться из ресурсов, а именно из строкового ресурса about_text . Сейчас он подсвечен красным цветом, сигнализируя об отсутствии информации. Можно было нажать Alt+Enter и ввести текст в диалоговом окне. Но для нашего примера этот способ не подойдёт, так как наш текст будет многострочным, с использованием управляющих символов. Поэтому поступим по-другому. Откроем файл res/values/strings.xml и вводим следующий текст вручную:

    У лукоморья дуб зелёный;\n Златая цепь на дубе том:\n И днём и ночью кот учёный\n Всё ходит по цепи кругом;\n Идёт направо - песнь заводит,\n Налево - сказку говорит.

    Мы использовали простейшие HTML-теги форматирования текста типа , , . Для нашего примера достаточно выделить жирным слова, которые относятся к коту и направлению движения. Для перевода текста на новую строку используйте символы \n . Добавим ещё один строковый ресурс для заголовка нового экрана:

    О программе

    С разметкой разобрались. Далее необходимо создать класс для окна AboutActivity.java . Выбираем в меню File | New | Java Class и заполняем нужные поля. На первых порах достаточно указать только имя. Потом разберётесь с другими полями.

    Получим заготовку.

    Сейчас класс практически пустой. Добавим код вручную. Класс должен наследоваться от абстрактного класса Activity или его родственников типа FragmentActivity , AppCompatActivity и т.д. Дописываем extends Activity . У класса активности должен быть метод onCreate() . Ставим курсор мыши внутри класса и выбираем в меню Code | Override Methods (Ctrl+O). В диалоговом окне ищем нужный класс, можно набирать на клавиатуре первые символы для быстрого поиска. В созданном методе нужно вызвать метод setContentView() , который подгрузит на экран подготовленную разметку. У нас получится такой вариант.

    Package ru.alexanderklimov.helloworld; import android.app.Activity; import android.os.Bundle; /** * Created by Alexander Klimov on 01.12.2014. */ public class AboutActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); } }

    Теперь начинается самое главное. Наша задача - перейти на новый экран при щелчку кнопки на первом экране. Переходим обратно к классу MainActivity . Напишем обработчик щелчка кнопки:

    Public void onClick(View view) { Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); }

    Здесь я использовал способ обработки нажатия кнопки, о котором рассказывалось в занятии .

    Для запуска нового экрана необходимо создать экземпляр класса Intent и указать в первом параметре текущий класс, а во втором - класс для перехода, у нас это AboutActivity . После этого вызывается метод startActivity() , который и запускает новый экран.

    Если вы сейчас попытаетесь проверить работу приложения в эмуляторе, то получите сообщение об ошибке. Что мы сделали неправильно? Мы пропустили один важный шаг. Необходимо зарегистрировать новый Activity в манифесте AndroidManifest.xml . Найдите этот файл в своем проекте и дважды щёлкните на нём. Откроется окно редактирования файла. Добавьте новый тег после закрывающего тега для первой активности. Печатайте самостоятельно и активно используйте подсказки. Получится следующее:

    Вот и пригодился строковый ресурс about_title . Запускаем приложение, щёлкаем на кнопке и получаем окно О программе . Таким образом мы научились создавать новое окно и вызывать его по щелчку кнопки. А в нашем распоряжении появилась мегаудобная программа - теперь всегда под рукой будет подсказка, что делает кот, когда идёт налево.

    Ещё раз обращаю внимание, что второй создаваемый класс активности должен наследоваться от класса Activity или ему похожих (ListActivity и др.), иметь XML-файл разметки (если требуется) и быть прописан в манифесте.

    После вызова метода startActivity() запустится новая активность (в данном случае AboutActivity ), она станет видимой и переместится на вершину стека, содержащего работающие компоненты. При вызове метода finish() из новой активности (или при нажатии аппаратной клавиши возврата) она будет закрыта и удалена из стека. Разработчик также может перемещаться к предыдущей (или к любой другой) активности, используя всё тот же метод startActivity() .

    Создаём третий экран - способ для ленивых

    Программисты, как и коты, существа ленивые. Постоянно помнить, что для активности нужно создать разметку и класс, который наследуется от Activity , а затем не забыть прописать класс в манифесте - да ну нафиг.

    В этом случае выберите в меню File | New | Activity | Basic Activity (или другой шаблон). Дальше появится знакомое вам окно создания новой активности. Заполняем необходимые поля.

    Нажимаем на кнопку Finish и активность будет готова. Чтобы убедиться в этом, откройте файл манифеста и проверьте наличие новой записи. Про файлы класса и разметки я уже не говорю, они сами появятся перед вами.

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

    На первых порах я бы посоветовал вам вручную создавать все необходимые компоненты для новой активности, чтобы понимать взаимосвязь между классом, разметкой и манифестом. А когда набьёте руку, то можете использовать мастер создания активности для ускорения работы.

    Передача данных между активностями

    Мы использовали простейший пример для вызова другого экрана активности. Иногда требуется не только вызвать новый экран, но и передать в него данные. Например, имя пользователя. В этом случае нужно задействовать специальную область extraData , который имеется у класса Intent .

    Область extraData - это список пар ключ/значение , который передаётся вместе с намерением. В качестве ключей используются строки, а для значений можно использовать любые примитивные типы данных, массивы примитивов, объекты класса Bundle и др.

    Для передачи данных в другую активность используется метод putExtra() :

    Intent.putExtra("Ключ", "Значение");

    Принимающая активность должна вызвать какой-нибудь подходящий метод: getIntExtra() , getStringExtra() и т.д.:

    Int count = getIntent().getIntExtra("name", 0);

    Переделаем предыдущий пример. У нас уже есть три активности. У первой активности разместим два текстовых поля и кнопку. Внешний вид может быть следующим:

    У второй активности SecondActivity установим элемент TextView , в котором будем выводить текст, полученный от первой активности. Напишем следующий код для метода onCreate() у второй активности.

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "ЖЫвотное"; String gift = "дырку от бублика"; TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , вам передали " + gift); }

    Если сейчас запустить программу и просто вызвать второе окно, как это было описано в первой части статьи, то мы увидим надпись по умолчанию ЖЫвотное, вам передали дырку от бублика . Согласитесь, довольно обидно получать такие сообщения.

    Исправляем ситуацию. Добавляем код у первой активности:

    Public void onClick(View view) { EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Intent intent = new Intent(MainActivity.this, SecondActivity.class); // в ключ username пихаем текст из первого текстового поля intent.putExtra("username", userEditText.getText().toString()); // в ключ gift пихаем текст из второго текстового поля intent.putExtra("gift", giftEditText.getText().toString()); startActivity(intent); }

    Мы поместили в специальный контейнер объекта Intent два ключа со значениями, которые берутся из текстовых полей. Когда пользователь введёт данные в текстовые поля, они попадут в этот контейнер и будут переданы второй активности.

    Вторая активность должна быть готова к тёплому приёму сообщений следующим образом (выделено жирным).

    // Значения по умолчанию String user = "ЖЫвотное"; String gift = "дырку от бублика"; user = getIntent().getExtras().getString("username"); gift = getIntent().getExtras().getString("gift"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , вам передали " + gift);

    Теперь сообщение выглядит не столь обидным, а даже приятным для кое-кого. В сложных примерах желательно добавить проверку при обработке данных. Возможны ситуации, когда вы запустите вторую активность с пустыми данными типа null , что может привести к краху приложения.

    В нашем случае мы знаем, что ждём строковое значение, поэтому код можно переписать так:

    Intent intent = getIntent(); user = intent.getStringExtra("username");

    User = getIntent().getStringExtra("username");

    У программы есть недостаток - не понятно, от кого мы получаем приветы. Любая хорошо воспитанная мартышка не возьмет подарок от анонимного источника. Поэтому в качестве домашнего задания добавьте ещё одно текстовое поле для ввода имени пользователя, который отправляет сообщение.

    Google рекомендует для ключей использовать следующий формат: имя вашего пакета в качестве префикса, а затем сам ключ. В этом случае можно быть уверенным в уникальности ключа при взаимодействии с другими приложениями. Приблизительно так:

    Public final static String USER = "ru.alexanderklimov.myapp.USER";

    Кто подставил кота Ваську - получаем результат обратно

    Не всегда бывает достаточно просто передать данные другой активности. Иногда требуется получить информацию обратно от другой активности при её закрытии. Если раньше мы использовали метод startActivity(Intent intent) , то существует родственный ему метод startActivityForResult(Intent intent, int RequestCode) . Разница между методами заключается в дополнительном параметре RequestCode . По сути это просто целое число, которое вы можете сами придумать. Оно нужно для того, чтобы различать от кого пришёл результат. Допустим у вас есть пять дополнительных экранов и вы присваиваете им значения от 1 до 5, и по этому коду вы сможете определить, чей результат вам нужно обрабатывать. Вы можете использовать значение -1, тогда это будет равносильно вызову метода startActivity() , т.е. никакого результата не получим.

    Если вы используете метод startActivityForResult() , то вам необходимо переопределить в коде метод для приёма результата onActivityResult() и обработать полученный результат. Запутались? Давайте разберём пример.

    Предположим, вы сыщик. Поступила информация, что в ресторане со стола влиятельного человека украли два кусочка колбасы и другие продукты. Подозрение пало на трёх подозреваемых - ворона, сраный пёсик и кот Васька.

    Один из посетителей предоставил серию фотографий со своего понтового айфона:


    Также имеются показания другого свидетеля: А Васька слушает, да ест .

    Создаём новый проект Sherlock с двумя активностями. На первом экране будет кнопка для переключения на второй экран и текстовая метка, в которой будет отображено имя воришки.