5 dicas úteis e práticas para a
rotina androidiana
Alberto Souza
•@alberto_souza
•github.com/asouza
Parsear json
•Implementação padrão do Android(org.json)
•GSON
•Outros zilhões
JSON-JavaArrayList<Imovel> imoveis = new ArrayList<Imovel>();
try {
JSONObject imoveisComTotal = new JSONObject(imoveisJSON);
JSONArray jsonArrayDeImoveis = imoveisComTotal
.getJSONArray("imoveis");
for (int i = 0; i < jsonArrayDeImoveis.length(); i++) {
JSONObject jsonObjectDoImovel = new JSONObject(
jsonArrayDeImoveis.getJSONObject(i).toString());
JSONObject jsonImovel = new JSONObject(
jsonObjectDoImovel.getString("imovel"));
Imovel imovel = criaImovelEmFuncaoDo(jsonImovel);
JSONObject jsonImobilaria = jsonImovel
.getJSONObject("imobiliaria");
imovel.setImobiliaria(criaImobiliariaEmFuncaoDo(jsonImobilaria));
Braçal
•Deu trabalho então me entregue uma vantagem
GSON
private final static Gson gson = new Gson();
gson.toJson(serializable);
Justo
•Suporta as situações mais comuns
•Mas ainda achei meio lento
•Tem que ter o modelo compatível
Benchmarks
•Todos mentirosos :)
•https://github.com/eishay/jvm-serializers
•http://martinadamek.com/2011/01/31/comparison-of-json-parsers-performance-on-android/
JACKSON
ObjectMapper mapper = new ObjectMapper();
TodosImoveis todosImoveis = mapper.readValue(imoveisJSON,TodosImoveis.class);
Simples também
•Suporta as situações mais comuns
•Mais fléxivel em relação ao mapeamento, atributo ou getter/setter
•Realmente foi mais rápido.
Fallback esperto
@JsonAnySetter
public void handleUnknown(String key, Object value) {
if (key.equals("fallback_url")) {
this.linkOriginal = value.toString();
}
}
Modo hardtry{
JsonFactory f = new JsonFactory();
JsonGenerator g = f.createJsonGenerator(new StringWriter());
g.writeStartObject();
g.writeObjectFieldStart("imovel");
g.writeStringField("titulo","Casa de praia em salvador");
g.writeStringField("descricao", "Joe");
g.writeEndObject(); // for field 'name'
g.close(); // important: will force flushing of output, close underlying output stream
}
catch(Exception e ){//catch vazio, ninguém viu}
Supostas vantagens
•Bem mais rápido
•Tem que ler na ordem dos campos do json
•Tudo braçal
Ainda integrando
•Como fazer os requests?
AsyncTask
•Faz só o básico
Problemas
•Tentativa de conexão não deu certo
Vai perder fácil?
Problemas
•Pedir a resposta gzipada?
Problemas
•Tempo máximo de espera
Deixar esperando
Feedbacktry {
new BuscaProximos(proximosFragment)
.buscaAPagina(calculaPaginaAtual());
} catch (LocationProvidersOffException e) {
new GPSAlert(proximosFragment).show();
}
Loopj Android Async Task
•Configurações prontas
CódigoConnManagerParams.setTimeout(httpParams, socketTimeout);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(maxConnections));
ConnManagerParams.setMaxTotalConnections(httpParams, DEFAULT_MAX_CONNECTIONS);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeout);
HttpConnectionParams.setConnectionTimeout(httpParams, socketTimeout);
HttpConnectionParams.setTcpNoDelay(httpParams, true);
HttpConnectionParams.setSocketBufferSize(httpParams, DEFAULT_SOCKET_BUFFER_SIZE);
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUserAgent(httpParams, String.format("android-async-http/%s (http://loopj.com/android-async-http)", VERSION));
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
httpContext = new SyncBasicHttpContext(new BasicHttpContext());
httpClient = new DefaultHttpClient(cm, httpParams);
httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
@Override
public void process(HttpRequest request, HttpContext context) {
if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
for (String header : clientHeaderMap.keySet()) {
request.addHeader(header, clientHeaderMap.get(header));
}
}
});
Loopj Android Async Task
•Retry pronto
•Tempo máximo configurado
•GZIP
•Handler para binário
Simples de usar
AsyncHttpClient client = new AsyncHttpClient();
client.get(url,tratadorDoRetorno);
Handler padrão
DefaultRequestHandler<TodosImoveis> imoveisEncontradosHandler = new DefaultRequestHandler<TodosImoveis>() {
@Override
public void onSucess(TodosImoveis result) {
BuscaPeloFiltroTask.this.onPostExecute(result);
}
//onError...
Já fiz com Async Task do android
public void execute(Integer... params) {
enganaOCaraEUsaOutraLib(params);
}
Customizando
AsyncHttpClient client = new AsyncHttpClient();
DefaultHttpClient defaultClient = (DefaultHttpClient) client.getHttpClient();
HttpRequestRetryHandler retryHandler = defaultClient.getHttpRequestRetryHandler();
client.get(url,handler);
Um pouco de performance
•Carregar imagens por exemplo
Cache
•Tamanho do cache
Problemas
•Expiração
•Memória
•Tamanho
Baseado no aparelho
•Cache pronto para usar nas apps android
LRUCache
final int memClass = ((ActivityManager) this
.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
int memoryInBytes = 1024 * 1024 * memClass;
final int cacheSize = memoryInBytes / 8;
cache = new LruCache<String,Bitmap>(maxSize);
Tamanho das entradas do cache
•Como fazemos?
Mudamos o comportamento
cache = new LruCache<String,Bitmap>(maxSize) {
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount();
};
};
Pontos lentos
•Como descobrir?
App que consome serviço
•Vai olhar o serviço
Profile
•Vamos chorar
StrictMode
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.build());
Reclamação
04-05 11:07:54.598: E/StrictMode(6032): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
04-05 11:07:54.598: E/StrictMode(6032): java.lang.Throwable: Explicit termination method 'close' not called
04-05 11:07:54.598: E/StrictMode(6032): at dalvik.system.CloseGuard.open(CloseGuard.java:184)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWindow.<init>(CursorWindow.java:137)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWindow.<init>(CursorWindow.java:41)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:689)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:687)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWindow.newFromParcel(CursorWindow.java:698)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.BulkCursorProxy.getWindow(BulkCursorNative.java:196)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.BulkCursorToCursorAdaptor.onMove(BulkCursorToCursorAdaptor.java:94)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:178)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:201)
04-05 11:07:54.598: E/StrictMode(6032): at android.database.CursorWrapper.moveToFirst(CursorWrapper.java:65)
04-05 11:07:54.598: E/StrictMode(6032): at android_maps_conflict_avoidance.com.google.common.android.AndroidConfig.getSetting(AndroidConfig.java:219)
04-05 11:07:54.598: E/StrictMode(6032): at android_maps_conflict_avoidance.com.google.common.android.AndroidConfig.getDistributionChannelInternal(AndroidConfig.java:197)
04-05 11:07:54.598: E/StrictMode(6032): at android_maps_conflict_avoidance.com.google.common.Config.init(Config.java:273)
04-05 11:07:54.598: E/StrictMode(6032): at android_maps_conflict_avoidance.com.google.common.android.AndroidConfig.<init>(AndroidConfig.java:100)
04-05 11:07:54.598: E/StrictMode(6032): at android_maps_conflict_avoidance.com.google.common.android.AndroidConfig.<init>(AndroidConfig.java:87)
04-05 11:07:54.598: E/StrictMode(6032): at com.google.android.maps.MapActivity.onCreate(MapActivity.java:419)
04-05 11:07:54.598: E/StrictMode(6032): at android.support.v4.app.FragmentActivity.onCreate(Unknown Source)
04-05 11:07:54.598: E/StrictMode(6032): at br.com.homehunter.infra.UseStorageFragmentActivity.onCreate(UseStorageFragmentActivity.java:14)
04-05 11:07:54.598: E/StrictMode(6032): at br.com.homehunter.MainActivity.onCreate(MainActivity.java:28)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.Activity.performCreate(Activity.java:4465)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.ActivityThread.access$600(ActivityThread.java:123)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
04-05 11:07:54.598: E/StrictMode(6032): at android.os.Handler.dispatchMessage(Handler.java:99)
04-05 11:07:54.598: E/StrictMode(6032): at android.os.Looper.loop(Looper.java:137)
04-05 11:07:54.598: E/StrictMode(6032): at android.app.ActivityThread.main(ActivityThread.java:4424)
04-05 11:07:54.598: E/StrictMode(6032): at java.lang.reflect.Method.invokeNative(Native Method)
04-05 11:07:54.598: E/StrictMode(6032): at java.lang.reflect.Method.invoke(Method.java:511)
04-05 11:07:54.598: E/StrictMode(6032): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
04-05 11:07:54.598: E/StrictMode(6032): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
04-05 11:07:54.598: E/StrictMode(6032): at dalvik.system.NativeStart.main(Native Method)
Mais profile
•Traceview
Marca os pontos
public void buscaAPagina(int pagina) throws LocationProvidersOffException{
Debug.startMethodTracing("buscaPagina");
//possivel código ruim aqui
Debug.stopMethodTracing();
}
Busca o arquivo
./adb pull /sdcard/buscaPagina.trace /tmp
./traceview /tmp/buscaPagina
Agora vai caçar
Comandos para o emulador
•DDMS/Emulator control
Mas...
•Já tentou controlar a bateria?
•E quando subiu o emulador com o tamanho errado
Chique
•Conectar no emulador via telnet
Comando
Alterando algumas coisas a mais
power capacity 20
window scale 0.5
Valeu!@alberto_souza
github.com/asouza
Top Related