كيف صنعت قاطعًا مخصصًا لأختت من خلال كووتلين

لنبدأ ببيان المشكلة.

  1. من الضروري إرسال الرمز المميز ومعرف المستخدم في كل طلب في الرأس
  2. من الضروري سحب رمز مميز ومعرّف مستخدم جديد من كل إجابة من كل إجابة
  3. يجب أن يتم حفظ البيانات المستلمة.

مكتبة تفاعل الخادم هي التحديثية. Coroutines هي المسؤولة عن multithreading.
المهمة ليست صعبة ، تحتاج فقط إلى إضافة قاطع عميل Okhttp إلى كل طلب. نصف ساعة وكل شيء جاهز ، كل شيء يعمل ، الجميع سعداء. لكنني كنت أتساءل ، هل من الممكن أن تصنع قواطع دون عميل أوخطة؟

دعنا نبدأ في حل المشاكل بالترتيب. إذا لم تكن هناك مشكلة في إضافة رأس (تحتاج فقط إلى إضافةHeaderMap في الطلب) ، فكيف يمكن الحصول على الرؤوس التي تأتي في الاستجابة؟ في غاية البساطة ، نحتاج إلى التفاف ردنا في فئة الاستجابة ، التي تحتوي على طريقة رؤوس ().

هنا كانت واجهة الاستعلام:

@FormUrlEncoded @POST("someurl/") suspend fun request1(@Field("idLast") idLastFeed: Long, @Field("autoview") autoView: Boolean, @HeaderMap headers: Map<String, String?>): Answer1 @FormUrlEncoded @POST("someurl/") suspend fun request2(@Field("ransom") ransom: Long, @HeaderMap headers: Map<String, String?>): Answer2 

لكن هذا أصبح:

 @FormUrlEncoded @POST("someurl") suspend fun request1(@Field("idLast") idLastFeed: Long, @Field("autoview") autoView: Boolean, @HeaderMap headers: Map<String, String?>?): Response<Answer1> @FormUrlEncoded @POST("someurl") suspend fun request2(@Field("ransom") ransom: Long, @HeaderMap headers: Map<String, String?>?): Response<Answer2> 

الآن لكل طلب تحتاج إلى إضافة المعلمة headersMap. دعنا ننشئ فئة RestClient منفصلة لقضية الاستعلام بحيث لا يتم سحب الرمز المميز والمعرف من المراجع المشتركة باستمرار في المقدم. هكذا اتضح:

 class RestClient(private val api: Api, private val prefs: SharedPreferences) { suspend fun request1(last: Long, autoView: Boolean): Answer1 { return api.request1(last, autoView, headers()) } suspend fun request2(id: Long): Answer2 { return api.request2(id, headers()) } private val TOKEN_KEY = "Token" private val ID_KEY = "ID" fun headers(): Map<String, String> { return mapOf( TOKEN_KEY to prefs.getString(Constants.Preferences.SP_TOKEN_KEY, ""), ID_KEY to prefs.getLong(Constants.Preferences.SP_ID, -1).toString() ) } } 

يمكن أن نرى أننا نفعل الشيء نفسه:

  1. نحصل على بعض المعلمات للطلب.
  2. إضافة رؤوس إلى الطلب.
  3. استدعاء الأسلوب.
  4. نحصل على قيم جديدة من الرؤوس.
  5. نعود النتيجة.

لماذا لا نجعل وظيفة واحدة لجميع الطلبات؟ للقيام بذلك ، قم بتعديل الاستعلامات. بدلاً من المتغيرات الفردية من النوعField ، سنستخدم الآنFieldMap. ستكون هذه هي المعلمة الأولى لوظيفة لدينا - the percher. المعلمة الثانية سيكون لدينا هو الطلب نفسه. أنا هنا Kotlin DSL (أردت حقا أن). لقد أنشأت فئة الطلب حيث قمت بإنشاء وظيفة الإرسال للاتصال بالطلب.

هذا ما تبدو عليه واجهة الاستعلام:

 @FormUrlEncoded @POST("someurl/") suspend fun feedListMap(@FieldMap map: HashMap<String, out Any>?, @HeaderMap headers: Map<String, String?>?): Response<Answer1> @FormUrlEncoded @POST("someurl/") suspend fun feedListMap(@FieldMap map: HashMap<String, out Any>?, @HeaderMap headers: Map<String, String?>?): Response<Answer2> 

وهنا هو فئة الطلب:

 class Request<T>( var fieldHashMap: java.util.HashMap<String, out Any> = hashMapOf(), var headersHashMap: Map<String, String?>? = mapOf(), var req: suspend (HashMap<String, out Any>?, Map<String, String?>?) -> Response<T>? = { _,_ -> null} ){ fun send(): Response<T>? { return runBlocking { try { req.invoke(fieldHashMap, headersHashMap) } catch (e: Exception) { throw Exception(e.message ?: " ") } catch (t: Throwable) { throw Exception(t.message ?: " ") } } } } 

الآن تبدو الفئة RestClient كالتالي:

 class RestClient(private val api: Api, private val prefs: SharedPreferences) { private val TOKEN_KEY = "Token" private val ID_KEY = "ID" fun headers(): Map<String, String> { return mapOf( TOKEN_KEY to prefs.getString(Constants.Preferences.SP_TOKEN_KEY, ""), ID_KEY to prefs.getLong(Constants.Preferences.SP_ID, -1).toString() ) } fun <T> buildRequest(request: Request<T>.() -> Unit): T? { val req = Request<T>() request(req) val res = req.send() val newToken = res?.headers()?.get(TOKEN_KEY) val newID = res?.headers()?.get(ID_KEY)?.toLong() if (newToken.notNull() && newID.notNull()) { prefs.edit() .putString(TOKEN_KEY, newToken) .putLong(ID_KEY, newID) .apply() } return res?.body() } fun fiedsMapForRequest1(last: Long, autoView: Boolean) = hashMapOf("idLast" to last, "autoview" to autoView) fun fiedsMapForRequest2(ransom: Long, autoView: Boolean) = hashMapOf("ransom" to ransom) } 

وأخيرًا ، هكذا نسمي طلباتنا في المقدم:

 try { val answer1 = restClient.buildRequest<Answer1> { fieldHashMap = restClient.fiedsMapForRequest1(1, false) headersHashMap = restClient.headers() req = api::request1 } val answer2 = restClient.buildRequest<Answer2> { fieldHashMap = restClient.fiedsMapForRequest2(1234) headersHashMap = restClient.headers() req = api::request2 } // do something with answer } catch (e: Exception) { viewState.showError(e.message.toString()) } finally { viewState.hideProgress() } 

أنا هنا قدمت قواطع مخصصة بمساعدة Kotlin.

ملحوظة: كان حل هذه المشكلة مثيرًا للغاية ، لكن للأسف ، يستخدم المشروع أداة كسر Okhttp.

Source: https://habr.com/ru/post/ar465781/


All Articles