Не важливи чи ви їх любите прямо з коробки чи з хрусткими піджареними на вогні з золотою кіркою та розтопленою серединою, чи в пухкій формі, хто ж не любить зефір? Ми точно його любимо! З запуску розробницької версії M Developer Preview на Google I/O в травні, ми були задоволені вашим вкладом та відгуками. Сьогодні разом з фінальною версією оновлення Developer Preview, ми представляємо офіційний Android 6.0 SDK та відкриваємо Google Play для публікації ваших додатків для нового API level 23 в Android Marshmallow.
вторник, 18 августа 2015 г.
воскресенье, 16 августа 2015 г.
Що робити, коли користувач не надав вам доступ в Android M
Порада професіонала +Wojtek Kaliciński
Новенька версія Android M Developer Preview 2 включає в себе методи для обробки надання дозволів (Permissions): Activity.shouldShowRequestPermissionRationale().
Він інформує ваш додаток, про необхідність надати інформацію про дозвіл, на який іде запит, до того як буде показаний сам діалог запиту дозволу на ту чи іншу функцію.
При першому запуску додатку метод повертає false, таким чином ви можете в той же час запитати на дозвіл необхідного в даний момент. Якщо користувач вже відмовився надавати дозвіл, метод поверне true. У випадку, якщо ви вважаєте за необхідне відобразити пояснення перед викликом діалогу запиту дозволу знову, ви маєте мати на увазі, що слід робити тільки у випадку, якщо дозвіл не самопояснюваний.
Новенька версія Android M Developer Preview 2 включає в себе методи для обробки надання дозволів (Permissions): Activity.shouldShowRequestPermissionRationale().
Він інформує ваш додаток, про необхідність надати інформацію про дозвіл, на який іде запит, до того як буде показаний сам діалог запиту дозволу на ту чи іншу функцію.
При першому запуску додатку метод повертає false, таким чином ви можете в той же час запитати на дозвіл необхідного в даний момент. Якщо користувач вже відмовився надавати дозвіл, метод поверне true. У випадку, якщо ви вважаєте за необхідне відобразити пояснення перед викликом діалогу запиту дозволу знову, ви маєте мати на увазі, що слід робити тільки у випадку, якщо дозвіл не самопояснюваний.
пятница, 14 августа 2015 г.
Погода на Марсі з використанням бібліотеки Volley
Вступ
У цій статті, я покажу вам один з можливих практичних способів використання знань, які ви здобули в попередній статті про бібліотеку Volley. Ми будемо створювати додаток для відображення погоди на Марсі, використовуючии інформацію зібрану ровером Curiosity, яка тепер доступна кожному завдяки NASA через {MAAS} API.Спочатку, ми налаштує проект в Android Studio та спроектуємо користувацький інтерфейс. Далі ми будемо конструювати ядро додатку за допомогою Volley. Зважаючи на те, що кожен додаток, так чи інакше, оперує зображеннями, я покажу, як стягнути випадкове зображення використовуючи Flickr API. Ми будемо завантажувати зображення за допомогою Volley, в основному через її чудову систему кешування. І в кінці, ми додамо декілька прикрашальних функцій, щоб надати нашому додатку ефектності.
четверг, 13 августа 2015 г.
Знайомство з Volley
Volley - це бібліотека для роботи з мережею, розроблена копанією Google та представлена протягом презентації Google I/O в 2013 році. Вона була розроблена через відстутність в Android SDK класу здатного працювати без втручання в UX.
До випуску бібліотеки Volley, єдиними доступними варіантами для розробників були Java class
Відклавши в бік той факт, що ці два класи не звільняють вас від винекнення багів, слід відмітити, як все, що проходить поза простими HTTP транзакціями має бути написано заново. Якщо ж вам потрібно було закешувати зображення чи оптимізувати запити, ви мали розробляти його з нуля.
На щастя, зараз бібліотке Volley, повністю задовольняє такі потреби.
До випуску бібліотеки Volley, єдиними доступними варіантами для розробників були Java class
java.net.HttpURLConnection
та Apache org.apache.http.client,
так розробники могли реалізовувати роботу між клієнтом та сервером для RESTful систем.Відклавши в бік той факт, що ці два класи не звільняють вас від винекнення багів, слід відмітити, як все, що проходить поза простими HTTP транзакціями має бути написано заново. Якщо ж вам потрібно було закешувати зображення чи оптимізувати запити, ви мали розробляти його з нуля.
На щастя, зараз бібліотке Volley, повністю задовольняє такі потреби.
Ярлыки:
Андроід українською,
робота з мережею,
Робота з мережею в Android,
Android,
HttpClient,
HttpUrlConnection,
library,
networking,
RESTful system,
Volley
вторник, 11 августа 2015 г.
TabLayout: з бібліотеки підтримки Android
TabLayout забезпечує можливість створення горизонтальних вкладок.
Де заховати пароль в додатку на Android
Я хотів би пройти крізь декілька напівреалістичних прикладів та пояснити, що приховано за деякими з стратегій, та чому вони можуть бути не такими ефективними як ви могли б сподіватись.
Огляд не охоплює всі можливі варіанти, ми розгляними тільки декілька найбліьш популярних та доступних із способів збереження secret, і, що може піти не так:
Огляд не охоплює всі можливі варіанти, ми розгляними тільки декілька найбліьш популярних та доступних із способів збереження secret, і, що може піти не так:
- Вбудовувати в файл strings.xml
- Приховати у вихідному коді
- Приховати в BuildConfigs
- Використовувати Proguard
- Замасковані/Зашифровані файли String
- Приховати в Native Libraries
понедельник, 3 августа 2015 г.
Централізація бібліотек підтримки в Gradle
Працюючи з мульти-модульними проектами, часто корисно централізувати залежності, особливо це відноситься до бібліотек підтримки.
Правильним шляхом вважається розділяти білд-файли gradle, записуючи таким чином:
Правильним шляхом вважається розділяти білд-файли gradle, записуючи таким чином:
вторник, 21 июля 2015 г.
Стилізація Snackbar
Вітаю, ми повертаємось до наступника діда-Toast нового молодіжного і сучасного Snackbar. Сьогодні ми розглянемо декілька надзвичайно вражаючих можливостей з бібліотеки підтримки (design support library) і собливо Snackbar.
Stay tuned!
Виглядатиме наш додаток так:
Stay tuned!
Стилізація Snackbar
В попередній публікації, ми розібралися, як користуватися Snackbar, а сьогодні ми поглянемо як можна кастомізувати snackbar та відобразити його іншим кольором, стилізованим під наші потреби, щоб це мало значення для користувача, наприклад відображати червоним помилки.Виглядатиме наш додаток так:
Ярлыки:
Андроід українською,
Кастомізація snackbar,
Стилізація Snackbar,
Українською,
Android,
Android design support library,
Snackbar,
Styling Snackbar,
Toast
Место:
Київ, Україна
Робота з мережею в Android: OkHttp, Volley та Gson
Програмуючи під Android є речі, які ви просто не можете уникати: робота з мережею (networking). Що б це не було: завантаження зображення, робота з API чи просто 1 байт з інтернету - все це робота з мережею.
Враховуючи те на скільки робота з мережею є важливою та фундаментальною в розробці, одне з основних питань з якими стикаються Android розробники це вибір правильного рішення для реалізації конкретної задачі.
Причиною того, що нам доводиться використовувати сторонні бібліотеки є неспроможність android фреймворку реалізувати нормально роботу з мережею, ще з давніх часів, коли панували такі динозаври як Froyo та Gingerbread, доводилося писати раз за разом один і той же код. Враховуючи динаміку з якою розвивався Android було логічно спробувати написати щось своє, чи використати готове рішення від сторонніх розробників, які все розвивались і розвивались.
Для вдалого експерименту припустимо, що для обміну даними з сервером ви використовуєте JSON, працюєте в Android Studio з Gradle.
OkHttp це достатньо новий, швидкий та ефективний Http клієнт, який підтримує HTTP/2 та SPDY і виконує за вас безліч однотипної роботи. Прекрасний спосіб зрозуміти наскільки важко працювати з мережею це поглянути на все те що OkHttp для установки звязку, кешуваання і т.д. OkHttp працює як транспортний рівень.
Враховуючи те на скільки робота з мережею є важливою та фундаментальною в розробці, одне з основних питань з якими стикаються Android розробники це вибір правильного рішення для реалізації конкретної задачі.
Причиною того, що нам доводиться використовувати сторонні бібліотеки є неспроможність android фреймворку реалізувати нормально роботу з мережею, ще з давніх часів, коли панували такі динозаври як Froyo та Gingerbread, доводилося писати раз за разом один і той же код. Враховуючи динаміку з якою розвивався Android було логічно спробувати написати щось своє, чи використати готове рішення від сторонніх розробників, які все розвивались і розвивались.
In the old days networking on Android was a nightmare, nowadays the problem is to find out which solution best fits the project necessities.В цій статті ми поговоримо про конкретні рішення на базі OkHttp, Volley та Gson.
Для вдалого експерименту припустимо, що для обміну даними з сервером ви використовуєте JSON, працюєте в Android Studio з Gradle.
OkHttp це достатньо новий, швидкий та ефективний Http клієнт, який підтримує HTTP/2 та SPDY і виконує за вас безліч однотипної роботи. Прекрасний спосіб зрозуміти наскільки важко працювати з мережею це поглянути на все те що OkHttp для установки звязку, кешуваання і т.д. OkHttp працює як транспортний рівень.
OkHttp використовує Okio, бібліотекою, що доповнює java.io and java.nio та допомагає легше отримати доступ, зберігати та користуватися вашою інформацією.
І OkHttp, і Okio розроблені хлопцями з Square.
Volley це бібліотека, що полегшує роботу з побутовими задачами мережі. Бере на себе запити, завантаження, кешування, поточність, синхронізацію та інші штуки. Легко працювати з JSON, зображеннями, кешем, текстом та дозволяє кастомізованим.
Volley була спроектована для RPC стилю роботи з мережею, що популяризує UI. Являється прекрасною альтернативою для простих, коротких задач.
Volley за замовчуванням використовується на транспортному рівні як Apache Http stack на Froyo та HttpURLConnection stack на Gingerbread і вище. Біда в тому, що є деякі проблеми з http stack на різних версіях Android.
Volley дає можливість простіше налаштувати OkHttp як транспортний рівень.
Volley була розроблений компанією Google.
Gsonце бібліотека серіалізації та десеріалізації JSON, що використовує рефлекцію для попляризації вашої Java моделі об'єктів з об'єктів JSON.
Gson була розроблений компанією Google.
понедельник, 20 июля 2015 г.
Кнопка Google Plus в додатках на Android
Перше питання, - "Навіщо?". Все заради популярності вашого додатку. Дана кнопка допоможе підвищи рейтинг в Play Store.
Перш за все, потрібно додати бібліотеку у ваш проект або ж залежність у файл gradle.
EditText плаваючі заголовки: Бібліотека підтримки Android
Новий TextInputLayout дозволяє нам запаковувати EditText для можливості показувавти плаваючі заголовки над полями EditText. Такж ми маємо можливість показувати помилки під полем EditText. Коил форма EditText в фокусі, підказка піднімається над view в ліву частину.
Перш за все нам необхіжно додати бібліотеку або прописати залежність в файлі gradle.
четверг, 16 июля 2015 г.
Android Studio на SSD
Маю ноутбук HP envy 4-1152er з SSD диском, але на жаль він всього-на-всього на 32GB і так вийшло, що Android Studio займає занадто багато місця. Якщо у вас така ж проблема то зараз ви дізнаєтесь як з цим боротися.
Android Studi встановлюємо на диск D.
2. В налаштуваннях за допомогою пошуку знаходимо наш sdk і змінюємо на нову.
3. Зберігаємо налаштування:
Android Studi встановлюємо на диск D.
SDK
1. SDK переносимо на диск D, в зручну для вас директорію, в мене це D:\Program Files\android-sdk.2. В налаштуваннях за допомогою пошуку знаходимо наш sdk і змінюємо на нову.
3. Зберігаємо налаштування:
понедельник, 6 июля 2015 г.
Вступ до RxJava для Android #1
Сам я мав деякі сумніви щодо реактивного програмування і вирішив докладно розібратися в даному полі, а заодно і донести свої знання до громади, може комусь і знадобиться.
RxJava - це бібліотека реактивного програмування, що дозволяє вам представити будь-що у вигляді асинхронного потоку даних, який може бути створений в будь-якому потоці, може бути функціонально трансформований та бути використаний чим завгодно.
Реактивне програмування - парадигма програмування, орієнтована на потоки даних і поширення змін. Це означає, що повинна існувати можливість легко висловлювати статичні і динамічні потоки даних, а також те, що виконувана модель повинна автоматично поширювати зміни крізь потік даних.
Відмовостійкість, орієнтованість на події і масштабованість - чотири принципи нині популярного реактивного програмування. Саме дотримуючись їх створюється backend великих систем з одночасною підтримкою десятків тисяч з'єднань.
Простота, гнучкість і розширюваність коду - принципи, які можна закріпити за реактивним UI.
RxJava - це бібліотека реактивного програмування, що дозволяє вам представити будь-що у вигляді асинхронного потоку даних, який може бути створений в будь-якому потоці, може бути функціонально трансформований та бути використаний чим завгодно.
Реактивне програмування - парадигма програмування, орієнтована на потоки даних і поширення змін. Це означає, що повинна існувати можливість легко висловлювати статичні і динамічні потоки даних, а також те, що виконувана модель повинна автоматично поширювати зміни крізь потік даних.
Відмовостійкість, орієнтованість на події і масштабованість - чотири принципи нині популярного реактивного програмування. Саме дотримуючись їх створюється backend великих систем з одночасною підтримкою десятків тисяч з'єднань.
Простота, гнучкість і розширюваність коду - принципи, які можна закріпити за реактивним UI.
Snackbar - логічний фінал Toast
Сьогодні поговоримо про компонент з Android design support library під назвою “Snackbar”.
Snackbar - логічний фінал Toast
“Providing lightweight, quick feedback about an operation is a perfect opportunity to use a snackbar.”Snackbar компонент доступний в design support library. Використовуючи Snackbar, ми можемо показувати швидкі повідомлення в нижній частині екрану (в осносному). Даний компонент дуже схожий на Toast, але більш гнучкий:
- Він автоматично зникає після таймауту чи після взаємодії з користувачем.
- Опціонально містить в собі дію.
- Можна відмінти FAB свайпом з екрану.
- На відміну від Toast перекриває екран, а не накладається
- Являється частиною UI та є контексозалежним.
- Тільки один snackbar може відображатися в один проміжок часу.
Синтаксис:
Поглянемо на маленький приклад:Snackbar.make(view, message, duration) .setAction(action message, click listener) .show(); |
make()
– Змусити Snackbar відображати повідомлення;setAction()
– Налаштувати дію;show()
– Показати Snackbar;
- Перший параметр методу make() це view, snackbar спробує знайти батьківський view для утримання snackbar. Snackbar прогляне все дерево шарів і закріпиться на верхньому.
- Як вже згадувалось раніше, аргумент тривалості такий же як і в Toast, але тільки LENGTH_SHORT чи LENGTH_LONG, так тут не можна явно вказати тривалість.
Приклад:
Snackbar.make(rootlayout, "Hello SnackBar!" , Snackbar.LENGTH_SHORT) .setAction( "Undo" , new View.OnClickListener() { @Override public void onClick(View v) { // Perform anything for the action selected } }) .show(); |
Тут, кореневий шар (layout) framelayout має FAB, який в свою чергу викликає
Snackbar
.Натисніть на FAB та перевірте результат:
Так, все працює але на жаль не так як мало б взаємодіяти з UX. Насправді снекбар мав би зсунути FAB трох вверх, як зображено нижче, а також сказано в документації:
Having a CoordinatorLayout in your view hierarchy allows Snackbar to enable certain features, such as swipe-to-dismiss and automatically moving of widgets like FloatingActionButton.Ми поговоримо про CoordinatorLayout в наступній статті.
Налаштування Snackbar
Ми можемо використовувати деякі додаткові налаштування в snackbar наприклад:setActionTextColor
та setDuration
:Snackbar.make(rootlayout, "Hello SnackBar!" , Snackbar.LENGTH_SHORT) .setAction( "Undo" , new View.OnClickListener() { @Override public void onClick(View v) { // Perform anything for the action selected } }) .setActionTextColor(R.color.material_blue) .setDuration( 4000 ).show(); |
Джерела:
Підсумкт
Ми трохи поговорили про Snackbar, що функціонує подібно до TOAST але з більш ширшими та гнучкішими налаштуваннями, він може також вміщувати в собі єдину дію та бути відхиленим простим свайпом з екрану або автоматично після закінчення виділеного інтервалу часу, чи навіть після взаємодії з користувачем.Ми безумовно побачимо більше ефектів та поведінки завдяки підключенню CoordinatorLayout, але це буде в наступній статті.
source
Ярлыки:
Андроід,
Андроід українською,
курси,
Українською,
уроки,
Android,
Android design support library,
Android support library,
FAB,
Snackbar,
Toast
среда, 24 июня 2015 г.
Про Gradle: #2 Синтаксис
В першій частині ми говорили про таски та їх стадії життєвого циклу. Але вже після публікації я зрозумів що перед ти як ми поринемо в особливості Gradle важливо зрозуміти з чим саме ми маємо справу - зрозуміти його синтаксис та перестати боятися вигляду файлу
Якщо з Groovy почуваєтесь на ти - не бачу проблем щоб не пропустити декілька абзаців.
Є один дужу важливий нюанс в Groovy, який вам необхідно зрозуміти для повного розуміння скриптів Gradle - Closure.
По суті це блок коду, який виконуються при виклику, а не при стоворенні. Подивимось на простй приклад Closure:
Або тут closure який приймає параметр:
Або якщо closure приймає тільки один параметр, він може виглядати як
Чи коли closure приймає декілька параметрів:
Крім того, тип аргументу опціональний, далі бачимо спрощений приклад без типів:
Ще одна гарна можливість closure може посилатися на змінні з поточного контексту(читай класу). За замовчуванням, поточний контекст - це клас створений в даному closure:
Ще одна можливість в тому що поточний контекст для closure може бути змінений викликом
Як ви могли помітити, в момент коли ми створюємо closure, змінна
В цьому випадку я модифікував теперішній стан контексту для closure прямо перед тим як виконати його, тож
Раніше ми також викоритсовували closure для передачі екземпляру іншого класу. А тепер переглянемо інші методи closure:
Ви тільки подивіться! Знаючи синтаксис Groovy ми розуміємо що саме коїться в даному прикладі!
Прекрасно, але ця інформація сама по собі насправді не допомагає... Тепер треба визначити де саме це все виконується.
А відповіддю буде - Project
Спробуємо знайти метод
Якщо будемо шукати
Якщо продовжимо читати документацію по
ScriptHandler from buildscript. Це означає, що обсяг виконня для closure, який ми передаємо як вхідний параметр, буде змінений на ScriptHandler. В нашому випадку ми передаємо closure який запускає метод
І ми його знаходимо - void dependencies(Closure configureClosure), щ згідно з документацією, конфігурує залежність для скрипту. Тут ми натикаємось на ще один термін: Executes the given closure against the DependencyHandler. Що означає те ж саме що й "lделегується до [чогось]" - цей closure буде виконано в рамках іншого класу (в нашому випадку - DependencyHandler)
Для повноти, давайте подивимось, що трапиться коли ми виконаємо closure
Отже в нашому closure ми зконфігуруємо
Це означає, що якщо ви бачите щось на кшталт
Подивимось на скрипт білду Android
Якщо придивитися до скрипту build - ви побачите що перед запуском методу
Але де нам знайти документацію плагінів Android? ЇЇ можна завантажити з офіційного веб сайту Android Tools.
Ми використали властивість
Тож якщо зараз ми запустимо
На практиці цього краще не робити.
Happy gradling!
Source.
build.gradle
. І за допомогою цієї статті я спробую заповнити дану прогалину.Синтаксис
Скрипти Gradle написані мовою Groovy, тож до того як ми почнемо їх аналізувати, я хотів би зачепити (коротко) деякі ключові концепти Groovy. Синтаксис Groovy деяким чином схожий на Java, тож сподіваюсь у вас не буде великих проблем з його розумінням.Якщо з Groovy почуваєтесь на ти - не бачу проблем щоб не пропустити декілька абзаців.
Є один дужу важливий нюанс в Groovy, який вам необхідно зрозуміти для повного розуміння скриптів Gradle - Closure.
Closures
Closure - це ключовий компонент який нам необхідно зрозуміти перед освоєнням Gradle. Closure це незалежний блок коду, який може приймати аргументи, повертати значення та бути присвоєним змінній. Це такий собі мікс між інтерфейсамиCallable
, Future
, та покажчиком на функцію.По суті це блок коду, який виконуються при виклику, а не при стоворенні. Подивимось на простй приклад Closure:
def myClosure = { println 'Hello world!' }
//виелик closure
myClosure()
#output: Hello world!
Або тут closure який приймає параметр:
def myClosure = {String str -> println str }
//виклик closure
myClosure('Hello world!')
#output: Hello world!
Або якщо closure приймає тільки один параметр, він може виглядати як
it
:def myClosure = {println it }
//виклик closure
myClosure('Hello world!')
#output: Hello world!
Чи коли closure приймає декілька параметрів:
def myClosure = {String str, int num -> println "$str : $num" }
//виклик closure
myClosure('my string', 21)
#output: my string : 21
Крім того, тип аргументу опціональний, далі бачимо спрощений приклад без типів:
def myClosure = {str, num -> println "$str : $num" }
//виклик closure
myClosure('my string', 21)
#output: my string : 21
Ще одна гарна можливість closure може посилатися на змінні з поточного контексту(читай класу). За замовчуванням, поточний контекст - це клас створений в даному closure:
def myVar = 'Hello World!'
def myClosure = {println myVar}
myClosure()
#output: Hello world!
Ще одна можливість в тому що поточний контекст для closure може бути змінений викликом
Closure#setDelegate()
. Ця можливість буде дуже важливою трохи пізніше:def myClosure = {println myVar} //Зсилаємося на myVar з класу MyClass
MyClass m = new MyClass()
myClosure.setDelegate(m)
myClosure()
class MyClass {
def myVar = 'Hello from MyClass!'
}
#output: Hello from MyClass!
Як ви могли помітити, в момент коли ми створюємо closure, змінна
myVar
ще не існує. І тут це повністю нормально - вона має бути присутньою в контексті closure в момент виконання. В цьому випадку я модифікував теперішній стан контексту для closure прямо перед тим як виконати його, тож
myVar
доступна.Передача closure як аргумента
Користь від closures - в можливості передавати closure іншим методам, що допомагає нам відокремити логіку від вииконання.Раніше ми також викоритсовували closure для передачі екземпляру іншого класу. А тепер переглянемо інші методи closure:
- Методи приймає один парамет - closure
myMethod(myClosure)
- Якщо метод приймає один парамет - дужки можна не використовувати
myMethod myClosure
- Внутрішній closure
myMethod {println 'Hello World'}
- Метод приймає два параметри
myMethod(arg1, myClosure)
- Те ж що й 4
myMethod(arg1, { println 'Hello World' })
- Якщо останній параметр closure - то його можна винести
myMethod(arg1) { println 'Hello World' }
Gradle
З синтаксисом трохи ознайомилися, тепер розберемося як же, все-таки, це відноситься до скриптів Gradle? Подивимось на простий приклад скрипту Gradle і постараємось його зрозуміти:buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
allprojects {
repositories {
jcenter()
}
}
Ви тільки подивіться! Знаючи синтаксис Groovy ми розуміємо що саме коїться в даному прикладі!
- Метод
buildscript
що приймає значення closure:
def buildscript(Closure closure)
- Метод
allprojects
приймає closure:
def allprojects(Closure closure)
Прекрасно, але ця інформація сама по собі насправді не допомагає... Тепер треба визначити де саме це все виконується.
А відповіддю буде - Project
Project
Це ключ для розуміння скриптів Gradle:
Всі вирази на вищому рівні в скрипті build заделеговані в екземплярі Project
Це означає, що Project - є початковою точкою.Спробуємо знайти метод
buildscript
. Якщо будемо шукати
buildscript
- ми знайдемо блок скрипту buildscript {}
. Секундочку.. А що ж це таке, чорт забирай??? Згідно з документацією: Блок скриптів це виклик методу який бере closure як параметрДобре! Знайшли! Ось що насправді трапляється, коли ми викликаємо
buildscript { ... }
- ми запускаємо метод buildscript
який приймає Closure.Якщо продовжимо читати документацію по
buildscript
то дізнаємось: Delegates to: ScriptHandler from buildscript. Це означає, що обсяг виконня для closure, який ми передаємо як вхідний параметр, буде змінений на ScriptHandler. В нашому випадку ми передаємо closure який запускає метод
repositories(Closure)
і метод dependencies(Closure)
. З того часу як closure заделегований в ScriptHandler
, спробуємо знайти метод dependencies
в класі ScriptHandler
.І ми його знаходимо - void dependencies(Closure configureClosure), щ згідно з документацією, конфігурує залежність для скрипту. Тут ми натикаємось на ще один термін: Executes the given closure against the DependencyHandler. Що означає те ж саме що й "lделегується до [чогось]" - цей closure буде виконано в рамках іншого класу (в нашому випадку - DependencyHandler)
"delegates to [something]" та "configures [something]" - 2 вирази, що мають одне значення - closure буде виконано в зазначеному класі.Gradle постійно використовує стратегію делегатів, отже важливо тут розуміти термінологію.
Для повноти, давайте подивимось, що трапиться коли ми виконаємо closure
{classpath 'com.android.tools.build:gradle:1.2.3'}
в контексті DependencyHandler
. Згідно з документацією цей клас конфігурує залежності і має виглядати як: <configurationName> <dependencyNotation1>
Отже в нашому closure ми зконфігуруємо
classpath
для використання com.android.tools.build:gradle:1.2.3
як залежності.Блоки скриптів
За замовчуванням, існують попередньо встановлені блоки вProject
, але плагіни Gradle дозволяють додавати нові блоки самостійно!Це означає, що якщо ви бачите щось на кшталт
something { ... }
на верхньому рівні вашого білд скрипту і ви не можете знайти ні блок скриптів, ні метод, який приймає closure в документації - схоже на те, що один з плагінів, які ви використовувал, додав цей блок скриптів.
android
Script block
Подивимось на скрипт білду Android app/build.gradle
за замовчуванням:apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.trickyandroid.testapp"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Як ми можемо бачити, здається, що тут має бути методи android
який приймає Closure як параметр. Але якщо ми спробуємо знайти такий метод в документації Project
то не знайдемо нічого подібного. Причина проста - такого методу просто не має :)Якщо придивитися до скрипту build - ви побачите що перед запуском методу
android
- ми застосовуємо плагін com.android.application
! Це і є відповідь на наше запитання! Android наслідує Project
з блоком скриптів android
(що є просто методом, який приймає Closure та делегує його до lкласу1 AppExtension
).Але де нам знайти документацію плагінів Android? ЇЇ можна завантажити з офіційного веб сайту Android Tools.
Якщо ми відкриємо документацію AppExtension
то знайдемо всі методи та атрибути, які необхідні.Вправа
Спробуємо самотушки щось переналаштувати, бо ми тепер знаємо як це робиться :)В AppExtension
є блок скриптів testOptions
який делегує Closure в клас TestOptions
. Перейдемо до класу TestOptions
ми бачимо дві властивості: reportDir
та resultsDir
. Згідно з документацією, reportDir
несе відповідальність за місце розташування протоколу тестування. Змінимо його.android {
......
testOptions {
reportDir "$rootDir/test_reports"
}
}
Ми використали властивість
rootDir
з класу Project
що вказує на корінь папки проекту.Тож якщо зараз ми запустимо
./gradlew connectedCheck
, звіт про тестування відправиться в папку[rootProject]/test_reports
.На практиці цього краще не робити.
Happy gradling!
Source.
вторник, 23 июня 2015 г.
Про Gradle: #1 Таски
Цією публікацією, я б хотів розпочати серію статей пов'язаних з Gradle, ох, хотілося б мені знати це, коли я почав писати скрипти на Gradle.
Сьогодні ми поговоримо про таски в Gradle, а особливо про їх конфігурацію та виконання частин таску. Зважаючи на те, що багато термінів можуть виявитися невідомими більшості читачів, буде набагато легше приводити приклади. По суті ми постараємось виявити в чому різниця між цими трьома прикладами:
Моя основна ціль написати таск, який виводить на екран текст "Hello, World!" при виконанні.
Коли я починав розбиратися з Gradle, першими з моїх варіантів, була реалізація подібним чином:
Зараз, спробуємо запустити таск!
Здається все працює! Ми бачимо "Hello, World!".
АЛЕ! Воно працює не так, як ми очікували. І ось чому. Давайте-спробуємо викликати
Секундочку! Чому наше "Hello, World!" вивелось на екран? Ми ж просто викликали
Причина чому це трапляється в тому, що таски Gradle матюь 2 стадії життєвого циклу:
Справа в тому, що Gradle має сконфігурувати всі таски зазначені в скрипті перед тим як білд буде запущено. Немає значення, якщо деякі таски будуть запущені - вони все-одно мають бути сконфігуровані.
Знаючи це, як нам знати, яка частина таску виконується під час конфігурації, а яка під час виконання?
Відповіддю є - частина вказана у верхній частині таску - це і є секція конфігурації таску:
Ось чому, коли ми викликали
То як нам сказати Gradle зробити щось коли наш таск буде виконуватись?
Щоб зробити це нам необхідно зазначити дію. Найлегший спосіб зробити це через Task#doLast() метод:
Тепер наш "Hello, World!" текст буде виведено тільки тоді, коли буде явно введена команда
Круто, тепер ми знаємо як зконфігурувати і змусити наш таск виконувати ту роботу, яку ми йому задамо тільки тоді, коли ми його викликаємо. Залишився тільки третій варіант, що використовує символ "
Насправді, це просто коротка версія від
Отже, тепер все знаходиться в блоці виконання, я не можу зконфігурувати мій таск таким же чином отже ми це зробимо завдяки конструкції
Happy gradling!
Source.
Сьогодні ми поговоримо про таски в Gradle, а особливо про їх конфігурацію та виконання частин таску. Зважаючи на те, що багато термінів можуть виявитися невідомими більшості читачів, буде набагато легше приводити приклади. По суті ми постараємось виявити в чому різниця між цими трьома прикладами:
task myTask {
println "Hello, World!"
}
task myTask {
doLast {
println "Hello, World!"
}
}
task myTask << {
println "Hello, World!"
}
Моя основна ціль написати таск, який виводить на екран текст "Hello, World!" при виконанні.
Коли я починав розбиратися з Gradle, першими з моїх варіантів, була реалізація подібним чином:
task myTask {
println "Hello, World!"
}
Зараз, спробуємо запустити таск!
user$ gradle myTask
Hello, World!
:myTask UP-TO-DATE
Здається все працює! Ми бачимо "Hello, World!".
АЛЕ! Воно працює не так, як ми очікували. І ось чому. Давайте-спробуємо викликати
gradle tasks
і побачимо, які інші такски в нас є:user$ gradle tasks
Hello, World!
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
..........
Секундочку! Чому наше "Hello, World!" вивелось на екран? Ми ж просто викликали
tasks
, Чому ж запустився наш таск!Причина чому це трапляється в тому, що таски Gradle матюь 2 стадії життєвого циклу:
- Стадія конфігурації
- Стадія виконання
Справа в тому, що Gradle має сконфігурувати всі таски зазначені в скрипті перед тим як білд буде запущено. Немає значення, якщо деякі таски будуть запущені - вони все-одно мають бути сконфігуровані.
Знаючи це, як нам знати, яка частина таску виконується під час конфігурації, а яка під час виконання?
Відповіддю є - частина вказана у верхній частині таску - це і є секція конфігурації таску:
task myTask {
def name = "Pavel" //<-- this is evaluated during configuration
println "Hello, World!"////<-- this is also evaluated during configuration
}
Ось чому, коли ми викликали
gradle tasks
то було видно текст "Hello,
World!" - це була виконана наша частина конфігурції. Але це не те, що нам було потрібно - нам потрібно що текст "Hello, World!" був надрукований, коли ми явно викликаємо таск.То як нам сказати Gradle зробити щось коли наш таск буде виконуватись?
Щоб зробити це нам необхідно зазначити дію. Найлегший спосіб зробити це через Task#doLast() метод:
task myTask {
def text = 'Hello, World!' //configure my task
doLast {
println text //this is executed when my task is called
}
}
Тепер наш "Hello, World!" текст буде виведено тільки тоді, коли буде явно введена команда
gradle myTask
Круто, тепер ми знаємо як зконфігурувати і змусити наш таск виконувати ту роботу, яку ми йому задамо тільки тоді, коли ми його викликаємо. Залишився тільки третій варіант, що використовує символ "
<<
"?:task myTask2 << {
println "Hello, World!"
}
Насправді, це просто коротка версія від
doLast
. Буде виконано теж саме, коли ми напишемо:task myTask {
doLast {
println 'Hello, World!' //this is executed when my task is called
}
}
Отже, тепер все знаходиться в блоці виконання, я не можу зконфігурувати мій таск таким же чином отже ми це зробимо завдяки конструкції
doLast
(це досі можливо, але трохи по-іншому). Стає зрозуміло, що цей спосіб буде незамінними при невеликих таксках без блоку конфігурації, але якщо ви маєте щось більше ніж "Hello,
World!" - можливо вам буде в нагоді doLast
.Happy gradling!
Source.
понедельник, 22 июня 2015 г.
Залізна людина тепер реактивна: RxJava
Дана стаття присвячена перевагам, що можуть бути надані нашим проектам деякими функціональними штрихами.
Фреймворки типу RxJava та ReactiveX можуть легко вправитися з середовищами, що працюють у фоні та в UI потоці.
Ця стаття також фокусується на тому, як оператори можуть мінімізувати час на загальну розробку завдань, реактивні розширення пропонують широкий спектр операторів, щоб зробити ваше життя простіше.
Як завжди, код на Github, не соромтеся коментувати, відкрити питання або скаржитися!.
Retrolambda це бекпорт, що з'явився для вирішення даної проблеми, переклад байткодів Java 8 на попередні версії Java дає можливість користуватися лямда-виразами та іншими можливостями нової платформи.
Retrolamda може працювати з Gradle та Maven, я обрав Gradle так як він йде в комплекті з Android Studio, для використання вам досить додати в корінь файлу build.gradle плагін Retrolambda та застосувати у вашому модулі build.gradle, встановити рівень мови на 1.8 в Android Studio і все готово.
build.gradle (root)
{ваш модуль}/build.gradle
Retrolambda дозволяє вам писати менше шаблонного коду, а також робить код зрозумілішим. У цьому прикладі написаному Den Lew ви можете побачити різницю.
Без використання RetroLambda
З використанням RetroLambda
А тепер на прикладі додатку Месники:
ReactiveX також має API для асинхронного програмування, з цим фреймворком насправді дуже легко реалізовувати завдання асинхронно.
Таким чином, ми маємо спостережуваний API, а не блокуючий API.
Клас Observable створює об'єкт чи серію об'єктів ці об'єкти отримуються методом Observer, що наледить класу "Observable".
Необхідно щоб Observer був прив'язаний до Observable, в іншому випадку Observer не видасть нічого. Коли
Коли
Обожнюю цю картинку:)
Коли usecase запущено - повертається об'єкт типу
Коли ми запускаємо
Ви маєте бути на сторожі в залежності від того де використовується, Retrofit виконує запити в потоці де ваш
Source.
Фреймворки типу RxJava та ReactiveX можуть легко вправитися з середовищами, що працюють у фоні та в UI потоці.
Ця стаття також фокусується на тому, як оператори можуть мінімізувати час на загальну розробку завдань, реактивні розширення пропонують широкий спектр операторів, щоб зробити ваше життя простіше.
Як завжди, код на Github, не соромтеся коментувати, відкрити питання або скаржитися!.
RetroLambda
Інколи, у великих додатках, розроблених з Java, або великих фреймворках як android дуже важко, чи навіть неможливо (android) використовувати можливості Java 8 такі як лямда-вирази.Retrolambda це бекпорт, що з'явився для вирішення даної проблеми, переклад байткодів Java 8 на попередні версії Java дає можливість користуватися лямда-виразами та іншими можливостями нової платформи.
Retrolamda може працювати з Gradle та Maven, я обрав Gradle так як він йде в комплекті з Android Studio, для використання вам досить додати в корінь файлу build.gradle плагін Retrolambda та застосувати у вашому модулі build.gradle, встановити рівень мови на 1.8 в Android Studio і все готово.
build.gradle (root)
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
apply plugin: 'me.tatarka.retrolambda'
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
}
Retrolambda дозволяє вам писати менше шаблонного коду, а також робить код зрозумілішим. У цьому прикладі написаному Den Lew ви можете побачити різницю.
Без використання RetroLambda
Observable.just("Hello, world!")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
Observable.just("Hello, world!") .subscribe(
s -> System.out.println(s)
);
А тепер на прикладі додатку Месники:
mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe(
character -> onAvengerReceived(character),
error -> manageError(error)
);
mComicsSubscription = mGetCharacterComicsUsecase
.execute().subscribe(
comics -> Observable.from(comics).subscribe(
comic -> onComicReceived(comic)),
error -> manageError(throwable)
);
ReactiveX
ReactiveX - це колекція з проектів з відкритим вихідним кодом серед їх основних принципів є шаблон проектування Спостерігач, шаблон Ітератор та функціональне програмування.ReactiveX також має API для асинхронного програмування, з цим фреймворком насправді дуже легко реалізовувати завдання асинхронно.
ReactiveX як асинхронний клієнт
Гарна штука, що користуєчись ReativeX можна створювати повністю асинхронний API чи клієнт, а потім вже при реалізації вирішувати, який код буде працювати асинхронно чи в окремому потоці (Thread) чи синхронно.Таким чином, ми маємо спостережуваний API, а не блокуючий API.
public interface Usecase<T> {
Observable<T> execute();
}
public interface Repository {
Observable<Character> getCharacter (final int characterId);
Observable<List<Comic>> getCharacterComics (final int characterId);
}
Чим же насправді є RxJava
Необхідно щоб Observer був прив'язаний до Observable, в іншому випадку Observer не видасть нічого. Коли
Observer
пррив'язаний, об'єкт типу Subscription
створюється, він використовується для відв'язування Observable
, це крисно при роботі з Activity
та Fragment
в методах onStop
чи onPause
, наприклад.mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe( ... );
@Override
public void onStop() {
if (!mCharacterSubscription.isUnsubscribed())
mCharacterSubscription.unsubscribe();
if (!mComicsSubscription.isUnsubscribed())
mComicsSubscription.unsubscribe();
}
Observer
прив'язаний до Observable
він має отримати три методи.onNext (T)
метод для отримання об'єктів позначиених 'Observable' помилковимиonError (Exception)
, метод який викликається при виявленні помилокonCompleted()
, метод який викликаєть колиObservable
завершує створення об'єктів.
Обожнюю цю картинку:)
Компоненти зв'язку
Тепер подивимось на те як можна використовуватиGetCharacterInformationUsecase
. Варіаннти реалізації інтерфейсу Usecase <T>
:public interface Usecase<T> {
Observable<T> execute();
}
Observable
,
корисна можливість бути зв'язаним з observable та операторами з меншими зусиллями, ми ще побачимо велику силу операторів в подальшому.Коли ми запускаємо
GetCharacterInformationUsecase
ми говоримо нашому репозиторію запросити у відведеного джерела даних:@Override
public Observable<Character> execute() {
return mRepository.getCharacter(mCharacterId);
// .awesomeRxStuff();
}
AvengerDetailPresenter
буде нашим Observer
в даному випадку буде тим хто піписується до подій надісланих Observable
, це робиться за допомогою методу subscribe
, що зв'язує Observer
з Observable
.onNext
та onError
реалізовані для управління результатом операції. Метод onCompleted
не реаалізований в даному випадку так як не є необхідним. mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe(
character -> onAvengerReceived(character),
error -> manageError(error));
Retrofit & RxJava
Retrofit зі Square, RxJava підтримує методи типуrx. Observable
так що запити можна робити за допомогою Observers
редагувати та трансформувати.Ви маєте бути на сторожі в залежності від того де використовується, Retrofit виконує запити в потоці де ваш
Observable
виходить, отже якщо ви будете його викликати в UI потоці (activity чи Fragment) отримаєте помилку.Посилання
- ReactiveX
- Reactive Programming in the Netflix API with RxJava
- Use Lambdas on Java 7 and older - Esko Luontola
- Grokking RxJava, Part1: The basics - Dan Lew
Source.
воскресенье, 21 июня 2015 г.
Можливо ви не знали: onResumeFragments
Вся суть в одному реченні: якщо ви використовуєте підкласи
Якщо ви відчуваєте, що бачите деякі прогалини чи неточності в своїх знаннях, запрошую до читання. В іншому випадку сподіваюсь здивувати вас наступного разу.
Все ще тут? Добре.
FragmentActivity
(такі як AppCompatActivity
) і думаєте над якимись транзакціями в onResume
, краще зробіть це в onResumeFragments
.Якщо ви відчуваєте, що бачите деякі прогалини чи неточності в своїх знаннях, запрошую до читання. В іншому випадку сподіваюсь здивувати вас наступного разу.
Все ще тут? Добре.
В чому різниця між
onResume
та onResumeFragments
? З документації для FragmentActivity.onResume
:Dispatch onResume() to fragments. Note that for better inter-operation with older versions of the platform, at the point of this call the fragments attached to the activity are not resumed. This means that in some cases the previous state may still be saved, not allowing fragment transactions that modify the state. To correctly interact with fragments in their proper state, you should instead override onResumeFragments().
Простіше кажучи, ви не можете бути впевнен, що існуючий фрагмент актівіті буде відновлений в актівіті onResume(), і краще уникнути транзакцій фрагментів до onResumeFragments, поки їх стан не поновлено і вони повністю не відновлені.
Притримуючись сказаного ви можете уникнути
IllegalStateException, який
Android викидає кожного разу як ви намагаєтесь виконати транзакцію з фрагментом після того/, як його стан був збережений (через onSaveInstanceState
). Якщо актіві фрагменту знищено і перестворено, ви втратите всі вподальному збережені дані. Для більш повного та детального пояснення, пропоную прочитати статтю, Alex Lockwood's "Fragment Transactions & Activity State Loss".
Правду кажучи, я дізнався про
onResumeFragments
задовго після того як дізнався про фрагменти та транзакції між ними. Більшість матеріалів по життєвому циклу актівіті опускає його оскільки він існує тільки в FragmentActivity в біблітоці підтримки (FragmentActivity), а не в класі SDK актівіті. Однак, onResumeFragments
краще, все ж таки, знати.
Після всйого сказаного, хочу додати, що все ж кращу уникати транзакцій між фрагментамив життєвому циклі актівіті настільки наскільки це можливо і особливо в
onResume/onResumeFragments
це скоріше гарна підказка для вашої бізнес логіки та UI/UX аніж правило.
Зустрінимось.
Подписаться на:
Сообщения (Atom)