OOZOU
تواصلوا معنا
العودة إلى المدونة

استدعاء خدمة ويب باستخدام Android Architecture Component

تركّز هذه المقالة على استدعاء خدمة ويب (web service) باستخدام Android Architecture Component.

17 يوليو 2017
6 دقائق للقراءة
استدعاء خدمة ويب باستخدام Android Architecture Component

مقدمة

كان Android Architecture Component من أكثر المواضيع التي أثارت اهتمامي (وأظن أنني لست الوحيد، بل كثير من مطوّري Android). توجد اليوم بنى برمجية كثيرة مثل MVP وMVVM وغيرها. لكن Google قدّمت هذه المرة دليلًا رسميًا يساعدكم على تصميم بنية تطبيق Android، ولذلك يستحق التجربة فعلًا. سأركّز في هذه المقالة على استدعاء خدمة ويب (web service) باستخدام هذه البنية. الكود المصدري لهذا المشروع موجود على حسابي في Github. قبل البدء **تركّز هذه المقالة على استدعاء خدمة ويب باستخدام Android Architecture Component. ولن تتناول أساسيات Kotlin أو المكتبات الأخرى مثل Dagger وRetrofit _. _

كيف تبدو هذه البنية؟

الصورة أعلاه مأخوذة من موقع Android الرسمي. وأود تقسيمها إلى طبقتين.

طبقة البيانات (Data Layer)

  1. Repository: يتواصل مع مصدر البيانات المحلي (قاعدة البيانات) ومصدر البيانات البعيد (خدمة الويب)
  2. مصدر البيانات البعيد: يتصل بخدمة الويب

طبقة العرض (Presentation Layer)

  1. ViewModel: يتواصل مع الـ Repository ثم يحدّث البيانات في الواجهة (fragment/activity) تبعًا لذلك
  2. Fragment/Activity: كل ما يخص الواجهة (تجهيزها وتحديثها)

التطبيق التجريبي

يجلب التطبيق التجريبي البيانات من https://swapi.co، ويعرض قائمة بالأنواع (species) في سلسلة Star War.

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

طبقة البيانات

مصدر البيانات البعيد

نستخدم Retrofit مصدرًا للبيانات البعيدة للاتصال بخدمة الويب. الكود أدناه هو الـ interface الخاص بالـ API. إذا كنتم تستخدمون Retrofit، فهو مألوف لكم بالتأكيد.

حزمة الكود المصدري_: boonya.ben.callingwebservice.api _

interface Swapi {
    @GET("species/")
    fun getSpecies(): Call<SpeciesList>
}

يحتوي على endpoint واحد فقط من أجل التبسيط. Repository

هنا يحدث استدعاء خدمة الويب، ويشمل أيضًا استقبال البيانات والأخطاء منها. لنلقِ نظرة على الكود أدناه.

حزمة الكود المصدري: boonya.ben.callingwebservice.species

class SpeciesRepositoryImpl(val apiService: Swapi) : SpeciesRepository {

    override fun getSpecies(successHandler: (List<Species>?) -> Unit, failureHandler: (Throwable?) -> Unit) {
        apiService.getSpecies().enqueue(object : Callback<SpeciesList> {
            override fun onResponse(call: Call<SpeciesList>?, response: Response<SpeciesList>?) {
                response?.body()?.let {
                    successHandler(it.speciesList)
                }
            }

            override fun onFailure(call: Call<SpeciesList>?, t: Throwable?) {
                failureHandler(t)
            }
        })
    }
}

كما ترون، الدالة getSpecies هي دالة من رتبة أعلى (higher-order function)الدالة من رتبة أعلى** هي دالة تستقبل دوالًا كمعاملات أو تُرجع دالة. تستقبل getSpecies دالتين كوسائط

  1. (successHandler: (List<Species>?) -> Unit ) تُستدعى هذه الدالة عندما ينجح استدعاء خدمة الويب. وتستقبل List<Species>، أي بيانات الاستجابة من خدمة الويب، كوسيط. وسترون لاحقًا كيف يصل الـ ViewModelإلى هذه البيانات
  2. (failureHandler: (Throwable?) -> Unit) تُستدعى هذه الدالة عندما يفشل استدعاء خدمة الويب. وتستقبل أيضًا Throwable كوسيط، وسنتعامل معه في الـ ViewModel.

بوجود الـ Repository، لن تحتاج طبقة العرض (Activity/Fragment وViewModel) إلى الوصول مباشرة إلى المصادر البعيدة. لذلك إذا أردنا استخدام مصدر بعيد آخر بدلًا من Retrofit، يمكننا فعل ذلك دون تغيير الكود في طبقة العرض.

طبقة العرض

قبل أن نتابع، دعوني أعرّفكم بمكوّن جديد آخر اسمه LiveData.

إليكم شرحًا موجزًا.

LiveData يجعل صنف النموذج العادي قابلًا للمراقبة (observable).MutableLiveData هو تطبيق لـ LiveData. MutableLiveData يمكنه استخدام دالة اسمها setValue لإسناد قيمة جديدة إلى الـ **_LiveData. _ViewModel

الـ ViewModel مكوّن جديد قُدّم ضمن Android Architecture Component. فبدلًا من وضع كل شيء في Activity/Fragment، يمكننا فصل الكود غير المرتبط بالواجهة ونقله إلى ViewModel. إضافة إلى ذلك، يبقى الـ ViewModel قائمًا عند حدوث تغيير في الإعدادات (configuration change) مثل تدوير الشاشة. ففي العادة يُعاد إنشاء Activity/Fragment وكل ما بداخلهما عند حدوث تغيير في الإعدادات. لكن باستخدام ViewModel، يمكن إعادة استخدام النسخة الموجودة دون إنشاء نسخة جديدة.

لنلقِ نظرة على مثال. حزمة الكود المصدري: boonya.ben.callingwebservice.species

class SpeciesListViewModel : ViewModel() {

    @Inject
    lateinit var repository: SpeciesRepository

    var isLoading = MutableLiveData<Boolean>()

    var apiError = MutableLiveData<Throwable>()

    var speciesResponse = MutableLiveData<List<Species>>()

    fun getSpecies() {
        isLoading.value = true
        repository.getSpecies(
                {
                    speciesResponse.value = it
                    isLoading.value = false
                },

                {
                    apiError.value = it
                    isLoading.value = false
                })
    }
    //ignore other code
}

جهّزنا ثلاثة متغيرات من نوع MutableLiveData لتُراقَب من الـ activity/fragment.

  1. isLoading: تُضبط على true عند بدء استدعاء خدمة الويب، وتتغير إلى false عند نجاح الاستدعاء أو فشله.
  2. apiError: إذا حدث خطأ في استدعاء خدمة الويب، تُسند بيانات الـ Throwable إلى هذا المتغير.
  3. speciesResponse: عند الحصول على البيانات من خدمة الويب بنجاح، تُسند بيانات الاستجابة إلى هذا المتغير.

استدعاء الـ Repository من الـ ViewModel

لكي يستدعي الـ Repository خدمة الويب، علينا تشغيل الدالة getSpecies. وتستدعي هذه الدالة بدورها دالة أخرى في الـ Repository شرحتها في قسم Repository.

كما ترون، تستقبل repository.getSpecies(…. , ….) دالتين كوسائط. وإليكم شرح كل وسيط.

  1. الوسيط الأول هو الدالة التي تُستدعى عند نجاح استدعاء خدمة الويب. وتعود بيانات الاستجابة من خدمة الويب، ويمكن الإشارة إليها بـ it2. أما دالة الوسيط الثاني فتُستدعى عند فشل استدعاء خدمة الويب، ويمكن الإشارة إلى بيانات الـ Throwable بـ it.

Activity

لن تحتوي الـ activity إلا على الكود المرتبط بالواجهة. وإليكم كود الـ Activity.

class SpeciesActivity : AppCompatActivity() {

    private val registry = LifecycleRegistry(this)
    private lateinit var viewModel: SpeciesListViewModel
    private lateinit var adapter: SpeciesListAdapter

    override fun getLifecycle(): LifecycleRegistry = registry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_species)

        //set up ui
        viewModel = createViewModel()
        attachObserver()
        viewModel.getSpecies()
    }

    private fun attachObserver() {
        viewModel.isLoading.observe(this, Observer<Boolean> {
            it?.let { showLoadingDialog(it) }
        })
        viewModel.apiError.observe(this, Observer<Throwable> {
            it?.let { Snackbar.make(rvSpecies, it.localizedMessage, Snackbar.LENGTH_LONG).show() }
        })
        viewModel.speciesResponse.observe(this, Observer<List<Species>> {
            it?.let { adapter.notifyDataSetChanged() }
        })
    }

    private fun createViewModel(): SpeciesListViewModel =
            ViewModelProviders.of(this).get(SpeciesListViewModel::class.java).also {
                ComponentInjector.component.inject(it)
            }

    private fun showLoadingDialog(show: Boolean) {
        if (show) progressBar.visibility = View.VISIBLE else progressBar.visibility = View.GONE
    }
}

لكي تعمل الـ activity مع Android Architecture Component، يجب أن تطبّق LifecycleRegistryOwner وأن تعيد تعريف الدالة getLifeCycle() كما في الكود أعلاه.

لنلقِ نظرة أقرب على الدالة attachObserver(). ستراقب هذه الـ activity ثلاثة متغيرات MutableLiveData في الـ ViewModel.

  1. viewModel.isLoading: عند حدوث تغيير في هذا المتغير، تُستدعى الدالة showLoadingDialog لإظهار progressBar أو إخفائه2. viewModel.apiError: يظهر Snackbar برسالة الخطأ عند حدوث تغيير في هذا المتغير.
  2. viewModel.speciesResponse: يُبلَّغ الـ recycler adapter عند إسناد بيانات إلى هذه القيمة

الخلاصة

أحب Android Architecture Component كثيرًا. فهو لا يتيح لكم كتابة كود أسهل في الاختبار والصيانة فحسب، بل يحل أيضًا مشكلات يعاني منها معظم مطوّري Android، مثل التعامل مع تغيير الإعدادات. وإذا كنتم على وشك بدء مشروع جديد، فهذه البنية تستحق التجربة فعلًا.

المرجع

- https://blacklenspub.com/พอกันทีกับ-god-activity-มาวางโครงดีๆ-ด้วย-architecture-components-d89302734ab8

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

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

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد