Similar presentations:
Технология разработки мобильных приложений. Android: тогда и сейчас
1.
ТЕХНОЛОГИЯ РАЗРАБОТКИМОБИЛЬНЫХ ПРИЛОЖЕНИЙ
2.
ANDROID: ТОГДА И СЕЙЧАС2008 год
T-Mobile G1
2017 год
Google Pixel 2 XL
3.
РАЗРАБОТКА ПОД ANDROIDJava
2008 – Java 6
2013 – Java 7
2017 – Java 8 (некоторый функционал доступен только на
API 24)
Kotlin
до 2017 – поддержка с помощью плагинов
2017 – поддержка в Android Studio 3.0 из коробки
4.
ПРОЦЕНТ УСТРОЙСТВ С ANDROID РАЗЛИЧНЫХ ВЕРСИЙVersion
Codename
API
Distribution
2.3.3 –
2.3.7
Ginderbread
10
0.5%
4.0.3 –
4.0.4
Ice Cream
Sandwich
15
0.5%
4.1x
Jelly Bean
16
2.2%
4.2x
17
3.1%
4.3
18
0.9%
4.4
KitKat
19
13.8%
5.0
Lollipop
21
6.4%
22
20.8%
5.1
6.0
Marshmallow
23
30.9%
7.0
Nougat
24
17.6%
25
3.0%
7.1
5.
ПРОЦЕНТ УСТРОЙСТВ С ANDROID РАЗЛИЧНЫХ ВЕРСИЙПроцент устройств
Ginderbread
Ice Cream
Sandwitch
Jelly Bean
KitKat
Lollipop
Marshmallow
Nougat
Oreo
6.
ПОДДЕРЖКА СТАРЫХ ВЕРСИЙ ANDROIDБиблиотеки поддержки
com.android.support:appcompat-v7:27.0.1
com.android.support:design:27.0.1
com.android.support:support-v13:27.0.1
и другие
Библиотеки добавляются в файл gradle уровня app
7.
ИСТОЧНИКИ ИНФОРМАЦИИОфициальная документация
Гайды, обучение, дизайн, классы, best practices, обзор новых
инструментов
https://developer.android.com/develop/index.html
Stack Overflow
99,9% вопросов, которые у вас возникнут, уже были заданы и
отвечены тут
https://stackoverflow.com/questions/tagged/android
Блок разработчиков Android
Новые инструменты, best practices и немного историй из жизни
8.
ОСНОВНЫЕ КОМПОНЕНТЫ ANDROID ПРИЛОЖЕНИЯApplication
Activity
Service
AndroidManifes
t.xml
BroadcastReceiver
ContentProvider
9.
APPLICATION10.
ACTIVITYpublic class MainActivity extends
AppCompatActivity {
@Override
protected void onCreate(Bundle
savedInstanceState) {
<activity android:name=“.MainActivity”>
<intent-filter>
<action
android:name=“android.intent.action.MAI
N”/>
super.onCreate(savedInstanceState); <category
android:name=“android.intent.category.L
setContentView(R.layout.activity_main); AUNCHER”/>
}
}
</intent-filter>
</activity>
11.
SERVICEpublic class CustomService extends
IntentService {
public CustomService() {
super(“CustomService”);
}
@Override
protected void onHandleIntent(Intent
intent) {
//TODO: load file
}
}
<service
android:name=“.CustomService”
android:exported=“false”/>
12.
BROADCASTRECEIVERpublic class CustomReceiver extends BroadcastReceiver {
@Override
public void onReceiver(Context context, Intent intent) {
//TODO: start service
}
}
13.
CONTEXT. ДОСТУП К РЕСУРСАМString appName =
context.getString(R.string.app_name);
int colorAccent =
ContextCompat.getColor(context, R.color.colorAccent);
try {
context.getAssets().open(“filename.txt”);
} catch (IOException e) {
e.printStackTrace();
}
14.
CONTEXT. ДОСТУП К СИСТЕМНЫМ ВОЗМОЖНОСТЯМУСТРОЙСТВА
AlarmManager am = (AlarmManager)
context.getSystemService(Context.
ALARM_SERVICE);
FingerprintManager fm = (FingerprintManager)
context.getSystemService(Context.
FINGERPRINT_SERVICE);
15.
CONTEXT. ДИНАМИЧЕСКОЕ ИЗМЕНЕНИЕ ИНТЕРФЕЙСАTextView textView = new TextView(context);
textView.setText(“Тонких Артём Петрович”);
16.
CONTEXT. СОЗДАНИЕ ФАЙЛОВSharedPreferences preferences =
context.getSharedPreferences(“myAppPrefs”,
Context.MODE_PRIVATE);
preferences.edit()
.putString(“KING_OF_THE_NORTH”,
“Тонких Артём Петрович”)
.apply();
String kingOfTheNorth =
preferences.getString(“KING_OF_THE_NORTH”,
“open vacancy”);
17.
ИСТОЧНИКИ CONTEXT И ИХ РАЗЛИЧИЕgetApplicationContext() != getContext();
ApiManager mApiManager =
ApiManager.getLocalManager
(getApplicationContext());
WeakReference<Context>weakContext =
new WeakReference<Context>(getContext());
context = weakContext.get();
if (context != null) {
// do something
}
18.
ACTIVITYГлавный компонент приложения, с помощью которой
пользователь взаимодействует с приложением
посредством UI – пользовательского интерфейса.
19.
ЖИЗНЕННЫЙ ЦИКЛ ACTIVITY (УПРОЩЕННАЯ ВЕРСИЯ)Resumed
(visible)
onResume()
onPause()
onResume()
Paused
(partly visiable)
Started
(visible)
onStart()
onStop()
onStart()
Created
onCreate()
onRestart()
Stopped
(hidden)
onDestroy()
Destroyed
20.
ПОРЯДОК ВЫЗОВА МЕТОДОВActivityЖИЗНЕННОГО
2
ИКЛА ПРИ ЗАПУСКЕ ДОЧЕРНЕЙ ACTIVITY
Activity 1
onCreate()
onStart()
onResume()
*Запуск второй активити*
onPause()
onStop()
onRestart()
onCreate()
onStart()
onResume()
*возврат назад*
onPause()
21.
УНИЧТОЖЕНИЕ АКТИВИТИСистема считает за нормальное поведение:
нажатие кнопки «назад»
вызов метода finish()
Система сохраняет стейт при следующих случаях:
изменении конфигурации (поворот экрана, смена языка,
доступность клавиатуры)
уничтожение фоновой Activity при нехватке памяти для
рабочей Activity
22.
VIEW И VIEWGROUP<ViewGroup>
//Иерархическая структура
разметки, XML правила
<View/>
<View/>
<ViewGroup>
<View/>
<View/>
</ViewGroup>
</ViewGroup>
23.
ЧАСТО ИСПОЛЬЗУЕМЫЕ VIEWЭлементы интерфейса
из Android SDK.
Большая их часть настраивается
и редактируется
24.
ADAPTERVIEWСписок однородных
элементов.
Данные поставляет одна
из реализации Adapter
25.
LinearLayoutРасполагает свои элементы друг за другом вертикально
или горизонтально.
Направление определяется атрибутом orientation.
Распределяет свободное пространство по длине или
ширине через веса:
•Атрибут layout_weight – на дочерних View-элементах
•Атрибут weightSum – на LinearLayout-контейнере.
В качестве значения эти атрибуты принимают любые
числа.
Если значение weightSum не равно сумме layout_weight
дочерних элементов, то на разметке останется
неиспользованное пространство.
26.
LinearLayoutКорневой LinearLayout
(фиолетовый):
android:orientation=“vertical”
Вложенный LinearLayout
(малиновый):
android:orientation=“horizontal”
android:weightSum=“4”
Кнопки горизонтального LinearLayout:
android:layout_weight=“1” / ”2”
android:layout_width=“0dp”
27.
RelativeLayoutView элементы располагаются относительно контейнера и
друг друга.
Больше гибкости без необходимости верстать вложенные
контейнеры.
Большой выбор различных атрибутов для выстраивания
интерфейса.
28.
RelativeLayout•layout_alignParentLeft(Right, Top, Bottom, Start, End) –
выравнивает элемент по указанному краю родителя
•layout_alignLeft(Right, Top, Bottom, Start, End) –
выравнивает сторону элемента по соответствующей
стороне указанного элемента
•layout_below(above) – устанавливает элемент под/над
указанным элементом
•layout_toLeftOf(Right, Start, End) - устанавливает элемент
с указанной стороны указанного элемента
•layout_centerHorizontal(Vertical) – устанавливает
элемент по центру контейнера
•и другие
29.
RelativeLayoutButton 1 – выровнена по верхнему левому
краю RelativeLayout.
Button 2 – находится под и справа от
Button 1.
Button 3 – выровнена по центру
RelativeLayout.
Button 4- находится справа от Button 3 и
нижняя граница соответствует нижней
границе Button 3.
Button 5 – левый край соответствует
левому краю Button 3, правый край
соответствует правому краю Button 4,
30.
FrameLayoutИспользуется как контейнер для программно добавляемых
View.
Используется, когда нужно установить одну View над
другой. Порядок отрисовки View соответствует их порядку
в файле разметки.
31.
ConstraintLayoutНовый ViewGroup.
Идейный наследник RelativeLayout, но превосходит его по
возможностям.
Для разметки используются констрейнты – правила.
Следует использовать только тогда, когда необходимо.
Начать использовать легко – добиться мастерства гораздо
сложнее.
32.
GridLayout и TableLayoutИспользуются для формирования разметки в виде
таблицы. Не очень удобны.
TableLayout – каждый элемент находится в отельной
строке.
Для верстки элементов в строке используется TableRow.
GridLayout – каждый элемент имеет атрибуты layout_row и
layout_column для определения местоположения в
таблице.
33.
ImageViewImageView – основной элемент для показа изображений.
В XML
android:src=“@drawable/my_image”
В Java
image.setImageResource(R.drawable.my_image);
34.
ScaleTypeДля ImageView можно задать правило для
масштабирования в разметке через атрибут scaleType или
программно через метод setScaleType()
Варианты значений:
35.
EditTextСтандартное поле ввода
Полезные атрибуты:
•hint – подсказка
•maxLength –
ограничение по количеству символов
•inputType – выбор вводимых
данных (текст, число, номер, почта,
пароль и др.)
•imeOptions – кастомизация кнопки
ввода (done, send, next,
search и другие)
36.
Что такое Gradle?Gradle – система автоматической сборки, построенная на
принципах Apache Ant и Apache Maven, но
предоставляющая DSL на языке Groovy вместо
традиционной XML-образной формы представления
конфигурации проекта.
37.
Dependenciesdependencies {
})
implementation fileTree(dir: ‘libs’,
include: [‘*.jar’])
androidTestImplementation(
implementation
‘com.android.support:appcompatv7:26.1.0’
implementation ‘com.android.
‘com.android.support.
support.constraint:
test.espresso:espresso-core:2.2.2’, {
constraint-layout:1.0.2’
exclude group:
‘com.android.support’,
annotations’
module: ‘support-
testImplementation ‘org.jetbrains:
annotations:15.0’
}
38.
Product FlavorsflavorDimensions ‘buildType’
yourapi.com/free/”’
productFlavors {
}
free {
pro {
buildConfigField ‘String’,
‘YOUR_PARAM_NAME’,
‘”YOUR STRING VALUE”’
versionName “0.0.1-pro”
buildConfigField ‘String’,
API_BASE_URL’,
yourapi.com/pro/”’
versionName “0.0.1-free”
buildConfigField ‘String’,
‘API_BASE_URL’,
}
}
‘”https://
39.
BuildTypesbuildTypes {
yourapi.com/beta/"‘
debug {
}
buildConfigField 'String',
'API_BASE_URL',
'"https://
yourapi.com/debug/"‘
}
release {
buildConfigField 'String',
'API_BASE_URL',
release/"‘
beta {
}
buildConfigField 'String',
'API_BASE_URL',
'"https://
}
'"https://yourapi.com/
40.
Build Variant41.
BuildConfigFielddefaultConfig {
applicationId “com.e_legion.coursera”
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName “1.0”
testInstrumentationRunner
“android.support.test.runner.AndroidJUnitRunner”
buildConfigField 'String', 'YOUR_NAME',
'"DEFAULT STRING"'
42.
ToastToast (также тост) – это всплывающее сообщение.
Легко реализуется.
Может использоваться как в целях дебага, так и для
уведомления пользователя.
43.
Создание обычного ToastToast.makeText(
<– вызов статического метода для создания
MainActivity.this,
<– первый параметр – контекст
“Connection lost”, <– второй параметр – текст (или
R.string.###ресурс)
Toast.LENGTH_LONG)
<– третий параметр – продолжительность
.show();
<– вызов метода для показа
LENGTH_SHORT
<– 2 секунды
LENGTH_LONG
<– 3.5 секунды
44.
Порядок создания кастомного ToastЧтобы создать кастомный Toast, нужно:
1. Создать желаемую XML верстку
2. Объявить и инициализировать переменную класса
Toast
3. Преобразовать верстку во View с помощью
LayoutInflater
4. Задать желаемые значения для элементов View
5. Применить метод toast.setView(View v).
Дополнительно можно задать длительность и gravity.
45.
Menu. Добавление ресурса46.
Добавление меню@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu,menu);
return true;
}
47.
Обработка нажатий@Override
public boolean onOptionsItemSelected
(MenuItem item) {
switch (item.getItemId()) {
“Search clicked”,
Toast.LENGTH_SHORT).show();
return true;
case R.id.settings:
“Settings clicked”,
Toast.makeText(this,
default: return
Toast.makeText(this,
super.onOptionsItemSelected(item);
Toast.LENGTH_SHORT).show();
return true;
case R.id.search:
}
}
48.
Редактирование в runtime@Override
public boolean onPrepareOptionsMenu (Menu menu) {
if (!isUserAuthorized()) {
menu.removeItem(R.id.logout);
return true;
}
return super.onPrepareOptionsMenu(menu);
}
49.
Обработка нажатия на контекстное меню@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_ID :
Toast.makeText(this, “Context menu clicked”,
Toast.LENGTH_SHORT).show();
return true;
default:
return super.onContextItemSelected(item);
}
}
50.
Знакомство с Fragment<?xml version=“1.0” encoding=“utf-8”?/
<FrameLayout xmlns:android=
“http://schemas.android.com/apk/res/android” xmlns:tools=
“http://schemas.android.com/tools”
android:id=“@+id/fr_container”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:fitsSystemWindows=“true”/>
51.
Варианты использования Fragment<fragment
android:id=“@+id/fragment_example”
android:name=“com.e_legion.coursera.ExampleFragment”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
52.
Основные классы при работе с Fragment•Fragment
•FragmentManager
•FragmentTransaction
53.
Методы FragmentTransactionFragmentTransaction transaction =
getFragmentManager().beginTransaction();
transaction.add(R.id.fr_container, fragment);
transaction.replace(R.id.fr_container, fragment);
transaction.remove(fragment);
transaction.hide(fragment);
transaction.show(fragment);
transaction.detach(fragment);
transaction.attach(fragment);
transaction.commit();
54.
Backstacktransaction.addToBackStack(fragment.getClass().getSimpleName())
;
getFragmentManager().popBackStack();
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStack EntryCount()>0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
55.
Жизненный цикл фрагментаCreated
onAttach()
onCreate()
onCreateView()
onActivityCreated()
Started
onStart()
Resumed
onResume()
56.
Жизненный цикл фрагментаPaused
onPause()
Stopped
onStop()
Destroyed
onDestroyView()
onDestroy()
onDetach()
57.
JSONJSON – это текстовый формат данных,
легко читаемый человеком и используемый
для сериализации объектов и обмена
данными.
58.
Создание POJO на основе jsonhttp://www.jsonschema2pojo.org
Плагины для Android Studio, поиск по слову “pojo” или
“json”
59.
GSONПодключение в файле gradle уровня app
dependencies {
implementation
‘com.google.code.gson:gson:2.8.2’
}
Аннотации GSON
@SerializedName (“name”)
@Espose
Мы оставляем поведение по умолчанию, сериализуя и
десериализуя все поля. Но есть возможность выбрать поля
которые будут только сериализованы или только
60.
Объект класса HumanHuman father = new Human();
father.setAge(38);
father.setName(“Тонких Артём Петрович”);
Human kid = new Human();
kid.setName(“Тонких Артём Артёмович”);
kid.setAge(4);
kid.setKids(null);
List<Human> kids = new ArrayList<>();
kids.add(kid);
father.setKids(kids);
61.
СериализацияString json = new Gson().tojson(human);
System.out.print(json);
{“name”:”Тонких Артём Петрович”, “age”:42,
“kids”:[{“name”: “Тонких Артём Артёмович”, “age”:8}]}
62.
Генерация метода toString()@Override
public String toString() {
return “Human{“ +
“name=” + name + ‘\’ +
“,age=” + age +
“,kids=” + kids +
‘}’;
}
63.
ДесериализацияHuman fromJson = new Gson().fromJson(json,
Human.class);
System.out.println(fromJson.toString());
toString() – Human{name=‘Тонких Артём Петрович’,
age=42, kids=[Human{name=‘Тонких Артём Артёмович’,
age=8, kids=null}]}
json – {“name”:”Тонких Артём Петрович”, “age”:42, “kids”:
[{“name”:”Тонких Артём Артёмович”, “age”:8}]}
64.
Многопоточность. Процессы и потокиПроцесс – глобальная сущность,
выделенные ресурсы.
Поток – внутренняя сущность процесса,
выполняет программный код.
65.
Что с Android?Пользователь
нажал на кнопку
Запрос
передается
в фоновый
поток
Запуск
фонового
потока
Показ
результата
Загрузка
Сетевой
запрос
BG
TH read
Результат
передается
в главный
поток
Завершение
фонового
потока
UI
TH read
66.
Thread и Runnablepublic class MyThread extends Thread{
}
@Override
});
public void run() {
new MyThread().start();
//do something
}
}
new Thread (new Runnable() {
@Override
public void run() {
//do something
67.
synchronizedpublic synchronized void doSomething() { }
//метод синхронизирован на
уровне объекта
private final static Object lock = new
Object();
}
public void doSomethingStaticBlock() {//…
public void doSomethingBlock {
synchronized (lock) {//блок
синхронизирован на уровне класса с
помощью статистического объекта
lock}
//…
synchronized (this) {
//блок синхронизирован на уровне
объекта}
//…
}
68.
wait/notify/notifyAllThread 2
Thread 1
1
3
synchronized
2
if (condition()){
wait()
}
4
5
7
notify()
6
69.
ExecutorService/Callable/FutureExecutorService executorService =
Executors.newFixedThreadPool(4);
Future<String> future = executorService.submit(new
Callable<String>() {
@Override
public String call() throws Exception {
return result; }
});
while (!future.isDone()) {
TimeUnit.MILLISECONDS.sleep(100); }
String result = future.get();
70.
java.util.concurrentБлокирующая очередь
Thread 1
Thread 2
BlockingQueue
Put
Take
71.
Знакомство с ServiceService – это компонент приложения, который
используется для выполнения долгих операций в
бэкграунде, без взаимодействия с пользовательским
интерфейсом.
<service
android:name=“.CustomService”
android:enabled=“true”
android:exported=“true” />
72.
Виды ServiceForeground – заметно для пользователя
Background – незаметно для пользователя
Bound – взаимодействие через интерфейс
73.
Создание Servicepublic class MyService extends Service {
public CustomService() {
}
@Override
@Nullable
public Ibinder onBind(Intent intent) {
return null;
}
}
74.
Создание Servicepublic class AnotherService extends IntentService {
public AnotherService(String name) {
super (name);
}
@Override
protected void onHandleIntent (Intent intent) {
//do something with data
}
}
75.
Жизненный цикл ServiceCall to
startService()
Call to
bindService()
onCreate()
onCreate()
onStartCommand()
onBind()
Service
running
Clients are
bound to
service
The service is
stopped by itself or a
client
Active
LifeTime
The service is
stopped by itself or
a client
onUnBind()
76.
Что такое BroadcastReceiver?BroadcastReceiver – это приемник сообщений,
посылаемых системой, либо другими
приложениями при каком-либо событии,
реагирующий на них и выполняющий
какую-либо работу, отдельно от обычного
процесса взаимодействия с приложением.
77.
Создание BroadcastReceiver•Добавляем новый класс, отнаследованный от
BroadcastReceiver
•Переопределяем метод onReceive()
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//TODO: do something
}
}
78.
Регистрация в манифесте<receiver
android:name=“.MyReceiver”
android:enabled=“true”
android:exported=“true”>
<intent-filter>
<action android:name=
“android.intent.action.HEADSET_PLUG”/>
</intent-filter>
</receiver>
79.
Регистрация в кодеMyReceiver myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter(Intent.
ACTION_HEADSET_PLUG);
registerReceiver (myReceiver, filter);
80.
Отправка сообщенийМы можем использовать BroadcastReceiver, чтобы
передавать свои собственные сообщения.
Intent intent = new Intent();
intent.setAction
(“com.e_legion.coursera.SOMETHING_JUST_HAPPEN”);
intent.putExtra (“ARG_DATA”, “SOME_VALUE”);
sendBroadcast(intent);
81.
Дополнительные возможности• sendOrderedBroadcast()
приоритет задается в IntentFilter
• LocalBroadcastManager.sendBroadcast()
LocalBroadcastManager.registerReceiver()
сообщения будут видны только в
пределах приложения
82.
Интерфейс AsyncTaskmSampleTask.execute(10L)
mSampleTask.cancel(true)
class SampleTask extends AsyncTask<Long, Integer, String> {
void onPreExecute();
String doInBackground(Long…longs);
void onPostExecute(String s);
void publishProgress(1,2,3,4)
void onProgressUpdate(Integer… values);
boolean isCanceled();
void onCanceled();
}
83.
Загружаем картинку с помощью AsyncTask84.
DownloadImageTaskprivate class DomnloadImageTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String… strings) {
return getBitmap(strings[0]);
}
@Override
85.
Код getBitmap()private Bitmap getBitmap(String url) {
try {
InputStream is = (InputStream) new
URL(url).getContent();
Bitmap d = BitmapFactory.decodeStream(is);
is.close();
return d;
} catch (Execution e) {
return null;
}
}
86.
В Activity.onCreate()mProgressBar = findViewById(R.id.progressBar);
mImageView = findViewById(R.id.image);
Button startBtn = (Button)
findViewById(R.id.btn_start);
startBtn.setOnClickListener (new View.OnClickListener() {
@Override
public void onClick(View v) {
String url =
“http://i0.kym-cdn.com/entries/icons/
mobile/000/013/564/doge.jpg”;
new DownloadImageTask().execute(url);
87.
Утечка Context@Override
protected void onPostExecute(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
//ссылка на поле активити
mProgressBar.setVisibility(View.INVISIBLE);
//тоже
}
88.
B Activitynew DownloadImageTask(MainActivity.this).execute(url);
/// –
ImageView getImageView() {
return findViewById(R.id.image);
}
ProgressBar getProgressBar() {
return findViewById(R.id.progressBar);
}
89.
Плюсы и минусы AsyncTaskПлюсы
•Прост для восприятия
•Гибко настраивается
•Хороший вариант для недолгих задач
Минусы:
•Возможность утечки контекста усложняет использование
•Определенно не подходит для долгих задач
•Создание и запуск только в UI-потоке
90.
HaMeR. О процессах и потокахКаждое приложение в Android по умолчанию работает в
своем собственном процессе, в своей области памяти. В
память чужого процесса попасть нельзя, это
гарантируется системой.
Первый поток, запущенный в процессе, называется
главным потоком.
Главный поток – main thread – UI thread – в контексте
Android синонимы.
91.
MainThread не уничтожается самПочему MainThread не умирает?
•Благодаря Looper.
Что делает Looper?
•Looper в бесконечном цикле проверяет MessageQueue.
Что такое MessageQueue?
•Очередь объектов Message, которые нужно обработать.
Как сообщения попадают в MessageQueue?
•Handler, связанный с Looper, отправляет сообщения в
очередь Looper.
Кто обрабатывает сообщения?
•В сообщении есть ссылка на Handler, который это
сообщение должен обработать
92.
HaMeR = Handler + Message + RunnableБесконечно проверяет
очередь сообщений
Looper
0
Message
1 2 …
…
n
Target:
to Handler 2
Message
Handler 2
Handler 1
Обрабатывает
сообщение
Постит сообщение
в очередь
93.
HandlerHandler handler = new Handler();
Handler bgHandler = new Handler(bgLooper);
Handler mainHandler = new Handler(Looper.getMainLooper());
handler.post (new Runnable() {
@Override
public void run() {
}
});
handler.postDelayed (new Runnable(), 4000);
94.
HandlerThreadHandlerThread – это поток, в котором есть Looper и
MessageQueue.
MyHandlerThread extends HandlerThread
mMyHandlerThread.start();
mMyHandlerThread.getLooper();
@Override
protected void onLooperPrepared() {
mMainHandler = new
Handler(Looper.getMainLooper());
}
95.
LoaderLoader – это API, позволяющее загружать данные из
различных источников (сервер, БД, content-provider) вне
зависимости от жизненного цикла.
LoaderManager- класс, который запускает Loader. Для
получения экземпляра менеджера – LoaderManager
getSupportLoaderManager()
LoaderManager.LoaderCallbacks – содержит методы,
которые вызываются при определенных событиях у
лоадера
96.
LoaderManagerLoaderManager- класс, который запускает Loader. Для
получения экземпляра менеджера – LoaderManager
getSupportLoaderManager()
Loader<D> initLoader(int id, Bundle args,
LoaderManager.LoaderLoaderCallbacks<D>callback)
Loader<D> restartLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback)
boolean hasRunningLoaders();
Loader<D> getLoader(int id);
void destroyLoader(int id);
97.
LoaderCallbacksLoaderManager.LoaderCallbacks – содержит методы,
которые вызываются при определенных событиях у
лоадера
onCreateLoader(int, Bundle)
onLoadFinished(Loader<D>, D)
onLoaderReset(Loader<D>)
98.
LoaderLoader – базовый класс. Наследуемся от него, если нужно
сделать какую-то уникальную реализацию. Иначе, можно
использовать системные реализации.
AsyncTaskLoader – лоадер, который инкапсулирует
AsyncTask.
CursorLoader – наследуется от AsyncTaskLoader,
инкапсулирует Cursor.
99.
ContentProvidersContentProvider – механизм, который
инкапсулирует доступ к данным,
дополнительно позволяя обращаться к ним
из разных процессов.
ContentProvider позволяет безопасно
делиться данными с другими
приложениями
100.
Экраны со списками101.
Системный ContentProviderТелефонная книга
•Чаты
•Банки
Мультимедиа
•Чаты
•Плееры
Календарь
•Органайзеры
•Почта
102.
Зачем нужна архитектура? Что такое бизнес-логика?Бизнес-логика (бизнес-правила) – это то, что делает
приложение.
Описание бизнес-логики не требует значительных
технических знаний.
Бизнес-правила одного и того же приложения на
различных платформах должны быть максимально
идентичны.
103.
Смешивание отображения и логики@Override
lers.mainThread())
public void onCreate
(@Nullable Bundle
savedInstanceState) {
.subscribe(
response -> {
mErrorView.setVisibility(Vie
w.VISIBLE);
super.onCreate(savedInsta mErrorView.setVisible(View. mRecyclerView.setVisibility(
View.GONE);
nceState);
GONE);
});
setContentView(R.layout.act
ivity_main);
mRecyclerView.setVisibility( }
mRecyclerView.setAdapter( View.VISIBLE);
mProjectsAdapter);
ApiUtils.getApiService().get mProjectsAdapter.addData(
Projects(BuildConfig.API_Q response.getProjects(),
UERY)
true);
104.
MVCТонких Артём Петрович в 1978-79 гг.
― Model – бизнес-логика
―View – отображение
―Controller – обработка ввода
View!=android.view.View
105.
Зачем нужна архитектура?•Лучшее понимание и больший
контроль над приложением
•Легче ввод новых программистов
на проект
•Проще тестировать бизнес-логику
•Возможность переиспользования
компонентов в других модулях
106.
SOLID – это…S – Принцип единой ответственности (SPR)
O – Принцип открытости/закрытости (OCP)
L – Принцип заменяемости (LCP)
I – Принцип разделения интерфейсов (ISP)
D – Принцип инверсии зависимостей (DIP)
107.
Single Responsibility Principle. Принцип единойответственности
A class should have only one reason to change.
Каждый объект должен иметь одну
ответственность и эта ответственность
должна быть полностью инкапсулирована
в класс.
108.
Выносим лишние методы в другие классыpublic class Employee{
private long employeeId;
private String name;
private Date dateOfJoining;
public boolean isPromotionDueThisYear(){ }
public Double calcIncomeTaxForCurrentYear(){ }
public class FinITCalculations {
public Double calcIncomeTaxForCurrentYear(Employee emp){ }
}
public class HRPromotions {
public boolean isPromotionDueThisYear(Employee emp){ }
109.
The Open Closed Principle. Принципоткрытости/закрытости
Software entities (classes, modules,
functions, etc) should be open for extension,
but closed for modification.
Программные сущности(классы, модули,
функции и т.д.) должны быть открыты для
расширения,
но закрыты для изменения
110.
The Substitution Principle. Принцип подстановки Тонких АртёмаПетровича
Functions that use pointers to base classes
must be able to use objects of derived classes
without knowing it.
Функции, которые используют базовый
тип, должны иметь возможность
использовать подтипы базового типа, не
зная об этом.
111.
Нарушение принципа подстановки Тонких АртёмаПетровича
public class Parent{
//x.value теперь равно 0
protected int value;
if (x.value > 0) {…}
private String text;
//код не выполнится
void setText(String text){
public class Child extends
Parent{
@Override
void setText(String text){
super.setText(text);
this.text = text;
}
}
Parent x = new Child();
x.value = 5;
x.setText (“Name”);
value = 0;
}
}
112.
The Interface Segregation Principle. Принцип разделенияинтерфейса
Clients should not be forced to depend
on methods that they do not use.
Клиенты не должны зависеть от методов,
которые они не используют.
113.
Неправильноpublic interface OnAllClickListener {
void onSubmitClick();
void onCancelClick();
void onDenyClick();
void onRetryClick();
}
114.
Правильноpublic interface OnSubmitClickListener {
void onSubmitClick();
}
public interface OnCancelClickListener {
void onCancelClick();
}
public interface OnDenyClickListener {
void onDenyClick();
}
public interface OnRetryClickListener {
void onRetryClick();
115.
The Dependency Inversion Principle. Принцип инверсиизависимостей
A. High-level modules should not depend on low-level
modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should
depend on abstractions.
А. Модули верхних уровней не должны зависеть от
модулей нижних уровней. Оба типа модулей должны
зависеть от абстракции.
В. Абстракции не должны зависеть от деталей. Детали
должны зависеть от абстракции.
116.
Reporterpublic class Reporter
{
public void sendReports()
{
ReportBuilder reportBuilder = new
ReportBuilder();
List<Report> reports =
reportBuilder.createReports();
if (reports.size() == 0)
throw new NoReportsException();
EmailReportSender reportSender = new
EmailReportSender();
117.
Дополнительные принципыDRY
Don’t repeat yourself –
Не повторяйся.
KISS
Keep it simple, stupid –
Не усложняй, дурачок.
YAGNI
You aren’t gonna need it –
Тебе это не понадобится
118.
Что нам дает соблюдение принципов?Соблюдая принципы, мы получаем классы, которые
можем с легкость
•понять, что он делает и за что отвечает
•переиспользовать в другом модуле или проекте
•протестировать с помощью unit тестов
•изменить, не ломая другие классы
119.
MVPModel – данные и методы их получения,
сохранения, обработки
View – визуальное представление
данных, экран
Presenter – получение данных,
управление отображением
120.
Схема взаимодействияДействие пользователя
События
GUI
View
-presentor
Обновление вида
Событие изменения модели
Presenter
-model
-IView
Model
Изменение модели
121.
View – SampleViewpublic interface SampleView {
void setData(List<Item>items);
}
122.
Presenter – SamplePresenterpublic class SamplePresenter {
private SampleView mView;
public SamplePresenter(SampleView view) {
mView = view;
}
void loadData() {
//load data from server
mView.setData(items);
}
}
123.
Плюсы и минусы MVPПлюсы:
•возможность модульного тестирования
•упрощение написания и понимания кода
Минусы:
•увеличение кодовой базы
124.
Что нам даёт Moxy?Presenter
View
View State
View
Commands
Model
125.
Как использовать Moxypublic class ProjectsFragment
extends MvpAppCompatFragment
implements ProjectsView {
@InjectPresenter
public ProjectsPresenter mPresenter;
@ProvidePresenter
ProjectsPresenter providePresenter() {
D comeDependency = new D;
return new
ProjectsPresenter(someDependency);
}
126.
MvpViewpublic interface ProjectsView extends BaseView, MvpView {
@StateStrategyType(value = SingleStateStrategy.class)
void showProjects(@NonNull List<Project> projects);
@StateStrategyType(value = SkipStrategy.class)
void openProfileFragment(@NonNull String username);
}
127.
Стандартные стратегииAddToEndStrategy – выполнить команду
и добавить команду в конец очереди
AddToEndSingleStrategy – выполнить
команду, добавить ее в конец очереди
и удалить все ее предыдущие экземпляры
SingleStateStrategy – выполнить команду,
очистить очередь и добавить в нее команду
SkipStrategy – выполнить команду
OneExecuteStrategy – выполнить команду
при первой возможности
128.
MVVMModel – данные и методы их получения,
сохранения, обработки
View – визуальное представление
данных, экран
ViewModel – абстракция представления,
прослойка между View и Model
129.
ViewModelpublic class ViewModel {
private String mUserName;
void updateUserName() {
mUserName = “John Smith”;
}
}
130.
Схема взаимодействиявызывает
вызывает
View
Model
ViewModel
связывание
databinding
уведомляет
131.
Двухстороннее связываниеView
ViewModel
новый символ
в поле
новое назначение
поля
валидация
показ
состояния
ошибки
изменение
состояния
ошибки
132.
Плюсы и минусы MVVMПлюсы:
•компоненты слабо связаны
•Databinding уменьшает количество кода
•Несколько View → одна ViewModel
Минусы:
•Показ Toast и диалогов
•Показ анимаций или данных с задержкой
•Необходимость обработки команды во View
133.
Итоги MVVMКогда использовать MVVM?
•Экран только показывает данные
•Экран с простой логикой
Когда следует воздержаться?
•Экраны со сложной логикой или сложно определяемым
состоянием
•Экраны с множеством диалогов и
сложными/прерываемыми анимациями
134.
Обзор Android Architecture ComponentsActivity/Fragment
ViewModel
LiveData3
Repository
Model
Room
SQLite
Remote Data Source
Retrofit
webservice
135.
Основные тезисы•Нельзя хранить контент или состояние
в компонентах и компоненты не должны
зависеть друг от друга
•Интерфейс и контент приложения
должны заполняться, опираясь
на модель. Модель не должна зависеть
от компонентов андроид
136.
LifeCycleSTATES
INITIALIZED
(initial start)
DESTROYED
(dead state)
RESUMED
STARTED
CREATED
ON_CREATE
ON_START
EVENTS
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
INITIALIZED
(initial start)
STATES
DESTROYED
(dead state)
CREATED
STARTED
RESUMED
137.
Dependency Inversion Principle•Модули верхних уровней не должны
зависеть от модулей нижних уровней.
Оба типа модулей должны зависеть от абстракций.
•Абстракции не должны зависеть
от деталей. Детали должны зависеть
от абстракций.
Классы должны зависеть от абстракций
138.
Inversion of ControlФреймворк
Custom module
2
3
библиотеки
Приложение В
custom vodule
1
Приложение А
1
2
3
Инверсия управления – это принцип проектирования, в
котором части программы, написанные вручную
разработчиком, получают поток управления из какого-
139.
Цели IoCОтделение вызова от релизации задачи
Концентрация на самой задаче, а не на
обработке вызова
Отсутствие допущений о том, как система
работает внутри, использование вместо
этого общепринятых контрактов
Предотвращение сайд-эффектов от
замены модуля
140.
Реализация IoC―Dependency Injection
―Service Locator
―Контекстуальный список
―Паттерн «Абстрактная фабрика»
―Паттерн «Стратегия»
141.
Dependency InjectionID-контейнер – класс или библиотека,
которая занимается только тем, что готовит
зависимости для других классов.
Внедрение зависимости – это техника
программирования, в которой один объект
(контейнер) снабжает зависимостями
(сервисами) другие объекты (клиентов).
142.
Какие вопросы решает DI?Как сделать работу класса независимой
от того, как были созданы его зависимости?
Как перенести сборку зависимостей
в отдельные конфигурационные файлы?
Как сделать несколько различных
конфигураций для приложения?
Как сделать всю работу приложения
независимой от того, как были созданы
его компоненты?
143.
Типы внедряемых зависимостейConstructor Injection – внедрение через
конструктор обязательной зависимости
Property (Setter) Injection –
переопределение через сеттер
необязательной зависимости
Method Injection – передача в метод
зависимости, которая пользуется
только в этом методе
144.
Внедрение тестовых зависимостейDependency
Unit Test
Unit
Mock
Dependency
145.
Плюсы и минусы DIПлюсы:
•Выбор реализации
•Независимое тестирование
•Слабая связность кода
•Параллельная разработка функциональности
Минусы:
•Сложность отладки из-за разделения мест и
использования компонентов
•Зависимость приложения от фреймворка для внедрения
зависимости
146.
Clean Architecture•Entities – Сущности
•Use Cases – Методы использования
•Interface Adapters – Интерфейс-Адаптеры
•Frameworks and Drivers – Место скопления деталей
147.
User•Быть тестируемой
•Не зависеть от UI
•Не зависеть от БД
•Не зависеть от внешних фреймворков и библиотек
•Не зависеть от какого-либо внешнего сервиса
148.
Model viewpresenter
Data
layer
Domian
layer
Boundaries
Presentation
layer
Interactions
Реализация User
Regular Java
Objects
Repository
pattern
149.
Схема работы данныхView
Presenter
Service
Use Case
Repository
150.
Плюсы и минусы Clean ArchitectureПлюсы:
Минусы
1.Модульное разделение;
1.Громоздкость;
2. Правило зависимостей;
2.Порог вхождения.
3. Тестирование;
4. Наличие Domain слоя;
5. Использовать любой
понравившийся вам MV-паттерн для
UI-слоя;
6. Кастомизация;
7. Хорошее комьюнити;
8. Гайды и богатая база исходных
151.
Итоги Clean ArchitectureКогда использовать Clean Architecture?
•Много бизнес-логики
•Действительно большое приложение
•Необходимо качественное покрытие тестами
•Постоянный рост или нужен задел на будущее
•Планируется мультиплатформа
Когда следует воздержаться?
•Простое приложение в котором практически нет логики
programming