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
42
Other Decks in Programming
See All in Programming
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
140
datadog dash 2025 LLM observability for reliability and stability
ivry_presentationmaterials
0
110
AIコーディング道場勉強会#2 君(エンジニア)たちはどう生きるか
misakiotb
1
240
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
1.2k
Create a website using Spatial Web
akkeylab
0
300
Deep Dive into ~/.claude/projects
hiragram
7
1.2k
deno-redisの紹介とJSRパッケージの運用について (toranoana.deno #21)
uki00a
0
140
Benchmark
sysong
0
250
Effect の双対、Coeffect
yukikurage
5
1.4k
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
840
Cline指示通りに動かない? AI小説エージェントで学ぶ指示書の書き方と自動アップデートの仕組み
kamomeashizawa
1
570
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
2
230
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
8
670
Git: the NoSQL Database
bkeepers
PRO
430
65k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
What's in a price? How to price your products and services
michaelherold
246
12k
Scaling GitHub
holman
459
140k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Rebuilding a faster, lazier Slack
samanthasiow
81
9k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
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