SlideShare une entreprise Scribd logo
1  sur  63
Télécharger pour lire hors ligne
DICAS PARA
INTERFACES PERFORMÁTICAS
NO SEU APP ANDROID
INTEL SOFTWARE DAY 2013
CONTEXTO
INTERAÇÕES COM A UI
Sonho de consumo são 60 FPS...
A cada 16ms, um FPS certamente se perde
Quanto mais FPSs perdidos, mais a
experiência do usuário com a UI degrada...
COMO PERDER FPSs
UI Thread pausada na hora da interação
UI Thread está executando alguma operação
(lenta) no momento da interação
GARBAGE COLLECTION
POR QUÊ ELE IMPORTA
GARBAGE COLLECTION
Android 2.3+ implementa variante de CMS
FORÇA PAUSAS DA UI THREAD PARA GC
Pausas prolongadas e/ou frequentes durante
a interação do usuário PRECISAM ser evitadas
NÃO GERE LIXO
DESNECESSÁRIO
AUTO BOXING
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1024, "Android");
map.put(2048, "performance");
map.put(5096, "matters");
List<Double> values = new ArrayList<Double>();
values.add(3.1415);
map.put(1024, "Android");

new Integer(1024);
SPARSE ARRAYS
SparseArray<String> sparseArray = new SparseArray<String>();
sparseArray.put(665, "Android");
sparseArray.put(666, "rocks");
STRINGS
String facebookAvatarURL =
"http://graph.facebook.com/" +
facebookID +
"/picture?type=large";

T
’
N
O
D

String numberStr = "" + number;
STRINGS
String facebookAvatarURL =
"http://graph.facebook.com/" +
facebookID +
"/picture?type=large";
....
String numberStr = "" + number;

new StringBuilder();
SEMPRE ÓTIMO ???
StringBuilder builder = new StringBuilder();
for (int i = 0; i < count; i++) {
builder.append("ANDROID");
}
return builder.toString();
FATOS
StringBuilder trabalha com um array de
caracteres de tamanho pré-fixado...
Estourar o limite significa criar um novo array de
caracteres e concatenar no já existente...
BOAS PRÁTICAS
final String androidRocks = "android" + "rocks";
// Constantes serão otimizadas pelo compilador
// e concatenadas em tempo de compilação
final String facebookAvatarURL =
GRAPH_BASE_URL.concat(facebookID);
// String.concat() melhor para uma variável String
StringBuilder builder = new StringBuilder(200);
// Garantir que StringBuilder aloca caracteres suficientes
// evita a criação de novos arrays de caracteres
ARRAY LISTS
@Override
public void onCompleted(List<GraphUser> users, Response response) {
List<FacebookFriend> friends = new ArrayList<FacebookFriend>();
if (users != null) {
for (GraphUser user : users) {
FacebookFriend friend = new FacebookFriend(user);
friends.add(friend)
}
mAdapter = new FriendsAdapter(this, friends);
mFriendsList.setAdapter(mAdapter);
}

}
FATOS
ArrayList, HashMaps, TreeMaps trabalham sobre
Object[], uma estrutura imutável
Se o tamanho pré-definido da Collection estoura,
arrays subjacentes serão substituídos por novas
instâncias
BOAS PRÁTICAS
DIMENSIONE o tamanho das suas listas
List<FacebookFriend> friends = new ArrayList<FacebookFriend>(500);

EVITE adicionar elementos em uma posição
específica da lista
friends.add(10,friend);
ABSTRAÇÕES EM EXCESSO ...
REUSAR SEMPRE
QUE POSSÍVEL
OBJECT POOL
Reusar instâncias de objetos ao invés
de criar e destruir com (muita!)
frequência
http://en.wikipedia.org/wiki/Object_pool_pattern
Um random por bloco
public class BlocksEngine extends CCLayer {
public void blocksEngine(float dt) {
if (new Random().nextInt(300) == 0) {
getDelegate().createBlock(
new Block(Assets.block).generate(), 1, 1);
}
}
}

Novo bloco a cada
chamada da engine
Random agora é constante
public static final Random sRANDOM = new Random();
public class BlocksEngine extends CCLayer {

}

public void blocksEngine(float dt) {
if (sRANDOM.nextInt(300) == 0) {
final Block b = BlocksPool.acquire();
// configurar seu bloco
getDelegate().createBlock(b);
}
}

Reuse um bloco previamente existente !!!
private static final int MSG_DESIRED_EVENT = 0xb0b0;
public void sendMessage(Handler handler, Object eventInfo) {
final Message message = new Message();
message.what = MSG_DESIRED_EVENT;
message.obj = eventInfo;
handler.sendMessage(message);
}

Uma mensagem nova para cada
evento de interesse
private static final int MSG_DESIRED_EVENT = 0xb0b0;
public void sendMessage(Handler handler, Object eventInfo) {
final Message message = Message.obtain();
message.what = MSG_DESIRED_EVENT;
message.obj = eventInfo;
handler.sendMessage(message);
}

Obtém uma mensagem de um
pool, ou cria uma nova
ADAPTERS
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View cellView =
mInflater.inflate(R.layout.list_item, parent, false);
final MovieInfo i = getItem(position);

T
’
N
O
D

((TextView) cellView.findViewById(R.id.title)).setText(i.getTitle());
((TextView) cellView.findViewById(R.id.subtitle)).setText(i.getSubs());
return cellView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, parent, false);
}
final MovieInfo i = getItem(position);
((TextView) convertView.findViewById(R.id.title))
.setText(i.getTitle());
((TextView)convertView.findViewById(R.id.subtitle))
.setText(i.getSubs());
return convertView;
}

Reusa uma View já
criada se possível !
E PARA ESSE
TIPO DE LISTA ????
EXECUÇÃO ÓTIMA

CODIFIQUE PARA A PERFORMANCE
FOR LOOP
List<FacebookFriend> friends = new ArrayList<FacebookFriend>();
if (users != null) {
for (GraphUser user : users) {
FacebookFriend friend = new FacebookFriend(user);
friends.add(friend)
}
}

Otimizada pelo compilador !!!
PARCELLABLE E SERIALIZABLE

http://www.developerphil.com/parcelable-vs-serializable/
PARCELLABLE E SERIALIZABLE
Serializable é muito mais fácil de implementar
Parcellable é muito mais eficiente na prática
Serializable para um objeto
Parcellable para coleções de objetos
CACHE DE OPERAÇÕES
static class
public
public
public
}

ViewHolder {
TextView friendName;
TextView friendStatus;
ImageView friendImage;

Cachear a posição das Views na
hierarquia de Views da linha !
public abstract class FasterArrayAdapter<T> extends ArrayAdapter<T> {
@Override public View getView(int position, View convertView, ViewGroup parent) {
Object viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(layoutResourceForItem(), parent, false);
setupHolder(convertView, viewHolder);
convertView.setTag(viewHolder);
} else {
viewHolder = convertView.getTag();
}
fillHolder(viewHolder, position);
return convertView;
}
}
public abstract class FasterArrayAdapter<T> extends ArrayAdapter<T> {
@Override public View getView(int position, View convertView, ViewGroup parent) {
Object viewHolder = null;

Calcula posições e faz cache

if (convertView == null) {
convertView = mInflater.inflate(layoutResourceForItem(), parent, false);
viewHolder = new ViewHolder();
setupHolder(convertView, viewHolder);
convertView.setTag(viewHolder);
} else {
viewHolder = convertView.getTag();
}

Recupera o cache

fillHolder(viewHolder, position);
return convertView;
}
}

Preenche seu item
LEMBRETES GERAIS
OTIMIZE o acesso à suas variáveis
EVITE malabarismos com java.lang.reflect
EVITE annotations em tempo de execução
http://developer.android.com/training/articles/perf-tips.html
MULTITHREADING

HARD WORK FORA DA UI THREAD
JAVA THREADS
USE CASO TENHA CERTEZA
ABSOLUTA DO QUE ESTÁ FAZENDO !!
Se o item anterior for cumprido, então priorize
a UI Thread
private static final int MSG_DONE = 0xcafe;
private Handler mHandler = new Handler(Looper.getMainLooper());
private void workOnBigFile(final String filePath) {
new Thread(new Runnable() {
@Override
public void run() {
Process.setThreadPriority(
Process.THREAD_PRIORITY_BACKGROUND);
File f = new File(filePath);
Data d = DataUtils.extractFrom(f);
Message.obtain(mHandler, MSG_DONE, d).sendToTarget();
}
}).start();
}

Prioridade mais baixa para sua Thread
ASYNCTASK
private class DownloadFilesTask extends AsyncTask<URL, Void , Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;

}

}

for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
}
return totalSize;

protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
PROBLEMAS COM ASYNCTASK
Comportamento é inconsistente ao longo
das versões de API do Android
Difícil para cancelar tarefas já executando
em background ...
USANDO ASYNCTASK
Assegure-se de que tarefas serão
executadas em paralelo (backporting API14+)
Recomendada para tarefas curtas (segundos)
Cuidados ao declarar como inner class ou
ao associar callbacks após a execução
INTENT SERVICE
Service com uma Thread Worker
MUITO BOM para executar tarefas únicas
Finaliza sozinho após o trabalho executado
Callback mais burocrático após tarefa
executada (BroadcastReceiver)
public class HardWorkIntentService extends IntentService {
public HardWorkIntentService() {
super(“HardWorkIntentService”);
}
@Override
protected void onHandleIntent(Intent intent) {
// EXECUTE O SEU TRABALHO PESADO AQUI !!!!
}
}

Intent toHardWork = new Intent(this, HardWorkIntentService.class);
// Coloque seus parâmetros como extras!
startService(toHardWork);
LAYOUTS

VOCÊ JÁ OTIMIZOU O SEU HOJE?
HIERARQUIA DE VIEWS
Nested Linear Layout

A Crazy Title
A simple subtitle

Relative Layout
PROCESSAMENTO DE LAYOUTS
Mais lento conforme
Profundidade da hierarquia de Views
Quantidade de Views por hierarquia

Profilling via delay nos métodos
onMeasure( ), onLayout( ), onDraw( )
OTIMIZAÇÕES EM LAYOUTS
Pelo menos dois pontos básicos
Conversão de declarações em XML em hierarquias
Recuperação de itens dentro de uma hierarquia

NA PRÁTICA

Precisamos de hierarquias
mais leves e planas !!!
FLATTENING
RELATIVE LAYOUT
GRID LAYOUT
COMPOUND DRAWABLES
LAZY LOADING DE VIEWS
...
<ViewStub
android:id="@+id/stub"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:inflatedId="@+id/inflatedLayout"
android:layout="@layout/lazy_layout" />

View inflated = ((ViewStub) findViewById(R.id.stub)).inflate();
IMAGENS
São redimensionados em tempo de execução
SEMPRE FORNEÇA TODOS OS CONJUNTOS DE IMAGENS
Para imagens obtidas via IO, procure
cachear os Bitmaps já processados
CONCLUSÕES

A HORA DE PRESTAR ATENÇÃO !!!
A EXPERIÊNCIA
COM A UI CAI
UM FPS POR VEZ
NÃO GERE LIXO
DESNECESSÁRIO
REUSE SEMPRE
QUE POSSÍVEL
CODIFIQUE PARA
O DESEMPENHO
HARD WORK FORA
DA UI THREAD
OTIMIZE SEUS
LAYOUTS
“DON`T AIM CORRECT,
AIM FOR AWESOME”
Lucas Rocha,
Firefox for Android
ANDROID
DEVELOPER
@ubiratanfsoares
gplus.to/ubiratanfsoares
ubiratansoares.com.br/blog

Contenu connexe

Tendances

Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Fabrízio Mello
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o JavascriptMichel Ribeiro
 
(A13) LabMM3 - JavaScript - Arrays multidimensionais
(A13) LabMM3 - JavaScript - Arrays multidimensionais(A13) LabMM3 - JavaScript - Arrays multidimensionais
(A13) LabMM3 - JavaScript - Arrays multidimensionaisCarlos Santos
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - BrazilStephen Chin
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Carlos Duarte do Nascimento
 
A1 - Sql Injection na Prática Parte 01
A1 - Sql Injection na Prática Parte 01A1 - Sql Injection na Prática Parte 01
A1 - Sql Injection na Prática Parte 01Reinaldo Junior
 

Tendances (12)

Resta um java
Resta um javaResta um java
Resta um java
 
Cakephp 2.0 - O que mudou
Cakephp 2.0 - O que mudouCakephp 2.0 - O que mudou
Cakephp 2.0 - O que mudou
 
Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012
 
Servlets
ServletsServlets
Servlets
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 
(A13) LabMM3 - JavaScript - Arrays multidimensionais
(A13) LabMM3 - JavaScript - Arrays multidimensionais(A13) LabMM3 - JavaScript - Arrays multidimensionais
(A13) LabMM3 - JavaScript - Arrays multidimensionais
 
55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil55 New Things in Java 7 - Brazil
55 New Things in Java 7 - Brazil
 
Palestra sql injection oficial
Palestra sql injection oficialPalestra sql injection oficial
Palestra sql injection oficial
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
 
A1 - Sql Injection na Prática Parte 01
A1 - Sql Injection na Prática Parte 01A1 - Sql Injection na Prática Parte 01
A1 - Sql Injection na Prática Parte 01
 
Introdução ao Apache Ant
Introdução ao Apache AntIntrodução ao Apache Ant
Introdução ao Apache Ant
 

Similaire à Dicas para interfaces performáticas no Android

Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javJulio Viegas
 
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Rafael Ponte
 
Os 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFOs 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFtarsobessa
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineCampus Party Brasil
 
Programação funcional em JavaScript: como e por quê?
Programação funcional em JavaScript: como e por quê?Programação funcional em JavaScript: como e por quê?
Programação funcional em JavaScript: como e por quê?Arthur Xavier
 
Apache NiFi com postgresql
Apache NiFi com postgresqlApache NiFi com postgresql
Apache NiFi com postgresqlGerdan Santos
 
Apache NiFi com PostgreSQL - PGConf.Brasil 2018
Apache NiFi com PostgreSQL - PGConf.Brasil 2018Apache NiFi com PostgreSQL - PGConf.Brasil 2018
Apache NiFi com PostgreSQL - PGConf.Brasil 2018Davy Alvarenga Machado
 
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"flaviohalmeida
 
Como conectar programas em linguagem java a bases de dados
Como conectar programas em linguagem java  a bases de dadosComo conectar programas em linguagem java  a bases de dados
Como conectar programas em linguagem java a bases de dadosHenrique Fernandes
 
Drupal 7 Direto das Trincheiras
Drupal 7  Direto das TrincheirasDrupal 7  Direto das Trincheiras
Drupal 7 Direto das TrincheirasRafael Caceres
 
Backbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosBackbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosHenrique Gogó
 
Produtividade em Java com Grails
Produtividade em Java com GrailsProdutividade em Java com Grails
Produtividade em Java com GrailsWanderson Oliveira
 
Javaone Brazil 2012: Integrando Ext JS 4 com Java EE
Javaone Brazil 2012: Integrando Ext JS 4 com Java EEJavaone Brazil 2012: Integrando Ext JS 4 com Java EE
Javaone Brazil 2012: Integrando Ext JS 4 com Java EELoiane Groner
 
Integração do Flex com PHP através do AMFPHP
Integração do Flex com PHP através do AMFPHPIntegração do Flex com PHP através do AMFPHP
Integração do Flex com PHP através do AMFPHPelliando dias
 
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...Arquitetura executável: Documentando e automatizando a comunicação da equipe ...
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...WeOp - The Operations Summit
 
PHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosPHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosDaniel Brandão
 
JavaFX 8, Collections e Lambdas
JavaFX 8, Collections e LambdasJavaFX 8, Collections e Lambdas
JavaFX 8, Collections e LambdasjesuinoPower
 

Similaire à Dicas para interfaces performáticas no Android (20)

Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
Os 10 maus habitos dos desenvolvedores jsf (JustJava e CCT)
 
Os 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFOs 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSF
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App Engine
 
Programação funcional em JavaScript: como e por quê?
Programação funcional em JavaScript: como e por quê?Programação funcional em JavaScript: como e por quê?
Programação funcional em JavaScript: como e por quê?
 
Php FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHPPhp FrameWARks - sem CakePHP
Php FrameWARks - sem CakePHP
 
Apache NiFi com postgresql
Apache NiFi com postgresqlApache NiFi com postgresql
Apache NiFi com postgresql
 
Apache NiFi com PostgreSQL - PGConf.Brasil 2018
Apache NiFi com PostgreSQL - PGConf.Brasil 2018Apache NiFi com PostgreSQL - PGConf.Brasil 2018
Apache NiFi com PostgreSQL - PGConf.Brasil 2018
 
Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"Flávio Almeida MEAN Stack "to be or not to be mean"
Flávio Almeida MEAN Stack "to be or not to be mean"
 
Como conectar programas em linguagem java a bases de dados
Como conectar programas em linguagem java  a bases de dadosComo conectar programas em linguagem java  a bases de dados
Como conectar programas em linguagem java a bases de dados
 
Drupal 7 Direto das Trincheiras
Drupal 7  Direto das TrincheirasDrupal 7  Direto das Trincheiras
Drupal 7 Direto das Trincheiras
 
Backbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosBackbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectados
 
Produtividade em Java com Grails
Produtividade em Java com GrailsProdutividade em Java com Grails
Produtividade em Java com Grails
 
Javaone Brazil 2012: Integrando Ext JS 4 com Java EE
Javaone Brazil 2012: Integrando Ext JS 4 com Java EEJavaone Brazil 2012: Integrando Ext JS 4 com Java EE
Javaone Brazil 2012: Integrando Ext JS 4 com Java EE
 
Integração do Flex com PHP através do AMFPHP
Integração do Flex com PHP através do AMFPHPIntegração do Flex com PHP através do AMFPHP
Integração do Flex com PHP através do AMFPHP
 
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...Arquitetura executável: Documentando e automatizando a comunicação da equipe ...
Arquitetura executável: Documentando e automatizando a comunicação da equipe ...
 
NoSQL Livre
NoSQL LivreNoSQL Livre
NoSQL Livre
 
Firebird
FirebirdFirebird
Firebird
 
PHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosPHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de Dados
 
JavaFX 8, Collections e Lambdas
JavaFX 8, Collections e LambdasJavaFX 8, Collections e Lambdas
JavaFX 8, Collections e Lambdas
 

Dicas para interfaces performáticas no Android

  • 1. DICAS PARA INTERFACES PERFORMÁTICAS NO SEU APP ANDROID INTEL SOFTWARE DAY 2013
  • 3.
  • 4. INTERAÇÕES COM A UI Sonho de consumo são 60 FPS... A cada 16ms, um FPS certamente se perde Quanto mais FPSs perdidos, mais a experiência do usuário com a UI degrada...
  • 5. COMO PERDER FPSs UI Thread pausada na hora da interação UI Thread está executando alguma operação (lenta) no momento da interação
  • 7. GARBAGE COLLECTION Android 2.3+ implementa variante de CMS FORÇA PAUSAS DA UI THREAD PARA GC Pausas prolongadas e/ou frequentes durante a interação do usuário PRECISAM ser evitadas
  • 8.
  • 10. AUTO BOXING Map<Integer, String> map = new HashMap<Integer, String>(); map.put(1024, "Android"); map.put(2048, "performance"); map.put(5096, "matters"); List<Double> values = new ArrayList<Double>(); values.add(3.1415);
  • 12. SPARSE ARRAYS SparseArray<String> sparseArray = new SparseArray<String>(); sparseArray.put(665, "Android"); sparseArray.put(666, "rocks");
  • 13. STRINGS String facebookAvatarURL = "http://graph.facebook.com/" + facebookID + "/picture?type=large"; T ’ N O D String numberStr = "" + number;
  • 14. STRINGS String facebookAvatarURL = "http://graph.facebook.com/" + facebookID + "/picture?type=large"; .... String numberStr = "" + number; new StringBuilder();
  • 15. SEMPRE ÓTIMO ??? StringBuilder builder = new StringBuilder(); for (int i = 0; i < count; i++) { builder.append("ANDROID"); } return builder.toString();
  • 16. FATOS StringBuilder trabalha com um array de caracteres de tamanho pré-fixado... Estourar o limite significa criar um novo array de caracteres e concatenar no já existente...
  • 17. BOAS PRÁTICAS final String androidRocks = "android" + "rocks"; // Constantes serão otimizadas pelo compilador // e concatenadas em tempo de compilação final String facebookAvatarURL = GRAPH_BASE_URL.concat(facebookID); // String.concat() melhor para uma variável String StringBuilder builder = new StringBuilder(200); // Garantir que StringBuilder aloca caracteres suficientes // evita a criação de novos arrays de caracteres
  • 18. ARRAY LISTS @Override public void onCompleted(List<GraphUser> users, Response response) { List<FacebookFriend> friends = new ArrayList<FacebookFriend>(); if (users != null) { for (GraphUser user : users) { FacebookFriend friend = new FacebookFriend(user); friends.add(friend) } mAdapter = new FriendsAdapter(this, friends); mFriendsList.setAdapter(mAdapter); } }
  • 19. FATOS ArrayList, HashMaps, TreeMaps trabalham sobre Object[], uma estrutura imutável Se o tamanho pré-definido da Collection estoura, arrays subjacentes serão substituídos por novas instâncias
  • 20. BOAS PRÁTICAS DIMENSIONE o tamanho das suas listas List<FacebookFriend> friends = new ArrayList<FacebookFriend>(500); EVITE adicionar elementos em uma posição específica da lista friends.add(10,friend);
  • 23. OBJECT POOL Reusar instâncias de objetos ao invés de criar e destruir com (muita!) frequência http://en.wikipedia.org/wiki/Object_pool_pattern
  • 24. Um random por bloco public class BlocksEngine extends CCLayer { public void blocksEngine(float dt) { if (new Random().nextInt(300) == 0) { getDelegate().createBlock( new Block(Assets.block).generate(), 1, 1); } } } Novo bloco a cada chamada da engine
  • 25. Random agora é constante public static final Random sRANDOM = new Random(); public class BlocksEngine extends CCLayer { } public void blocksEngine(float dt) { if (sRANDOM.nextInt(300) == 0) { final Block b = BlocksPool.acquire(); // configurar seu bloco getDelegate().createBlock(b); } } Reuse um bloco previamente existente !!!
  • 26. private static final int MSG_DESIRED_EVENT = 0xb0b0; public void sendMessage(Handler handler, Object eventInfo) { final Message message = new Message(); message.what = MSG_DESIRED_EVENT; message.obj = eventInfo; handler.sendMessage(message); } Uma mensagem nova para cada evento de interesse
  • 27. private static final int MSG_DESIRED_EVENT = 0xb0b0; public void sendMessage(Handler handler, Object eventInfo) { final Message message = Message.obtain(); message.what = MSG_DESIRED_EVENT; message.obj = eventInfo; handler.sendMessage(message); } Obtém uma mensagem de um pool, ou cria uma nova
  • 28. ADAPTERS @Override public View getView(int position, View convertView, ViewGroup parent) { final View cellView = mInflater.inflate(R.layout.list_item, parent, false); final MovieInfo i = getItem(position); T ’ N O D ((TextView) cellView.findViewById(R.id.title)).setText(i.getTitle()); ((TextView) cellView.findViewById(R.id.subtitle)).setText(i.getSubs()); return cellView; }
  • 29. @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item, parent, false); } final MovieInfo i = getItem(position); ((TextView) convertView.findViewById(R.id.title)) .setText(i.getTitle()); ((TextView)convertView.findViewById(R.id.subtitle)) .setText(i.getSubs()); return convertView; } Reusa uma View já criada se possível !
  • 30. E PARA ESSE TIPO DE LISTA ????
  • 32. FOR LOOP List<FacebookFriend> friends = new ArrayList<FacebookFriend>(); if (users != null) { for (GraphUser user : users) { FacebookFriend friend = new FacebookFriend(user); friends.add(friend) } } Otimizada pelo compilador !!!
  • 34. PARCELLABLE E SERIALIZABLE Serializable é muito mais fácil de implementar Parcellable é muito mais eficiente na prática Serializable para um objeto Parcellable para coleções de objetos
  • 35. CACHE DE OPERAÇÕES static class public public public } ViewHolder { TextView friendName; TextView friendStatus; ImageView friendImage; Cachear a posição das Views na hierarquia de Views da linha !
  • 36. public abstract class FasterArrayAdapter<T> extends ArrayAdapter<T> { @Override public View getView(int position, View convertView, ViewGroup parent) { Object viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(layoutResourceForItem(), parent, false); setupHolder(convertView, viewHolder); convertView.setTag(viewHolder); } else { viewHolder = convertView.getTag(); } fillHolder(viewHolder, position); return convertView; } }
  • 37. public abstract class FasterArrayAdapter<T> extends ArrayAdapter<T> { @Override public View getView(int position, View convertView, ViewGroup parent) { Object viewHolder = null; Calcula posições e faz cache if (convertView == null) { convertView = mInflater.inflate(layoutResourceForItem(), parent, false); viewHolder = new ViewHolder(); setupHolder(convertView, viewHolder); convertView.setTag(viewHolder); } else { viewHolder = convertView.getTag(); } Recupera o cache fillHolder(viewHolder, position); return convertView; } } Preenche seu item
  • 38. LEMBRETES GERAIS OTIMIZE o acesso à suas variáveis EVITE malabarismos com java.lang.reflect EVITE annotations em tempo de execução http://developer.android.com/training/articles/perf-tips.html
  • 40.
  • 41. JAVA THREADS USE CASO TENHA CERTEZA ABSOLUTA DO QUE ESTÁ FAZENDO !! Se o item anterior for cumprido, então priorize a UI Thread
  • 42. private static final int MSG_DONE = 0xcafe; private Handler mHandler = new Handler(Looper.getMainLooper()); private void workOnBigFile(final String filePath) { new Thread(new Runnable() { @Override public void run() { Process.setThreadPriority( Process.THREAD_PRIORITY_BACKGROUND); File f = new File(filePath); Data d = DataUtils.extractFrom(f); Message.obtain(mHandler, MSG_DONE, d).sendToTarget(); } }).start(); } Prioridade mais baixa para sua Thread
  • 43. ASYNCTASK private class DownloadFilesTask extends AsyncTask<URL, Void , Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; } } for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); } return totalSize; protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); }
  • 44. PROBLEMAS COM ASYNCTASK Comportamento é inconsistente ao longo das versões de API do Android Difícil para cancelar tarefas já executando em background ...
  • 45. USANDO ASYNCTASK Assegure-se de que tarefas serão executadas em paralelo (backporting API14+) Recomendada para tarefas curtas (segundos) Cuidados ao declarar como inner class ou ao associar callbacks após a execução
  • 46. INTENT SERVICE Service com uma Thread Worker MUITO BOM para executar tarefas únicas Finaliza sozinho após o trabalho executado Callback mais burocrático após tarefa executada (BroadcastReceiver)
  • 47. public class HardWorkIntentService extends IntentService { public HardWorkIntentService() { super(“HardWorkIntentService”); } @Override protected void onHandleIntent(Intent intent) { // EXECUTE O SEU TRABALHO PESADO AQUI !!!! } } Intent toHardWork = new Intent(this, HardWorkIntentService.class); // Coloque seus parâmetros como extras! startService(toHardWork);
  • 49. HIERARQUIA DE VIEWS Nested Linear Layout A Crazy Title A simple subtitle Relative Layout
  • 50. PROCESSAMENTO DE LAYOUTS Mais lento conforme Profundidade da hierarquia de Views Quantidade de Views por hierarquia Profilling via delay nos métodos onMeasure( ), onLayout( ), onDraw( )
  • 51. OTIMIZAÇÕES EM LAYOUTS Pelo menos dois pontos básicos Conversão de declarações em XML em hierarquias Recuperação de itens dentro de uma hierarquia NA PRÁTICA Precisamos de hierarquias mais leves e planas !!!
  • 53. LAZY LOADING DE VIEWS ... <ViewStub android:id="@+id/stub" android:layout_width="fill_parent" android:layout_height="fill_parent" android:inflatedId="@+id/inflatedLayout" android:layout="@layout/lazy_layout" /> View inflated = ((ViewStub) findViewById(R.id.stub)).inflate();
  • 54. IMAGENS São redimensionados em tempo de execução SEMPRE FORNEÇA TODOS OS CONJUNTOS DE IMAGENS Para imagens obtidas via IO, procure cachear os Bitmaps já processados
  • 55. CONCLUSÕES A HORA DE PRESTAR ATENÇÃO !!!
  • 56. A EXPERIÊNCIA COM A UI CAI UM FPS POR VEZ
  • 60. HARD WORK FORA DA UI THREAD
  • 62. “DON`T AIM CORRECT, AIM FOR AWESOME” Lucas Rocha, Firefox for Android