Slide 1

Slide 1 text

Seu app está ruim e a culpa é sua Otimizações de Performance em aplicações android @_paulacr

Slide 2

Slide 2 text

Um pouco de teoria… 30 frames por segundo convincente sensação de movimento 60 frames por segundo Transições suaves (smooth transitions)

Slide 3

Slide 3 text

Um pouco de teoria… 16ms 16ms 16ms Calculando: 1000ms 60 frames =16.666ms/frame Em 16ms: • Computação • Desenhar componentes na tela • Atualização de views na tela • Animações • Tempo para o GC recolher objetos

Slide 4

Slide 4 text

GPU Profiling tool 16ms Navigation Performance Active application performance NotificationBar performance

Slide 5

Slide 5 text

GPU Profiling tool cuidado: acima linha verde = animações sofrem pausa Tempo upload Bitmap na GPU atualizando/enviando display list gpu ++ , CPU aguardando measure/layout - hierarquia++ Desenho - métodos desenho sobrecarregado animações - usar outra thread entre frames - usar outra thread 16ms

Slide 6

Slide 6 text

…e quando a animação trava…

Slide 7

Slide 7 text

• Numero de vezes que um pixel é redesenhado (a cada frame) • Algumas vezes colocamos background sem precisar • O desenho excessivo (em situações que poderiam ser evitadas) é o overdraw Overdraw

Slide 8

Slide 8 text

Nome Loren ipsun loren loren ipsun loren favoritar compartilhar Nom Loren ipsun loren loren ipsun loren favoritar compartilhar Nome Loren ipsun loren loren ipsun loren favoritar compartilhar Como você vê seu app Como Android vê seu app

Slide 9

Slide 9 text

Como habilitar GPU Overdraw Toolbar 1x Overdraw 2x Overdraw 3x Overdraw 4x Overdraw

Slide 10

Slide 10 text

Como corrigir overdraw <item name=“android:windowBackground”>…</item> Escolha um tema para o background default da aplicação Dica: crie um tema que estender do tema padrão para outras telas (com background diferente)

Slide 11

Slide 11 text

Como corrigir o overdraw Sem background 
 no layout main Sem background 
 no item • Passo 1: Removendo background layout pai • Passo 2: removendo background layout item android:background="@color/white">

Slide 12

Slide 12 text

Hierarchy Viewer

Slide 13

Slide 13 text

Mais dicas • Verificar se o componente precisa de um layout extra • Customizar temas da aplicação • Reduzir layouts com transparência (The hidden cost of transparency) 
 https://www.youtube.com/watch?v=wIy8g8yNhNk • Desenhar somente o que está visível para o usuário. Ex: customviews (Udacity) • ConstraintLayout
 https://android-developers.googleblog.com/2017/08/understanding- performance-benefits-of.html

Slide 14

Slide 14 text

Garbage Collector Garbage Collector Objetos Memória • Gerenciamento de memória automático (automatic memory management) • Desenvolvedor não tem controle de quando GC passa

Slide 15

Slide 15 text

Object Lifecycle Object Object Object Activity Lifecycle LEAK Memory leak (vazamento de memória) • Uma porção de memória que não é liberada • Está referenciada por outra instancia/objeto • A referência impede a memória de ser liberada • Todos os itens que estão ancorados à activity também sofrem leaks (adapters, views, etc)

Slide 16

Slide 16 text

Como um leak surge (não é do além) Device rotacionado • A activity é destruída • Outra activity é criada • Se tiver leaks na activity destruída, ela não é coletada • Parabéns: você ganhou uma activity de brinde :)

Slide 17

Slide 17 text

Como um leak surge (não é do além) • Toda vez que a configuração muda, a activity é recriada • Se houver um leak a activity não será desalocada da memória android:configChanges= ["mcc", "mnc", "locale","touchscreen", "keyboard", "keyboardHidden","navigation", "screenLayout", "fontScale","uiMode", "orientation", "screenSize","smallestScreenSize"]

Slide 18

Slide 18 text

Leak 1 - Contexto estático public class MainActivity extends AppCompatActivity { private static Activity activity; @Override protected void onCreate(Bundle onSavedInstance) activity = this; } }

Slide 19

Slide 19 text

Leak 1 - Solução • Pra que usar contexto estático? (se pergunte pelo menos 10 vezes) • Recomendado: não utilizar o contexto estático • Utilizar o contexto da aplicação • Banco de Dados, Singleton, etc • Inicialização libs (Fabric, Crashlytics, facebook)

Slide 20

Slide 20 text

Inner classes (não estáticas) e classes anônimas • Facilitam a implementação • Permitem melhor organização do código • Mas podem trazem um problema: Referência implícita

Slide 21

Slide 21 text

Leak 2 - Referenciar contexto (direta ou indiretamente) em chamadas assíncronas class MainActivity extends AppCompatActivity { ImageView imageView; private class DownloadImageTask extends AsyncTask { ... @Override protected void onPostExecute(Bitmap result) { imageView.setImageBitmap(result); } } } Leak Threads, Callbacks, AsyncTask Leak

Slide 22

Slide 22 text

@Override protected void onCreate(Bundle savedInstanceState) { ... new Timer().schedule(new TimerTask() { @Override public void run() { image.setImageResource(R.drawable.imagem); } }, LONG_TIME); } Leak 3 - Referenciar views em classes anônimas que tem tempo de vida maior Leak Cuidado com Handlers

Slide 23

Slide 23 text

Solução 1 - Listener private static class DownloadImageTask extends AsyncTask< , , > { private Listener listener; interface Listener { void onSuccess(Bitmap bitmap); } public void setListener(Listener listener) { this.listener = listener; } }

Slide 24

Slide 24 text

Solução 1 - Listener public class SecondActivity extends AppCompatActivity { ... downloadImageTaskWithListener = new DownloadImageTask(); downloadImageTaskWithListener.setListener(createListener()); }

Slide 25

Slide 25 text

Solução 1 - Listener private DownloadImageTask.Listener createListener() { return new DownloadImageTask.Listener() { @Override public void onSuccess(Bitmap bitmap) { imageView.setImageBitmap(bitmap); } };

Slide 26

Slide 26 text

Solução 1 - Listener @Override protected void onDestroy() { downloadImageTask.setListener(null); super.onDestroy(); } Dica: se não setar nulo no listener, vai causar leaks

Slide 27

Slide 27 text

private static MyAsync extends AsyncTask< , , > { private final WeakReference imagem; public MyAsync(ImageView image) { this.image = new WeakReference(image) } } Solução 2 - weak reference

Slide 28

Slide 28 text

Solução 2 - weak reference @Override protected void onPostExecute(Bitmap bitmap) { ImageView imageView = imageViewWeakReference.get(); if(imageView != null) { imageView.setImageBitmap(bitmap); } } Dica: nunca esqueça de verificar se o objeto não está nulo

Slide 29

Slide 29 text

Outras possíveis soluções • IntentServices • RxJava (com cuidado) • EventBus • Architecture Components

Slide 30

Slide 30 text

Leak Canary • Adicionado como dependência do projeto • Ao usar o app, você recebe uma notificação quando há leaks • Ao clicar na notificação, mostra o ponto que sofreu leak

Slide 31

Slide 31 text

Profiling Tools

Slide 32

Slide 32 text

Profiling de memória GC / Dump / Record Alloc Count Depth Retained size

Slide 33

Slide 33 text

Profiling de CPU Thread Ativa Thread ativa, aguardando Sleeping thread Total de threads

Slide 34

Slide 34 text

Profiling de rede

Slide 35

Slide 35 text

Dicas • Não referencie views em chamadas assíncronas • Não referencie views em classes anônimas que tenham tempo de vida mais longo que a activity • Use as ferramentas de profiling e Leak Canary para detectar leaks e ver o comportamento do seu app

Slide 36

Slide 36 text

Outras otimizações • AppLaunch • Threads (bibliotecas que usam ThreadPool) • Estrutura de dados (SparseArray e ArrayMap) • …tem muita coisa para otimizar!!!!

Slide 37

Slide 37 text

Referências • https://classroom.udacity.com/courses/ud825 (curso Udacity) • https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE 
 (Android Performance Patterns) • https://developer.android.com/training/best-performance.html • https://www.youtube.com/watch?v=wIy8g8yNhNk (Custos de transparência) • https://github.com/paulacr/PerformanceApp • https://youtu.be/gwqQT5NrhUg (Loving lean layouts - Huyen Tue Dao)