آموزش پیاده سازی Retrofit در اندروید


آموزش retrofit در اندروید

کتابخانه Retrofit در اندروید چیست؟

کار اصلی که لایبرری retrofit در اندروید برای ما انجام میده اینه که HTTP Api رو برامون روی یک Interface میاره و با اتصال آسون تر ما می تونیم فقط روی نحوه پیاده سازی متدهای GET و POST ، کارهای مورد نیازمون رو عملی کنیم.

قبل اینکه وارد مثال بشیم باید یک سایتی رو بهتون معرفی کنم که یه سری داده fake در اختیارمون میذاره که به راحتی می تونیم با همین داده ها مثال رو پیش ببریم :

https://jsonplaceholder.typicode.com

انواع مدل کاری سایت jsonplaceholder

ملاحظه می کنید که در این سایت ما چند مدل کلی برای داده ها داریم. اینجا من از todos استفاده کردم.

کوئری های متوعی میتونیم روی این داده ها امتحان کنیم مثل:

https://jsonplaceholder.typicode.com/todos/19

خروجی سایت jsonplaceholder

لینک زیر یک مثال دیگر می باشد:

https://jsonplaceholder.typicode.com/todos?id=1

خروجی سایت jsonplaceholder

حالا بی هیچ حرف اضافه ای میریم سراغ مثال. فقط قبلش بطور کلی میگم قراره چه کارهایی کنیم.

  1. یک interface می سازیم که بین متدهایی که لازم داریم و سرورمون واسط میشه. یه مدل کلاس میزنیم که داده را توصیف کنه.
  2. هر jsonObject شامل چه موارد از چه نوعیه و البته متد سازنده(Constructor) و همچنین متدهای getter, setter .
  3. یه کلاس ApiClient که وظیفه ش ساخت یک نمونه از کلاس Retrofit در اندروید هست.

 

قدم اول : ساخت Layout برای Query ها

یک پروژه با یک اکتویتی خالی می سازیم. میریم داخل layout و 4 تا دکمه قرار میدیم. کدهای xml به شکل زیر می باشد.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="get todos"
        android:onClick="getTodos"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="getTodo using route parameter"
        android:onClick="getTodoUsingRouteParameter"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="get todos using query"
        android:onClick="getTodosUsingQuery"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Post todo"
        android:onClick="postTodo"/>



</LinearLayout>

خروجی مانند شکل زیر می باشد

طراحی layout برای پروژه رتروفیت در اندروید

همانطور که در کدهای XML بالا مشخص هست ، برای هر کدام از دکمه ها یک OnClick معین کردیم.

حالا با نوشتن کدهای زیر در کلاس MainActivity و بعد از OnCreate ، متدهای OnClick را برای هر کدام از دکمه ها تعریف می کنیم.

در ادامه ی مقاله کدهایی خواهیم زد که خروجی Json این Query ها را به کمک کتابخانه Retrofit در اندروید می گیریم.

public void getTodos(View view)
{

}

public void getTodoUsingRouteParameter(View view)
{

}

public void getTodosUsingQuery(View view)
{

}

public void postTodo(View view)
{

}

قدم دوم: تعریف کلاس مدل Todo

در قدم بعدی کلاس Todo را تعریف می کنیم و فیلدهای مورد نظر را برای آن مانند کد زیر می نویسیم.

public class Todo {
    private int id;
    private int userId;
    private String title;
    private boolean completed;
}

در کد بالا با زدن alt+insert می توانیم متدهای سازنده (constructor) و setter و getter را تعریف کنیم.

 

قدم سوم: تعریف کلاس واسطه برای پیاده سازی Retrofit در اندروید

حالا نیازه برای دریافت اطلاعات، یک شی از نوع retrofit در اندروید استودیو بسازیم که کارها را مدریت کند.

پس میریم سراغ ساخت کلاس ApiClient. این کلاس دارای Base_URL و یک متد static هست که یک instance از نوع Retrofit در اختیار ما قرار میدهد:

public class ApiClient {
    private static final String BASE_URL = "https://jsonplaceholder.typicode.com";
    private static Retrofit retrofit = null;

    public static Retrofit getCilent()
    {
        if(retrofit==null)
        {
            retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
        }
        return retrofit;
    }
}

کاری که از اینجا به بعد انجام میدیم تا حدی تکرار شونده هست. سه تا متد GET و یک متد POST داریم. که هر کدام را در اینترفیس مون معرفی می کنیم و سپس در اکیتیویتی اصلی هر کدام را به هر شکلی که می خواهیم پیاده سازی می کنیم.

 

قدم چهارم: کدهای مربوط به متد getTodos

متد اولمون getTodos() بود که قراره یک آرایه از جنس شی Todo بهمون برگردونه. به این شکل معرفی میشه:

public interface ApiInterface {

    @GET(“/todos”)
    Call<List<Todo>> getTodos();
    
}

داخل MainActivity باید از اینترفیس مون یک نمونه بگیریم که هر بار به کمک آن وصل بشیم.

پس یک field از نوع ApiInterface تعریف می کنیم و داخل onCreate یک نمونه از آن می سازیم.

ApiInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    apiInterface = ApiClient.getCilent().create(ApiInterface.class);
}

در قدم بعدی میریم سراغ متد getTodos() داخل MainActivity و همان call ای که تو اینترفیس زدیم را اینجا هم می نویسیم، به این شکل:

public void getTodos(View view)
{
    Call<List<Todo>> call = apiInterface.getTodos();
    call.enqueue(new Callback<List<Todo>>() {
        @Override
        public void onResponse(Call<List<Todo>> call, Response<List<Todo>> response) {
            
        }

        @Override
        public void onFailure(Call<List<Todo>> call, Throwable t) {

        }
    });
}

instance که ساختیم وظیفه ش اینه که بره و جوابی رو در قالب آرایه ای از شی todo بگیره و این لیست میتونه برای ما تداعی از یک صف داشته باشه.

این کار با صدا زدن متد enqueue انجام میشه که همون طور که میشه فکرش رو کرد، هم امکان گرفتن جواب با موفقیت هست هم ممکنه مشکلی در گرفتن جواب پیش بیاد.

پس همون اول کار براش مشخص می کنیم که در هر کدام از دو حالت چه اتفاقی بیفتد.البته شما وقتی ورودی enqueue رو new می کنید خواهید دید که خود تابع به این شکل نوشته میشه.

اولین کاری که به ذهن میرسه استفاده از لاگ مناسبه:

call.enqueue(new Callback<List<Todo>>() {
    @Override
    public void onResponse(Call<List<Todo>> call, Response<List<Todo>> response) {
        Log.e(TAG, "onResponse: " + response.body() );
    }

    @Override
    public void onFailure(Call<List<Todo>> call, Throwable t) {
        Log.e(TAG, "onFailure: " + t.getLocalizedMessage() );
    }
});

بدون شک الان با این مسیری که رفتیم موقع run گرفتن به مشکل می خوریم با یک عبارت زیبا : missing internet permission بله یادتون باشه افزودن این پرمیشن به مانیفست، موقع کار با اینترنت ضروریه.

<uses-permission android:name="android.permission.INTERNET"/>

حالا یک خروجی می گیریم. خروجی LogCat در عکس زیر مشخص است.

خروجی پروژه Retrofit در لاگ کت - 4

همون طور که می بینید عملیات response گرفتن درست انجام شده. جواب گرفتیم و لاگ کت پر شد از جیسون آبجکت های مورد نظرمون. ولی این خروجی ها، شباهتی به جیسون هایی که اول مقاله باهم دیدیم، ندارند. پس در ادامه کدهایی که مورد نیاز باشد را با هم می نویسیم.

بر میگردیم به کلاس Todo و با زدن alt + insert متد toString رو ایجاد می کنیم که متناسب با کلاسی که ساختیم override بشه.

@Override
public String toString() {
    return "Todo{" +
            "id=" + id +
            ", userId=" + userId +
            ", title='" + title + '\'' +
            ", completed=" + completed +
            '}';
}

و نتیجه کار موقع ران :

خروجی پروژه Retrofit در لاگ کت - 2

دقیقا لیستی از todo ها رو برگردوند که تمام موارد id, userId, title, completed رو دارند.

 

قدم پنجم: کدهای مربوط به متد getTodoUsingRouteParameter

حالا برمیگردیم به دومین متد در mainActivity یعنی متد getTodoUsingRouteParameter

پس برگردیم به اینترفیس مون چون نیاز داریم یک Call انجام بدیم. هنوز قصد داریم جوابی دریافت کنیم پس از نوع GET خواهد بود

با نوشتن کد زیر میگیم که بر اساس چه داده ای جواب بگیر.

@GET("/todos/{id}")
Call<Todo> getTodo(@Path("id") int id);

برمیگردیم به متد و شبیه کاری که در متد قبلی کردیم رو انجام میدیم. فقط به جای id به دلخواه یک عدد وارد کردم:

public void getTodoUsingRouteParameter(View view)
{
    Call<Todo> todoCall = apiInterface.getTodo(19);
    todoCall.enqueue(new Callback<Todo>() {
        @Override
        public void onResponse(Call<Todo> call, Response<Todo> response) {
            Log.e(TAG, "onResponse: " + response.body());
        }

        @Override
        public void onFailure(Call<Todo> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t.getLocalizedMessage() );
        }
    });
}

حالا خروجی میگیریم و مشاهده میکنیم خیلی راحت جواب گرفتیم:

خروجی پروژه Retrofit در لاگ کت - 3

 

قدم ششم: کدهای مربوط به متد getTodosUsingQuery

بریم سراغ سومین متد یعنی getTodosUsingQuery

دوباره برمی گردیم به اینترفیسی که ساخته بودیم. حالا اینجا سوالی که مطرح میشه اینکه می خواهیم چه کوئری ای بزنیم؟

برای مثال من اینجا میخوام با مشخص کردن userId  و completed یه لیست از جواب بگیرم. در jsonArray ای که دارم چه جوابی بهم برمیگردونه اگر userId=5 و completed=trueپس شکل کوئری به این صورت در میاد :

https://jsonplaceholder.typicode.com/todos?userId=5&completed=true

همین url رو به این حالت در معرفی متد مون داخل interface بیان می کنیم که برو به همون آدرس تا قسمت todos و بعد راحت تره که بگیم حالا برای هر کدوم پارامترها من یک کوئری دارم به اسم های… :

 

@GET("/todos")
Call<List<Todo>> getTodosUsingQuery(@Query("userId") int userId, @Query("completed") boolean completed);

باز برگردیم به mainActivity و متدمون رو مثل قبلی ها تکمیل می کنیم. اینجا هم بطور دستی من دوتا پارامتر مربوطه را به متد پاس دادم و نتیجه خروجی به این شکل در اومد :

خروجی پروژه Retrofit در لاگ کت - 4

public void getTodosUsingQuery(View view)
{
    Call<List<Todo>> listCall = apiInterface.getTodosUsingQuery(5, true);
    listCall.enqueue(new Callback<List<Todo>>() {
        @Override
        public void onResponse(Call<List<Todo>> call, Response<List<Todo>> response) {
            Log.e(TAG, "onResponse: " + response.body());
        }

        @Override
        public void onFailure(Call<List<Todo>> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t.getLocalizedMessage() );
        }
    });
}

اما برای متد آخر بیاین تست کنیم چه طور میشه چیزی رو به api پست کرد. سراغ اینترفیس میریم و می دونیم که محتوایی که برامون قابل دریافت بود درست چیزی مثل کلاس Todo بود پس قطعا اگر بخوایم دیتایی رو به api بدیم هم عین جواب مون باید باشه.

خب حالا می تونیم بریم متد رو تکمیل کنیم. قراره یک todo ی جدید به سرور بفرستیم. پس یک instance از کلاس Todo می گیریم و موقعی که میخواد ساخته بشه یادمون میاد متد سازنده ای (Constructor) که نوشته بودیم id هم می گرفت، اما از اونجایی که id منحصر بفرده و auto Increment هست نیازی نیست من اینجا چیزی رو به سرورم اعلام کنم.

پس یک سازنده (Constructor) مناسب این کار در نظر می گیریم که فقط سه تا فیلد لازم مون رو بتونیم مقدار دهی کنیم.

public Todo(int userId, String title, boolean completed) {
    this.userId = userId;
    this.title = title;
    this.completed = completed;
}

به روال قبلی متد رو تکمیل می کنیم :

public void postTodo(View view)
{
    Todo todo = new Todo(3, "Build last method in MainActivity", true);
    Call<Todo> todoPostCall = apiInterface.postTodo(todo);
    todoPostCall.enqueue(new Callback<Todo>() {
        @Override
        public void onResponse(Call<Todo> call, Response<Todo> response) {
            Log.e(TAG, "onResponse: " + response.body() );
        }

        @Override
        public void onFailure(Call<Todo> call, Throwable t) {
            Log.e(TAG, "onFailure: " + t.getLocalizedMessage() );
        }
    });
}

در نهایت خروجی نهایی به شکل زیر می باشد.

خروجی نهایی پروژه retofot در اندروید

 

به این پست امتیاز دهید

روی ستاره های کلیک کنید و امتیاز بدید

میانگین امتیاز / 5. تعداد:

2 دیدگاه در نوشته: “آموزش پیاده سازی Retrofit در اندروید

  1. دوست 100 گفت:

    سلام خوب بود.
    فقط در مورد متد پست گویی اینترفیس اش رو ننوشتید.
    یه سوال داشتم. استفاده از کتابخانه لوپ جی برای اتصال به سرور بهتره یا همین رتروفیت؟

    1. نسیم نژند گفت:

      سلام
      من از کتابخونه ی لوپ جی استفاده نکردم
      و راستش الان این اسم رو سرچ کردم داکیومنت هاش رو هم پیدا نکردم .

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *




Enter Captcha Here : *

Reload Image