Retrofit عبارت است از یک REST Client برای Java و Android که توسط Square ارائه می شود. این کتابخانه، بازیابی و بارگذاری JSON یا هر داده ی ساخت یافته ی دیگری را از طریق یک وب سرویس مبتنی بر REST انجام می دهد( Retrofit برای سرویس های بر پایه REST). Retrofit را می توان با یک converter تنیظم نموده و برای serialize داده ها مورد استفاده قرار داد. معمولا برای داده هایی که در فرمت JSON ذخیره شده اند از Gson استفاده می شود، با این حال شما می توانید converter های اختصاصی و دلخواه خود را جهت پردازش XML یا دیگر پروتکل ها مورد استفاده قرار دهید. Retrofit از کتابخانه ی OkHttp برای مدیریت درخواست های HTTP بهره می گیرد.
Retrofit به شما این امکان را می دهد از Converter های زیر استفاده نمایید .
Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml
برای کار با Retrofit به سه کلاس زیر احتایج دارید.
کلاس model ویژه ی نگاشت داده های JSON.
Interface هایی که عملیات و توابع HTTP را تعریف می کنند.
کلاس Retrofit.Builder – نمونه ای که از این interface استفاده می کند. Builder API امکان تعریف آدرس URL (آدرس سرویس) endpoint را برای عملیات HTTP فراهم می آورد.
می توانید با مراجعه به سایت زیر، داده های مبتنی بر JSON خود را به فرمت POJO (آبجکت های ساده و بدون متد جاوا) تبدیل نمایید.
تمرین: استفاده از Retrofit برای کوئری گرفتن و پرس و جو از Stackoverflow در اندروید
هدف از این تمرین
StackOverflow یک سایت پر بازدید است که برنامه نویس ها مشکلات برنامه نویسی خود را در آن مطرح می کنند. این سایت یک REST API ارائه می کند که به خوبی مستندسازی شده و با توضیحات لازم در اختیار توسعه دهندگان قرار می گیرد. Query ها را می توان با استفاده از این API ساخت. می توانید جهت مشاهده ی مستندات این API و استفاده از قابلیت های آن به آدرس https://api.stackexchange.com/docs/search مراجعه نمایید. در تمرین زیر با کتابخانه ی Retrofit REST و بر اساس تگ هایی که مشخص می شود، می توانید از سوال های پاسخ داده یا تایید نهایی نشده کوئری بگیرید.
در مثال جاری URL کوئری زیر را بکار می بریم. تگ ها از طریق کد ما مشخص می شوند.
https://api.stackexchange.com/2.2/search?order=desc&sort=activity&
tagged=android&site=stackoverflow
آموزش ساخت پروژه و تنظیمات اولیه
یک اپلیکیشن اندروید به نام com.vogella.android.retrofitstackoverflow ایجاد نمایید. این اپلیکیشن بایستی اسم com.vogella.android.retrofitstackoverflow را به عنوان top level package مورد استفاده قرار دهد.
کتابخانه ی زیر را به فایل build.gradle اضافه نمایید
compile ‘com.squareup.retrofit:retrofit:2.0.0-beta2’
compile ‘com.squareup.retrofit:converter-gson:2.0.0-beta2
مجوز لازم برای دسترسی به اینترنت را در فایل تنظیمات (manifest) اپلیکیشن تنظیم نمایید.
آموزش API و کلاس adapter Retrofit
در پاسخ JSON ای که از StackOverflow دریافت می شود، تنها به title و link نیاز داریم. کلاس های زیر را ایجاد نمایید.
package android.vogella.com.retrofitstackoverflow;
// This is used to map the JSON keys to the object by GSON
public class Question {
String title;
String link;
@Override
public String toString() {
return(title);
}
}
package android.vogella.com.retrofitstackoverflow;
import java.util.List;
public class StackOverflowQuestions {
List<question> items;
}
</question>
با پیاده سازی interface زیر REST API را برای Retrofit تعریف نمایید.
توجه:
از آنجایی stackoverflow پاسخ را در یک آبجکت جاسازی می کند، لازم است ساختار داده ای مورد نیاز را از نوع list تعریف نمایید.
package com.vogella.android.retrofitstackoverflow;
import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Query;
import retrofit.Call;
public interface StackOverflowAPI {
@GET(“/2.2/questions?order=desc&sort=creation&site=stackoverflow”)
Call<stackoverflowquestions> loadQuestions(@Query(“tagged”) String tags);
}</stackoverflowquestions>
یک منوی XML مشابه زیر با نام main_menu.xml ایجاد نمایید.
<!–?xml version=”1.0″ encoding=”utf-8″ ?–>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>
<item android:id=”@+id/menu_load” android:title=”Load”>
</item></menu>
<!–?xml version=”1.0″ encoding=”utf-8″ ?–>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>
<item android:id=”@+id/menu_load” android:title=”Load”>
</item></menu>
کد کلاس activity خود را طوری ویرایش نمایید که به شما امکان کوئری گرفتن از سوال هایی را بدهد که با رشته ی “android” علامت یا تگ گذاری شده اند.
package com.vogella.android.retrofitstackoverflow;
import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;
import retrofit.Call;
import retrofit.Callback;
import retrofit.GsonConverterFactory;
import retrofit.Response;
import retrofit.Retrofit;
public class MainActivity extends ListActivity implements Callback<stackoverflowquestions> {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);
ArrayAdapter<question> arrayAdapter =
new ArrayAdapter<question>(this,
android.R.layout.simple_list_item_1,
android.R.id.text1,
new ArrayList<question>());
setListAdapter(arrayAdapter);
setProgressBarIndeterminateVisibility(true);
setProgressBarVisibility(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
setProgressBarIndeterminateVisibility(true);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“https://api.stackexchange.com”)
.addConverterFactory(GsonConverterFactory.create())
.build();
// prepare call in Retrofit 2.0
StackOverflowAPI stackOverflowAPI = retrofit.create(StackOverflowAPI.class);
Call<stackoverflowquestions> call = stackOverflowAPI.loadQuestions(“android”);
//asynchronous call
call.enqueue(this);
// synchronous call would be with execute, in this case you
// would have to perform this outside the main thread
// call.execute()
// to cancel a running request
// call.cancel();
// calls can only be used once but you can easily clone them
//Call<stackoverflowquestions> c = call.clone();
//c.enqueue(this);
return true;
}
@Override
public void onResponse(Response<stackoverflowquestions> response, Retrofit retrofit) {
setProgressBarIndeterminateVisibility(false);
ArrayAdapter<question> adapter = (ArrayAdapter<question>) getListAdapter();
adapter.clear();
adapter.addAll(response.body().items);
}
@Override
public void onFailure(Throwable t) {
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
}
</question></question></stackoverflowquestions></stackoverflowquestions></stackoverflowquestions></question></question></question></stackoverflowquestions>
به منظور تست Retrofit، یک اپلیکیشن به نام Retrofit Github ایجاد نمایید. اسم com.vogella.android.retrofitgithub را به عنوان top level package مورد استفاده قرار دهید.
برای استفاده از Retrofit در اپلیکیشن مورد نظر، کتابخانه (dependency) زیر را به فایل build.gradle خود اضافه نمایید.
compile ‘com.squareup.retrofit:retrofit:2.0.0-beta2’
compile ‘com.squareup.retrofit:converter-gson:2.0.0-beta2’
مجوز لازم برای دسترسی به اینترنت را در فایل تنظیمات اپلیکیشن (manifest) تنظیم نمایید.
<!–?xml version=”1.0″ encoding=”utf-8″ ?–>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android” package=”com.vogella.android.retrofitgithub”>
<uses-permission android:name=”android.permission.INTERNET”>
<application android:allowbackup=”true” android:icon=”@mipmap/ic_launcher” android:label=”@string/app_name” android:theme=”@style/AppTheme”>
<activity android:name=”.MainActivity” android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”>
<category android:name=”android.intent.category.LAUNCHER”>
</category></action></intent-filter>
</activity>
</application>
</uses-permission></manifest>
Interface و کلاس زیر را برای Retrofit API ایجاد نمایید.
package com.vogella.android.retrofitgithub;
// This is used to map the JSON keys to the object by GSON
public class GithubRepo {
String name;
String url;
@Override
public String toString() {
return(name + ” ” + url);
}
}
package com.vogella.android.retrofitgithub;
// This is used to map the JSON keys to the object by GSON
public class GithubUser {
String login;
String name;
String email;
@Override
public String toString() {
return(login);
}
}
package com.vogella.android.retrofitgithub;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface GithubAPI {
String ENDPOINT = “https://api.github.com”;
@GET(“/users/{user}”)
Call<githubuser> getUser(@Path(“user”) String user);
@GET(“users/{user}/repos”)
Call<list<githubrepo>> getRepos(@Path(“user”) String user);
}
package com.vogella.android.retrofitgithub;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends Activity implements Callback<githubuser> {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
Gson gson = new GsonBuilder()
.setDateFormat(“yyyy-MM-dd’T’HH:mm:ssZ”)
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GithubAPI.ENDPOINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
GithubAPI githubUserAPI = retrofit.create(GithubAPI.class);
switch (view.getId()) {
case R.id.loadUserData:
// prepare call in Retrofit 2.0
Call<githubuser> callUser = githubUserAPI.getUser(“vogella”);
//asynchronous call
callUser.enqueue(this);
break;
case R.id.loadRepositories:
Call<list<githubrepo>> callRepos = githubUserAPI.getRepos(“vogella”);
//asynchronous call
callRepos.enqueue(repos);
break;
}
}
Callback repos = new Callback<list<githubrepo>>(){
@Override
public void onResponse(Call<list<githubrepo>> call, Response<list<githubrepo>> response) {
if (response.isSuccessful()) {
List<githubrepo> repos = response.body();
StringBuilder builder = new StringBuilder();
for (GithubRepo repo: repos) {
builder.append(repo.name + ” ” + repo.toString());
}
Toast.makeText(MainActivity.this, builder.toString(), Toast.LENGTH_SHORT).show();
} else
{
Toast.makeText(MainActivity.this, “Error code ” + response.code(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<list<githubrepo>> call, Throwable t) {
Toast.makeText(MainActivity.this, “Did not work ” + t.getMessage(), Toast.LENGTH_SHORT).show();
}
};
@Override
public void onResponse(Call<githubuser> call, Response<githubuser> response) {
int code = response.code();
if (code == 200) {
GithubUser user = response.body();
Toast.makeText(this, “Got the user: ” + user.email, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, “Did not work: ” + String.valueOf(code), Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<githubuser> call, Throwable t) {
Toast.makeText(this, “Nope”, Toast.LENGTH_LONG).show();
}
}
</githubuser></githubuser></githubuser></list<githubrepo></githubrepo></list<githubrepo></list<githubrepo></list<githubrepo></list<githubrepo></githubuser></githubuser></list<githubrepo></githubuser>
url مقابل https://api.github.com/users/vogellaرا در نوار آدرس مرورگر وارد نمایید. پس از پیمایش به آدرس مذکور، یک کلاس data model و interface با داده های مورد نظر ایجاد کنید. حال این داده ها را با Retrofit خوانده و در یک لیست به نمایش بگذارد.