Розробка програми для операційної системи "Android"
Операційна система Android: поняття та загальна характеристика, оцінка переваг та недоліків, принципи програмування в ній. Основні типи елементів інтерфейсу, використання адаптерів. Розробка програми, головні файли, система взаємодії. Асинхронні запити.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | украинский |
Дата добавления | 13.05.2014 |
Размер файла | 1,4 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Размещено на http://www.allbest.ru/
Розробка програми для операційної системи «Android»
Вступ
У сучасному світі мобільні електронні пристрої поширюються дуже швидко. Потужності збільшуються в геометричній прогресії. З'являються нові технології, які дозволяють розмістити ще більші потужності на меншій площі. Компанії зі сфери розробки програмного забезпечення пропонують безліч засобів для розв'язання тих чи інших проблем. Проте часто виникає потреба розв'язати нетривіальну задачу або просто створити новий продукт. У такому разі єдине, що залишається - це розробка унікального продукту. Для того, щоб він виявився успішним, він повинен відповідати найвищим стандартам своєї галузі. Тому кожний створений продукт повинен бути потрібний користувачам, добре продуманий, спроектований та реалізований. Якщо потрібно, щоб продукт став поширений серед користувачів, він повинен бути також професійно представлений.
Взагалі розробка будь-якого програмного продукту потребує великих затрат: як часу, так і ресурсів (людських та матеріальних). Тому під час розробки чогось нового, потрібно врахувати усі ризики.
Я вибрав тему «Розробка програми для операційної системи Android», так як зараз це найпоширеніша операційна система для мобільних пристроїв. Це відносно нова система, тому кількість якісних програм для неї досить не велика. Багато сайтів та компанії потребують реалізацію їх продуктів для платформи Android.
Метою даної роботи було створити програму для обміну даними з віддаденим сервером. У программі повинна бути реєстрація користувача та можливість доступу до інформації, яка завантажується з серверу.
1. Операційна система android
1.1 Загальні відомості
Android - операційна система від Google для мобільних пристроїв, таких як планшетні комп'ютери, комунікатори, мобільні телефони, камери та багато інших. Вона створена на базі ядра Linux. Android використовує для роботи віртуальну машину Dalvik.
Dalvik - віртуальна машина Java, створена під час розробки Android для мінімального використання ресурсів. Вона, як і звичайна віртуальна машина Java (JVM), інтерпретує байт-код в машинний код. Проте Dalvik використовує свій байт-код, який відрізняється від звичайного байт-коду Java. Причиною цього є те, що в Android використовується своя реалізація Java, відмінна від Java SE чи Java ME. Вихідний код конвертується у байт-код (файли з розширенням.class, які можуть бути об'єднані в архіви.jar - Java Archive). Після цього утиліта dx конвертує.class файли у файли з розширенням.dex, які використовує віртуальна машина на Android. При конвертації коду в байт-код всі ідентичні ресурси конвертуються тільки один раз для економії пам'яті. Так як саму віртуальну машину можна встановити майже на будь-якому пристрої, Android можна запускати навіть на електронних годинниках.
1.2 Розробка програмного забезпечення для Android
Для розробки програмного забезпечення для Android використовується Android Software Development Kit (Android SDK). Код пишеться на Java. Для тестування програм можна використовувати як пристрій, підключений до комп'ютера, так і емулятор Android, який іде у пакеті з Android SDK. Також можна використовувати Android Native Development Kit (Android NDK). NDK дозволяє писати програмне забезпечення для Android на C, C++ та інших поширених мовах програмування. Проте у цьому разі при розробці не буде доступне відлагодження. Програми для Android можна розповсюджувати через Android Market (Google Play).
ПЗ (програмне забезпечення) для Android зазвичай розробляється у програмі Eclipse. У пакеті Android SDK є версія даної програми зі всіма потрібними для розробки бібліотеками.
Щоб створити порожній проект, достатньо вибрати відповідний пункт меню. Після цього будуть створені базові папки та файли, необхідні для роботи з проектом. Створюються папки src, gen, assets, bin, libs, res. У папці src (source) знаходяться вихідні коди програми у файлах з розширенням.java. У папці gen (generated) знаходяться автоматично згенеровані файли. Вони присвоюють кожному логічному елементу програми унікальний ідентифікатор, зберігають дані про ресурси та інше. У папці asssets знаходяться додаткові ресурси, якщо вони потрібні. У папці bin розташовані файли компільованого проекту. Також там знаходиться.apk файл, який використовується для встановлення програми на пристрої з Android. У папці libs (libraries) розміщені додаткові бібліотеки, якщо такі використовуються. Щоб додати додаткову бібліотеку, достатньо її завантажити та додати, використовуючи відповідний пункт меню. У останній згенерованій папці res (resources) знаходяться ресурси, потрібні для роботи програми. У цій папці розташовані дочірні папки drawable, layout, menu, values та інші. У папці drawable розміщують графічні ресурси, у папці layout - файли-макети програми, у папці menu - макети меню, у папці values - ресурси, такі як стрічки (Strings), кольори (Colors), розміри (Dimens), стилі макетів (Styles) та інші. Якщо для різних розширень потрібно використати різні ресурси, їх розміщують у відповідних папках з суфіксами. У папках з суфіксом - hdpi - ресурси та макети для великих екранів, - ldpi - не великих екранів, - mdpi - середніх за щільністю екранів. Щільність екрана вимірюється у DPI (dots per inch) - крапках на дюйм. Відповідні розміри: ~120 dpi - невеликий екран (-ldpi), ~160 dpi - середній екран (-mdpi), ~240 dpi - великий екран (-hdpi). З появою екранів з великим розширенням (Retina) були введені ще два розміри екранів: ~260 dpi - дуже великий екран (-xhdpi) та >260 dpi - надвеликий екран (-xxhdpi). Також використовують суфікси, які залежать не від щільності, а від розміру екрану:
- small, - medium, - large, - xlarge.
Якщо програма використовує різні макети для різних положень екранів, файли відповідних макетів розміщують у різних папках. За вертикальне положення відповідає суфікс - port, за горизонтальне - - land. При повороті екрану програма буде використовувати ресурси з відповідних директорій. Для локалізації програми при розробці достатньо продублювати папку values з відповідними суфіксами. Суфікс папки values повинен відповідати міжнародному позначенню країни (ресурси для української версії розміщують у папці values-ua, англійської - values-en). Якщо для країни не вказана відповідна папка, програма буде використовувати ресурси з папки values (без суфікса).
Отже, структура програм для Android добре продумана. Можна легко додати локалізації чи адаптувати програму для різних розмірів екранів. Це надзвичайно важливо, так як існують сотні різних пристроїв на Android з різною конфігурацією та різними розмірами екранів.
операційний програма інтерфейс запит
1.3 Створення інтерфейсу користувача
Інтерфейс користувача створюється за допомогою виглядів (View), груп виглядів (ViewGroup), та макетів (Layouts) (рисунок 1.1). Об'єкти вигляду зазвичай є елементами інтерфейсу користувача, такими як кнопки, поля для введення інформації, текстові поля та інші. Групи виглядів - невидимі об'єкти. Вони є контейнерами, які визначають вигляд дочірніх виглядів, наприклад, сіткою (grid) чи вертикальним списком (vertical list). Весь інтерфейс базується на ієрархії виглядів. Самі вигляди зберігаються у файлах формату.xml.
Рисунок 1.1 - Ієрархія виглядів деякого макету
Вигляди та макети можуть бути задані як у файлах з розширенням.xml, так і програмним шляхом. Але розробники Android пропонують визначати елементи інтерфейсу у файлах макетів, оскільки це забезпечує більш гнучке пристосування до різних екранів: достатньо створити альтернативний макет для іншого розширення та розмістити його у відповідній папці, після чого програму можна буде використовувати на іншому екрані. Визначення інтерфейсу програмним шляхом вимагає дублювання частини коду. Також у програмі Eclipse є візуальний редактор, який дозволяє візуально редагувати файли макетів. Якщо їх визначати програмним шляхом, візуальний редактор буде недоступний.
1.4 Основні типи елементів інтерфейсу
Linear Layout - лінійне розташування. У ньому об'єкти інтерфейсу розміщуються горизонтально або вертикально у тій послідовності, у якій вони задані. Розробник сам визначає, як відображати об'єкти у блоці LinearLayout за допомогою атрибуту android:orientation, який може приймати усього два значення: horizontal(горизонтально) або vertical (вертикально).
При використанні LinearLayout доступний ще один важливий атрибут - android:layout_weight. Він дозволяє задати розміри дочірніх елементів пропорційно батьківському.
Рисунок 1.2 - приклад лінійного розташування
Relative Layout - відносне розташування. У ньому об'єкти інтерфейсу розташовуються відносно один одного (справа, зліва, під та інші). Для визначення розміщення використовуються такі атрибути: android: layout_alignParentTop (приймає значення true або false, якщо true, то верхня межа елементу рівняється з верхньою межею батьківського елемента), android:layout_centerVertical (якщо true, то дочірній елемент розміщується вертикально по середині), android:layout_below (аргументом виступає ідентифікатор елементу, під яким буде розташований даний елемент) та багато інших. Всі атрибути такого типу приймають значення boolean (true або false) або ідентифікатор елементу, відносно якого вони мають розташовуватись.
Рисунок 1.3 - відносне розташування
ListView - список, група виглядів (View Group), у якій всі елементи розташовуються у списку з можливістю прокрутки по вертикалі. Для додання елементів у список використовується клас адаптерів (Adapter), який отримує інформацію з деякого джерела (масив, список і т. д.), та конвертує її у елементи списку, які додаються до елементу ListView.
Рисунок 1.4 - приклад списку елементів
Grid View - сітка, група виглядів, яка відображає елементи у вигляді двовимірної сітки, елементи якої можуть прокручуватися вертикально. Для додання елементів до елементу GridView також використовують клас адаптерів.
Рисунок 1.5 - приклад сітки
1.5 Використання адаптерів
Коли інформація для деякого елементу інтерфейсу динамічна, використовують спеціалізований шаблонний клас адаптерів Adapter, та його дочірні класи: Simple Adapter, SimpleCursorAdapter та ArrayAdapter<T>, де T - тип елементів, які будуть використовуватись у списку. Адаптер виступає у ролі буфера між списком та джерелом даних (рисунок 1.6).
ArrayAdapter adapter = new ArrayAdapter<String> (this, android.R.layout.simple_list_item_1, myStringArray);
Рисунок 1.6
Даний адаптер використовує елементи типу String. Макет для кожного елементу має ідентифікатор android.R.layout.simple_list_item_1. Даний макет стандартний та розташований у стандартній бібліотеці, на що вказує префікс android.R.layout.simple_list_item_1. Якщо потрібно використати власний макет, досить його створити та вказати у якості ідентифікатора R.layout.my_own_item_view. Файл R.java у директорії gen містить автоматично згенеровані ідентифікатори для усіх ресурсів та макетів проекту, тому досить звернутися до нього, щоб отримати адресу потрібного нам елемента. Першим аргументом конструктору є елемент типу Context (контекст активного вікна програми), останнім - масив елементів типу String. Також масив стрічок можна передати у адаптер використовуючи метод createFromResource(), у випадку, якщо він (масив) заданий у файлі ресурсів.
Розглянемо ще один варіант адаптеру - SimpleCursorAdapter. При використанні цього адаптеру, ми повинні вказати ідентифікатор для елемента нашого списку, який, на відміну від попереднього прикладу, може містити декілька елементів (минулий містив тільки один елемент, якому присвоювалося значення елементу String з масиву). Після того, як макет елементу створений, при зберіганні файлу йому автоматично буде наданий ідентифікатор, який, буде збережений у файлі R.java.
Припустимо, що у макеті є два текстових поля для імені та телефону абонентів зі списку контактів. Потрібно сформувати масив даних, та відповідний йому масив ідентифікаторів, куди будуть записані дані (рисунок 1.7).
String[] fromColumns = {ContactsContract. Data.DISPLAY_NAME,
ContactsContract. CommonDataKinds. Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};
Рисунок 1.7
Щоб отримати контакти, потрібно використати об'єкт Cursor, що поверне список пар ім'я - телефон, які будуть використані для запису до макету та формування списку. Далі потрібно створити сам адаптер, вибрати список, та передати йому об'єкт адаптера (рисунок 1.7).
SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);
Рисунок 1.7
Spinner - елемент інтерфейсу, який створює меню, що випадає. За замовчуванням обраний перший елемент. Для заповнення цього елементу також використовуються адаптери: ArrayAdapter, CursorAdapter та SpinnerAdapter.
1.6 Основні процеси програм для Android
Під час користування програмою, об'єкти типу Activity («діяльність») змінюють свої стани, зупиняються, продовжуються та завершуються. Під час написання програми, можна вказати, як повинна поводитись діяльність впродовж своєї роботи. Наприклад, якщо ви створюєте онлайн відео програвач, можна переривати з'єднання з Інтернетом та призупиняти мовлення коли користувач згортає програму та переключається на іншу. Це забезпечить економію інтернет-трафіку користувача. Коли користувач знову переключиться на вашу програму, діяльність може відновити підключення та продовжити відео-мовлення з моменту, на якому воно було зупинене. Принцип роботи Activity продемонстровано на рисунку 1.8
Рисунок 1.8
Кожна активність починається з методу void onCreate (Bundle instance). Для того, щоб створити свою активність, потрібно створити клас, який буде розширювати клас Activity, та перевизначити метод onCreate(). У ньому потрібно викликати батьківський конструктор, та передати йому об'єкт типу Bundle, який буде передано в перевизначений метод onCreate() автоматично при запуску діяльності. Далі, якщо дана діяльність використовує макет, потрібно його вказати, передавши методу setContentView() ідентифікатор макету. Тільки після цього з ним можна буде працювати. Простий приклад діяльності показаний на рисунку 1.9.
public class Start extends Activity {
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.activity_start);
}
}
Рисунок 1.9
Важливо, що діяльність перезапускається при повороті екрану. Тому якщо це може вплинути на коректну роботу програми, потрібно обробити такі ситуації. Якщо потрібно, можна заборонити перезапуск діяльності. Для цього досить вказати у файлі маніфесту атрибут для даної діяльності.
1.7 ФАЙЛ МАНІФЕСТУ
Файл маніфесту (AndroidManifest.xml) обов'язково повинен бути у кожній програмі. Він містить важливу інформацію для системи Android про програму, її вимоги, які діяльності вона включає, назву програми, які можливості пристрою вона буде використовувати, як вона буде взаємодіяти з іншими програмами, а також мінімальну та максимельну версію API, потрібну для коректної роботи системи.
2. Розробка програми
2.1 Постановка завдання
операційний програма інтерфейс запит
Моїм завданням було розробити клієнт для роботи з сайтом tokmate.com. Мета цього сайту спростити спілкування між користувачами, що працюють у групах, та спростити їх доступ до спільних ресурсів, таких як спільна пошта. Програма взаємодіє не на пряму з сайтом, а з його базою даних. Сайт використовує базу даних mySql. При компіляції програми, створюється файл з розширенням.apk, який потім може бути відкритий за допомогою архіватору, після чого можна отримати доступ до ресурсів програми. Також можна декомпілювати і сам файл.dex, у якому знаходиться байт-код програми. Через це клієнт не повинен мати доступу до бази даних на пряму. Доступ реалізовано через POST_запити. Це забезпечує достатній рівень безпеки. Скрипти на сервері оброблюють всі запити та відповідно на них відповідають. Також сервер додатково обробляє та перевіряє всю інформацію, яка йому передається, для того, щоб уникнути sql-ін'єкцій (атак, спрямованих на отримання доступу до бази даних і до даних серверу). Обмін інформації відбувається у формати JSON (JavaScript Object Notation) - це текстовий обмін даними, який походить від JavaScript. Проте він використовується у багатьох мовах програмування через свою лаконічність, зручність та швидкість обробки.
2.2 Структура програми
Нижче приведений список файлів та папок з написаним кодом, створених для нього макетів та ресурсів.
Папка з кодом (src):
- Aboout.java
- Main.java
- MainListItem.java
- Register.java
- SimpleAlert.java
- SingleLetter.java
- SpinnerArrayAdapter.java
- SpinnterItem.java
- Start.java
- StaticFunctions.java
Папка з макетам (layout):
- about.xml
- activity_start.xml
- custom_dialog.xml
- list_item.xml
- main.xml
- registration.xml
- single_letter.xml
- spin_row.xml
Папка ресурсів (values):
- colors.xml
- dimens.xml
- strings.xml
- styles.xml
2.3 Файл «about.java»
Цей файл відповідає за діяльність «Про програму». Він лише виводить на екран макет, у якому вказана інформація про автора та програму. Відповідний макет (about.xml) задається, як показано на прикладі нижче (рисунок 2.1):
public class About extends Activity {
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.about);
}
}
Рисунок 2.1
2.4 Файл «start.java»
У файлі Start.java знаходиться діяльність, яка запускається при відкритті програми. Для того, щоб діяльність запускалась першою, для неї потрібно вказати відповідний фільтр (intent-filter) у файлі маніфесту (Рисунок 2.2):
<activity
android:name= «com.tokmate. Start»
android:label= "@string/app_name» >
<intent-filter>
<action android:name= «android.intent.action.MAIN» />
<category android:name= «android.intent.category.LAUNCHER» />
</intent-filter>
</activity>
Рисунок 2.2
У файлі макету діяльності Start розташовані такі елементи: текстове поле, два поля для вводу даних (логіну та паролю), приховане текстове поле, у якому у разі потреби, з'являється попередження про відсутність доступу до мережі, та дві кнопки («Увійти» - у разі наявності аккаунта, «Створити» - у разі потреби створити новий аккаунт). Макет має відносне розташування (RelativeLayout). Розташування елементів задане у файлі стилів. Відповідні стилі підключені до кожного елементу макету.
Також даний файл містить меню. Меню працює за таким принципом: кожному елементу меню задаємо елемент Intent - об'єкт операції, яку потрібно виконати, та перевизначаємо метод, який відповідає за вибір деякого пункту меню. Після вибору пункту потрібно дістати об'єкт Intent з вибраного елементу, та почати нову діяльність, передавши методу запуску діяльності (void startActivity (Intent intent)) цей об'єкт.
Щоб створити меню, потрібно перевизначити метод батьківського класу public boolean onCreateOptionsMenu (Menu menu) вказати макет меню, що знаходиться у папці menu, та присвоїти кожному елементу свою операцію (рисунок 2.3).
@Override
public boolean onCreateOptionsMenu (Menu menu) {
getMenuInflater().inflate (R.menu.start, menu);
menu.findItem (R.id.action_about).setIntent (new Intent (this, About.class));
return true;
}
Рисунок 2.3
Далі перевизначаємо метод, що відповідає за вибір окремого пункту меню. Йому передається елемент меню (об'єкт MenuItem), який потрібно передати батьківському методу вибору елемента меню, а далі розпочати діяльність, використовуючи об'єкт операції Intent, який знаходиться у цьому елементі меню (рисунок 2.4).
@Override
public boolean onOptionsItemSelected (MenuItem item) {
super.onOptionsItemSelected(item);
startActivity (item.getIntent());
return true;
}
Рисунок 2.4
Далі потрібно ініціалізувати кнопки. Під час натискання на кнопку, виникає подія OnClick. Для того, щоб її обробити, кожна кнопка повинна мати об'єкт OnClickListener, метод якого (public void onClick (View v)) викликається у разі виникнення події OnClick. При викликанні цього методу, йому автоматично передається вигляд (View) елементу, на який натиснув користувач, після чого з цим виглядом можна виконати потрібні нам операції (наприклад отримати введений текст, вивести текст в текстове поле чи просто виконати потрібні нам дії) (рисунок 2.5).
View. OnClickListener regOnClickListener = new View. OnClickListener() {
@Override
public void onClick (View v) {
Intent regIntent = new Intent (v.getContext(),
Register.class);
startActivity(regIntent);
}
};
Рисунок 2.5
Для того, щоб оперувати текстовими полями, кнопками та подібними елементами, потрібно створити для них об'єкти відповідних типів, та присвоїти їм потрібні вигляди, які можна отримати методом findViewById (int id). Цьому методу потрібно передати ідентифікатор елементу, після чого він поверне об'єкт View, що відповідає цьому елементу. Для всіх типів елементів повертається однаковий об'єкт View (об'єкт їх батьківського класу). Тому перед присвоєнням, нам необхідно привести елемент до потрібного нам типу. Створення всіх елементів сторінки та присвоєння деяким елементам об'єктів типу OnClickListener відбувається у методі private final void setViewsandButtons().
private final void setViewsandButtons() {
reg = (Button) findViewById (R.id.button_register);
reg.setOnClickListener(regOnClickListener);
login = (Button) findViewById (R.id.button_login);
login.setOnClickListener(loginOnClickListener);
netAlert = (TextView) findViewById (R.id.login_alert_msg);
}
Рисунок 2.6 - вибір об'єктів
Об'єкт netAlert - текстове поле, у якому з'являється попередження, у разі виникнення проблем підключення до мережі. Для того, щоб перевірити стан підключення, потрібно отримати об'єкт ConnectivityManager. Він відповідає за запити щодо стану мережі та інформує програму, коли стан мережі змінюється. У цього об'єкту є метод, який в свою чергу повертає об'єкт NetworkInfo, в якому знаходиться інформація про підключення до мережі. Щоб дізнатись, чи пристрій підключений до мережі, потрібно перевірити, чи об'єкт не пустий, чи пристрій підключений до мережі та чи мережа доступна. За це відповідає метод private final boolean isOnline().
private final boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo!= null && netInfo.isConnectedOrConnecting()
&& netInfo.isAvailable()) {
return true;
}
return false;
}
Рисунок 2.7 - реалізація методу isOnline()
Якщо мережа не доступна, потрібно проінформувати про це користувача. Для цього потрібно вставити повідомлення про помилку у текстове поле для попередження, та зробити його видимим. Щоб дістати повідомлення (чи будь-який інший ресурс), потрібно створити об'єкт потрібного типу, та за допомогою методу getResources() вибрати за ідентифікатором ресурс. Метод private final void connectionCkeck() - метод, який відповідає за перевірку стану мережі та попередження користувача.
private final void connectionCkeck() {
alertMsg = getResources().getString (R.string.no_connection);
if (! isOnline()) {
netAlert.setText(alertMsg);
netAlert.setVisibility (View.VISIBLE);
}
}
Рисунок 2.8 - метод перевірки з'єднання
2.5 Файл «register.java»
Файл Register.java відповідає за реєстрацію нових користувачів. У макеті цієї діяльності є чотири поля для вводу інформації, два списки, що випадають, кнопка для продовження реєстрації та текстове поле з назвою сторінки. Користувачу потрібно ввести ім'я, прізвище, телефон та пароль. Зі списків, що випадають потрібно вибрати навчальний заклад та групу. Якщо користувачем заповнено не всі поля, програма не продовжить роботу та покаже попередження, що потрібно заповнити усі поля, за допомогою діалогу (AlertDialog). Якщо ж усі поля заповнені, данні з них будуть асинхронно (у паралельному потоці) відправлені на сервер на перевірку. Сервер отримує данні, перевіряє їх, після чого додає до бази даних. Якщо дані були занесені до бази успішно, користувачу, на вказаний при реєстрації номер телефону, буде відправлене текстове повідомлення з кодом підтвердження свого аккаунту. Підтвердження номеру телефону потрібно тому, що цей номер буде надалі використовуватися для входу в систему, для відновлення паролю та отримання різних оповіщень. Після того, як програма отримає відповідь від серверу про успішну реєстрацію, з'явиться діалог, у якому користувачу потрібно буде ввести код, отриманий у текстовому повідомленні. Після натискання на кнопку підтвердження номеру, до серверу надсилається ще один асинхронний POST_запит, з кодом. Сервер перевіряє, чи співпадає код з кодом у базі даних. Якщо співпадає, то аккаунт користувача активується. Після активації аккаунту, користувач отримує доступ до головної діяльності (Main Activity).
2.6 Асинхронні запити
Усі http запити в програмах Android повинні відбуватись асинхронно (у окремому потоці, незалежно від основного потоку). Для таких запитів є клас AsyncTask<T, T, T>. Все, що відбувається асинхронно, повинно бути вказано у методі protected T doInBackground (T2… params) де Т2 - перший з трьох параметрів класу. Другий тип потрібний, якщо використовується діалог для відображення прогресу запиту. В даній програмі це не використовується, тому другий параметр буде параметр типу Void. Третій тип параметру повертає метод protected T doInBackground (T2… params), та приймає метод protected void onPostExecute (T result).
2.7 Діалоги
Класи діалогових вікон наслідують класи FragmentDialog. Об'єкт FragmentDialog показує діалогове вікно поверх головного вікна діяльності. Для настроювання конкретного діалогу потрібно перевизначити метод public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState). Якщо потрібно використати свій макет для діалогу, його потрібно вказати у цьому методі. Також у ньому потрібно додати до потрібний елементів об'єкти типу Listener.
@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setTitle (getArguments().getString («title»));
View v = inflater.inflate (R.layout.custom_dialog, container, false);
Button button = (Button) v.findViewById (R.id.dialog_but);
final EditText cod = (EditText) v.findViewById (R.id.dialog_text);
button.setOnClickListener (new OnClickListener() {
public void onClick (View v) {
ckeckCode (cod.getText().toString());
CheckTask task = new CheckTask();
task.execute(requeslUrl);
}
});
return v;
}
Рисунок 2.9
2.8 Обробка відповіді серверу
Відповідь сервера приходить у формати JSON. Для подальшої роботи програми, потрібно обробити відповідь. Для цього потрібно дістати інформацію, яка міститься у масиві JSON. Для цього був написаний спеціальний клас, який отримує JSON масив та повертає об'єкт ArrayList, з яким зручно працювати стандартними методами Java. Структура масиву JSON показана на рисунку 2.10.
Рисунок 2.10
Метод обробки такого масиву знаходиться у файлі StaticFunctions.java. Він зроблений статично, так як використовується часто. Створювати кожний раз не має необхідності та це вимагає надлишкових витрат пам'яті. Метод public static ArrayList<HashMap<String, String>> parse (String str, String jsonArrName, String[] fields). Він приймає три параметри. Перший параметр - сам масив у вигляді стрічки. Його повертає метод doInBackground() після успішного виконання запиту до сервера. Другий параметр - назва масиву. Це константне значення, як вказується у глобальній стрічковій змінній. Третій параметр - масив з назвами ключів, які потрібно дістати з масиву JSON. Метод повертає об'єкт типу ArrayList, кожним елементом якого є об'єкт типу HashMap<String, String> - структура пар ключ - значення, де ключами є елементи з масиву ключів, що були передані методу parse() останнім параметром, а значеннями - відповідні значення, взяті з масиву JSON. Для того, щоб отримати дані з масиву, створюється об'єкт JSONObject, конструктору якому передаємо стрічку масиву. Далі створюється об'єкт JSONArray. Йому присвоюється значення, яке повертає метод об'єкту JSONObject - JSONArray getJSONArray (String jsonArrName), якому передаємо назву массиву, з якого потрібно дістати дані. Об'єкт JSONArray - масив об'єктів JSON, з яких за ключем можна отримати потрібні нам дані.
public static ArrayList<HashMap<String, String>> parse (String str, String jsonArrName, String[] fields)
throws JSONException
{
JSONObject json = new JSONObject(str);
JSONArray jsonArr = json.getJSONArray(jsonArrName);
ArrayList<HashMap<String, String>> dataList = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < jsonArr.length(); i++) {
JSONObject row = jsonArr.getJSONObject(i);
HashMap<String, String> map = new HashMap<String, String>();
for (int j = 0; j < fields.length; j++) {
map.put (fields[j], row.getString (fields[j]));
}
dataList.add(map);
}
return dataList;
}
Рисунок 2.11 - метод обробки массиву JSON
Відповідь від сервера отримаємо у форматі InputStream. Для отримання стрічки, використовується статичний метод public static String isToString (InputStream is). Для спрощення коду методу можна було використати бібліотеку Apache, але метод був реалізований стандартними методами Java для зменшення розміру програми.
public static String isToString (InputStream is) throws IOException {
BufferedReader r = new BufferedReader (new InputStreamReader(is));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine())!= null) {
total.append(line);
}
return total.toString();
}
Рисунок 2.12 - метод повернення стрічки з потоку
2.9 Випадаючі списки
При запуску діяльності Register програма асинхронно отримує від серверу список навчальних закладів та їх ідентифікатори в базі даних. Через об'єкти MainListItem які передаються адаптеру, значення назв та ідентифікаторів передаються відповідним текстовим полям.
public class MainListItem {
private String name;
private String id;
MainListItem (String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return this.name;
}
public String getId() {
return this.id;
}
}
Рисунок 2.13 - приклад елементу адаптеру
Доки навчальний заклад не вибраний, список груп пустий. Це зроблено з метою економії мережного трафіку, так як кожний заклад може містити безліч груп. Тому тільки після вибору навчального закладу програма передає його ідентифікатор серверу та отримує у відповідь список груп. Після цього користувач має змогу вибрати потрібну групу та завершити реєстрацію. Програма передає серверу дані об'єктом ArrayList<HashMap<String, String>> dataList, ключами виступають назви параметрів, які відомі серверу. Сервер, знаючи назви параметрів що передаються у POST_запиті, отримує потрібні йому значення, на основі яких формує відповідь.
@Override
public void onItemSelected (AdapterView<?> parent, View view, int position, long id) {
TextView currId = (TextView) view.findViewById (R.id.spinner_row_id);
dataToSend = new HashMap<String, String>();
dataToSend.put («mode», «getGroup»);
dataToSend.put («institution», currId.getText().toString());
Retreiver task = new Retreiver();
task.execute («groups», requeslUrl);
}
Рисунок 2.14 - метод що викликається при виборі елменту зі списка
2.10 Файл «main.java»
Діяльність Main - це головна діяльність користувача. У ній користувач отримує доступ до потрібної йому інформації. При запуску діяльності, відсилається запит серверу, у відповідь отримуються останні дані з серверу та формується список елементів (ListView) з заголовків листів. У заголовку міститься ідентифікатор листа, його автор та тема. Сам лист не завантажується, так як завантаження кожного листа створить великі витрати трафіку (при завантаженні сотень листів, та розмірі одного близько 10 кб, загальний трафік буде дуже великий). Після вибору потрібного заголовку, метод, який спрацьовує при виникненні події OnClick отримує ідентифікатор вибраного листа, та передає його у діяльність, у якій запускаються окремі листи. Щоб передати дані діяльності, їх потрібно додати до об'єкту операції (Intent), який передається діяльності. Це можна зробити за допомогою методу putExtra(). Даному методу потрібно передати назву елемента (ключ), та його значення. Знаючи ключ, значення можна буде отримати у новій діяльності. Нова діяльність отримує ідентифікатор листа, після чого завантажує його вміст з серверу. Після цього користувач має змогу отримати всю потрібну йому інформацію. Інші діяльності мають аналогічну чи простішу структуру та використовують розглянуті елементи та методи.
Висновок
В результаті роботи була створення програма для Android, яка взаємодіє з віддаленим сервером, та обмінюється з ним інформацією у POST_запитах. Всі запити відбуваються у паралельному потоці. У разі виникнення помилок програма повідомляє про це користувача за допомогою діалогових вікон. Програма протестована на планшетному комп'ютері Ainol Novo 9 Spark (Android 4.3), смартфоні Sony Ericsson Xperia Arc (Android 2.3) та ще одному планшетному комп'ютері Ainol Novo 7 (Android 4.0). На всіх пристроях програма коректно встановлювалась та працювала. За рахунок використаних алгоритмів збереження мережного трафіку, програма швидко отримувала потрібну інформацію від серверу навіть при повільній швидкості підключення.
У програмі може бути покращений інтерфейс користувача - можна додати більше функції у випадаюче меню. Також можна максимально ефективно використовувати екран якщо використовується пристій з великим екраном. Для цього потрібно додати декілька макетів та задати їм відповідну поведінку в залежності від розміру екрану. Також замість стандартних макетів можна використовувати фрагментацію інтерфейсу. Ця технологія дозволяє більш гнучко керувати розміщенням елементів на екрані користувача.
Для збільшення швидкості роботи у програму можна додати кешування заголовків листів, які програма отримує від серверу. Кешування у Android відбувається за допомогою запису потрібної інформації до бази даних SQLite. SQLite - база даних, яка для зберігання інформації використовує текстові файли. При запуску програмі потрібно буде лише зрівняти останній ідентифікатор листа з останнім ідентифікатором листа на сервері, та, якщо вони різні, підвантажити потрібні заголовки. При першому запуску програми будуть завантажені лише 30 останніх заголовків. Якщо користувачу потрібно отримати доступ до старіших листів, йому достатньо прокрутити блок заголовків униз. Під час прокрутки старіші заголовки будуть кешовані та надалі доступні користувачу без потреби взаємодії з мережею. Також можна додати кешування прочитаних листів. Кешування всіх листи може вимагати забагато пам'яті. Тому лише після того, як користувач відкриє окремий лист, програма його завантажить з серверу, збереже та покаже користувачу. Тому якщо у користувача виникне потреба переглянути уже прочитаний лист, це можна буде зробити без підключення до мережі.
У програму також можна додати коментарі до листів. Вони будуть кожний раз завантажуватися з серверу у JSON - масиві, після чого користувач зможе їх прочитати та додати свій. Це дасть змогу користувачам зручно коментувати листи, які їх зацікавили.
Список літератури
1. Брюс Еккель. Філосовія Java. «Питер» - 2006. - 648 с.
2. Офіційна документація операційної системи Android [Електронний ресурс]. Режим доступу до ресурсу: http://developer.android.com
3. Офіційна документація мови програмування Java [Електронний ресурс]. Режим доступу до ресурсу: http://docs.oracle.com/javase/6/docs
4. Вей-Менг Лі. Android Application Development Cookbook. «Питер» -2013. -408 с.
5. Коматинени С., Маклин Д., Хашими С. Розробка програм для Android. «Питер». - 2011. -736 с.
6. Дейтел П., Дейтел Х., Дейтел Э., Моргано М. Android для програмістів. Створюємо програми на Android. «Питер». -2012. -560 с.
Додаток А
Вихідний код програми
«About.java»
package com.tokmate;
import android.app. Activity;
import android.os. Bundle;
public class About extends Activity {
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.about);
}
}
«Main.java»
package com.tokmate;
import java.io. InputStream;
import org.apache.http. HttpResponse;
import org.apache.http.client.methods. HttpPost;
import org.apache.http.impl.client. DefaultHttpClient;
import org.json.JSONException;
import android.app. Activity;
import android.content. Context;
import android.content. Intent;
import android.net. ConnectivityManager;
import android.net. NetworkInfo;
import android.os. AsyncTask;
import android.os. Bundle;
import android.view. View;
import android.widget. AdapterView;
import android.widget. ListAdapter;
import android.widget. ListView;
import android.widget. TextView;
import java.util. ArrayList;
import java.util. HashMap;
import java.util. Map;
import android.widget. SimpleAdapter;
import android.widget. AdapterView. OnItemClickListener;
public class Main extends Activity {
private ListAdapter adapter = null;
private ListView list = null;
private final String lettersURL = «http://tokmate.com/get_data.php»;
private final String jsonArrName = «mail_data»;
Map<String, String> dataToSend = null;
Integer start = 0;
ArrayList<HashMap<String, String>> dataList = null;
String[] fields = {«subject», «from», «uid»};
int[] ids = {R.id.item_subj, R.id.item_from, R.id.item_id};
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.main);
list = (ListView) findViewById (R.id.list_headers);
list.setOnItemClickListener (new OnItemClickListener() {
@Override
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
String sb = ((TextView) view.findViewById (R.id.item_subj)).getText().toString();
String fr = ((TextView) view.findViewById (R.id.item_from)).getText().toString();
String idL = ((TextView) view.findViewById (R.id.item_id)).getText().toString();
Intent in = new Intent (getApplicationContext(), SingleLetter.class);
in.putExtra («subj», sb);
in.putExtra («from», fr);
in.putExtra («id», idL);
startActivity(in);
}
});
if (isOnline())
loadLetters();
}
public void loadLetters() {
dataToSend = new HashMap<String, String>();
dataToSend.put («start», start.toString());
LetterRetreiver task = new LetterRetreiver();
task.execute();
}
private class LetterRetreiver extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground (Void… params) {
String response = «»;
DefaultHttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(lettersURL);
try {
httpPost.setEntity (StaticFunctions.setEntity(dataToSend));
HttpResponse execute = client.execute(httpPost);
InputStream content = execute.getEntity().getContent();
response = StaticFunctions.isToString(content);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
@Override
protected void onPostExecute (String result) {
try {
dataList = StaticFunctions.parse (result, jsonArrName, fields);
} catch (JSONException e) {
e.printStackTrace();
}
setData();
}
}
private void setData() {
adapter = new SimpleAdapter (this, dataList,
R.layout.list_item,
fields, ids);
list.setAdapter(adapter);
}
private final boolean isOnline() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService (Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo!= null && netInfo.isConnectedOrConnecting() && netInfo.isAvailable()) {
return true;
}
return false;
}
}
«MainListItem.java»
package com.tokmate;
public class MainListItem {
private String name;
private String id;
MainListItem (String name, String id) {
this.name = name;
this.id = id;
}
public String getName() {
return this.name;
}
public String getId() {
return this.id;
}
}
«Register.java»
package com.tokmate;
import java.io. InputStream;
import java.io. UnsupportedEncodingException;
import java.math. BigInteger;
import java.net.URLEncoder;
import java.security. MessageDigest;
import java.security. NoSuchAlgorithmException;
import java.util. ArrayList;
import java.util. HashMap;
import java.util. List;
import java.util. Map;
import org.apache.http. HttpResponse;
import org.apache.http.client.methods. HttpPost;
import org.apache.http.impl.client. DefaultHttpClient;
import org.apache.http.params. BasicHttpParams;
import org.apache.http.params. HttpParams;
import org.apache.http.params. HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import android.app. Activity;
import android.app. DialogFragment;
import android.content. Context;
import android.content. Intent;
import android.net. ConnectivityManager;
import android.net. NetworkInfo;
import android.os. AsyncTask;
import android.os. Bundle;
import android.view. LayoutInflater;
import android.view. Menu;
import android.view. View;
import android.view. ViewGroup;
import android.view. View. OnClickListener;
import android.widget. AdapterView;
import android.widget. AdapterView. OnItemSelectedListener;
import android.widget. Button;
import android.widget. EditText;
import android.widget. Spinner;
import android.widget. TextView;
public class Register extends Activity {
private List<SpinnerItem> instAdapter;
private List<SpinnerItem> groupAdapter;
private Button reg;
private Spinner spinInst;
private Spinner spinGroup;
private EditText firstName;
private EditText lastName;
private EditText phone;
private EditText pass;
private View. OnClickListener nextOnclickListener;
private String locale;
private static Map<String, String> dataToSend;
private final static String requeslUrl = «http://tokmate.com/register.php»;
private final String successUrl = «http://tokmate.com/success.php»;
private final String idField = «id»;
private final String instArrName = «institutions»;
private final String groupArrName = «groups»;
ArrayList<HashMap<String, String>> dataList;
private String [] instFields = {«name», «id», «name_ru»};
private String [] groupFields = {«name», «id», «name_ru»};
private String defInstVal;
private String defGroupVal;
private String conError;
private String fillAll;
private String code_info;
private String userExists;
private static String okAct;
private static String errAct;
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.registration);
init();
try {
getInts();
} catch (JSONException e) {
e.printStackTrace();
}
setListeners();
}
private void formList (String[] names, String[] ids, int type) {
if (names.length == ids.length)
switch (type) {
case 1:
instAdapter = new ArrayList<SpinnerItem>();
for (int i = 0; i < names.length; i++) {
instAdapter.add (new SpinnerItem (names[i], ids[i]));
}
break;
case 2:
groupAdapter = new ArrayList<SpinnerItem>();
for (int i = 0; i < names.length; i++) {
groupAdapter.add (new SpinnerItem (names[i], ids[i]));
}
break;
}
}
private void init() {
spinInst = (Spinner) findViewById (R.id.input_facility);
spinGroup = (Spinner) findViewById (R.id.input_group);
firstName = (EditText) findViewById (R.id.input_first_name);
lastName = (EditText) findViewById (R.id.input_last_name);
phone = (EditText) findViewById (R.id.input_phone);
pass = (EditText) findViewById (R.id.input_reg_pass);
reg = (Button) findViewById (R.id.button_register_action);
locale = this.getResources().getConfiguration().locale.getCountry();
dataToSend = null;
defInstVal = getResources().getString (R.string.hint_facility);
defGroupVal = getResources().getString (R.string.hint_group);
conError = getResources().getString (R.string.no_connection);
fillAll = getResources().getString (R.string.fill_all);
code_info = getResources().getString (R.string.code_info);
userExists = getResources().getString (R.string.exists);
okAct = getResources().getString (R.string.okAct);
errAct = getResources().getString (R.string.errAct);
setInstAdapter (new String[] {defInstVal}, new String[] {«0»});
setGroupAdapter (new String[] {defGroupVal}, new String[] {«0»});
}
@Override
public boolean onCreateOptionsMenu (Menu menu) {
getMenuInflater().inflate (R.menu.start, menu);
menu.findItem (R.id.action_about).setIntent (new Intent (this, About.class));
return true;
}
private void setListeners() {
nextOnclickListener = new View. OnClickListener() {
@Override
public void onClick (View v) {
String name = null;
try {
name = URLEncoder.encode (firstName.getText().toString(), «UTF_8»);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String nameL = null;
try {
nameL = URLEncoder.encode (lastName.getText().toString(), «UTF_8»);
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String password = pass.getText().toString();
String telephone = phone.getText().toString();
String instId = ((TextView) spinInst.findViewById (R.id.spinner_row_id)).getText().toString();
String groupId = ((TextView) spinGroup.findViewById (R.id.spinner_row_id)).getText().toString();
if (name.matches(«») || nameL.matches(«») || password.matches(«») || telephone.matches(«»)
|| instId.equals («0») || groupId.equals («0»))
showDialog(fillAll);
else
if (isOnline()) {
MessageDigest m = null;
try {
m = MessageDigest.getInstance («MD5»);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.update (password.getBytes(), 0, password.length());
password = new BigInteger (1, m.digest()).toString(16);
dataToSend = new HashMap<String, String>();
dataToSend.put («mode», «register»);
dataToSend.put («firstName», name);
dataToSend.put («lastName», nameL);
dataToSend.put («pass», password);
dataToSend.put («phone», telephone);
dataToSend.put («institution», instId);
dataToSend.put («group», groupId);
Retreiver task = new Retreiver();
task.execute («register», successUrl);
} else {
showDialog(conError);
}
}
};
reg.setOnClickListener(nextOnclickListener);
spinInst.setOnItemSelectedListener (new OnItemSelectedListener() {
@Override
public void onItemSelected (AdapterView<?> parent, View view, int position, long id) {
TextView currId = (TextView) view.findViewById (R.id.spinner_row_id);
dataToSend = new HashMap<String, String>();
dataToSend.put («mode», «getGroup»);
Подобные документы
Значення операційної системи - програми, яка завантажується при включенні комп'ютера. Компоненти Windows, передача параметрів у мові С++. Системні ресурси та принципи їх роботи. Розробка алгоритму програми емуляції роботи командного процесора ОС.
курсовая работа [37,5 K], добавлен 18.06.2010Методи первинної обробки даних - згладжування та характеристика сплайнів. Загальна характеристика об'єктно-орієнтованої мови Java. Принципи побудови графічного інтерфейсу. Розробка алгоритму програми та інтерфейсу користувача програмного продукту.
дипломная работа [3,3 M], добавлен 10.10.2013Проектування інтерфейсу програми. Вимоги до продукту. Вхідні дані на розробку автоматизованої системи. Вибір середовища програмування. Розробка структури бази даних. Функціональна та логічна структура програми. Розробка структури таблиць бази даних.
курсовая работа [43,1 K], добавлен 30.06.2015Розробка інтерфейсу програми "Автоматизована інформаційна система автошколи". Вибір архітектури, характеристика користувача. Генерація, проектування схеми бази даних, детальне програмування. Розробка структури таблиць. Лістинг програми, результат роботи.
курсовая работа [2,7 M], добавлен 11.09.2015Головні принципи візуального програмування, опис компонентів Delphi, використаних при розробці проекту. Опис програми-додатку "Психологічний тест" та список дій користувача. Алгоритм роботи програми, її форма та ієрархія. Опис графічного інтерфейсу.
курсовая работа [1,2 M], добавлен 08.06.2010Аналіз особливостей мови програмування Java та середовища Android Studio. Розробка програмного забезпечення для якісного та ефективного вивчення іноземних слів. Побудова базових алгоритмів і структури даних. Вибір мови програмування, реалізація програми.
курсовая работа [335,3 K], добавлен 11.01.2015Об’єктно-орієнтоване програмування мовою С++. Основні принципи об’єктно-орієнтованого програмування. Розробка класів з використанням технології візуального програмування. Розробка класу classProgressBar. Базовий клас font. Методи тестування програми.
курсовая работа [211,3 K], добавлен 19.08.2010Основні розрахунки резисторів мікросхеми. Розробка алгоритму рішення задачі методом блок-схем. Характеристика та розробка програми на мові С++ з використанням принципів модульного і структурного програмування. План тестування і налагоджування програми.
курсовая работа [2,9 M], добавлен 05.12.2012Основні переваги програмування на мові Delphi. Використання стандартних операторів при створенні інтерфейсу користувача. Вибір складу технічних і програмних засобів, організація вхідних і вихідних даних. Розробка програми, блок-схеми та тексту програми.
реферат [316,1 K], добавлен 22.01.2013Розробка схеми бази даних бібліотеки для отримання довідки про книги та читачів, програмного забезпечення системи управління БД. Розгляд функціональних підсистем та побудова інтерфейсу. Проведення тестування програми, та виділення переваг та недоліків.
курсовая работа [432,1 K], добавлен 24.01.2011