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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Rafael Araujo
August 25, 2017
Programming
3
210
Permissões com Headless Fragment
Slides do talk apresentado no Android Dev Conference 2017 (pt-br)
Rafael Araujo
August 25, 2017
Tweet
Share
More Decks by Rafael Araujo
See All by Rafael Araujo
Qualidade de código Android
orafaaraujo
0
44
Other Decks in Programming
See All in Programming
インターン生でもAuth0で認証基盤刷新が出来るのか
taku271
0
190
AWS re:Invent 2025参加 直前 Seattle-Tacoma Airport(SEA)におけるハードウェア紛失インシデントLT
tetutetu214
2
120
AIエージェント、”どう作るか”で差は出るか? / AI Agents: Does the "How" Make a Difference?
rkaga
4
2k
登壇資料を作る時に意識していること #登壇資料_findy
konifar
4
1.3k
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
470
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
Raku Raku Notion 20260128
hareyakayuruyaka
0
330
責任感のあるCloudWatchアラームを設計しよう
akihisaikeda
3
180
コマンドとリード間の連携に対する脅威分析フレームワーク
pandayumi
1
460
それ、本当に安全? ファイルアップロードで見落としがちなセキュリティリスクと対策
penpeen
7
3.9k
AI時代の認知負荷との向き合い方
optfit
0
160
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
430
Featured
See All Featured
Statistics for Hackers
jakevdp
799
230k
Paper Plane (Part 1)
katiecoart
PRO
0
4.3k
Claude Code のすすめ
schroneko
67
210k
How to Talk to Developers About Accessibility
jct
2
130
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
830
GraphQLとの向き合い方2022年版
quramy
50
14k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.2k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
67
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
0
140
Six Lessons from altMBA
skipperchong
29
4.2k
Amusing Abliteration
ianozsvald
0
100
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