Retrofit2 على Android باستخدام Kotlin

اليوم سننظر في العمل مع Retrofit 2. من أجل الحقيقة ، تجدر الإشارة إلى أننا سنعمل مع مكتبتين منفصلتين ، وهما Picasso و Spots-Dialar .



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



0. إنشاء المشروع



كل شيء هنا بسيط قدر الإمكان ، قم بإنشاء مشروع جديد في Android Studio ، وحدد Empty Activity. بعد ذلك ، تحتاج إلى تحديد لغة برمجة ، سيكون لدينا Kotlin.



1. أضف التبعيات



نحتاج الآن إلى إضافة جميع المكتبات المطلوبة ، لذلك نذهب إلى build.gradle ونضيف ما يلي:



dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
    implementation 'com.squareup.picasso:picasso:2.71828'

    //noinspection GradleCompatible
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.github.d-max:spots-dialog:1.1@aar'
}


كما لاحظت ، قمنا هنا بإضافة جميع المكتبات الضرورية ، بما في ذلك مربع حوار تقدم Spots. يمكنك قراءة المزيد عنها هنا. بعد ذلك ، في build.gradle (Modul: app) ، يجب علينا إدراج هذا:



 compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }


يبقى فقط الذهاب إلى البيانات وإضافة إذن لاستخدام الهاتف
  <uses-permission android:name="android.permission.INTERNET"/>




2. إضافة فئات البيانات



قبل الانتقال إلى النقطة الثانية ، نحتاج إلى معرفة من أين نحصل على البيانات؟ سيكون التحليل من هنا.



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







ما تراه على اليمين هو نصنا ، الذي قمنا بنسخه ، وما هو على اليمين هو بيانات تمت معالجتها بالفعل.



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



كود كامل
data class Movie(
    var name: String? = null,
    var realname: String? = null,
    var team: String? = null,
    var firstapperance: String? = null,
    var createdby: String? = null,
    var publisher: String? = null,
    var imageurl: String? = null,
    var bio: String? = null
)




إذا كنت تتساءل عن سبب تسمية المجلد باسم النموذج ، فسأخبرك أن:



النموذج هو المنطق المرتبط ببيانات التطبيق. بمعنى آخر ، هذه هي POJOs ، فئات للعمل مع API ، قاعدة بيانات.



3. إنشاء العميل



بعد ذلك ، نقوم بإنشاء مجلد Retrofit ، وفي المجلد نقوم بإنشاء كائن وتسميته RetrofitClient ، ثم نقوم بإنشاء متغير تحديثي من النوع Retrofit ، وبعد ذلك نقوم بإنشاء وظيفة ونسميها getCleint (baseUrl: String) ونوع الإرجاع هو Retrofit. في نص الوظيفة ، من الضروري التحقق من التعديل التحديثي للقيمة الخالية وإذا كان التعديل التحديثي فارغًا ، فسنقوم بتعيين التعديل التحديثي إلى التعديل التحديثي. يقوم الباني () بإرفاق baseUrl مع المعلمة baseUrl ، ثم إرفاق طريقة addconverterFactory مع المعلمة GsonConverterFactory.create () والبناء باستخدام البناء ( ) وإعادة التعديل التحديثي إلى نوع غير صفري



كود كامل

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
    private var retrofit: Retrofit? = null

    fun getClient(baseUrl: String): Retrofit {
        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofit!!
    }
}




يعد Builder in Retrofit مثيلًا يستخدم واجهة Builder وواجهة برمجة التطبيقات لتحديد تعريف نقطة نهاية عنوان URL لعمليات HTTP



4. العمل مع الواجهة



الواجهة - مطلوب لإنشاء فئات مجردة.



قم بإنشاء حزمة واجهة فيه وضعنا واجهة وأطلقنا عليها اسم RetrofitServieces. قم بإنشاء طلب Get بين قوسين ، واكتب علامات الاقتباس ، وفي علامات الاقتباس تشير إلى الفرع الذي سنقوم بتحليل البيانات منه ، وهذا أعجوبة. ولكن قبل ذلك، يجدر القول ما GET وطلب POST هم

GET - طلبات الحصول على البيانات من مورد محددة (الموقع)

وظيفة - ترسل البيانات إلى الخادم لمزيد من المعالجة



طيب، الآن تحتاج إلى إنشاء دالة getMovieList، والتي يجب أن تعود مكالمة من نوع MutableList، وينبغي أن يكون MutableList نوع الفيلم



كود كامل

import com.example.retrofitmarvel.Model.Movie
import retrofit2.Call
import retrofit2.http.*

interface RetrofitServices {
    @GET("marvel")
    fun getMovieList(): Call<MutableList<Movie>>
}




5. مشترك



الآن علينا إنشاء المجلد المشترك ، في هذا المجلد نضع كائنًا ونطلق عليه اسم Common ، وننشئ متغيرًا ، نسميه BASE_URL وفيه يجب أن نضع الرابط الذي نقوم بتحليل البيانات منه ، ولكن لا نضع الفرع الأخير ، حيث نتلقى البيانات منه. ... نقوم بإنشاء متغير retrofitServices ، وله طريقة get () ، ونقوم بتعيين RetrofitClient له ، وعندها فقط نقوم بشبكة طريقة getClient مع معلمة RetrofitServices :: class.java إلى RetrofitClient



كود كامل

import com.example.retrofitmarvel.Interface.RetrofitServices
import com.example.retrofitmarvel.Retrofit.RetrofitClient

object Common {
    private val BASE_URL = "https://www.simplifiedcoding.net/demos/"
    val retrofitService: RetrofitServices
        get() = RetrofitClient.getClient(BASE_URL).create(RetrofitServices::class.java)
}




6. التخطيط



انتقل إلى activity_main.xml وأضف RecyclerView هناك



XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerMovieList"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>




في مجلد التخطيط ، قم بإنشاء item_layout في عنصر الجذر ، وحدد CardView



item_layout
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="8dp"
    android:layout_margin="8dp">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="167dp">


        <ImageView
            android:id="@+id/image_movie"
            android:layout_width="0dp"
            android:layout_height="100dp"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/txt_name"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.238" />

        <TextView
            android:id="@+id/txt_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="192dp"
            android:layout_marginLeft="192dp"
            android:layout_marginTop="16dp"
            android:text="name"
            android:textColor="@android:color/black"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/txt_team"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="196dp"
            android:layout_marginLeft="196dp"
            android:layout_marginTop="8dp"
            android:text="team"
            android:textColor="@android:color/black"
            android:textSize="16sp"
            android:textStyle="normal"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/txt_name" />

        <TextView
            android:id="@+id/txt_createdby"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="184dp"
            android:layout_marginLeft="184dp"
            android:layout_marginTop="12dp"
            android:text="createdby"
            android:textColor="@android:color/black"
            android:textSize="18sp"
            android:textStyle="italic"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/txt_team" />


    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>




7. محول



الآن يتعين علينا إنشاء حزمة محول ، نضع فيها فئة ونسميها MyMovieAdapter

Adapter مسؤول عن استرداد البيانات من مجموعة بيانات وإنشاء كائنات عرض بناءً على هذه البيانات.



في فئة MyMovieAdapter ، نقوم بإنشاء متغيرات ستكون متاحة فقط في هذه الفئة الخاصة val movieList: قائمة متغيرة من النوع Movie وتحديد نوع القيمة المرتجعة ، سيكون لدينا RecyclerView.Adapter من النوع MyMovieAdapter.MyViewHolder



طرق التنفيذ ، وهي onCreateViewHolder و getItemCount و onBindViewHolder

نقوم بإنشاء فئة MyViewHolder ، في هذه الفئة نحدد المعلمة itemView: View ونوع الإرجاع RecyclerView.ViewHolder ونضع المتغيرات في جسم هذه الفئة ، على سبيل المثال:



val image: ImageView = itemView.image_movie يتم رسم image_movie من item_layout

ولذا فإننا نحدد لجميع عناصر العرض المتبقية.



دعنا ننشئ وظيفة ربط مع listItem: معلمة الفيلم ، هنا يمكننا جعل عناصر العرض قابلة للنقر ، أعتقد أنه يمكنك القيام بذلك.



بعد ذلك ، نعيد كتابة getItemCount () لتجاوز متعة getItemCount () = movieList.size. كل شيء بسيط هنا ، أنشأنا وظيفة وأعدنا movieList.size. رائع ، كل ما تبقى هو التعامل مع onBindViewHolder و onCreateViewHolder



onCreateViewHolder - يقوم بإنشاء كائن ViewHolder جديد كلما احتاجه RecyclerView.



onBindViewHolder - يأخذ كائن ViewHolder ويعين البيانات الضرورية للسطر المقابل في مكون العرض



سنقوم الآن بتحليل الحالة باستخدام نوع الإرجاع onCreateViewHolder MyViewHolder.

قم بإنشاء متغير itemView ، وقم بتعيينه LayoutInflater.from (parent.context) .inflate (R.layout.item_layout ، الأصل ، false) وأعد MyViewHolder مع معلمة itemView. انتقل الآن إلى onBindViewHolder في الجسم ، وقمنا بإنشاء قائمة متغيرة العنصر: فيلم وقم بتعيين قائمة الفيلم [موضع]. بعد ذلك ، نرفق طريقة الربط مع معلمات listItem بـ holder'y. بعد ذلك ، نستخدم مكتبة بيكاسو.



Picasso.get (). تحميل (movieList [position] .imageurl) .into (holder.image). ثم أضف holder.txt_name.text = movieList [position] .name ، وهذه هي الطريقة التي نفعل بها مع جميع عناصر العرض لدينا



كود كامل

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.example.retrofitmarvel.Model.Movie
import com.example.retrofitmarvel.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.item_layout.view.*

class MyMovieAdapter(private val context: Context,private val movieList: MutableList<Movie>):RecyclerView.Adapter<MyMovieAdapter.MyViewHolder>() {

    class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
        val image: ImageView = itemView.image_movie
        val txt_name: TextView = itemView.txt_name
        val txt_team: TextView = itemView.txt_team
        val txt_createdby: TextView = itemView.txt_createdby

        fun bind(listItem: Movie) {
            image.setOnClickListener {
                Toast.makeText(it.context, "  ${itemView.image_movie}", Toast.LENGTH_SHORT)
                    .show()
            }
            itemView.setOnClickListener {
                Toast.makeText(it.context, "  ${itemView.txt_name.text}", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return MyViewHolder(itemView)
    }

    override fun getItemCount() = movieList.size

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val listItem = movieList[position]
        holder.bind(listItem)

        Picasso.get().load(movieList[position].imageurl).into(holder.image)
        holder.txt_name.text = movieList[position].name
        holder.txt_team.text = movieList[position].team
        holder.txt_createdby.text = movieList[position].createdby
    }

}





8. MainActivity



ممتاز! غادر قليلا فقط. انتقل إلى MainActivity لتبدأ ، وسننشئ متغيرات ، ولكي لا نعلن عن نوع فارغ ، سنعلنها من خلال lateinit var mService: RetrofitServices ، نحتاج إلى إنشاء 3 أكثر من هذه ، وهي: LinearLayoutManager ، MyMovieAdapter ، AlertDialog. يمكنك الاتصال بهم ما تريد ، لا يهم. في طريقة onCreate ، نقوم بتعيين Common.retrofitServices إلى RetrofitServices. في السطر التالي ، نرفق setHasFixedSize (true) بعرض إعادة التدوير الخاص بنا - بفضل هذه الطريقة يمكننا تحسين قائمتنا ، ثم نقوم بتعيين LinearLayoutManager (هذا) إلى layoutManager الخاص بنا.



مدير التخطيط- هذا هو الشيء المسؤول عن تحديد موضع مكونات العرض التي لم تعد مرئية للمستخدم. علاوة على ذلك ، من السهل أيضًا إرفاق layoutManager بقائمتنا وتعيين layoutManager بالفعل على ذلك. حسنًا ، أعمل الآن مع مكتبة SpotsDialog. نحدد المتغير المسمى سابقًا بالنوع AlertDialog الذي قمنا بتعيينه SpotsDialog ، ونرفق طريقة Builder ، ثم نرفق طريقة setCancelablec بالمعامل الحقيقي بهذا ، يجب أن نرفق طريقة setContext مع هذه المعلمة ونعلق طريقة الإنشاء.



الآن علينا إنشاء وظيفة جديدة خارج طريقة onCreate تسمى الوظيفة getAllMovieList. في نص هذه الوظيفة ، يجب علينا تحديد مربع الحوار وإرفاق طريقة show () به ،

ثم إضافة طريقة getMovieList إلى mService .enqueue (الكائن: Callback <MutableList> {)



الآن نحن بحاجة إلى تنفيذ الطرق ، لدينا اثنان منها onResponse و onFailure

و onResponse ، وبالتحديد في نص هذه الطريقة نقوم بتعيينها إلى adaptor



MyMovieAdapter(baseContext, response.body() as MutableList<Movie>)


علاوة على ذلك ، نقوم بتعيين طريقة notifyDataSetChanged () للمحول. إلى قائمتنا ، نعلق المحول ونخصص المحول. ثم نقوم بتعيين طريقة الاستبعاد () للحوار. هذا يعني أن مربع الحوار الخاص بنا سيختفي بعد تحميل بياناتنا.



كود كامل

import android.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.retrofitmarvel.Adapter.MyMovieAdapter
import com.example.retrofitmarvel.Common.Common
import com.example.retrofitmarvel.Interface.RetrofitServices
import com.example.retrofitmarvel.Model.Movie
import com.example.retrofitmarvel.R

import dmax.dialog.SpotsDialog
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

    lateinit var mService: RetrofitServices
    lateinit var layoutManager: LinearLayoutManager
    lateinit var adapter: MyMovieAdapter
    lateinit var dialog: AlertDialog

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

        mService = Common.retrofitService
        recyclerMovieList.setHasFixedSize(true)
        layoutManager = LinearLayoutManager(this)
        recyclerMovieList.layoutManager = layoutManager
        dialog = SpotsDialog.Builder().setCancelable(true).setContext(this).build()

        getAllMovieList()
    }

    private fun getAllMovieList() {
        dialog.show()
        mService.getMovieList().enqueue(object : Callback<MutableList<Movie>> {
            override fun onFailure(call: Call<MutableList<Movie>>, t: Throwable) {

            }

            override fun onResponse(call: Call<MutableList<Movie>>, response: Response<MutableList<Movie>>) {
                adapter = MyMovieAdapter(baseContext, response.body() as MutableList<Movie>)
                adapter.notifyDataSetChanged()
                recyclerMovieList.adapter = adapter

                dialog.dismiss()
            }
        })
    }
}




ممتاز! في هذه المقالة ، تعلمنا كيفية العمل مع Retrofit2 ووضعه في RecyclerView.



All Articles