диплом (1222502), страница 5
Текст из файла (страница 5)
В файле манифеста приложения в Активити Profile, объявим через одиночный тег <action> действие MAIN, а через одиночный тег <category> категорию LAUNCHER.
Действия являются строки, определяющий действие, которое нужно выполнить. Внутри своего приложения можно создавать собственные действия, помимо стандартных определенных классами платформы. Действие MAIN определяет Активити как точку входа приложения.
Категориями являются строки, содержащие информацию о том, какой компонент должен обрабатывать этот интент. Категория LAUNCHER указывает на то, что Активити является стартовой задачей приложения и именно этот Активити будет отображен при запуске приложения. [26, 27]
После объявления всех нужных параметров в манифесте можно приступить к разработке непосредственно Активити, из которых состоит приложение. Однако прежде чем описывать разработку самих Активити, следует описать создание вспомогательных классов, используемых всеми Активити приложения.
4.3 Разработка вспомогательных классов для приложения
В приложении предполагается работа с личными данными пользователя, в частности с паролем. Очевидно, что хранить и тем более передавать по сети пароль в открытом небезопасно. В целях безопасности следует создать класс, который будет использоваться для хеширования пароля. Класс MessageDigest позволяет получать значения хэш-функции фиксированной длины из данных произвольной длины. Для этого следует создать объект класса MessageDigest, далее, с помощью метода getInstance() установить используемый алгоритм хеширования, в данном приложении SHA-1 (по стандарту Java MessageDigest обязательно должен поддерживать алгоритмы MD5, SHA-1 и SHA-256). Хотя поддержка SHA-1 гарантируется, следует предусмотреть возможность выбрасывания исключения NoSuchAlgorithmException. Далее пароль преобразованный в байтовый массив в кодировке ASCII передается методу update объекта MessageDigest. Далее требуется только получить результат хэш-функции и, предварительной преобразовав полученный байтовый массив в строковое представление, вернуть результат преобразования В, листинг В.1 [28, 29].
Следующим классом, используемым большинством Активити является класс, позволяющий проверить корректность заполнения полей форм. Безусловно, такая проверка может быть проведена и на стороне сервера, язык PHP предоставляет для этого простые и удобные в использовании средства, однако, так как мобильные устройства могут зачастую иметь ограничения на использование интернет-трафика, то проверку корректности данных следует выполнять до того, как данные будут переданы.
В некоторых случаях будет достаточно проверить, что поле не пусто, пример кода приведен в листинге ниже.
public static boolean notEmpty(EditText eText){
String txt = eText.getText().toString().trim();
eText.setError(null);
if(txt.length() == 0){
eText.setError(requiredMsg);
return false;
}
return true;
}
В листинге выше метод получает в качестве параметра объект EditText, получает текст, который, предположительно, ввел в него пользователь. Удаляет установленную для объекта ошибку, если таковая имеется, и проверяет был ли введен текст, если длина полученного из EditText текста равна нулю, то метод устанавливает EditText ошибку и возвращает из метода false. Если текст в поле присутствует, метода возвращает true и никакого сообщение об ошибки EditText не присваивается.
На основе метода, приведенного в листинге 7, можно строить другие, которые будут проверять, например, на соответствие текста, введенного в EditText, шаблону, или проверять на равенство содержимое двух полей (листинг приведен ниже).
public static boolean notEqual(EditText check, EditText comparison){
check.setError(null);
if(!check.getText().toString().equals(comparison.getText().toString())) {
check.setError(notEqualMsg);
return false;
}
if(!notEmpty(check)){
check.setError(requiredMsg);
return false;
}
return true;
}
В методе (используется для подтверждения того факта, что пользователь не допустил никаких ошибок при вводе пароля при его смене или первоначальной регистрации и точно знает, какой пароль ввел) из листинга выше внутри первого блока if проверяется равно ли содержимое двух EditText друг другу, при различии введенных строк объекту EditText, переданному в качестве первого параметра, будет установлено сообщение об ошибке. Второй блок if присутствует для того, чтобы в случае, если пользователь по какой-либо причине не заполнил EditText, переданный вторым параметром, и сразу перешел к первому при отсутствии этого блока ошибки бы не было выведено, так как, фактически, условия равенства содержимое объектов EditText отвечает, однако поле не может быть пустым, о чем и сообщит ошибка из второго блока if.
Так как приложение, фактически, представляет собой личный кабинет и использует функцию входа в аккаунт, логично предположить, что для пользователя, использующего приложение на своем личном устройстве, всякий раз при входе в него вводить логин и пароль не очень удобно.
Android предоставляет безопасный и простой способ для хранения личных данных пользователя через SharedPreferences.
SharedPreferences представляет собой интерфейс для обеспечения доступа и внесения изменений в данные предпочтений пользователя. Доступ к сохраненным данным осуществляется через метод getSharedPreferences(String, int). Все изменения в хранимые данные следует вносить исключительно через SharedPreferences.Editor, который гарантирует целостность данных. SharedPreferences организуют данные в виде пар «ключ-значение». Внесение данных в осуществляется через метод объекта Editor, соответствующий типу хранимых данных, первый параметр которого всегда является ключом, а второй – значением (для хранения значения типа Boolean используется метод putBoolean(String key, boolean value) и т.д). Подтверждение внесения изменений осуществляется через метод commit(), удаление данных – через метод clear().
Создадим класс SessionManager, который позволяет хранить данные о сессии пользователя, сохраняя логин и пароль(хэш) пользователя в SharedPreferences, получать данные о сессии из SharedPreferences, а так же вызывать Активити, отвечающую за авторизацию пользователя, если таких данных не обнаружено, и уничтожать данные о сессии в SharedPreferences, если она прервана. Полный код класса SessionManager находится в приложении В, листинг В.2 [28, 30-31].
Основная работа приложения заключается в обмене данных с базой данных через сервер. Как уже неоднократно было упомянуто в тексте в качестве промежуточного формата обмена выбран формат JSON. На стороне сервера за формирования JSON-представления отвечают возможности языка PHP, Java предоставляет схожий функционал, в частности через классы JSONObject и JSONArray.
Сценарии, осуществляющие работу с базой данных, требуют определенный набор данных переданных им методом POST, которые сценарии после используют для совершения операций над базой данных и возвращают приложению JSON-ответ. Для формирования HTTP-запроса для выполнения запрошенной операции над базой данных создадим в приложении класс JSONRequest.
Работу по формированию HTTP-запроса осуществляет метод класса JSONRequest makeHttpRequest(String url, String method, HashMap<String, String> param). В качестве первого параметра метод принимает URL сценария, который требуется выполнить, второй параметр указывает каким методом осуществляется передача данных ресурсу, третий параметр представляет собой HashMap, структура данных, организующая данные в пары «ключ-значение», где каждому ключу соответствует только одно значение, в данном случае, и ключ и данные представлены строковыми значениями, в этом параметре методу makeHttpRequest() передаются все данные необходимые для работы запрошенного в первом параметре сценария.
Сначала требуется преобразовать полученные в третьем параметре метода данные в форму, которая бы позволила использовать их в качестве параметров URL, то есть кодировать все символы, которые не являются буквами латинского алфавита или цифрами, их шестнадцатеричным кодом, которому предшествует символ «%», из которых далее формируется строка параметров URL (имена параметров и их значения разделяются знаком равенства, а сами параметры – амперсандом). Если в качестве второго параметра методу makeHttpRequest() был указан метод GET, то сформированная ранее строка присоединяется к URL через знак вопроса. В силу специфики обрабатываемой приложением информации метод GET ему не подходит, поэтому рассмотрим подробно работу makeHttpRequest() с методом POST (листинг приведен ниже).
urlObject = new URL(url);
connect = (HttpURLConnection)urlObject.openConnection();
connect.setDoOutput(true);
connect.setRequestMethod("POST");
connect.setRequestProperty("Accept-Charset",charset);
connect.setReadTimeout(10000);
connect.setConnectTimeout(15000);
connect.connect();
prmString = parameters.toString();
doStream = new DataOutputStream(connect.getOutputStream());
doStream.writeBytes(prmString);
doStream.flush();
doStream.close();
Для установления соединения с ресурсом через URL используется с использованием протокола HTTP в Android используется класс HttpURLConnection. Для установления соединения создается экземпляр класса URL, названный urlObject, который был инициализирован URL, переданным в метод. Далее из urlObject вызывается метод openConnection(), создающий новое соединение с ресурсом по URL, а результат этого метода передается экземпляру класса HttpURLConnection connect. Так как для работы запрошенного сценария требуется передача данных, требуется разрешить присоединения к URL тела запроса, что и происходит в третьей строке листинга выше. Далее требуется установить все необходимые параметры подключения: в качестве метода запроса устанавливается метод POST, в качестве кодировки используется UTF-8, время ожидания на установление cсоединения – 15 с, время ожидания на чтение данных – 10 с. После выставления параметров соединение устанавливается методом connect().
Далее требуется передать ресурсу необходимые данные. HttpURLConnection отправляет данные через выходной поток, используя метод getOutputStream().
После отправки данных приложение ожидает ответа от ресурса. Полученные от ресурса данные читаются во входной поток с использованием метода getInputStream().
После того как данные успешно считаны, соединение разрывается с помощью метода disconnect(). А makeHttpRequest() создает новый экземпляр JSONObject, сохраняет в него полученные данные и возвращает его, вызвавшему метод классу. Далее из полученного объекта любой класс, используя средства языка Java, сможет получить необходимые ему данные [27, 32-33]. Польный код класса расположен в приложении В, листинг В.3.
На этом разработка вспомогательных классов завершена и можно приступить к разработке функционала активных экранов приложения.
4.4 Разработка Активити приложения
Активити – это компонент, реализующий пользовательский интерфейс, направленный на решение определенной задачи. Для организации пользовательского интерфейса к Активити осуществляется привязка XML-макета с помощью функции setContentView(View), в которой макет выступает как аргумент функции.
Все Активити в системе организуются в стек Активити. Когда запускается новый Активити, он помещается в вершину стека и становится активным, а все ранее запущенные Активити остаются в фоновом режиме в стеке и будут оставаться там, пока Активити в вершине стека активен.
Для каждого Активити можно выделить четыре основных состояния:
– если Активити видим, то есть находится в вершине стека Активити, то его называют активным;
– если Активити потерял фокус, но все еще видим (ситуация возникает, если фокус получил прозрачный Активити или Активити, который не занимает полный экран устройства), то Активити называют приостановленным. Такие Активити остаются привязанными к менеджерам окон и хранят все данные, как если бы были активны, но могут быть уничтожены системой, если оперативная память устройства будет сильно перегружена;
– если Активити полностью перекрыт другим Активити, то его называют остановленным. Такой Активити все еще сохраняет все данные, но окно его полностью скрыто, поэтому остановленные Активити часто уничтожаются системой, если память требуется для выполнения каких-то других функций;
– если Активити остановлено или приостановлено, то система может потребовать от него завершения или же просто уничтожить процесс этого Активити, в таком случае если потребуется снова отобразить Активити пользователю, то его придется полностью перезапустить заново и восстановить состояние до того, как оно было закрыто или уничтожено.
В Android существует семь методов жизненного цикла:
– onCreate(Bundle);
– onStart();
– onRestart();
– onResume();
– onPause();
– onStop();
– onDestroy().
Метод onCreate() вызывается при первом создании Активити. В этом методе выполняются все статические настройки: создаются представления, списки связываются с данными и т.д. За вызовом onCreate() всегда следует onStart().
Метод onStart() вызывается, когда Активити становится видим пользователю, за ним следует вызов onResume(), если Активити перемещается на передний план, или onStop(), если Активити скрывается.
Метод onRestart() вызывается, если приложение было остановлено и его нужно снова перезапустить. За вызовом onRestart() всегда следует вызов onStart().
Метод onResume() вызывается, когда приложение начинает взаимодействовать с пользователем, в этот момент Активити находится на вершине стека Активити. За onResume() всегда вызывается onPause().
Метод onPause() вызывается, когда система возобновляет предыдущий Активити. Метод как правило используется для того, чтобы зафиксировать несохраненные изменения, остановить анимацию или прекратить деятельность, поглощающую ресурсы процессора. За onPause() следует вызов onResume(), если Активити переходит на передний план, и onStop(), если он скрывается от пользователя.
Метод onStop() вызывается, когда Активити более не виден пользователю, потому что был возобновлен другой Активити или данный Активити разрушается. За onStop() всегда следует onRestart(), если Активити подготавливается для взаимодействия с пользователем, или onDestroy(), если Актвити закрывается.