Quem sou eu? Rafael Toledo Dev Java / Android www.rafaeltoledo.net
Integração REST Praticamente nenhum app funciona isoladamente Integração com APIs é essencial Eficiência é um requisito, sempre!
Material Necessário
Material Necessário
Material Necessário
Material Necessário Tesoura Sem Ponta (para não se machucar)
REST de Referência https://api.example.com GET - /product /product/1 /product?name=? POST - /product (json no corpo) PUT - /product/1 (json no corpo) DELETE - /product/1
Product JSON { } "id": 55041 "name": "Biscoito (ou bolacha?) Recheado", "categories-array": [ "doce", "biscoito", "bolacha" ], "description": "...", "permalink": "http://example.com/product/55041",
Método 1 - Apache HttpClient final String ENDPOINT = "https://api.example.com"; HttpClient client = DefaultHttpClient.getInstance(); HttpGet get = new HttpGet(ENDPOINT + "/product"); HttpResponse response = client.execute(get); if (response.getstatusline().getstatuscode() == HttpStatus.SC_OK) { String raw = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONArray json = new JSONArray(raw); for (int i = 0; i < json.length(); i++) { Product product = new Product(); product.setname(json.getjsonobject(i).getstring("name")); product.setid(json.getjsonobject(i).getlong("id"));...
Agravante Uso de AsyncTasks, Services ou WorkerThreads Gerenciar a request em uma thread separada / atualizar a UI na main thread
OkHttp http://square.github.io/okhttp SPDY/HTTP GZIP transparente Gerenciamento de Cache Recover automático em caso de falhas de rede
Método 1A - OkHttp Apache Wrapper HttpClient client = new OkApacheClient(); HttpGet get = new HttpGet(ENDPOINT + "/product"); HttpResponse response = client.execute(get); if (response.getstatusline().getstatuscode() == HttpStatus.SC_OK) { String raw = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONArray json = new JSONArray(raw); for (int i = 0; i < json.length(); i++) { Product product = new Product(); product.setname(json.getjsonarray(i).getstring("name"));... }
Dependências // build.gradle do módulo do app... dependencies {... compile 'com.squareup.okhttp:okhttp-apache:2.0.+' }
Método 2 - OkHttp OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(ENDPOINT + "/product").build(); Response response = client.newcall(request).execute(); String raw = response.body().string(); JSONArray json = new JSONArray(raw);...
Dependências // build.gradle do módulo do app... dependencies {... compile 'com.squareup.okhttp:okhttp:2.0.+' }
Método 2A - OkHttp + Gson public class Product { } private String name; @SerializedName("categories-array") private List<String> categoriesarray;...
Método 2A - OkHttp + Gson OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(ENDPOINT + "/product").build(); Response response = client.newcall(request).execute(); String raw = response.body().string(); JSONArray json = new JSONArray(raw); Gson gson = new Gson(); for (int i = 0; i < json.length(); i++) { Product product = gson.fromjson(json.getjsonobject(i).tostring(), Product.class);... }
Método 2A - OkHttp + Gson OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(ENDPOINT + "/product").build(); Response response = client.newcall(request).execute(); String raw = response.body().string(); Type listtype = new TypeToken<List<Product>>{}.getType(); List<Product> products = new Gson().fromJson(raw, listtype);
Dependências // build.gradle do módulo do app... dependencies {... compile 'com.squareup.okhttp:okhttp:2.0.+' compile 'com.google.code.gson:gson:2.3' }
Retrofit http://square.github.io/retrofit Transforma o seu REST em uma interface! Integração com o OkHttp (classpath)
Método 3 - Retrofit public interface ExampleService { @GET("/product") List<Product> getproducts(); @POST("/product") void saveproduct(@body Product product); @PUT("/product/{id}") void updateproduct(@path("id") long id, @Body Product product); } @DELETE("/product/{id}") void deleteproduct(@path("id") long id);
Método 3 - Retrofit public interface ExampleService { @GET("/product/{id}") Product getproduct(@path("id") long id); } @GET("/product") Product getproductbyname(@query("name") String name);
Método 3 - Retrofit public class ExampleApi { private static ExampleService instance; public static ExampleService getinstance() { if (instance == null) { RestAdapter adapter = new RestAdapter.Builder().setEndpoint("https://api.example.com").build(); instance = adapter.create(exampleservice.class); } } } return instance;
Método 3 - Retrofit E pronto! Product product = ExampleApi.getInstance().getProduct(1);
Porém Ainda depende do uso de AsyncTasks, Services ou WorkerThreads
Método 3A - Retrofit com Callbacks public interface ExampleService { @GET("/product") List<Product> getproducts(); //...modificamos para... @GET("/product") void getproducts(callback<list<product>> callback);
Método 3A - Retrofit com Callbacks E pronto! ExampleApi.getInstance().getProduct(1, new Callback<Product>() { @Override public void success(product product, Response response) {} @Override public void failure(retrofiterror error) {} });
Vantagens Gerenciado automaticamente para os callbacks serem executados na UI Dispensa o tratamento de exceptions na request (método failure)
Dependências // build.gradle do módulo do app... dependencies {... compile 'com.squareup.okhttp:okhttp:2.0.+' compile 'com.squareup.retrofit:retrofit:1.7.+' }
Calma!!! ainda pode melhorar...
Por que melhorar mais ainda? Verbosidade Código macarrônico Bagunça de código com chamadas encadeadas Muitas classes anônimas
RxJava Programação Funcional Reativa no Java É uma das grandes febres no Open Source Android hoje Ganhou mais fama ainda por causa do port Android feito pela Netflix
RxJava http://github.com/reactivex/rxjava Retrofit é compatível com RxJava! http://blog.danlew.net/ - Blog do GDE Dan Lew, com uma série de 4 tutoriais sobre RxJava
Método 4 - Retrofit e RxJava public interface ExampleService { @GET("/product/{id}") void getproduct(@path("id") long id, Callback<Product> callback); //...modificamos para... @GET("/product/{id}") Observable<Product> getproduct(@path("id") long id);
Método 4 - Retrofit e RxJava ExampleApi.getInstance().getProduct(1).subscribe(onSuccess, onerror); protected Action1<Product> onsuccess = new Action1<Product>() { @Override public void call(product product) {} }; protected Action1<Throwable> onerror = new Action1<Throwable>() { @Override public void call(throwable error) {} };
Dependências // build.gradle do módulo do app... dependencies {... compile 'com.squareup.okhttp:okhttp:2.0.+' compile 'com.squareup.retrofit:retrofit:1.7.+' compile 'com.netflix.rxjava:rxjava-android:0.20.+' }
Qual a necessidade disso? Chamada mais limpa e clara Maior coesão no tratamento de erro / sucesso Se o tratamento for comum a todas as Activities / Fragments, você pode criar a implementação comum e estender :)
Calma aí!!! E como fica o controle na thread de UI? Já testei e deu pau!
Método 4 - Retrofit e RxJava ExampleApi.getInstance().getProduct(1).observeOn(AndroidSchedulers.mainThread()).subscribe(onSuccess, onerror);
Apesar de bacana... Ainda temos o problema da "verbosidade" do Java
Retrolambda Porque o Java 5/6/7 não poderia ficar de fora! https://github.com/orfjackal/retrolambda Traz ao Java 5/6/7 uma das mais poderosas características do Java 8: o uso de lambdas!
Retrolambda Como o Java do Android é o 6 e 7 (full, a partir do Kitkat), precisávamos disso! https://github.com/evant/gradle-retrolambda
Retrolambda - Como Usar // no build.gradle principal buildscript { } dependencies { classpath 'com.android.tools.build:gradle:0.13.3' classpath 'me.tatarka:gradle-retrolambda:2.4.0' }
Retrolambda - Como Usar // no build.gradle do projeto apply plugin: 'com.android.application' apply plugin: 'retrolambda' android {... compileoptions { sourcecompatibility JavaVersion.VERSION_1_8 targetcompatibility JavaVersion.VERSION_1_8 } }
Método 4 - Sem Retrolambda ExampleApi.getInstance().getProduct(1).subscribe(onSuccess, onerror); protected Action1<Product> onsuccess = new Action1<Product>() { @Override public void call(product product) {} }; protected Action1<Throwable> onerror = new Action1<Throwable>() { @Override public void call(throwable error) {} };
Método 5 - Com Retrolambda ExampleApi.getInstance().getProduct(1).subscribe(onSuccess, onerror); protected Action1<Product> onsuccess = product -> { }; protected Action1<Throwable> onerror = error -> { };
Método 5 - Com Retrolambda protected Action1<Throwable> onerror = error -> { dialog.dismiss(); }; protected Action1<Throwable> onerror = error -> dialog.dismiss();
Obrigado! www.rafaeltoledo.net