Retrofit sample
09 Dec 2017From Hackmd : https://hackmd.io/jaW43Q3OTkCqnYJEU-NaWg?both
Outline
- What is Retrofit?
- Before start
- Http libraries
- Before start
- Http libraries
- OKhttp
- Retrofit
- Q&A
What is Retrofit?
Retrofit turns your HTTP API into a Java interface.
Before start
- RESTful API
- JSON
- Gson
- Annotation
RESTful API
rule or concept
- 每一個URI代表一種資源
- 客戶端通過四個HTTP動詞,對服務器端資源進行操作
@GET("users/list") @GET("user/{userid}")
JSON & Gson
public static <T> T fromJson(String json, Class<T> klass) {
return new Gson().fromJson(json, klass);
}
public static <T> List<T> fromJsonArray(String json, Class<T[]> klass) {
T[] objects = new Gson().fromJson(json, klass);
return objects == null ? new ArrayList<>()
: new ArrayList<T>(Arrays.asList(objects));
}
public static String toJson(Object object) {
return new GsonBuilder()
.create()
.toJson(object);
}
public String toJson() {
return new Gson().toJson(this);
}
Annotation
Usage
- Dagger
- Retrofit
- Gson
- DBflow
- Butterknife
How to build Annotation
@Bind(R.id.text)
TextView text;
- build a Annotation class
- write a Singleton class to handle TODO
- inject the class when activity oncreate
preference : https://b013040034.github.io/ohmyblog/android/2018/02/06/annotation.html
Http libraries
- HttpClient
- OkHttp
- Volley
- retrofit
OKHttp
Find the bug 1
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
OkHttpClient client = new OkHttpClient();
String url = MessageFormat.format(ApiClient.Postal, 408);
final Request request = new Request.Builder()
.url(ApiClient.BASE_URL + url)
.build();
client.newCall(request).execute().body().string();
} catch (IOException e) {
e.printStackTrace();
}
}
Error Msg 1
android.os.NetworkOnMainThreadException
Resolve 1
- build a Singleton
- init okhttp in constuctor
- write a method to handle request
public void getData(String url, Callback callback) {
final Request request = new Request.Builder()
.url(BASE_URL + url)
.build();
client.newCall(request).enqueue(callback);
}
Callback -> Find the bug 2
apiClient.getDataWithCallBack(url, new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
text.setText(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String resStr = response.body().string();
text.setText(resStr);
}
});
Error Msg 2
Only the original thread that created a view hierarchy can touch its views.
AsyncTask
new AsyncTask<String, Void, String>() {
@Override
protected String doInBackground(String... urls) {
try {
return apiClient.getDataWithAsync(url);
} catch (IOException e) {
return e.getMessage();
}
}
@Override
protected void onPostExecute(String resStr) {
text.setText(resStr);
}
};
Okhttp Conclusion
- you have to make request in work thread or use callback
- you have to change to ui thread after callback –> thread safe –> Encapsulation 封裝
Encapsulation
Volley vs Retrofit
- Gson Get : call -> get object Post : make object -> call
- Restful Api easy way to set url and data
What I expect
Lazy Lazy Lazy Lazy
- No need to custom request -> No need to encapsulation
- Api class looks like Api Document -> easy to find & add & fix api
- get object and post object
Retrofit
dependencies
dependencies {
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
}
Website
https://github.com/square/retrofit.
Singleton
public class ApiClient {
public static final String BASE_URL = "https://api/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Api : Get
public interface ApiService {
@GET("weather/{lat}/{lng}")
Call<WeatherData> getWeather(@Path("lat") String lat, @Path("lng") String lng);
}
Api : Get (Volley and okHttp)
public static final String coordinate = "weather/{0}/{1}";
String url = MessageFormat.format(ApiClient.coordinate, lat, lng);
Convert json to Object
- Website http://www.jsonschema2pojo.org/
- Plugins
Object
public class WeatherData implements Serializable {
@SerializedName("location")
public String location;
@SerializedName("temp")
public float temperature;
}
You can use Kotlin + paracle instead
Get data
public void getWeatherData() {
Retrofit retrofit = ApiClient.getClient();
apiService = retrofit.create(ApiService.class);
Call<WeatherData> data = apiService.getWeather("24","120");
data.enqueue(new Callback<WeatherData>() {
@Override
public void onResponse(Call<WeatherData> call, Response<WeatherData> response) {
WeatherData weatherData = response.body();
}
@Override
public void onFailure(Call<WeatherData> call, Throwable t) {
}
});
}
Api : Post
public interface ApiService {
@POST("AccessToken")
Call<AccessToken> getTokenDebug(@Body AccessTokenInput tokenInput);
}
Post data
Call<AccessToken> dataDebug = apiService.getTokenDebug(accessToken);
dataDebug.enqueue(new Callback<AccessToken>() {
@Override
public void onResponse(Call<AccessToken> call, Response<AccessToken> response) {
AccessToken accessToken = response.body();
caculateResult(accessToken, textResultDebug);
}
@Override
public void onFailure(Call<AccessToken> call, Throwable t) {
textResultDebug.setText(t.getMessage());
}
});
Api : Post (Volley)
- StringRequest : with param
- JsonObjectRequest : with json
Query String
@GET("news")
Call<News> getItem(@Query("type") String type);
@GET("news")
Call<News> getItem(@QueryMap Map<String, String> map);
Post with field
@FormUrlEncoded
@POST("news")
Call<User> postItem(@Field("type") String type);
@FormUrlEncoded
@POST("news")
Call<User> postItem(@FieldMap Map<String, String> map);
Other features
- 簽名 : Signature
- 標頭 : Headers
- 檔案 : Multipart
signature
https://github.com/square/okhttp/wiki/Interceptors
Multipart
https://chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files/
perference
http://square.github.io/retrofit/ https://ihower.tw/blog/archives/1542 https://itw01.com/V33WE9D.html https://bng86.gitbooks.io/android-third-party-/content/retrofit.html