OData + RxJava + Retrofit 2 لتطبيق Android

واجهت مشروع مع مشكلة غير مرئية حتى الآن. اضطررت إلى تدخين الوثائق وفي هذه المقالة سأخبرك بكيفية استخدام RxJava و Retrofit 2 - يمكنك حل مشكلة إنشاء عميل Odata لتطبيق Android.

شكرا جزيلا جيك وارتون لخلق هذه الأدوات المريحة.

مرحبا بكم في عالم السحر


لدينا تطبيق ، وفقًا لبروتوكول Odata ، يجب أن يستخرج البيانات من الخادم ، ويعرضها في قوائم يجب تحميلها أثناء التمرير ، وإرسال البيانات التي أنشأها المستخدم إلى الخادم. مهمة تافهة ، لكنها لم تكن هنا ، ما يعمل بدون مشكلة في Java - لا يريد العمل مع android أيضًا.

والمكتبات والوثائق على Odata فقط من Apache - Olingo و Microsoft في C #.

في هذه المقالة لن أفكر في بروتوكول Odata ، لدى Microsoft وثائق جيدة للغاية وسأترك الروابط في نهاية المقالة.

فيما يلي تعريف موجز باستخدام Wiki Open_Data_Protocol

بروتوكول البيانات المفتوحة (OData)
Open Data Protocol (OData) — - . , HTTP-, XML JSON.

4.0, OData — , OASIS.

وهنا يبدأ الجزء الأكثر إثارة للاهتمام ، Odata هو نوع من SQL في واجهة برمجة تطبيقات REST ، وهذا ما هو عليه للبيانات التي يتم إنشاؤها ديناميكيًا.

ولكن لدينا لغة مكتوبة بقوة وبدون معرفة النموذج - تعمل معالجة البيانات وتخزينها على إنشاء مهمة صعبة إلى حد ما.

الحل الذي لا يمكن أن يكون قياسيًا وموصوفًا بشكل متكرر على الشبكة.

سأقول أكثر من ذلك ، باستثناء هذه الروابط للوثائق على الشبكة - كل شيء سيئ في الموضوع.

لنقم بالسحر الآن:

قم بإنشاء خدمة للعمل مع الشبكة.

سنستخدم Retrofit 2 ومنتجات Square ذات الصلة.

أضف تبعيات إلى ملف build.gradle
// Network
    implementation 'com.squareup.retrofit2:retrofit:2.7.1' //   Retrofit 2
    implementation 'com.squareup.retrofit2:converter-gson:2.7.1' //     JSON 
    implementation 'com.squareup.okhttp3:logging-interceptor:4.3.1' //  
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1' //     RxJava
    implementation 'com.squareup.okhttp3:okhttp:4.3.1' // OkHttp -  HTTP-
listing 1

كل هذه التبعيات هي أقوى مكتبة شبكة في Java. لا أرى فائدة من

وصف كيفية العمل مع Retrofit 2 ، هنا دليل جيد: نحن نستخدم Retrofit 2 في تطبيق Android .

إنشاء فئة NetworkService:
public class NetworkService {

    private static final String TAG = "NetworkService";

    private static final NetworkService
            mInstance = new NetworkService();

    private String mToken;
    private Retrofit mRetrofit;

    public static NetworkService getInstance() {
        return mInstance;
    }

    private NetworkService() {

        RxJava2CallAdapterFactory rxAdapter =
                RxJava2CallAdapterFactory
                        .createWithScheduler(Schedulers.io());

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 

        OkHttpClient.Builder okHttpClient =
                new OkHttpClient.Builder()
                        .addInterceptor(interceptor)
                        .addInterceptor(chain -> {
                            Request newRequest =
                                    chain.request().newBuilder()
                                           .addHeader("Accept",
                                                     "application/json,text/plain,*/*")
                                           .addHeader("Content-Type",
                                                    "application/json;odata.metadata=minimal")
                                           .addHeader("Authorization", mToken)
                                    .build();

                            return chain.proceed(newRequest);
                        });

        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .create();

        mRetrofit = new Retrofit.Builder()
                .baseUrl(Const.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(rxAdapter)
                .client(okHttpClient.build())
                .build();
    }
    public ApiService getNetworkClient(){
        return mRetrofit.create(ApiService.class);
    }
}

listing 2

إنشاء API:
public interface ApiService {
//    
@GET("odata/product")
Observable<List<ProductsDto>> getProducts();
}
listing 3

وننشئ نوعًا من وحدة التحكم لسحب الطلبات:
public class ProductsController {

    private ApiService mApiService;

    private List<ProductsDto> listProducts;
    private Gson gson;

    public ProductsController() {

        mApiService = App.getNetworkService().getNetworkClient();

        listProducts = new ArrayList<>();

        gson = new Gson();
    }

    public void productsBtnClick() {

        mApiService.getProducts()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new DisposableObserver<List<ProductsDto>>() {
                    @Override
                    public void onNext(List<ProductsDto> products) {

                        listProducts.addAll(listProducts);
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }
listing 4

لذلك ، يتم تخزين نموذج بيانات Poduct على الخادم ، الذي يحتوي على بعض المعلمات والسمات. يتم نقل جميع البيانات بتنسيق JSON وللعمل نحتاج إلى فصل POJO.

أوصي في HttpLoggingInterceptor لتكوين مستوى تفاصيل الاعتراض - Level.BODY.

نقدم طلبًا مدرجًا بالقائمة رقم 4 لزيادة بنية البيانات إلى أقصى حد وستكون الإجابة تقريبًا بهذا التنسيق:

//         
//   JSON
{
  "@odata.context":"https://example.xxx/api/odata/$metadata","value":[
    {
      "name":"product","kind":"EntitySet","url":"product" //  
    },{
      "name":"blogs","kind":"EntitySet","url":"blogs"  // 
    },{
      "name":"posts","kind":"EntitySet","url":"posts"  // 
    },{
      "name":"comments","kind":"EntitySet","url":"comments" // 
    },{
      "name":"rates","kind":"EntitySet","url":"rates" // 
    }
  ]
}

قائمة 5

وبالفعل على أساس هذه البيانات من الممكن تشكيل طلب لمزيد من التلاعب بالبيانات.

أي أن هذا كائن كامل مع نوع من السلوك والسمات ، من أجل الحصول على هذه المعلومات عند إنشاء طلب ، من الضروري إضافة الشروط التي على أساسها سوف نتلقى مصدر البيانات الخاص بنا دون اختراع دراجة جديدة وبدون ثبات العكازات عليها.

ذروة وجرو فرحة الصك راحة


والآن هو لحظة حقيقية ، قوة وقوة وبساطة مكتبة التحديثية 2 . يمكنك الآن الحصول على خصائص باستخدام وثيقة خدمة Odata :

//   properties  product
@GET("odata/product?$filter=Id eq 111&$expand=dateReading($orderby=Date desc")
Observable<List<ProductsDto>> getProducts();

//  properties  blogs
@GET("odata/blogs?$orderby=Date desc")
Observable<List<BlogsDto>> getBlogs();

//        
@GET("odata/product?$filter=((Id eq 19) and (Name eq 'Available')) and ((Status eq 'OPEN') or ((Status eq 'CLOSED') and (Date ge 2020-02-13T06:39:48Z)))&$orderby=Status asc,Date desc&$top=10&$expand=AuthorId,CategoryId($expand=weight)&$count=true")
Observable<List<ProductsDto>> getProducts();
//        ,
//       . 

// :
@GET
Observable<List<ProductsDto>> getProducts(@Url String url);

قائمة 6

هنا مكتبة سيلوشكا البطولية التحديثية 2 . يأخذ Dynamic Url كل هذه الكتلة من المعلمات التي يمكنك اللعب بها في الكود طالما كان لديك ما يكفي من الخيال.

سيبدو شيئا من هذا القبيل:
private void buttonGetProduct() {
//     
        String one = "odata/product?$filter=Id eq ";
        String id = "777";
        String tree = "&$expand=dateReading($orderby=Date desc)";
        String url = one + id + tree;

        mApiService.getProduct(url)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new DisposableObserver<List<ProductDto>>() {
                    @Override
                    public void onNext(List<ProductDto> products) {

//       ,     JSON,
//         
                        mProductsDto.addAll(countersDtos);
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }
listing 7

ملخص


لقد كانت تجربة مفيدة ، والتي سارعت إلى مشاركتها ، في الوقت المناسب ستزيل هذه المقالة بالفعل مجموعة من المشاكل والأسئلة.

في المقالة ، لم أخوض في التفاصيل غير الضرورية حول التحديث التحديثي 2 و OData ، وأشرت إلى الروابط إلى الوثائق إذا كانت هناك حاجة إلى التعمق أكثر.

لا يمكنني تقديم النسخة الكاملة من الشفرة ، التي أعتذر عنها ، المنتج تجاري.

وكما هو متوقع ، الروابط:

←  وثائق Microsoft: بروتوكول البيانات المفتوح
←  الوثائق مكتبة OData 4.0 Java
←  إنشاء تطبيقات إنترنت تعمل بكامل طاقتها باستخدام بروتوكول البيانات المفتوح

All Articles