4. Nice to Meet You
ā Name - Artyom
ā Age - 32
ā At Android Academy for 4 years
ā 2 of them as Mentor
ā Work @Colu as Mobile Developer(yes iOS too)
7. What is Retrofit?
ā¢Retrofit is a type-safe HTTP client for Android
ā¢Uses an abstraction, by defining interfaces representing APIs
ā¢Can be āupgradedā with different type adapter, JSON parsers, interceptors, call
adapters
ā¢Uses by default OkHttp as HTTP engine
8. Retrofit Refresher - Steps to Initialisation
1. Add Retrofit dependency in build.gradle
2. Add permission in AndroidManifest.xml
3. Create an Interface abstraction representing server APIs
4. Create ServiceProvider.java
1. Declare BaseURL for all requests
2. Create and configure OkHttp client
3. Create Retrofit Instance and add OkHttp and BaseUrl to it
4. Expose retrofit.create() method
19. Why is everything static in ServiceProvider.java?
ā¢We want same configurations on each Service
ā¢Alternatives:
A. Use Dependency Injection
B. Use Singleton
20. Make a Network Call
public class MainActivity extends AppCompatActivity {
private ColuService mColuService;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mColuService = ServiceProvider.createService(ColuService.class);
getBusinesses();
}
21. Make a Network Call
public class MainActivity extends AppCompatActivity {
private ColuService mColuService;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mColuService = ServiceProvider.createService(ColuService.class);
getBusinesses();
}
22. Make a Network Call
public class MainActivity extends AppCompatActivity {
private ColuService mColuService;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mColuService = ServiceProvider.createService(ColuService.class);
getBusinesses();
}
23. Make a Network Call
public class MainActivity extends AppCompatActivity {
private ColuService mColuService;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mColuService = ServiceProvider.createService(ColuService.class);
getBusinesses();
}
24. Make a Network Call
public class MainActivity extends AppCompatActivity {
private void getBusinesses() {
mColuService
.getBusinessesAroundMe(āAZā, 20)
.enqueue(new Callback<List<Business>>() {
// ...
});
25. Make a Network Call
public class MainActivity extends AppCompatActivity {
.enqueue(new Callback<List<Business>>() {
@Override
public void onResponse(@NonNull Call<List<Business>> call,
@NonNull Response<List<Business>> response) {
// Check response
}
@Override
public void onFailure(@NonNull Call<List<Business>> call,
@NonNull Throwable t) {
}
26. Make a Network Call
public class MainActivity extends AppCompatActivity {
.enqueue(new Callback<List<Business>>() {
@Override
public void onResponse(@NonNull Call<List<Business>> call,
@NonNull Response<List<Business>> response) {
// Check response
}
@Override
public void onFailure(@NonNull Call<List<Business>> call,
@NonNull Throwable t) {
}
27. Make a Network Call
@Override
public void onResponse(@NonNull Call<List<Business>> call,
@NonNull Response<List<Business>> response) {
// Check response
if (response.code() == 200) {
// Do awesome stuff
} else {
// Handle other response codes
}
}
28. Status Codes
ā¢ 1xx - Informational Messages (Less useful)
ā¢ 2xx - Successful
ā¢ 3xx - Another action (i.e. Not Modified)
ā¢ 4xx - Client error (i.e. bad request)
ā¢ 5xx - Server error (i.e. requested resource was not found)
31. ā It is style of software architecture
ā Stands for REpresentational State Transfer
ā Uses HTTP Protocol
ā Can transfer any data
ā Data often being transferred as JSON
REST
32. Endpoints Interface Abstraction
public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
34. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
Logical Path to Data on Server
36. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
What to Do With Data
38. HTTP Action Verbs
HTTP ACTION VERB OPERATION MEANING
POST Create new resource in database
GET Retrieve data from database
PUT Update data in database
PATCH Partially update data in database
DELETE Delete data from database
39. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
What to Do With Data
41. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
What to Do With Data
46. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
What to Do With Data
47. Call object
ā¢ Call<List<Business>> - Retrofit will take the response body and try to
convert it to Java objects.Ā
ā¢ Call<ResponseBody> - This makes the raw response payload available, but
skips the mapping to Java objects
ā¢ Call<Void> - Skips response Ā
48. Download Large Files
Use @Streaming - It will tell Retrofit that instead of moving the entire file into memory, it'll pass
along the bytes right
@Streaming
@GET("/businesses")
Call<ResponseBody> getAllBusinessesInCountry(@Query("countryCode") String
countryCode);
49. Manipulate Call objects
public class MainActivity extends AppCompatActivity {
private Call<List<Business>> mGetBusinessesCall;
private void getBusinessesAroundMe() {
mGetBusinessesCall = mColuService.getBusinessesAroundMe(āAZā, 20);
mGetBusinessesCall.enqueue(
new Callback<List<Business>>() {
ā¦
}
50. Manipulate Call objects
public class MainActivity extends AppCompatActivity {
@Override
protected void onDestroy() {
super.onDestroy();
mGetBusinessesCall.cancel();
}
51. public interface ColuService {
@GET(ā/businessesā)
@Headers("Content-Type: application/json")
Call<List<Business>> getBusinessesAroundMe(@Query("orderedBy") String orderedBy,
@Query("radius") int inRadius);
...
}
What to Do With Data
69. Get Authentication Token
{
"username": "artyom",
"password": "123456"
}
200 OK
{
"token": ā437fh97b..ā,
}
Save Token in
Storage
POST https://coluserver.com/login
70. Add Token To Each Request
200 OK + Response Body
Header Authorization: 437fh97b..
GET https://coluserver.com/businesses
71. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Original Request
Request original = chain.request();
// Get previously saved Authentication token
String token = Storage.getInstance().getToken();
Add Token To Each Request - Right Way
72. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Original Request
Request original = chain.request();
// Get previously saved Authentication token
String token = Storage.getInstance().getToken();
Add Token To Each Request - Right Way
73. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Original Request
Request original = chain.request();
// Get previously saved Authentication token
String token = Storage.getInstance().getToken();
Add Token To Each Request - Right Way
74. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", token);
// Modified request
Request request = requestBuilder.build();
// Continue with request
return chain.proceed(request);
Add Token To Each Request - Right Way
75. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", token);
// Modified request
Request request = requestBuilder.build();
// Continue with request
return chain.proceed(request);
Add Token To Each Request - Right Way
76. @Override
public Response intercept(@NonNull Chain chain) throws IOException {
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", token);
// Modified request
Request request = requestBuilder.build();
// Continue with request
return chain.proceed(request);
Add Token To Each Request - Right Way
77. ServiceProvider.java
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
// ...
// ...
.addInterceptor(new AuthenticationInterceptor()));
Add Token To Each Request - Right Way
79. Control Interceptors Functionality
public interface ColuService {
//. . .
@POST("/users/login")
@Headers("AppInternal-NoAuth:true")
Call<LoginResponse> login(@Body LoginRequest credentials);
}
The trick: Create fake headers to signal the Interceptors what to do
80. Check Internal Headers Within Interceptors
AuthenticationInterceptor.java
// Original Request
Request request = chain.request();
// if NoAuth-flag header is presenting, no authentication will be added
if (request.header("AppInternal-NoAuth") != null) {
// Remove internal header from request
request = request.newBuilder()
.removeHeader("AppInternal-NoAuth")
.build();
} else {
81. Check Internal Headers Within Interceptors
AuthenticationInterceptor.java
// Original Request
Request request = chain.request();
// if NoAuth-flag header is presenting, no authentication will be added
if (request.header("AppInternal-NoAuth") != null) {
// Remove internal header from request
request = request.newBuilder()
.removeHeader("AppInternal-NoAuth")
.build();
} else {
82. Check Internal Headers Within Interceptors
AuthenticationInterceptor.java
// Original Request
Request request = chain.request();
// if NoAuth-flag header is presenting, no authentication will be added
if (request.header("AppInternal-NoAuth") != null) {
// Remove internal header from request
request = request.newBuilder()
.removeHeader("AppInternal-NoAuth")
.build();
} else {
83. Check Internal Headers Within Interceptors
AuthenticationInterceptor.java
// Original Request
Request request = chain.request();
// if NoAuth-flag header is presenting, no authentication will be added
if (request.header("AppInternal-NoAuth") != null) {
// Remove internal header from request
request = request.newBuilder()
.removeHeader("AppInternal-NoAuth")
.build();
} else {
91. Etag/If-None-Match
200 OK + Response Body
Header ETag: X
304 Not Modified (No body included)
Header If-None-Match: X
Cached response
Will be used
GET https://coluserver.com/businesses
GET https://coluserver.com/businesses
92. If-Modified-Since/Last-Modified
200 OK + Response Body
Header Last-Modified: X
304 Not Modified (No body included)
Header If-Modified-Since: X
Cached response
Will be used
GET https://coluserver.com/businesses
GET https://coluserver.com/businesses
93. Server Caching Configuration
ā¢ āCache Control : no-storeā
Disabled
Enabled, requires verification
Enabled, no need to verify during max-age
ā¢ āCache Control : must-revalidate, max-age=120ā
ā¢ āCache Control : no-cacheā
94. Enable Caching in Application
ServiceProvider.java
private static int cacheSize = 10 * 1024 * 1024; // 10 MB
private static Cache cache = new Cache(StorageUtils.
getCacheFolder(MyApplication.getAppContext()),
cacheSize);
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder()
.cache(cache)
...
95. ServiceProvider.java
private static int cacheSize = 10 * 1024 * 1024; // 10 MB
private static Cache cache = new Cache(StorageUtils.
getCacheFolder(MyApplication.getAppContext()),
cacheSize);
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder()
.cache(cache)
...
Enable Caching in Application
96. ServiceProvider.java
private static int cacheSize = 10 * 1024 * 1024; // 10 MB
private static Cache cache = new Cache(StorageUtils.
getCacheFolder(MyApplication.getAppContext()),
cacheSize);
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder()
.cache(cache)
...
Enable Caching in Application
97. What Was Improved
1. Internet traffic saved
2. Faster response
3. Better experience + Cost savings
98. Explore More
ā¢ Future Studio Retrofit Tutorials -
https://futurestud.io/tutorials/retrofit-getting-started-and-android-client
ā¢ HTTP Caching by Ilya Grigorik -
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficienc
y/http-caching