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
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
45
Other Decks in Programming
See All in Programming
TipKitTips
ktcryomm
0
160
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
500
エラーログのマスキングの仕組みづくりに役立ったASTの話
kumoichi
0
180
RAGでハマりがちな"Excelの罠"を、データの構造化で突破する
harumiweb
9
2.8k
エンジニアの「手元の自動化」を加速するn8n 2026.02.27
symy2co
0
140
「抽象に依存せよ」が分からなかった新卒1年目の私が Goのインターフェースと和解するまで
kurogenki
0
110
Swift ConcurrencyでよりSwiftyに
yuukiw00w
0
250
What Spring Developers Should Know About Jakarta EE
ivargrimstad
0
160
PJのドキュメントを全部Git管理にしたら、一番喜んだのはAIだった
nanaism
0
250
手戻りゼロ? Spec Driven Developmentとは@KAG AI week
tmhirai
1
190
What Spring Developers Should Know About Jakarta EE
ivargrimstad
0
390
Codex の「自走力」を高める
yorifuji
0
1.2k
Featured
See All Featured
Skip the Path - Find Your Career Trail
mkilby
1
75
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.8k
Fireside Chat
paigeccino
42
3.8k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
0
170
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
82
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
350
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
310
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.2k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
820
Site-Speed That Sticks
csswizardry
13
1.1k
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