Skip to content

Commit b34ace8

Browse files
authored
Merge pull request #18 from egorikftp/patch-1
Исправление ошибок и конвертация в книгу
2 parents 32fd048 + 9ecfe8d commit b34ace8

File tree

6 files changed

+36
-41
lines changed

6 files changed

+36
-41
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
* Каждая глава представлена отдельной директорией, в которой лежит текстовый файл и необходимые вложения
1010
* Формат текстовых файлов **M**ark**d**own (.md)
1111

12-
## Правила для контрибьютеров
12+
## Правила для контрибьюторов
1313

1414
* Написание каждой из глав происходит в отдельной feature ветке (см. [шпаргалку по Gitflow](https://danielkummer.github.io/git-flow-cheatsheet/index.ru_RU.html))
1515
* Изменения сливаются в develop посредством pull request
16-
* commit message осуществляются **сторого на русском языке**
16+
* commit message осуществляются **строго на русском языке**
1717

1818

cases/auth/Auth_article.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Аутентификация <br>
22
Думаю, что во многих приложениях, особенно в банковских, вы встречались со следующим поведением приложения: работаете, работаете, а потом вдруг появляется экран ввода пин-кода. Такое поведение обосновано мерами безопасности. Опишем данный процесс чуть более подробно с некоторыми техническими подробностями. <br>
3-
При старте приложения вам показывается экран с вводом пинкода. Вы посылаете запрос на сервер, и в случае успеха (верного пинкода) вам возвращается токен, и стартует сессия. Далее часть запросов вы шлете с использованием данного токена. Токен прикрепляется либо к заголовку запроса, либо к телу. Подобные запросы еще также называются запросами авторизованной зоны. То есть сессия - это время, в течении которого данный токен действителен на стороне сервера.<br>
3+
При старте приложения вам показывается экран с вводом пин-кода. Вы посылаете запрос на сервер, и в случае успеха (верного пин-кода) вам возвращается токен, и стартует сессия. Далее часть запросов вы шлете с использованием данного токена. Токен прикрепляется либо к заголовку запроса, либо к телу. Подобные запросы еще также называются запросами авторизованной зоны. То есть сессия - это время, в течении которого данный токен действителен на стороне сервера.<br>
44
Через какое-то время сессия завершается, обычно по истечению какого-то конкретного промежутка времени, и тогда токен "протухает". Запросы с протухшим токеном возвращают ошибку. Тогда либо нужно просто обновить токен специальным запросом, либо нужно пользователя снова перебросить на экран ввода пин-кода, обновить токен, и продолжить слать запросы авторизованной зоны с обновившимся токеном. <br>
55
А теперь представим, что подобное поведение вам необходимо реализовать в своем приложении. И архитектура вашего приложения - Чистая архитектура. <br>
66
Поэтому возникает ряд интересных вопросов: <br>
@@ -85,7 +85,7 @@ public class MainAuthenticator implements Authenticator {
8585
}
8686
```
8787
Благодаря добавлению ```synchronized``` к методу ```authenticate``` и блокирующему методу ```authHolder.refresh()``` мы добиваемся того, что при возникновении 401 ошибки мы первым делом идем обновлять токен. Все остальные запросы, которые возвращают 401 ошибку, тоже ждут обновления токена, и только после этого идут повторные запросы с обновленным токеном. Очень удобно!<br>
88-
Логичный вопрос. А как должен обновляться **AuthHolder**, через что он организизует свой запрос обновления токена. Так как опять-таки это внутренняя кухня организации работы с сервером, то Repositories и другие слои про это не знают. Это внутреннее дело **Data**. <br>
88+
Логичный вопрос. А как должен обновляться **AuthHolder**, через что он организует свой запрос обновления токена. Так как опять-таки это внутренняя кухня организации работы с сервером, то Repositories и другие слои про это не знают. Это внутреннее дело **Data**. <br>
8989
Хорошо, а через что тогда лучше осуществлять запрос? Через **CommonNetwork**, который будет включать классы для осуществления запросов неавторизованной зоны (запросов, не требующих токена). В [примере](https://github.com/AndroidArchitecture/AuthCase/tree/sample_1) эти классы объединены в **CommonNetworkModule**.<br>
9090
Обновленная схема приобретет вид:<br>
9191
![enter image description here](https://i.imgur.com/xvFKOZK.png)
@@ -280,7 +280,7 @@ public class AuthHolder {
280280
}
281281
```
282282
Обратим внимание на метод ```public void refresh()```. В нем мы обнуляем пинкод, сообщаем подписчику об истечении сессии, в данном случае сообщаем **AuthRepository**. Затем через обычный ```CountDownLatch``` мы блокируем поток до тех пор пока не будет вызван метод ```public void updatePinCode(@NonNull String pinCode)```. В данном методе приходит введенный пользователем пин-код (**синие стрелочки** на рисунке выше). <br>
283-
На всякий случай отмечу следующий момент. В данном случае обновление пин-кода - синхронная операция и выполняется она в главном потоке, поэтому с главного потока мы без проблем освобождаем поток, задержанный ```CountDownLatch```. Но если обновление пин-кода была бы асинхронной операцией, и выполнялась бы в другом потоке, то поток этот должен был браться не из ```Executors``` в **AuthNetwork**, иначе теоретически могло получиться, что все потоки были бы в режиме ожидания, и обновить пин-код было бы некому.<br>
283+
На всякий случай отмечу следующий момент. В данном случае обновление пин-кода - синхронная операция и выполняется она в главном потоке, поэтому с главного потока мы без проблем освобождаем поток, задержанный ```CountDownLatch```. Но если обновление пин-кода была бы асинхронной операцией, и выполнялась бы в другом потоке, то поток этот должен был браться не из ```Executors``` в **AuthNetwork**, иначе теоретически могло получиться, что все потоки были бы в режиме ожидания, и обновить пин-код было бы некому.<br>
284284
После того как пришел пин-код, поток, вызвавший ```refresh```, разблокируется и запускает запрос по обновлению токена (метод ```private Single<String> updateToken()```). В случае успешного обновления, остальные запросы с 401 ошибкой также перестартуются.<br>
285285
Конечно же, механизм по обновлению токена с ожиданиями через ```CountDownLatch``` вы можете переделать по своему усмотрению. В этом решении также могут быть не учтены некоторые крайние случаи. Тут важна опять-таки - концепция.<br>
286286
Вот собственно и все манипуляции =)

cases/wizards/Wizards_article.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
- максимальная переиспользуемость экранов без внесения изменений в соответствующие классы (Презентеры, Интеракторы и т.д.),<br>
1212
- независимость экранов, то есть чтобы экраны не знали друг о друге,<br>
13-
- сосредоточнение логики переходов в одном месте,<br>
13+
- сосредоточение логики переходов в одном месте,<br>
1414
- тестируемость данной логики.<br>
1515

1616
Что же, давайте начнем с [простого примера, ветка sample_1](https://github.com/AndroidArchitecture/WizardCase/tree/sample_1). Нам необходимо написать Визард регистрации пользователя. Состоять он будет из трех экранов:<br>
@@ -153,7 +153,6 @@ public class MainWizardSmartRouter {
153153
currentWizardStep = WizardStep.LICENSE;
154154
router.backTo(LICENSE_SCREEN);
155155
}
156-
157156
};
158157

159158
public WizardSmartRouter(Router router) {
@@ -322,7 +321,7 @@ public class InfoFinishFragment extends InfoFragment {
322321
Разве никак нельзя как-то избежать этого безжалостного дублирования кода? На самом деле можно. Давайте еще раз взглянем на схему:<br>
323322
![image](https://habrastorage.org/web/10e/68d/808/10e68d808c994bcdb3f8000724f36ee9.png)
324323

325-
На самом деле ее можно трансформитровать до такой схемы:<br>
324+
На самом деле ее можно трансформировать до такой схемы:<br>
326325
![image](https://habrastorage.org/web/b72/6ee/ab7/b726eeab7080457bb6a0258cfc2dd8db.png)
327326

328327
То есть последовательность экранов InformationScreen, LoginScreen и RegistrationScreen и логику их взаимодействия мы выделяем в новый **AccountWizard**. Этот **AccountWizard** может сообщить внешнему Визарду, допустим, только две вещи:<br>
@@ -356,7 +355,6 @@ public class AccountWizardSmartRouter {
356355
public void infoWizardBack() {
357356
router.finishChain();
358357
}
359-
360358
};
361359

362360
private final LoginWizardPart loginWizardPart = new LoginWizardPart() {
@@ -378,7 +376,6 @@ public class AccountWizardSmartRouter {
378376
accountWizardStep = REGISTRATION;
379377
router.navigateTo(REGISTRATION_SCREEN);
380378
}
381-
382379
};
383380

384381
private final RegistrationWizardPart registrationWizardPart = new RegistrationWizardPart() {
@@ -394,7 +391,6 @@ public class AccountWizardSmartRouter {
394391
accountWizardStep = LOGIN;
395392
router.backTo(LOGIN_SCREEN);
396393
}
397-
398394
};
399395

400396
public AccountWizardSmartRouter(Router router,

ebook/Android Architecture Book.epub

392 KB
Binary file not shown.

0 commit comments

Comments
 (0)