Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Permissões com Headless Fragment
Search
Rafael Araujo
August 25, 2017
Programming
220
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Permissões com Headless Fragment
Slides do talk apresentado no Android Dev Conference 2017 (pt-br)
Rafael Araujo
August 25, 2017
More Decks by Rafael Araujo
See All by Rafael Araujo
Qualidade de código Android
orafaaraujo
0
53
Other Decks in Programming
See All in Programming
typoなんかねぇよ
raspython3
0
660
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
110
in-process GraphQL のすすめ #ginzajs
izumin5210
4
1.5k
[KotlinConf Extended South Korea 2026] KotlinConf 2026 발표자 후기
wisemuji
0
100
FDEとは、何者なのか?
masapyon1212
0
140
Press start. Python's next generation.
willingc
PRO
3
310
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
140
ソフトウェアラスタライザ
fadis
1
790
週末にAI-DLCを本気で回したら$1,600溶けた
hbashimizu
0
130
What We Talk About When We Talk About XP
m_seki
2
360
高専、大学編入、そして未踏へ〜プロダクト開発とキャリアの歩み - Technical College, University Transfer, and On to “Mitou” / My Journey in Product Development and Career
pkmiya
0
140
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
110
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
810
WCS-LA-2024
lcolladotor
0
820
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Automating Front-end Workflow
addyosmani
1369
210k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.5k
The browser strikes back
jonoalderson
0
1.6k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
510
WENDY [Excerpt]
tessaabrams
12
39k
Transcript
Permissões com Headless Fragment 1
Rafael Araujo Android Developer Sênior Campinas - SP, Brasil 2
Todos na mesma página... Android 6.0 (Marshmallow - API level
23) Recursos específicos em run time Segurança Responsabilidade do desenvolvedor garantir o recurso na hora correta 3
Tirando uma foto class MainCurrentWayActivity : AppCompatActivity() { override fun
onCreate(savedInstanceState: Bundle?) { findViewById(R.id.activity_main_camera) .setOnClickListener { takeAPic() } } fun takeAPic() {} } 4
Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck
= ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 5
Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck
= ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 6
Usuário clicou para tirar uma foto findViewById(R.id.activity_main_camera).setOnClickListener { val permissionCheck
= ContextCompat.checkSelfPermission(this, CAMERA) if (permissionCheck == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { ActivityCompat.requestPermissions(this, arrayOf(CAMERA), PERMISSION_RC) } } 7
Requisitando a permissão 8
Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:
Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 9
Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:
Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 10
Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:
Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 11
Resultado da ação do usuário override fun onRequestPermissionsResult(requestCode: Int, permissions:
Arr...) { if (requestCode == PERMISSION_RC) { if (results[0] == PackageManager.PERMISSION_GRANTED) { takeAPic() } else { if (shouldShowRequestPermissionRationale(permissions[0])) { showRetryMessage() } else { showConfigurationMessage() } } } } 12
Caso usuário negar... 13
Alguns problemas Lógica na view Muito código Lidar com
muitos fluxos Boilerplate 14
Proposta? Headless Fragment! 15
Headless Fragment Fragments sem UI (sem inflar um XML) Reter
objetos grandes demais para o Bundle da Activity Lógica isolada da camada View Reutilizar em outras telas 16
Em arquiteturas VIEW VIEW MVP MVVM MODEL MODEL PRESENTER VIEW
MODEL 17
Em arquiteturas VIEW VIEW MVP MVVM MODEL MODEL PRESENTER VIEW
MODEL Headless Fragment Headless Fragment 18
Isolando o código View Headless Fragment 19
Isolando o código View Headless Fragment Permissão concedida? 20
Isolando o código View Headless Fragment Permissão concedida? Permitiu ou
Negou 21
Fácil reutilização View Model ViewModel Timeline View Model ViewModel Perfil
View Model ViewModel Chat 22
Fácil reutilização View Model ViewModel Permissão Câmera Timeline View Model
ViewModel Perfil View Model ViewModel Chat 23
Entendo o porque um Fragment onCreate() Inicio onResume() onPause() onAttach()
24
Requisitando a permissão ... requestPermissions() onResume() onPause() 25
Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 26
Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 27
Talk is cheap, show me the code! 28
Callbacks public interface PermissionListener { void onPermissionGranted(); void onPermissionDenied();
} 29
Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:
Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 30
Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:
Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 31
Activity class MainNewWayActivity : AppCompatActivity(), PermissionListener { override fun onCreate(savedInstanceState:
Bundle?) { findViewById(R.id.activity_main_camera).setOnClickListener { val helper: PermissionHelper = PermissionHelper() helper.requestPermissionIfNeeded(supportFragmentManager) } } override fun onPermissionGranted() { takeAPic() } override fun onPermissionDenied() { finish() } } 32
Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 33
Headless Fragment class PermissionHelper : DialogFragment() { override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) isCancelable = false } } 34
Configurando o Callback private lateinit var mListener: PermissionListener override fun
onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 35
Configurando o Callback private lateinit var mListener: PermissionListener override fun
onAttach(context: Context?) { super.onAttach(context) if (context is PermissionListener) { mListener = context } } 36
Configurando o Callback private fun onPermissionGranted() { dismiss() mListener.onPermissionGranted() }
private fun onPermissionDenied() { dismiss() mListener.onPermissionDenied() } 37
Método público private val PERMISSION_TAG = "PERMISSION_TAG" fun requestPermissionIfNeeded(fragmentManager: FragmentManager)
{ val fragment = fragmentManager.findFragmentByTag(PERMISSION_TAG) if (fragment == null) { show(fragmentManager, PERMISSION_TAG) } } 38
Requisitando a permissão private val PERMISSIONS = arrayOf(permission.CAMERA, permission.RECORD_AUDIO) private
val PERMISSION_RC = 100 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestPermissions(PERMISSIONS, PERMISSION_RC) } 39
Requisitando a permissão private val PERMISSIONS = arrayOf(permission.CAMERA, permission.RECORD_AUDIO) private
val PERMISSION_RC = 100 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestPermissions(PERMISSIONS, PERMISSION_RC) } 40
Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 41
Flags de contole private var mCheckPermissionStatus: Boolean = false private
var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 42
Flags de contole private var mCheckPermissionStatus: Boolean = false private
var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 43
Flags de contole private var mCheckPermissionStatus: Boolean = false private
var mAcceptedAll: Boolean = false private var mShouldRetry: Boolean = false private var mExternalRequestRequired: Boolean = false 44
OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus
&& mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 45
OnResume chamado após onCreate override fun onResume() { if (mCheckPermissionStatus
&& mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 46
Requisitando a permissão 47
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 48
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 49
Reinicia todas as flags de controle private fun resetFlags() {
mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 50
Reinicia todas as flags de controle private fun resetFlags() {
mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 51
Reinicia todas as flags de controle private fun resetFlags() {
mCheckPermissionStatus = true mAcceptedAll = false mShouldRetry = false mExternalRequestRequired = false } 52
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 53
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 54
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 55
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 56
override fun onRequestPermissionsResult(requestCode: Int, permissions: Arr...) { resetFlags() for (i
in permissions.indices) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (shouldShowRequestPermissionRationale(permissions[i])) { mShouldRetry = true return } else { mExternalRequestRequired = true return } } } mAcceptedAll = true } 57
Resultado da permissão ... requestPermissions() onResume() onPause() onRequestPermissionsResult() 58
OnResume chamado após ação do usuário override fun onResume() {
if (mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 59
Todas permissão foram aceitas? override fun onResume() { if (mCheckPermissionStatus
&& mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 60
Alguma permissão foi negada override fun onResume() { if (mCheckPermissionStatus
&& mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 61
Negou sem "Não perguntar novamente" override fun onResume() { if
(mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 62
Tentar novamente através de uma dialog private fun showRetryDialog() {
alert("Para continuar é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_RC) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 63
Recomeça o fluxo novamente private fun showRetryDialog() { alert("Para continuar
é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_RC) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 64
Callback negativo para a View private fun showRetryDialog() { alert("Para
continuar é necessário aceitar as permissões") { titleResource = "Permissão recusada" positiveButton("OK") { requestPermissions(PERMISSIONS, PERMISSION_REQUEST_CODE) } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 65
Dialog de tentar novamente 66
Negou com "Não perguntar novamente" override fun onResume() { if
(mCheckPermissionStatus && mAcceptedAll) { onPermissionGranted() } else { if (mShouldRetry) { showRetryDialog() } else if (mExternalRequestRequired) { showAppSettingDialog() } } } 67
Enviando para Configurações do Aplicativo private fun showAppSettingDialog() { alert("Conceda
as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 68
Envia usuário para as configurações private fun showAppSettingDialog() { alert("Conceda
as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 69
Callback negativo para a Activity private fun showAppSettingDialog() { alert("Conceda
as permissões nas configurações do aplicativo") { titleResource = "Permissão necessária" positiveButton("OK") { showAppSettings() } negativeButton("Cancelar") { onPermissionDenied() } }.show() } 70
Permissões nas configurações 71
Fluxo completo 72
Além do apresentado... Parametrização Permissões e mensangens por parâmetro Dagger
Facilidade na injeção de demais classes Escopo por Activity RxJava para Callbacks Verificar conexão com Headless Fragment 73
/oRafaAraujo /androidDevConference2017 74
Slides WEB: slides.com/orafaeldearaujo/permissoes-com-headless-fragment 75
Obrigado! @orafaaraujo /in/rafaeldearaujo /orafaaraujo 76