- Rafael Toledo

Propaganda
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
Download