بدون مقدمات طويلة ، سوف أخبرك بكيفية تنظيم بنية ملائمة لتطبيقك بسرعة وسهولة. ستكون المادة مفيدة لأولئك الذين ليسوا على دراية بنمط mvvm و corotines Kotlin.
لذلك ، لدينا مهمة بسيطة: تلقي ومعالجة طلب شبكة ، لعرض النتيجة في طريقة عرض.
إجراءاتنا: من النشاط (الجزء) ، نسمي الطريقة المطلوبة ViewModel -> يصل ViewModel إلى مقبض التعديل التحديثي ، ويقوم بتنفيذ الطلب من خلال coroutines -> يتم إرسال الاستجابة إلى البيانات المباشرة كحدث -> في النشاط الذي يستقبل الحدث ، نقوم بنقل البيانات إلى العرض.
إعداد المشروع
اعتمادا على
بيان رسمي
<manifest ...> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
التحديثية الإعداد
إنشاء كائن Kotlinovsky
NetworkService . سيكون هذا عميل شبكتنا - سينجلتون
يستخدم UPD المفرد لسهولة الفهم. أشارت التعليقات إلى أنه من الأنسب استخدام انقلاب التحكم ، ولكن هذا موضوع منفصل.
object NetworkService { private const val BASE_URL = " http://www.mocky.io/v2/"
واجهة API
نستخدم الطلبات المقفلة للخدمة المزيفة.
وقفة المرح ، وهنا يبدأ سحر corutin.
نحتفل وظائفنا مع الكلمة
تعليق المرح ....التعديل التحديثي الذي تم تعلمه للعمل مع Kotlin Suspendوظائف من الإصدار 2.6.0 ، والآن ينفذ مباشرة طلب شبكة ويعيد كائنًا مع البيانات:
interface Api { @GET("5dcc12d554000064009c20fc") suspend fun getUsers( @Query("page") page: Int ): ResponseWrapper<Users> @GET("5dcc147154000059009c2104") suspend fun getUsersError( @Query("page") page: Int ): ResponseWrapper<Users> }
ResponseWrapper هي فئة مجمّع بسيطة لطلبات شبكتنا:
class ResponseWrapper<T> : Serializable { @SerializedName("response") val data: T? = null @SerializedName("error") val error: Error? = null }
تاريخ فئة
المستخدمين data class Users( @SerializedName("count") var count: Int?, @SerializedName("items") var items: List<Item?>? ) { data class Item( @SerializedName("first_name") var firstName: String?, @SerializedName("last_name") var lastName: String? ) }
ViewModel
نقوم بإنشاء فئة
BaseViewModel مجردة والتي سيتم من خلالها توريث جميع
أنواع ViewModel الخاصة بنا. هنا نسهب في مزيد من التفاصيل:
abstract class BaseViewModel : ViewModel() { var api: Api = NetworkService.retrofitService()
حدث
أحد الحلول الرائعة من Google هو الالتفاف على فصول التاريخ في فئة مجمّع الأحداث ، والتي يمكن أن يكون لدينا فيها عدة حالات ، عادةً التحميل ، والنجاح ، والخطأ.
data class Event<out T>(val status: Status, val data: T?, val error: Error?) { companion object { fun <T> loading(): Event<T> { return Event(Status.LOADING, null, null) } fun <T> success(data: T?): Event<T> { return Event(Status.SUCCESS, data, null) } fun <T> error(error: Error?): Event<T> { return Event(Status.ERROR, null, error) } } } enum class Status { SUCCESS, ERROR, LOADING }
إليك كيف تعمل. أثناء طلب الشبكة ، نقوم بإنشاء حدث بالحالة LOADING. نحن في انتظار استجابة من الخادم ثم نلف البيانات بالحدث ونرسلها بالحالة المحددة. في العرض ، نتحقق من نوع الحدث ونعتمد على الحالات المختلفة للعرض بناءً على الحالة. يعتمد النمط المعماري MVI على نفس الفلسفة.
ActivityViewModel
class ActivityViewModel : BaseViewModel() {
وأخيرا
MainActivity
class MainActivity : AppCompatActivity() { private lateinit var activityViewModel: ActivityViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) activityViewModel = ViewModelProviders.of(this).get(ActivityViewModel::class.java) observeGetPosts() buttonOneClickListener() buttonTwoClickListener() }
شفرة المصدر