تجديد تعليمي مثال Retrofit على Android

مرحبًا بك في درس مثال Retrofit Android. اليوم سنستخدم مكتبة Retrofit التي طورتها Square للتعامل مع استدعاءات واجهة برمجة التطبيقات REST في تطبيق Android الخاص بنا.

Retrofit Android

Retrofit هو عميل REST آمن من النوع لنظام Android و Java يهدف إلى تسهيل استهلاك خدمات الويب RESTful. لن نتناول تفاصيل إصدارات Retrofit 1.x وسنقفز مباشرة إلى Retrofit 2 التي تأتي بالعديد من الميزات الجديدة وتغيير في واجهة برمجة التطبيقات الداخلية مقارنة بالإصدارات السابقة. يستفيد Retrofit 2 تلقائيًا من OkHttp كطبقة للتواصل ويعتمد عليه. يقوم Retrofit تلقائيًا بتسلسل استجابة JSON باستخدام POJO (Plain Old Java Object) يجب تعريفه مسبقًا لهيكل JSON. لتسلسل JSON ، نحتاج إلى محول لتحويله أولاً إلى Gson. يجب علينا إضافة التبعيات التالية في ملف build.gradle الخاص بنا.

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

تم شحن تبعية OkHttp مع تبعية Retrofit 2 بالفعل. إذا كنت ترغب في استخدام تبعية OkHttp منفصلة ، يجب عليك استبعاد تبعية OkHttp من Retrofit 2 كما يلي:

compile ('com.squareup.retrofit2:retrofit:2.1.0') {  
  // استبعاد تبعية OkHttp من Retrofit وتعريف وحدة النمط الخاصة بك
  exclude module: 'okhttp'
}
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttps:3.4.1'
  • يقوم المعامل المسجل بتوليد سلسلة تسجيل تحتوي على رد كامل.
  • هناك محولات أخرى لتحليل JSON إلى النوع الضروري. يتم سرد بعضها أدناه.
  1. Jackson : com.squareup.retrofit2:converter-jackson:2.1.0
  2. Moshi : com.squareup.retrofit2:converter-moshi:2.1.0
  3. Protobuf : com.squareup.retrofit2:converter-protobuf:2.1.0
  4. Wire : com.squareup.retrofit2:converter-wire:2.1.0
  5. XML بسيط : com.squareup.retrofit2:converter-simplexml:2.1.0

أضف الإذن للوصول إلى الإنترنت في ملف AndroidManifest.xml.

معطلات OkHttp

المعطلات هي آلية قوية موجودة في OkHttp يمكن أن تراقب، وتعيد كتابة، وتعيد المحاولات للاتصالات. يمكن تقسيم المعطلات بشكل أساسي إلى فئتين:

  • معطلات التطبيق : لتسجيل معطل تطبيق، نحتاج إلى استدعاء addInterceptor() على OkHttpClient.Builder
  • معطلات الشبكة : لتسجيل معطل شبكة، استدعاء addNetworkInterceptor() بدلاً من addInterceptor()

إعداد واجهة Retrofit

package com.journaldev.retrofitintro;

import com.journaldev.retrofitintro.pojo.MultipleResource;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

class APIClient {

    private static Retrofit retrofit = null;

    static Retrofit getClient() {

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();


        retrofit = new Retrofit.Builder()
                .baseUrl("https://reqres.in")
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();



        return retrofit;
    }

}

الطريقة getClient() في الشيفرة أعلاه ستتم استدعاؤها في كل مرة أثناء إعداد واجهة Retrofit. يوفر Retrofit قائمة من التعليقات لكل من أساليب HTTP: @GET ، @POST ، @PUT ، @DELETE ، @PATCH أو @HEAD. دعونا نرى كيف تبدو صفحتنا APIInterface.java.

package com.journaldev.retrofitintro;

import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;

interface APIInterface {

    @GET("/api/unknown")
    Call<MultipleResource> doGetListResources();

    @POST("/api/users")
    Call<User> createUser(@Body User user);

    @GET("/api/users?")
    Call<UserList> doGetUserList(@Query("page") String page);

    @FormUrlEncoded
    @POST("/api/users?")
    Call<UserList> doCreateUserWithField(@Field("name") String name, @Field("job") String job);
}

في الصف أعلاه، قمنا بتعريف بعض الأساليب التي تقوم بطلبات HTTP بتعليق. @GET("/api/unknown") يستدعي doGetListResources();. doGetListResources() هو اسم الطريقة. MultipleResource.java هو نموذج POJO لكائن الاستجابة الذي يُستخدم لربط معلمات الاستجابة بمتغيراتها الخاصة. تعتبر هذه الفئات POJO كنوع إرجاع للطريقة. يتم توفير فئة POJO بسيطة لـ MultipleResources.java أدناه.

package com.journaldev.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

import java.util.ArrayList;
import java.util.List;

public class MultipleResource {

    @SerializedName("page")
    public Integer page;
    @SerializedName("per_page")
    public Integer perPage;
    @SerializedName("total")
    public Integer total;
    @SerializedName("total_pages")
    public Integer totalPages;
    @SerializedName("data")
    public List<Datum> data = null;

    public class Datum {

        @SerializedName("id")
        public Integer id;
        @SerializedName("name")
        public String name;
        @SerializedName("year")
        public Integer year;
        @SerializedName("pantone_value")
        public String pantoneValue;

    }
}

@SerializedName يتم استخدام التعليق لتحديد اسم الحقل في استجابة JSON. قم بمعاينة فئة POJO وانسخها إلى هيكل مشروع Android Studio الخاص بك. تكون فئات POJO ملفوفة في فئة Retrofit نوعها Call. ملحوظة: يتم تسلسل JSONArray كقائمة من الكائنات في فئات POJO معلمات الطريقة: هناك مجموعة واسعة من الخيارات الممكنة لتمرير المعلمات داخل الطريقة:

  • @Body – يرسل كائنات Java كجسم طلب.
  • @Url – استخدم عناوين URL ديناميكية.
  • @Query – يمكننا ببساطة إضافة معلمة الأسلوب باستخدام @Query واسم معلمة الاستعلام ، مع وصف للنوع. لترميز URL للاستعلام ، استخدم النموذج: @Query(value = "auth_token",encoded = true) String auth_token
  • @Field – إرسال البيانات كـ form-urlencoded. يتطلب ذلك تعليق @FormUrlEncoded مع الأسلوب. معلمة @Field تعمل فقط مع POST

ملاحظة: @Field تتطلب معلمة إلزامية. في حالات عدم الحاجة إلى @Field ، يمكننا استخدام @Query بدلاً من ذلك وتمرير قيمة null.

هيكل مشروع مثال Retrofit Android

يحدد حزمة pojo أربع فئات نموذج لكل من ردود نهاية API المحددة في فئة APIInterface.java. User.java

package com.journaldev.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

public class User {

    @SerializedName("name")
    public String name;
    @SerializedName("job")
    public String job;
    @SerializedName("id")
    public String id;
    @SerializedName("createdAt")
    public String createdAt;

    public User(String name, String job) {
        this.name = name;
        this.job = job;
    }


}

تُستخدم الفئة أعلاه لإنشاء جسم الاستجابة لطريقة createUser() UserList.java

package com.journaldev.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

import java.util.ArrayList;
import java.util.List;

public class UserList {

    @SerializedName("page")
    public Integer page;
    @SerializedName("per_page")
    public Integer perPage;
    @SerializedName("total")
    public Integer total;
    @SerializedName("total_pages")
    public Integer totalPages;
    @SerializedName("data")
    public List<Datum> data = new ArrayList();

    public class Datum {

        @SerializedName("id")
        public Integer id;
        @SerializedName("first_name")
        public String first_name;
        @SerializedName("last_name")
        public String last_name;
        @SerializedName("avatar")
        public String avatar;

    }
}

إنشاء_رد_المستخدم.java

package com.journaldev.retrofitintro.pojo;

import com.google.gson.annotations.SerializedName;

public class CreateUserResponse {

    @SerializedName("name")
    public String name;
    @SerializedName("job")
    public String job;
    @SerializedName("id")
    public String id;
    @SerializedName("createdAt")
    public String createdAt;
}

تعد MainActivity.java المكان الذي نقوم فيه بالاتصال بكل نقاط نهاية واجهة البرمجة التطبيقية المعرفة في فئة الواجهة وعرض كل الحقول في Toast/TextView.

package com.journaldev.retrofitintro;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.journaldev.retrofitintro.pojo.CreateUserResponse;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    TextView responseText;
    APIInterface apiInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        responseText = (TextView) findViewById(R.id.responseText);
        apiInterface = APIClient.getClient().create(APIInterface.class);


        /**
         GET List Resources
         **/
        Call<MultipleResource> call = apiInterface.doGetListResources();
        call.enqueue(new Callback<MultipleResource>() {
            @Override
            public void onResponse(Call<MultipleResource> call, Response<MultipleResource> response) {


                Log.d("TAG",response.code()+"");

                String displayResponse = "";

                MultipleResource resource = response.body();
                Integer text = resource.page;
                Integer total = resource.total;
                Integer totalPages = resource.totalPages;
                List<MultipleResource.Datum> datumList = resource.data;

                displayResponse += text + " Page\n" + total + " Total\n" + totalPages + " Total Pages\n";

                for (MultipleResource.Datum datum : datumList) {
                    displayResponse += datum.id + " " + datum.name + " " + datum.pantoneValue + " " + datum.year + "\n";
                }

                responseText.setText(displayResponse);

            }

            @Override
            public void onFailure(Call<MultipleResource> call, Throwable t) {
                call.cancel();
            }
        });

        /**
         Create new user
         **/
        User user = new User("morpheus", "leader");
        Call<User> call1 = apiInterface.createUser(user);
        call1.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                User user1 = response.body();

                Toast.makeText(getApplicationContext(), user1.name + " " + user1.job + " " + user1.id + " " + user1.createdAt, Toast.LENGTH_SHORT).show();

            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                call.cancel();
            }
        });

        /**
         GET List Users
         **/
        Call<UserList> call2 = apiInterface.doGetUserList("2");
        call2.enqueue(new Callback<UserList>() {
            @Override
            public void onResponse(Call<UserList> call, Response<UserList> response) {

                UserList userList = response.body();
                Integer text = userList.page;
                Integer total = userList.total;
                Integer totalPages = userList.totalPages;
                List<UserList.Datum> datumList = userList.data;
                Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();

                for (UserList.Datum datum : datumList) {
                    Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
                }


            }

            @Override
            public void onFailure(Call<UserList> call, Throwable t) {
                call.cancel();
            }
        });


        /**
         POST name and job Url encoded.
         **/
        Call<UserList> call3 = apiInterface.doCreateUserWithField("morpheus","leader");
        call3.enqueue(new Callback<UserList>() {
            @Override
            public void onResponse(Call<UserList> call, Response<UserList> response) {
                UserList userList = response.body();
                Integer text = userList.page;
                Integer total = userList.total;
                Integer totalPages = userList.totalPages;
                List<UserList.Datum> datumList = userList.data;
                Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();

                for (UserList.Datum datum : datumList) {
                    Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
                }

            }

            @Override
            public void onFailure(Call<UserList> call, Throwable t) {
                call.cancel();
            }
        });

    }
}

apiInterface = APIClient.getClient().create(APIInterface.class); يُستخدم لتحقيق APIClient. لتعيين الفئة النمطية للاستجابة نستخدم: MultipleResource resource = response.body(); سيتم استدعاء التطبيق لكل من النقاط النهائية وعرض رسالة Toast لها وفقًا لذلك. يضع هذا حدا لبرنامج تعليمي مثال Retrofit android. يمكنك تنزيل مشروع مثال Retrofit Android من الرابط أدناه.

تنزيل مشروع مثال Retrofit Android

Source:
https://www.digitalocean.com/community/tutorials/retrofit-android-example-tutorial