<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های محمد معین عبدی</title>
        <link>https://virgool.io/feed/@moeinDeveloper</link>
        <description>توسعه دهنده نِیتیوْ(Native) موبایل ( اندروید/آی او اس(کنارگذاشته شده)) Moeindeveloper.ir</description>
        <language>fa</language>
        <pubDate>2026-06-16 14:49:29</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/12050/avatar/lISsYK.jpeg?height=120&amp;width=120</url>
            <title>محمد معین عبدی</title>
            <link>https://virgool.io/@moeinDeveloper</link>
        </image>

                    <item>
                <title>جت پک کمپوز، انقلابی در اندروید</title>
                <link>https://virgool.io/MobileLab/%D8%AC%D8%AA-%D9%BE%DA%A9-%DA%A9%D9%85%D9%BE%D9%88%D8%B2-%D8%A7%D9%86%D9%82%D9%84%D8%A7%D8%A8%DB%8C-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-qjgop06ubo0o</link>
                <description>چند روزیه که جت پک کمپوز استیبل شده و من از وقتی که وارد کانال بتا شد از اون استفاده کردم و قصد دارم از تجربیاتم تو این مدت بگم :) از بزرگترین و مهم ترین رویداد هایی که امسال در برنامه نویسی اندروید اتفاق افتاد، میشه به این موارد اشاره کرد:انتشار نسخه 1.5 کاتلین، که به گفته‌ی شرکت جت برینز بزرگ ترین رویداد سال ۲۰۲۱ بود!نسخه بتا و در نهایت انتشار جت پک کمپوز، فریمورکی برای طراحی یو ای به صورت declarative در اندرویداندروید استدیو نسخه Arctic fox، با قابلیت های زیادی مانند ادیتور و نمایشگر جت پک کمپوز و کلی امکانات دیگه... خب حالا جت پک کمپوز چیه؟ ی ابزار برای ساخت و توسعه یو ای به صورت declarative هست که از زبان برنامه نویسی کاتلین استفاده می‌کنه و نسبت به روش و ابزار های قدیمی برای ساخت یو ای، کد کمتری نوشته میشه و باگ های کمتری در روند ساخت یو ای به وجود میاد! اگه با فلاتر یا ری اکت نیتیو کار کردید بیشتر با مفهوم declarative آشنایی دارید! اگر با مفهوم declarative آشنایی ندارید حتما مقاله های زیر را مطالعه کنید: https://virgool.io/@leaksin/%DA%A9%D8%AF%D9%90-declarative-%DB%8C%D8%A7-%D8%A7%D8%B9%D9%84%D8%A7%D9%86%DB%8C-%DA%86%DB%8C%D8%B3%D8%AA-y2wbwbq7lsnt  https://virgool.io/devAndroid/%D9%85%D9%81%D9%87%D9%88%D9%85-declarative-ui-%DB%8C%D8%A7-%D8%B1%D8%A7%D8%A8%D8%B7-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-%D8%A7%D8%B9%D9%84%D8%A7%D9%86%DB%8C-n74m3jhpl9cw از کجا جت پک کمپوز رو یاد بگیرم؟برای شروع یادگیری اول مطمئن شوید که از آخرین نسخه اندروید استدیو یعنی arctic fox استفاده می‌کنید و سپس با استفاده از داکیومنت ها و کد لب هایی که در صفحه رسمی جت پک کمپوز برای شما قرار داده شده است می‌توانید یادگیری را شروع کرده و حتی اپ های قدیمی خودتون رو با اون ریفکتور کنید :) سمپل کد های کمپوز:  https://github.com/android/compose-samples  https://github.com/jetpack-compose/jetpack-compose-awesome ریپازیتوری پروژه دانشگاه خودمو هم اینجا میذارم شاید به کارتون بیاد :)  https://github.com/moeindev/InstaWeather در آخر هم توجه‌تون رو به این رشته توییت از آقای ادیب فرامرزی از تیم تپسی در مورد جت پک کمپوز جلب می‌کنم که نکات خیلی مهمی رو راجب کمپوز توضیح داده و از تجربه‌ش با کمپوز گفته: https://twitter.com/TheSNAKY/status/1416453656870805516 تجربه شخصی خودم:برای پروژه آخر ترم دانشگاه دوست داشتم که کار جدیدی انجام بدم و از این روال تکراری استفاده از دیتابایندینگ یا ویوبایندینگ خسته شده بودم تا اینکه به فکرم رسید که از جت پک کمپوز استفاده کنم که به تازگی وارد کانال بتا شده!نکته در مورد کانال های رلیز کتابخانه های گوگل:آلفا: در این فاز خیلی از APIها استیبل نیستن و ممکنه در هر نسخه به کلی عوض بشن و مجبور بشید که کل کدی که نوشتید رو بازنویسی کنید. ( تجربه ای که تو این چند وقت با نسخه کمپوز کتابخونه لاتی(Lottie) داشتم که کلا اسم متود ها و سینتکسشو عوض کرد!)بتا: تو این فاز اکثر APIهای مربوطه استیبل شده و باگ های بزرگ و اشکالات نسخه آلفا رو نداره. این نسخه معمولا بهترین وقتیه که قصد دارید یک فریمورک رو تست کنید!آرسی(RC): باگ های جزئی نسخه بتا در این نسخه رفع شده و برای رلیز نهایی استیج شده و یکبار دیگه تست میشه.نهایی: بعد از چنل RC نسخه نهایی منتشر میشه و فاصله بین RC و رلیز نهایی معمولا کمتر از یک هفته هست!طی این چند ماه تجربه لذت بخشی از کمپوز داشتم و هیچ وقت دوست ندارم که دوباره با  XML کار کنم:) تنها مشکلی که طی این چند ماه وجود داشت سر آپدیت های اندروید استدیو و کتابخونه ها بود که بعضی وقتا باهم همخونی نداشتن و یهو کل پروژه میرفت رو هوا :( اگه بازم وقت داشته باشم این مقاله رو کامل تر می‌کنم و ی سری مقاله راجب کمپوز منتشر می‌کنم پس یادتون نره انتشارات و من رو فالو کنید که اگه مطلب جدیدی گذاشتم سریعتر خبردار بشید :) </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 30 Jul 2021 18:42:01 +0430</pubDate>
            </item>
                    <item>
                <title>گریدل پروژتو تمیز کن</title>
                <link>https://virgool.io/MobileLab/%DA%AF%D8%B1%DB%8C%D8%AF%D9%84-%D9%BE%D8%B1%D9%88%DA%98%D8%AA%D9%88-%D8%AA%D9%85%DB%8C%D8%B2-%DA%A9%D9%86-uwzwrbyofpb0</link>
                <description>چند وقتیه که کثیف بودن گریدلم خیلی رو اعصاب بوده و گریدل اکثر پروژه هام در بهترین حالت ممکن این شکلی بود:Beforeو حالا با استفاده از Kotlin DSL میشه یکم مرتب ترش کرد:نکته: دو اسکریپت بالا واسه دو پروژه مختلف هستن و ربطی به هم ندارن! اما پروسه تغییر به کاتلین DSL رو این پایین می‌نویسم.برای اطلاعات بیشتر ارائه سنا عبادی رو در لاگ کت ببینید: https://www.youtube.com/playlist?list=PLT2xIm2X7W7jRcn9QvxaUA1JoZ3jrHv7W مرحله اول، ساخت پوشه buildSrc: در root پروژه خودتون، پوشه buildSource رو به صورت زیر و با این ترتیب بنویسید:بعد ساخت پوشه ابتدا پوشه سورس رو به ترتیب: src -&gt; main -&gt; javaایجاد کنید و فایل Dependencies.kt رو داخلش بسازید. بعد از این مرحله، گریدل اسکریپت خودتون رو داخل پوشه buildSrc ایجاد کنید:build.gradle.kts:import org.gradle.kotlin.dsl.`kotlin-dsl`
plugins {
    `kotlin-dsl`
}

repositories {
    jcenter()
}حالا پروژه رو sync کنید و منتظر بمانید!بعد از sync شدن پروژه، دو پوشه gradle و build به پوشه buildSrc اضافه میشه که اگه از ورژن کنترل(git) استفاده می‌کنید، بهتره که اونارو به gitignore اضافه کنید. به صورت دستی فایل گیت ایگنور رو اضافه کنید و به صورت زیر عمل کنید:.gradle
/buildحالا نوبت اینه که پروژه اصلیمون رو به کاتلین DSL منتقل کنیم!مرحله دوم، تغییر Settings به kts: settings.gradle:include &#039;:app&#039;
rootProject.name = &amp;quotStationery&amp;quotsettings.gradle.kts:include(&amp;quot:app&amp;quot)
rootProject.name = &amp;quotStationery&amp;quotپروژه رو Sync کنید.مرحله سوم، تغییر فایل های build:ابتدا فایل Dependencies رو به اینصورت بنویسید:object Dependencies {

    object Versions {
    }

    object DefaultConfig {
    }

    object Plugins {
    }

    object Libraries {
        object Test {
        }
    }

    object ClassPaths {
    }
}آبجکت Versions برای نگه داری نسخه ها، آبجکت DefaultConfig برای نگه داری کانفیگ گریدل app، آبجکت Plugins برای نگه داری پلاگین ها، آبجکت Libraries برای نگه داری کتابخونه ها و آبجکت Test برای نگه داری کتابخونه های تست، آبجکت ClassPaths برای نگه داری ClassPath های ما ?اول ClassPath ها و ورژنای اونارو اضافه می کنیم:object Versions {
    const val gradle = &amp;quot4.1.0&amp;quot
    const val kotlin = &amp;quot1.4.10&amp;quot
}object ClassPaths {
    const val gradle = &amp;quotcom.android.tools.build:gradle:${Versions.gradle}&amp;quot
    const val kotlin = &amp;quotgradle-plugin&amp;quot
}بیلد گردیل ماژول پروژه رو ویرایش می‌کنیم:build.gradle:// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = &amp;quot1.3.72&amp;quot
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath &amp;quotcom.android.tools.build:gradle:4.1.0&amp;quot
        classpath &amp;quotorg.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version&amp;quot

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}build.gradle.kts:// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        jcenter()
        mavenCentral()
        maven { url = uri(&amp;quothttps://jitpack.io&amp;quot) }
    }
    dependencies {
        classpath(Dependencies.ClassPaths.gradle)
        classpath(kotlin(Dependencies.ClassPaths.kotlin, version = Dependencies.Versions.kotlin))

        classpath(Dependencies.ClassPaths.hilt)
        classpath(Dependencies.ClassPaths.safeArgs)
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
        maven { url = uri(&amp;quothttps://jitpack.io&amp;quot) }
    }
}

tasks.register(&amp;quotclean&amp;quot,Delete::class){
    delete(rootProject.buildDir)
}حالا میرسیم به تغییر گریدل ماژول اپ، اول اطلاعاتی که لازم داریم رو داخل Dependencies که ساختیم اضافه میکنیم:object Dependencies {

    object Versions {
        const val gradle = &amp;quot4.1.0&amp;quot
        const val kotlin = &amp;quot1.4.10&amp;quot
        const val coreKTX = &amp;quot1.3.1&amp;quot
        const val appCompat = &amp;quot1.2.0&amp;quot
        const val constraintLayout = &amp;quot2.0.1&amp;quot
        const val legacySupport = &amp;quot1.0.0&amp;quot
        const val espresso = &amp;quot3.3.0&amp;quot
        const val jUnit = &amp;quot4.13&amp;quot
        const val arch = &amp;quot2.1.0&amp;quot
        const val concurrent = &amp;quot1.1.0&amp;quot
        const val lifeCycle = &amp;quot2.2.0&amp;quot
        const val hilt = &amp;quot2.28-alpha&amp;quot
        const val hiltAndroid = &amp;quot1.0.0-alpha02&amp;quot
        const val leakCanary = &amp;quot2.4&amp;quot
    }

    const val compileSdkVersion = 30
    const val buildToolsVersion = &amp;quot30.0.2&amp;quot

    object DefaultConfig {
        const val applicationID = &amp;quotir.moeindeveloper.stationery&amp;quot
        const val minSdKVersion = 19
        const val targetSdkVersion = 30
        const val versionCode = 1
        const val versionName = &amp;quot1.0&amp;quot
        const val testInstrumentationRunner = &amp;quotandroidx.test.runner.AndroidJUnitRunner&amp;quot
    }

    object Plugins {
        const val application = &amp;quotcom.android.application&amp;quot
        const val android = &amp;quotandroid&amp;quot
        const val kotlinExtensions = &amp;quotandroid.extensions&amp;quot
        const val kapt = &amp;quotkapt&amp;quot
        const val hilt = &amp;quotdagger.hilt.android.plugin&amp;quot
        const val safeArgs = &amp;quotandroidx.navigation.safeargs.kotlin&amp;quot
    }

    object Libraries {
        const val kotlin = &amp;quotorg.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}&amp;quot
        const val coreKTX = &amp;quotandroidx.core:core-ktx:${Versions.coreKTX}&amp;quot
        const val appCompat = &amp;quotandroidx.appcompat:appcompat:${Versions.appCompat}&amp;quot
        const val constraintLayout = &amp;quotandroidx.constraintlayout:constraintlayout:${Versions.constraintLayout}&amp;quot
        const val legacySupport = &amp;quotandroidx.legacy:legacy-support-v4:${Versions.legacySupport}&amp;quot
        const val concurrent = &amp;quotandroidx.concurrent:concurrent-futures-ktx:${Versions.concurrent}&amp;quot
        const val viewModel = &amp;quotandroidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.lifeCycle}&amp;quot
        const val liveData = &amp;quotandroidx.lifecycle:lifecycle-livedata-ktx:${Versions.lifeCycle}&amp;quot
        const val lifeCycleCommon = &amp;quotandroidx.lifecycle:lifecycle-common-java8:${Versions.lifeCycle}&amp;quot
        const val activity = &amp;quotandroidx.activity:activity-ktx:${Versions.activity}&amp;quot
        const val hilt = &amp;quotcom.google.dagger:hilt-android:${Versions.hilt}&amp;quot
        const val hiltCompiler = &amp;quotcom.google.dagger:hilt-android-compiler:${Versions.hilt}&amp;quot
        const val hiltAndroid = &amp;quotandroidx.hilt:hilt-lifecycle-viewmodel:${Versions.hiltAndroid}&amp;quot
        const val leakCanary = &amp;quotcom.squareup.leakcanary:leakcanary-android:${Versions.leakCanary}&amp;quot

        object Test {
            const val espressoContrib = &amp;quotandroidx.test.espresso:espresso-contrib:${Versions.espresso}&amp;quot
            const val espressoIntents = &amp;quotandroidx.test.espresso:espresso-intents:${Versions.espresso}&amp;quot
            const val espressoAccessibility = &amp;quotandroidx.test.espresso:espresso-accessibility:${Versions.espresso}&amp;quot
            const val espressoWeb = &amp;quotandroidx.test.espresso:espresso-web:${Versions.espresso}&amp;quot
            const val espressoIdlingConcurrent = &amp;quotandroidx.test.espresso.idling:idling-concurrent:${Versions.espresso}&amp;quot
            const val jUnit = &amp;quotjunit:junit:${Versions.jUnit}&amp;quot
        }
    }

    object ClassPaths {
        const val gradle = &amp;quotcom.android.tools.build:gradle:${Versions.gradle}&amp;quot
        const val kotlin = &amp;quotgradle-plugin&amp;quot
        const val hilt = &amp;quotcom.google.dagger:hilt-android-gradle-plugin:${Versions.hilt}&amp;quot
        const val safeArgs = &amp;quotandroidx.navigation:navigation-safe-args-gradle-plugin:${Versions.navigation}&amp;quot
    }
}خب حالا فایل گریدل ماژول اپ رو به کاتلین DSL تغییر میدیم:build.gradle:plugins {
    id &#039;com.android.application&#039;
    id &#039;kotlin-android&#039;
}

android {
    compileSdkVersion 30
    buildToolsVersion &amp;quot30.0.2&amp;quot

    defaultConfig {
        applicationId &amp;quotir.moeindeveloper.stationery&amp;quot
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName &amp;quot1.0&amp;quot

        testInstrumentationRunner &amp;quotandroidx.test.runner.AndroidJUnitRunner&amp;quot
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile&#40;&#039;proguard-android-optimize.txt&#039;&#41;, &#039;proguard-rules.pro&#039;
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = &#039;1.8&#039;
    }
}

dependencies {

    implementation &amp;quotorg.jetbrains.kotlin:kotlin-stdlib:$kotlin_version&amp;quot
    implementation &#039;androidx.core:core-ktx:1.2.0&#039;
    implementation &#039;androidx.appcompat:appcompat:1.1.0&#039;
    implementation &#039;com.google.android.material:material:1.1.0&#039;
    implementation &#039;androidx.constraintlayout:constraintlayout:1.1.3&#039;
    testImplementation &#039;junit:junit:4.+&#039;
    androidTestImplementation &#039;androidx.test.ext:junit:1.1.1&#039;
    androidTestImplementation &#039;androidx.test.espresso:espresso-core:3.2.0&#039;
}قسمت پلاگین:plugins {
    id(Dependencies.Plugins.application)
    kotlin(Dependencies.Plugins.android)
    kotlin(Dependencies.Plugins.kotlinExtensions)
    kotlin(Dependencies.Plugins.kapt)
    id(Dependencies.Plugins.hilt)
    id(Dependencies.Plugins.safeArgs)
}برای پلاگین هایی که برا کاتلین هستن از kotlin استفاده می کنیم مثل kotlin-android و دیگه نیازی نیست که کاتلین رو اول عبارت بنویسیم و اینطوری کافیه: const val android = &amp;quotandroid&amp;quotقسمت اندروید:android {
    compileSdkVersion(Dependencies.compileSdkVersion)
    buildToolsVersion(Dependencies.buildToolsVersion)

    defaultConfig {
        applicationId = Dependencies.DefaultConfig.applicationID
        minSdkVersion(Dependencies.DefaultConfig.minSdKVersion)
        targetSdkVersion(Dependencies.DefaultConfig.targetSdkVersion)
        versionCode = Dependencies.DefaultConfig.versionCode
        versionName = Dependencies.DefaultConfig.versionName
        multiDexEnabled = true
        testInstrumentationRunner = Dependencies.DefaultConfig.testInstrumentationRunner
    }

    buildTypes {
        getByName(&amp;quotrelease&amp;quot) {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile&#40;&amp;quotproguard-android-optimize.txt&amp;quot&#41;, &amp;quotproguard-rules.pro&amp;quot)
        }
    }

    buildFeatures {
        viewBinding = true
    }


    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }


    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }
}قسمت وابستگی ها:dependencies {
    implementation(Dependencies.Libraries.kotlin)
    implementation(Dependencies.Libraries.coreKTX)
    implementation(Dependencies.Libraries.appCompat)
    implementation(Dependencies.Libraries.constraintLayout)
    implementation(Dependencies.Libraries.legacySupport)

    /*
    arch components
     */
    implementation(Dependencies.Libraries.concurrent)
    implementation(Dependencies.Libraries.viewModel)
    implementation(Dependencies.Libraries.liveData)
    implementation(Dependencies.Libraries.lifeCycleCommon)
    implementation(Dependencies.Libraries.activity)
    /*
    arch components
     */


    /*
    Hilt
     */
    implementation(Dependencies.Libraries.hilt)
    kapt(Dependencies.Libraries.hiltCompiler)
    implementation(Dependencies.Libraries.hiltAndroid)
    /*
    Hilt
     */
    debugImplementation(Dependencies.Libraries.leakCanary)


    /*
    Test libs
     */
    androidTestImplementation(Dependencies.Libraries.Test.espressoCore)
    androidTestImplementation(Dependencies.Libraries.Test.espressoContrib)
    androidTestImplementation(Dependencies.Libraries.Test.espressoIntents)
    androidTestImplementation(Dependencies.Libraries.Test.espressoAccessibility)
    androidTestImplementation(Dependencies.Libraries.Test.espressoWeb)
    androidTestImplementation(Dependencies.Libraries.Test.espressoIdlingConcurrent)
    testImplementation(Dependencies.Libraries.Test.jUnit)
    /*
    Test libs
     */

}build.gradle.kts:plugins {
    id(Dependencies.Plugins.application)
    kotlin(Dependencies.Plugins.android)
    kotlin(Dependencies.Plugins.kotlinExtensions)
    kotlin(Dependencies.Plugins.kapt)
    id(Dependencies.Plugins.hilt)
    id(Dependencies.Plugins.safeArgs)
}
android {
    compileSdkVersion(Dependencies.compileSdkVersion)
    buildToolsVersion(Dependencies.buildToolsVersion)

    defaultConfig {
        applicationId = Dependencies.DefaultConfig.applicationID
        minSdkVersion(Dependencies.DefaultConfig.minSdKVersion)
        targetSdkVersion(Dependencies.DefaultConfig.targetSdkVersion)
        versionCode = Dependencies.DefaultConfig.versionCode
        versionName = Dependencies.DefaultConfig.versionName
        multiDexEnabled = true
        testInstrumentationRunner = Dependencies.DefaultConfig.testInstrumentationRunner
    }

    buildTypes {
        getByName(&amp;quotrelease&amp;quot) {
            isMinifyEnabled = false
            proguardFiles(getDefaultProguardFile&#40;&amp;quotproguard-android-optimize.txt&amp;quot&#41;, &amp;quotproguard-rules.pro&amp;quot)
        }
    }

    buildFeatures {
        viewBinding = true
    }


    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }


    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }
}
dependencies {
    implementation(Dependencies.Libraries.kotlin)
    implementation(Dependencies.Libraries.coreKTX)
    implementation(Dependencies.Libraries.appCompat)
    implementation(Dependencies.Libraries.constraintLayout)
    implementation(Dependencies.Libraries.legacySupport)

    /*
    arch components
     */
    implementation(Dependencies.Libraries.concurrent)
    implementation(Dependencies.Libraries.viewModel)
    implementation(Dependencies.Libraries.liveData)
    implementation(Dependencies.Libraries.lifeCycleCommon)
    implementation(Dependencies.Libraries.activity)
    /*
    arch components
     */


    /*
    Hilt
     */
    implementation(Dependencies.Libraries.hilt)
    kapt(Dependencies.Libraries.hiltCompiler)
    implementation(Dependencies.Libraries.hiltAndroid)
    /*
    Hilt
     */
    debugImplementation(Dependencies.Libraries.leakCanary)


    /*
    Test libs
     */
    androidTestImplementation(Dependencies.Libraries.Test.espressoCore)
    androidTestImplementation(Dependencies.Libraries.Test.espressoContrib)
    androidTestImplementation(Dependencies.Libraries.Test.espressoIntents)
    androidTestImplementation(Dependencies.Libraries.Test.espressoAccessibility)
    androidTestImplementation(Dependencies.Libraries.Test.espressoWeb)
    androidTestImplementation(Dependencies.Libraries.Test.espressoIdlingConcurrent)
    testImplementation(Dependencies.Libraries.Test.jUnit)
    /*
    Test libs
     */
}گریدل رو سینک کنید! کار شما تموم شد و گردیل شما مرتبه و هندل کردن اطلاعات آسون تر شده و به راحتی میتونید نسخه هارو تغییر بدید!نکته مهم: چینش کانفیگ شما به این صورت کاری زمان بر و وقت گیره! برای راحتی کار از این پلاگین استفاده کنید: https://github.com/jmfayard/refreshVersions اگه پیشنهادی، انتقادی یا سوالی داشتید در کامنت ها واسم بنویسید!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Tue, 20 Oct 2020 15:43:42 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از Dagger hilt به صورت پروژه محور (قسمت سوم)</title>
                <link>https://virgool.io/MobileLab/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-dagger-hilt-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%85%D8%AD%D9%88%D8%B1-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-nwm1js58fqal</link>
                <description>قسمت های قبلی: https://vrgl.ir/ez4b2  https://vrgl.ir/u5BLy در قسمت دوم، یک ماژول تعریف کردیم که قراره داخل این قسمت، وابستگی هارو بهش اضافه کنیم.برای شروع، بیس یو ار ال ها رو تامین می کنیم:@Provides
@Singleton
fun provideIceAndFireBaseURL(): String = &amp;quothttps://www.anapioficeandfire.com/&amp;quot

@Provides
@Singleton
fun provideQuotesBaseURL(): String = &amp;quothttps://got-quotes.herokuapp.com/&amp;quotخب الان ی مشکلی پیش میاد ? چون که از ما از دو وب سرویس متفاوت استفاده می کنیم و اینکه هر دو تامین کننده، ی نوع داده رو بازگشت میدن و باید به دگر بفمهمونیم که کجا از کدوم بیس یو ار ال استفاده کنه! اینجاست که ما از  Qualifier استفاده می کنیم.در پوشه di-&gt; annotation یک فایل به نام Annotations ایجاد می کنیم:@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IceAndFire

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Quotesحالا انوتیشن IceAndFire و Quotes رو به بیس یو ار ال های خودمون اضافه می کنیم:@IceAndFire
@Provides
@Singleton
fun provideIceAndFireBaseURL(): String = &amp;quothttps://www.anapioficeandfire.com/&amp;quot

@Quotes
@Provides
@Singleton
fun provideQuotesBaseURL(): String = &amp;quothttps://got-quotes.herokuapp.com/&amp;quotبرای مکانیزم کش و کلاینت کاستوم شده okHttp، به کلاس NetworkHelper نیاز داریم، و کلاس NetworkHelper هم برای کار، به Context نیاز داره! به این صورت تعریفش می کنیم:@Provides
@Singleton
fun provideNetworkHelper(@ApplicationContext context: Context): NetworkHelper = NetworkHelper(context)از انوتیشن ApplicationContext برای تزریق Context به NetworkHelper استفاده می کنیم. حالا کلاینت OkHttp رو تعریف می کنیم:@Provides
@Singleton
fun provideOkHttpClient(@ApplicationContext context: Context, networkHelper: NetworkHelper): OkHttpClient {

    val cacheSize = (5 * 1024 * 1024).toLong()
    val myCache = Cache(context.cacheDir, cacheSize)

    return OkHttpClient.Builder()
        .cache(myCache)
        .addInterceptor { chain -&gt;
            var request = chain.request()
            request = if (networkHelper.isNetworkConnected())
                request.newBuilder().header(&amp;quotCache-Control&amp;quot, &amp;quotpublic, max-age=&amp;quot + 5).build()
            else
                request.newBuilder().header(&amp;quotCache-Control&amp;quot, &amp;quotpublic, only-if-cached, max-stale=&amp;quot + 60 * 60 * 24 * 7).build()
            chain.proceed(request)
        }
        .build()
}دوباره برای تزریق Context از ApplicationContext استفاده می کنیم.حالا برای تامین Retrofit، چون دو بیس یو ار ال داریم، پس باید دو آبجکت از رتروفیت تعریف کنیم:@IceAndFire
@Provides
@Singleton
fun provideIceAndFireRetrofit(client: OkHttpClient, @IceAndFire baseUrl: String): Retrofit {
    return Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl(baseUrl)
        .client(client)
        .build()
}

@Quotes
@Provides
@Singleton
fun provideQuotesRetrofit(client: OkHttpClient, @Quotes baseUrl: String): Retrofit {
    return Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl(baseUrl)
        .client(client)
        .build()
}در اینجا دوباره از انوتیشن IceAndFire و Quotes استفاده کردیم که به دگر بفهمونیم در کجا از کدومش استفاده می کنیم! اگه دقت کرده باشید برای پارامتر بیس یو ار ال در هر دو فانکشن، مشخص کردیم که کدوم بیس یو ار ال رو میخوایم.حالا نوبت میرسه به تامین کلاس های نتورک و ApiHelper های اپلیکیشنه:@Provides
@Singleton
fun provideIceAndFireApiService(@IceAndFire retrofit: Retrofit) = retrofit.create(IceAndFireApiService::class.java)

@Provides
@Singleton
fun provideIceAndFireApiHelper(@Quotes retrofit: Retrofit) = retrofit.create(QuotesApiService::class.java)


@Provides
@Singleton
fun provideQuotesApiService(apiImpl: IceAndFireApiImpl): IceAndFireApiHelper = apiImpl

@Provides
@Singleton
fun provideQuotesApiHelper(apiImpl: QuotesApiImpl): QuotesApiHelper = apiImplخب، ماژول ما تموم شد و کد کامل شده:@Module
@InstallIn(ApplicationComponent::class)
class IceAndFireModule {

    @IceAndFire
    @Provides
    @Singleton
    fun provideIceAndFireBaseURL(): String = &amp;quothttps://www.anapioficeandfire.com/&amp;quot

    @Quotes
    @Provides
    @Singleton
    fun provideQuotesBaseURL(): String = &amp;quothttps://got-quotes.herokuapp.com/&amp;quot

    @Provides
    @Singleton
    fun provideNetworkHelper(@ApplicationContext context: Context): NetworkHelper = NetworkHelper(context)

    @Provides
    @Singleton
    fun provideOkHttpClient(@ApplicationContext context: Context, networkHelper: NetworkHelper): OkHttpClient {

        val cacheSize = (5 * 1024 * 1024).toLong()
        val myCache = Cache(context.cacheDir, cacheSize)

        return OkHttpClient.Builder()
            .cache(myCache)
            .addInterceptor { chain -&gt;
                var request = chain.request()
                request = if (networkHelper.isNetworkConnected())
                    request.newBuilder().header(&amp;quotCache-Control&amp;quot, &amp;quotpublic, max-age=&amp;quot + 5).build()
                else
                    request.newBuilder().header(&amp;quotCache-Control&amp;quot, &amp;quotpublic, only-if-cached, max-stale=&amp;quot + 60 * 60 * 24 * 7).build()
                chain.proceed(request)
            }
            .build()
    }

    @IceAndFire
    @Provides
    @Singleton
    fun provideIceAndFireRetrofit(client: OkHttpClient, @IceAndFire baseUrl: String): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .client(client)
            .build()
    }
    @Quotes
    @Provides
    @Singleton
    fun provideQuotesRetrofit(client: OkHttpClient, @Quotes baseUrl: String): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .client(client)
            .build()
    }


    @Provides
    @Singleton
    fun provideIceAndFireApiService(@IceAndFire retrofit: Retrofit) = retrofit.create(IceAndFireApiService::class.java)

    @Provides
    @Singleton
    fun provideIceAndFireApiHelper(@Quotes retrofit: Retrofit) = retrofit.create(QuotesApiService::class.java)

    @Provides
    @Singleton
    fun provideQuotesApiService(apiImpl: IceAndFireApiImpl): IceAndFireApiHelper = apiImpl

    @Provides
    @Singleton
    fun provideQuotesApiHelper(apiImpl: QuotesApiImpl): QuotesApiHelper = apiImpl
}و برای تست میریم که از ویومدل داخل اکتیویتی خودمون استفاده کنیم، قبل از هر کاری انوتیشن AndroidEntryPoint رو به اکتیویتی خودمون اضافه میکنیم:@AndroidEntryPoint
class MainActivity : AppCompatActivity()با اینکار به دگر اجازه میدیم که وابستگی های درخواستی رو به اکتیویتی تزریق کنه. از انوتیشن AndroidEntryPoint در موارد زیر استفاده میشه:اکتیویتیفرگمنت سرویسویوبرادکست رسیوربرای تزریق ویومدل در داخل اکتیویتی به این صورت عمل می کنیم:private val vm by viewModels&lt;MainViewModel&gt;()و یکی از لایودیتاها رو مشاهده می کنیم:vm.quote.observe(this, Observer { 
    Log.e(&amp;quotqoute&amp;quot,it.toString())
})کار ما تمام شد و با موفقیت دگر هیلت رو پیاده سازی کردیم!سورس کد پروژه در گیتهاب موجوده و در ادامه برای استفاده از ابزارهایی نظیر MotionLayout و... از این کد استفاده می کنیم که به یک اپلیکیشن کامل تبدیل بشه!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 31 Jul 2020 23:35:34 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از Dagger Hilt به صورت پروژه محور (قسمت دوم)</title>
                <link>https://virgool.io/MobileLab/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-dagger-hilt-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%85%D8%AD%D9%88%D8%B1-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-uxnywnzlh4je</link>
                <description>در قسمت اول، پروژه رو ساختیم و فایل های مربوطه به لایه نتورک رو ایجاد کردیم: https://vrgl.ir/ez4b2  https://vrgl.ir/bFnon قبل از شروع کد نویسی، شما باید با یک سری از مفاهیم Dagger آشنایی داشته باشید مثل Component، Module و... . اگه با دگر کار نکردید و مستقیم میخواید که با Dagger hilt کار کنید، باید این مفاهیمو یاد بگیرید که در ادامه بهش می پردازیم:به طور کلی ۴ انوتیشن (annotation) اصلی وجود دارد:ModuleComponentProvidesInjectبرای درک بهتر، ماژول را به عنوان تامین کننده وابستگی ها در نظر میگیریم و از طریق کمپوننت، وابستگی ها را به مصرف کننده، مانند اکتیویتی می دهد.کلاس ماژول از انوتیشن Module استفاده می کند که به دگر بفهماند این یک کلاس ماژول است و عملیات های مربوطه را انجام دهد! انوتیشن Provides برای تعریف و تامین یک وابستگی داخل کلاس ماژول به کار میره!کمپوننت یک اینترفیسه که با انوتیشن Component مشخص میشه ولی دیگه در Dagger hilt لازم نیست که اونو بسازیم و دگر هلیت اونو به صورت اتوماتیک generate می کنه!و در آخر از انوتیشن Inject برای تعریف یک وابستگی داخل مصرف کننده به کار میره!پیاده سازی Dagger Hilt:قبل از شروع هر کاری، یک کلاس از نوع Application بسازید و در اندروید منیفست قرار بدید:class IceAndFireApplication: Application()&lt;application
    ...
    android:name=&amp;quot.IceAndFireApplication&amp;quot
    ...
&lt;/application&gt;و سپس انوتیشن @HiltAndroidAppرا در بالای کلاس اپلیکیشن خود قرار دهید:@HiltAndroidApp
class IceAndFireApplication: Application()در بخش نتورک، دو کلاس IceAndFireApiImpl و  QuotesApiImpl که نیاز به تزریق دو اینترفیس QuotesApiService و IceAndFireApiService دارند؛ بنابراین، انوتیشین Inject را در Constructor قرار می دهیم:class IceAndFireApiImpl @Inject constructor(private val service: IceAndFireApiService) : IceAndFireApiHelper {
...
}class QuotesApiImpl @Inject constructor(private val service: QuotesApiService): QuotesApiHelper {
...
}برای ویومدل خود یک ریپازیتوری میسازیم: class MainRepository @Inject constructor(private val iceAndFireApiHelper: IceAndFireApiHelper,
                                         private val quotesApiHelper: QuotesApiHelper) {
    suspend fun getBooks(): Response&lt;List&lt;Book&gt;&gt; = iceAndFireApiHelper.getBooks()

    suspend fun getBook(bookID: Int): Response&lt;Book&gt; = iceAndFireApiHelper.getBook(bookID)

    suspend fun getCharacters(): Response&lt;List&lt;Character&gt;&gt; = iceAndFireApiHelper.getCharacters()

    suspend fun filterCharacters(
        name: String?,
        gender: String?,
        culture: String?,
        isAlive: Boolean?
    ): Response&lt;List&lt;Character&gt;&gt; = iceAndFireApiHelper.filterCharacters(name,gender,culture,isAlive)

    suspend fun getCharacter(characterID: Int): Response&lt;Character&gt; = iceAndFireApiHelper.getCharacter(characterID)

    suspend fun getHouses(): Response&lt;List&lt;House&gt;&gt; = iceAndFireApiHelper.getHouses()

    suspend fun getHouse(houseID: Int): Response&lt;House&gt; = iceAndFireApiHelper.getHouse(houseID)


    suspend fun getQuotes(): Response&lt;Quote&gt; = quotesApiHelper.getQuotes()

    suspend fun filterQuotes(character: String): Response&lt;Quote&gt; = quotesApiHelper.filterQuotes(character)
}ریپازیتوری اصلی ما، IceAndFireApiHelper و QuotesApiHelper را نیاز دارد که باید به آن تزریق کنیم!کلاس ویومدل ما بدین شکل است: class MainViewModel @ViewModelInject
constructor(private val mainRepository: MainRepository): ViewModel() {

    private val _quote = MutableLiveData&lt;Resource&lt;Quote&gt;&gt;()

    val quote : LiveData&lt;Resource&lt;Quote&gt;&gt; get() = _quote

    private val _books = MutableLiveData&lt;Resource&lt;List&lt;Book&gt;&gt;&gt;()

    val books : LiveData&lt;Resource&lt;List&lt;Book&gt;&gt;&gt; get() = _books

    private val _characters = MutableLiveData&lt;Resource&lt;List&lt;Character&gt;&gt;&gt;()

    val characters : LiveData&lt;Resource&lt;List&lt;Character&gt;&gt;&gt; get() = _characters

    private val _houses = MutableLiveData&lt;Resource&lt;List&lt;House&gt;&gt;&gt;()

    val houses : LiveData&lt;Resource&lt;List&lt;House&gt;&gt;&gt; get() = _houses


    init {
        getQuote()
        getBooks()
        getCharacters()
        getHouses()
    }


    fun getQuote(){
        viewModelScope.launch {

            _quote.postValue(Resource.loading(null))

            mainRepository.getQuotes().let {response -&gt;
                if (response.isSuccessful) {
                    _quote.postValue(Resource.success(response.body()))
                } else _quote.postValue(Resource.error(response.errorBody().toString(),null))
            }
        }
    }

    fun getBooks(){
        viewModelScope.launch {

            _books.postValue(Resource.loading(null))

            mainRepository.getBooks().let {response -&gt;
                if (response.isSuccessful) {
                    _books.postValue(Resource.success(response.body()))
                } else _books.postValue(Resource.error(response.errorBody().toString(),null))
            }
        }
    }

    fun getCharacters(){
        viewModelScope.launch {

            _characters.postValue(Resource.loading(null))

            mainRepository.getCharacters().let {response -&gt;
                if (response.isSuccessful) {
                    _characters.postValue(Resource.success(response.body()))
                } else _characters.postValue(Resource.error(response.errorBody().toString(),null))
            }
        }
    }

    fun getHouses(){
        viewModelScope.launch {
            _houses.postValue(Resource.loading(null))

            mainRepository.getHouses().let {response -&gt;
                if (response.isSuccessful) {
                    _houses.postValue(Resource.success(response.body()))
                } else _houses.postValue(Resource.error(response.errorBody().toString(),null))
            }
        }
    }
}برای تزریق وابستگی از ViewModelInject استفاده می کنیم که با استفاده از کتابخانه های زیر که به گریدل اضافه کردیم امکان پذیره:implementation &#039;androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02&#039;
kapt &#039;androidx.hilt:hilt-compiler:1.0.0-alpha02&#039;و در آخر برای چک کردن وضعیت اتصال، یک کلاس به نام NetworkHelper ایجاد می کنیم که به این صورته:class NetworkHelper(private val context: Context) {
    fun isNetworkConnected(): Boolean {
        var result = false
        val connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M) {
            val networkCapabilities = connectivityManager.activeNetwork ?: return false
            val activeNetwork =
                connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
            result = when {
                activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -&gt; true
                activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -&gt; true
                activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -&gt; true
                else -&gt; false
            }
        } else {
            connectivityManager.run {
                connectivityManager.activeNetworkInfo?.run {
                    result = when (type) {
                        ConnectivityManager.TYPE_WIFI -&gt; true
                        ConnectivityManager.TYPE_MOBILE -&gt; true
                        ConnectivityManager.TYPE_ETHERNET -&gt; true
                        else -&gt; false
                    }
                }
            }
        }
        return result
    }
}و در آخر فراموش نکنید که این دوتا دسترسی رو به اندروید منیفست اضافه کنید:&lt;uses-permission android:name=&amp;quotandroid.permission.ACCESS_NETWORK_STATE&amp;quot /&gt;
&lt;uses-permission android:name=&amp;quotandroid.permission.INTERNET&amp;quot/&gt;کانفیگ اولیه ماژول:class IceAndFireModule {
}همانطور که گفتیم، باید برای دگر ماژول را مشخص کنیم، پس از انوتیشن Dagger استفاده می کنیم:@Module
class IceAndFireModuleحالا باید پل ارتباطی یا همان Component را به ماژول معرفی کنیم، در دگر ۲ باید ماژول را به کمپوننت معرقی میکردیم اما حالا در دگر هیلت، با توجه به اینکه خود هیلت کامپوننت را میسازد، باید کامپوننت را با استفاده از انوتیشن InstallIn مشخص کنیم:@Module
@InstallIn(ApplicationComponent::class)
class IceAndFireModuleدر اینجا ما میخوایم که وابستگی های ماژول من در سطح Appplication باشه پس از ApplicationComponent استفاده میکنم.برای اطلاعات بیشتر در مورد ترتیب بندی کمپوننت ها، به عکس زیر دقت کنید:برای اطلاعات بیشتر: https://dagger.dev/hilt/components.html در قسمت سوم وابستگی ها را پیاده سازی می کنیم.</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 31 Jul 2020 17:37:11 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از Dagger hilt به صورت پروژه محور (قسمت اول)</title>
                <link>https://virgool.io/MobileLab/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-dagger-hilt-%D8%A8%D9%87-%D8%B5%D9%88%D8%B1%D8%AA-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%85%D8%AD%D9%88%D8%B1-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-x1aii1ugonek</link>
                <description>بعد از چند وقت تصمیم گرفتم که یک سری مقاله برای تکمیل کردن دوره توسعه اپلیکیشن های مدرن اندرویدی منتشر کنم. در دوره قبلی به علت کمبود وقت، Dagger 2 رو آموزش ندادم و به جای اون از KOIN استفاده کردم؛ اما چند وقت پیش با شنیدن ارائه Dagger Hilt این فکر به سرم زد که بیام و ی مقاله پروژه محور(سورس کد بعد از دوره در گیتهاب قرار خواهد گرفت) راجبش منتشر کنم. با ی سرچ ساده ی آموزش ساده از MindOrks پیدا کردم که خیلی ساده آموزشو پیش برده که برای این سری مقاله اکثر قسمتاشو مثل اون پیش میریم!قسمت ها: https://vrgl.ir/u5BLy  https://vrgl.ir/bFnon قدم اول: کار اپلیکیشنبرای اینکه اپلیکیشن تقریبا واقعی به نظر بیاد، به یک Web API نیاز داریم. با ی سرچ ساده، دو API برای یکی از سریال های محبوبم Game of thrones پیاده کردم?:An API of Ice And FireGame of Thrones Quotes APIقدم دوم: ساخت پروژهشروع به ساخت یک اپلیکیشن در اندروید استدیو کردم و اسم پروژه رو Ice and Fire گذاشتم. ساختار پوشه بندی اصلی:کتابخانه های اضافه شده: implementation &#039;androidx.constraintlayout:constraintlayout:2.0.0-rc1&#039; برای استفاده از Motion layout از ورژن ۲ کانسترینت لایوت استفاده می کنم.کتاب خانه های جت پک //android Arch components:
    implementation &amp;quotandroidx.concurrent:concurrent-futures-ktx:1.1.0-rc01&amp;quot
 def lifecycle_version = &amp;quot2.2.0&amp;quot
 def arch_version = &amp;quot2.1.0&amp;quot
 // ViewModel
    implementation &amp;quotandroidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version&amp;quot
 // LiveData
    implementation &amp;quotandroidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version&amp;quot
 // Annotation processor
    kapt &amp;quotandroidx.lifecycle:lifecycle-compiler:$lifecycle_version&amp;quot
    def nav_version = &amp;quot2.3.0&amp;quot
 //navigation
    implementation &amp;quotandroidx.navigation:navigation-fragment-ktx:$nav_version&amp;quot
 implementation &amp;quotandroidx.navigation:navigation-ui-ktx:$nav_version&amp;quotرتروفیت://retrofit
implementation &#039;com.squareup.retrofit2:retrofit:2.9.0&#039;
implementation &#039;com.squareup.retrofit2:converter-gson:2.9.0&#039;دگر هیلت و ماژول لایف سایکل ( برای ویومدل)://dagger hilt
implementation &#039;com.google.dagger:hilt-android:2.28-alpha&#039;
kapt &#039;com.google.dagger:hilt-android-compiler:2.28-alpha&#039;
//android lifecycle
implementation &#039;androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02&#039;
kapt &#039;androidx.hilt:hilt-compiler:1.0.0-alpha02&#039;در فایل Build.gradle ماژول پروژه و در قسمت Dependencies:classpath &#039;com.google.dagger:hilt-android-gradle-plugin:2.28-alpha&#039;و در قسمت repositories :repositories {
 google()
 jcenter()
 mavenCentral()
} و در فایل Build.gradle ماژول اپ:apply plugin: &#039;kotlin-kapt&#039;
apply plugin: &#039;dagger.hilt.android.plugin&#039;پس از انجام این مراحل، گریدل خود را Sync کنید!قدم سوم: ساخت لایه نتورکبرای شروع،دو کلاس برای برای اعلام وضعیت بین لایه نتورک و یو ای میسازیم و اسم اونو Resource و RequestStatus میذاریم: enum class RequestStatus {
 SUCCESS,
    ERROR,
    LOADING
}data class Resource&lt;out T&gt;(val status: RequestStatus, val data: T?, val Message: String?) {

 companion object {
 fun &lt;T&gt; success(data: T?): Resource&lt;T&gt; {
 return Resource(RequestStatus.SUCCESS,data,null)
  }

 fun &lt;T&gt; error(msg: String, data: T?): Resource&lt;T&gt; {
 return Resource(RequestStatus.ERROR,data,msg)
  }

 fun &lt;T&gt; loading(data: T?): Resource&lt;T&gt; {
 return Resource(RequestStatus.LOADING,data,null)
  }
 }

}سپس طبق مستندات API بالا، دیتاکلاس های نتورک رو میسازیم:data class Book(
 @SerializedName(&amp;quotauthors&amp;quot)
 val authors: List&lt;String&gt;,
 @SerializedName(&amp;quotcharacters&amp;quot)
 val characters: List&lt;String&gt;,
 @SerializedName(&amp;quotcountry&amp;quot)
 val country: String,
 @SerializedName(&amp;quotisbn&amp;quot)
 val isbn: String,
 @SerializedName(&amp;quotmediaType&amp;quot)
 val mediaType: String,
 @SerializedName(&amp;quotname&amp;quot)
 val name: String,
 @SerializedName(&amp;quotnumberOfPages&amp;quot)
 val numberOfPages: Int,
 @SerializedName(&amp;quotpovCharacters&amp;quot)
 val povCharacters: List&lt;String&gt;,
 @SerializedName(&amp;quotpublisher&amp;quot)
 val publisher: String,
 @SerializedName(&amp;quotreleased&amp;quot)
 val released: String,
 @SerializedName(&amp;quoturl&amp;quot)
 val url: String
)data class Character(
 @SerializedName(&amp;quotaliases&amp;quot)
 val aliases: List&lt;String&gt;,
 @SerializedName(&amp;quotallegiances&amp;quot)
 val allegiances: List&lt;Any&gt;,
 @SerializedName(&amp;quotbooks&amp;quot)
 val books: List&lt;String&gt;,
 @SerializedName(&amp;quotborn&amp;quot)
 val born: String,
 @SerializedName(&amp;quotculture&amp;quot)
 val culture: String,
 @SerializedName(&amp;quotdied&amp;quot)
 val died: String,
 @SerializedName(&amp;quotfather&amp;quot)
 val father: String,
 @SerializedName(&amp;quotmother&amp;quot)
 val mother: String,
 @SerializedName(&amp;quotname&amp;quot)
 val name: String,
 @SerializedName(&amp;quotplayedBy&amp;quot)
 val playedBy: List&lt;String&gt;,
 @SerializedName(&amp;quotpovBooks&amp;quot)
 val povBooks: List&lt;String&gt;,
 @SerializedName(&amp;quotspouse&amp;quot)
 val spouse: String,
 @SerializedName(&amp;quottitles&amp;quot)
 val titles: List&lt;String&gt;,
 @SerializedName(&amp;quottvSeries&amp;quot)
 val tvSeries: List&lt;String&gt;,
 @SerializedName(&amp;quoturl&amp;quot)
 val url: String
)data class House(
 @SerializedName(&amp;quotancestralWeapons&amp;quot)
 val ancestralWeapons: List&lt;String&gt;,
 @SerializedName(&amp;quotcadetBranches&amp;quot)
 val cadetBranches: List&lt;String&gt;,
 @SerializedName(&amp;quotcoatOfArms&amp;quot)
 val coatOfArms: String,
 @SerializedName(&amp;quotcurrentLord&amp;quot)
 val currentLord: String,
 @SerializedName(&amp;quotdiedOut&amp;quot)
 val diedOut: String,
 @SerializedName(&amp;quotfounded&amp;quot)
 val founded: String,
 @SerializedName(&amp;quotfounder&amp;quot)
 val founder: String,
 @SerializedName(&amp;quotheir&amp;quot)
 val heir: String,
 @SerializedName(&amp;quotname&amp;quot)
 val name: String,
 @SerializedName(&amp;quotoverlord&amp;quot)
 val overlord: String,
 @SerializedName(&amp;quotregion&amp;quot)
 val region: String,
 @SerializedName(&amp;quotseats&amp;quot)
 val seats: List&lt;String&gt;,
 @SerializedName(&amp;quotswornMembers&amp;quot)
 val swornMembers: List&lt;String&gt;,
 @SerializedName(&amp;quottitles&amp;quot)
 val titles: List&lt;String&gt;,
 @SerializedName(&amp;quoturl&amp;quot)
 val url: String,
 @SerializedName(&amp;quotwords&amp;quot)
 val words: String
)data class Quote(
 @SerializedName(&amp;quotcharacter&amp;quot)
 val character: String,
 @SerializedName(&amp;quotquote&amp;quot)
 val quote: String
)حالا نوبت میرسه به ساخت interface ها:interface IceAndFireApiHelper {


 suspend fun getBooks(): Response&lt;List&lt;Book&gt;&gt;

 suspend fun getBook(
 bookID: Int
 ): Response&lt;Book&gt;



 suspend fun getCharacters(): Response&lt;List&lt;Character&gt;&gt;


 suspend fun filterCharacters(
 name: String?,
        gender: String?,
        culture: String?,
        isAlive: Boolean?
 ): Response&lt;List&lt;Character&gt;&gt;

 suspend fun getCharacter(characterID: Int): Response&lt;Character&gt;

 suspend fun getHouses(): Response&lt;List&lt;House&gt;&gt;

 suspend fun getHouse(houseID: Int): Response&lt;House&gt;
}  class IceAndFireApiImpl(private val service: IceAndFireApiService) : IceAndFireApiHelper {

 override suspend fun getBooks(): Response&lt;List&lt;Book&gt;&gt; = service.getBooks()

 override suspend fun getBook(bookID: Int): Response&lt;Book&gt; = service.getBook(bookID)

 override suspend fun getCharacters(): Response&lt;List&lt;Character&gt;&gt; = service.getCharacters()

 override suspend fun filterCharacters(
 name: String?,
        gender: String?,
        culture: String?,
        isAlive: Boolean?
 ): Response&lt;List&lt;Character&gt;&gt; = service.filterCharacters(name,gender,culture,isAlive)

 override suspend fun getCharacter(characterID: Int): Response&lt;Character&gt; = service.getCharacter(characterID)

 override suspend fun getHouses(): Response&lt;List&lt;House&gt;&gt; = service.getHouses()

 override suspend fun getHouse(houseID: Int): Response&lt;House&gt; = service.getHouse(houseID)

}interface IceAndFireApiService {

 @GET(&amp;quotapi/books&amp;quot)
 suspend fun getBooks(): Response&lt;List&lt;Book&gt;&gt;


 @GET(&amp;quotapi/books/{id}&amp;quot)
 suspend fun getBook(
 @Path(&amp;quotid&amp;quot) bookID: Int
 ): Response&lt;Book&gt;


 @GET(&amp;quotapi/characters&amp;quot)
 suspend fun getCharacters(): Response&lt;List&lt;Character&gt;&gt;

 @GET(&amp;quotapi/characters&amp;quot)
 suspend fun filterCharacters(
 @Query(&amp;quotname&amp;quot) name: String?,
 @Query(&amp;quotgender&amp;quot) gender: String?,
 @Query(&amp;quotculture&amp;quot) culture: String?,
 @Query(&amp;quotisAlive&amp;quot) isAlive: Boolean?
 ): Response&lt;List&lt;Character&gt;&gt;

 @GET(&amp;quotapi/characters/{id}&amp;quot)
 suspend fun getCharacter(@Path(&amp;quotid&amp;quot) characterID: Int): Response&lt;Character&gt;


 @GET(&amp;quotapi/houses&amp;quot)
 suspend fun getHouses(): Response&lt;List&lt;House&gt;&gt;

 @GET(&amp;quotapi/houses/{id}&amp;quot)
 suspend fun getHouse(@Path(&amp;quotid&amp;quot) houseID: Int): Response&lt;House&gt;

}  interface QuotesApiHelper {

 suspend fun getQuotes(): Response&lt;Quote&gt;

 suspend fun filterQuotes(
 character: String
 ): Response&lt;Quote&gt;
}class QuotesApiImpl(private val service: QuotesApiService): QuotesApiHelper {

 override suspend fun getQuotes(): Response&lt;Quote&gt; = service.getQuotes()

 override suspend fun filterQuotes(character: String): Response&lt;Quote&gt; = service.filterQuotes(character)

} interface QuotesApiService {

 @GET(&amp;quotquotes&amp;quot)
 suspend fun getQuotes(): Response&lt;Quote&gt;

 @GET(&amp;quotquotes&amp;quot)
 suspend fun filterQuotes(
 @Query(&amp;quotchar&amp;quot) character: String
 ): Response&lt;Quote&gt;
}برای استفاده از coroutines از suspend fun استفاده میکنیم، و حتما در نظر داشته باشید که از ورژن 2.6+ رتروفیت استفاده کنید که کروتینز رو پشتیبانی کنه!خب برای این قسمت فک کنم تا اینجا کافی باشه! در قسمت بعدی مفاهیم دگر رو به صورت کلی بررسی خواهیم کرد و پروژه رو با دگر کانفیگ میکنیم! </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 31 Jul 2020 12:32:47 +0430</pubDate>
            </item>
                    <item>
                <title>باگ اندروید استدیو ۳.۴.۱</title>
                <link>https://virgool.io/MobileLab/%D8%A8%D8%A7%DA%AF-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A7%D8%B3%D8%AA%D8%AF%DB%8C%D9%88-%DB%B3%DB%B4%DB%B1-nnhhmffeiv8k</link>
                <description>چند روز پیش که با اندروید استدیو کار میکردم با این صحنه روبرو شدم???‍♂ فک کردم که مشکل از کشه و باید پاک بشه، بعد از پاک کردن کش دوباره بازم همین مشکل بود??‍♂ همه لایه ها باز میشن ولی به جز اون لایه ای که تازه طراحی کرده بودم?بعد که کمی دقت کردم، از کتابخونه متریال گوگل استفاده کرده بودم، نسخه های آلفای این کتابخونه با اندروید استدیو ۳.۴.۱ مشکل دارن و اگه در لایه خودتون از material button استفاده کنید، با این مشکل مواجه میشید.?ورژن کتابخونه:1.1.0-alpha06خب حالا میرسیم به راه حل: ازونجا که ورژن آلفای این کتابخونه امکانات زیادی داره و بهش نیاز دارم باید برم و اندروید استودیو ۳.۵ از چنل بتا دانلود کنم، مشکل در این نسخه حل شده?راه‌حل دوم اینه که ورژن کتابخونه رو دانگرید کنید به 1.0.0که اصلا پیشنهاد نمیکنم?جهت مطالعه بیشتر:  https://stackoverflow.com/questions/55791884/cannot-render-materialbutton-with-android-material1-1-x </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Sun, 16 Jun 2019 17:17:01 +0430</pubDate>
            </item>
                    <item>
                <title>کاتلین یا جاوا؟ مسئله این است.</title>
                <link>https://virgool.io/MobileLab/%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-%DB%8C%D8%A7-%D8%AC%D8%A7%D9%88%D8%A7-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A7%DB%8C%D9%86-%D8%A7%D8%B3%D8%AA-j6xmjbzfvqkb</link>
                <description>https://themindstudios.com/blog/kotlin-vs-java-will-kotlin-replace-java/مدت ها بحث و جدل در مورد برتری زبان کاتلین نسب به جاوا و یا برعکس در جامعه برنامه نویسان مخصوصا برنامه نویسان اندروید مطرحه. اما دوست دارم یک بار برای همیشه به این بحث خاتمه بدم!توضیحاتی در مورد کاتلین:زبان کاتلین به طور خلاصه یک زبان استاتیک تایپ، کراس پلتفرم است که در سال ۲۰۱۱ توسط شرکت جت برینز JetBrains از آن رونمایی شد و در سال ۲۰۱۶، نسخه ۱ استیبل آن رونمایی شد. توضیحات بیشتردر کنفراس گوگل I/O سال ۲۰۱۷، کاتلین به عنوان زبان رسمی توسعه اندروید معرفی شد و رسما تحت حمایت گوگل قرار گرفت.شایعات، خرافات و تعصبات الکی:اگه در گروه های تلگرامی توسعه دهندگان ایرانی عبارت کاتلین رو جستجو کنید، با انواع حرف ها و نظراتی در مورد کاتلین روبرو می شوید. نمونه:???راست میگه باید بذاریم دم بکشه?خب اینا نمونه هایی از پیام هایی هستن که با اونا مواجه میشید?حل مسئلهدر اینجا به یک سری از سوالات جواب می دهیم.آیا کاتلین از جاوا بهتر است و بلعکس؟خیر!نه!No!لا!?هردو زبان ویژگی هایی دارن و از یکسری قوانین و توابع پیروی میکنن ولی طبق گفته توسعه دهندگان کاتلین، هدف آنها از خلق این زبان، تولید زبانی بهتر از جاوا بوده پس در این صورت باید بگم که بله یکجورایی کاتلین سینتکس بهتری نسبت به جاوا داره و کدهای خواناتری نسبت به جاوا داره?نکته قابل توجهی که در مورد کاتلین وجود داره اینه که مقادیر null رو به خوبی هندل میکنه و مثلا به خاطر ی رشته نال، برنامه شما کرش نمیکنه!(در اینجا قرار نیست که به صورت تخصصی توضیح بدیم)در اینجا یک نمونه کد را در جاوا و کاتلین باهم مقایسه می کنیم:public class ClearBridge {
public static double calculate (double a, String op, double b) throws Exception {  	switch (op) {  		case “add”:  			return a + b;  		case “subtract”: 			return a - b; 		case “multiply”: 			return a * b;  		case “divide”:  			return a / b; 		default:  			throw new Exception(); 		}
 	} 
}کد بالا در کاتلین:
fun calculate (a: Double, op: String, b: Double): Double { 
	when (op) { 
		“add” -&gt; return a + b
		“subtract” -&gt; return a - b
		“multiply” -&gt; return a * b
		“divide” - &gt; return a / b 
		else -&gt; throw Exception()
	}
}قضاوت با شما?آیا لازمه برای یادگیری کاتلین، جاوا بلد باشیم؟خیر! برای یادگیری کاتلین نیازی به یادگرفتن جاوا ندارید و میتونید بدون واسطه کاتلین رو یادبگیرید اما اگر از جاوا به سمت کاتلین مهاجرت می کنید،یادگیری برای شما لذت بخش تر خواهد بود.آیا جاوا در اندروید کنار گذاشته میشه؟جواب قطعا خیر! اگه برنامه نویسی آی او اس کار کرده باشید، هنگام ساخت پروژه میتونید انتخاب کنید که زبان پروژه آبجکتیو سی باشه یا سویفت و در صورتی که سویفت محبوبیت زیادی داره، بازم آبجکتیو سی کنار گذاشته نشده و برنامه نویسان زیادی ازون استفاده میکنن! پس روال برای اندروید هم به اینصورت خواهد بود.در حال حاضر کدام زبان را یادبگیرم؟درحال حاضر، برای یادگیری برنامه نویسی اندروید بهتره از کاتلین شروع کنید.در پروژه های بزرگ از کاتلین استفاده نکنیم؟باور اشتباهی که هنوز خیلی از دوستان به اون اعتقاد دارن اینه که کاتلین چون زبان جدیدی هست نمیشه به اون برای پروژه های بزرگ اعتماد کرد! باید بگم خیر! کاتلین صد در صد قابل اعتماده و میتونید ازون در هر پروژه استفاده کنید!نکته: کاتلین کاملا با جاوا سازگاره و از کتابخانه های جاوا در پروژه های کاتلین استفاده کنید!نکته ۲: شما میتوانید از کد جاوا درون کاتلین استفاده کنید و به مشکلی بر نمیخورید! البته کاتلین شمارو از این کار بی نیاز میکنه.جمع بندی کلی:تعصب در هیچ موضوعی خوب نیست و امیدوارم که با این مقاله توجه شما رو به کاتلین جمع کنم و خواهشم از دوستانی که تا حالا کاتلین کار نکردن اینه که قبل از انتقاد کورکورانه، حتما این زبان رو امتحان کنند که باعث گمراهی افراد تازه کار در این حوزه نشوند!منابع: https://themindstudios.com/blog/kotlin-vs-java-will-kotlin-replace-java/  https://kotlinlang.org/docs/reference/comparison-to-java.html پی نوشت: یادگیری جاوا هم اجتناب ناپذیره و ممکنه شرایط برای شما پیش بیاد که مجبور باشید جاوا هم یادبگیرید( کد های آماده توسط شرکت به شما محول میشود). پس در نتیجه برای توسعه دهنده بهتری بودن، بهتره که هر دو ابزار رو در جعبه خودتون داشته باشید!از وقتی که بابت خواندن این مقاله گذاشتید ممنونم و دوست دارم نظرات شما رو بدونم! و اگه سوالی دارید در همینجا بپرسید که در مقاله قرار بدم.</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Sat, 30 Mar 2019 22:26:51 +0430</pubDate>
            </item>
                    <item>
                <title>آمار بازدید مطالب من در سال ۹۷</title>
                <link>https://virgool.io/@moeinDeveloper/%D8%A2%D9%85%D8%A7%D8%B1-%D8%A8%D8%A7%D8%B2%D8%AF%DB%8C%D8%AF-%D9%85%D8%B7%D8%A7%D9%84%D8%A8-%D9%85%D9%86-%D8%AF%D8%B1-%D8%B3%D8%A7%D9%84-%DB%B9%DB%B7-ay4uegppabjh</link>
                <description>من در سال گذشته، در مجموع ۱۱ مقاله در ویرگول منتشر کردم. در طول این سال مقالات من ۱۰۵ مرتبه لایک شدند و ۲۹ نظر نیز بر روی آن‌ها ارسال شد. با مطالعه این مقالات، ۵۵ نفر تصمیم گرفتند تا من را در ویرگول دنبال کنند تا از مقالات بعدی من باخبر شوند.مخاطبیندر طول این سال، مقالات من توسط ۲,۱۱۹ نفر در ویرگول مطالعه شده است. مدت زمانی که این افراد در حال مطالعه‌ی آن‌ها بوده‌اند برابر با ۱۴۷,۹۶۳ ثانیه است. اگر فرض کنیم در حال حاضر جمعیت ایران ۸۰ میلیون نفر است، این یعنی من توانسته‌ام سرانه مطالعه کشورم ایران را ۰/۰۰۱۸۵۰ ثانیه افزایش دهم. شاید بتوانیم این عدد را به «اثر پروانه‌ای» تشبیه کنیم؛ چرا که هر کدام از نویسندگان در ویرگول توانسته‌ایم عددی کوچک را به سرانه مطالعه کشور اضافه کنیم اما مجموعِ تک تکِ این اعداد، یک عدد بزرگ شده است. من در کنار سایر کاربرانِ ویرگول توانستیم در سال ۹۷، سرانه مطالعه ایران را ۴/۱۲۲۳۴۳ ثانیه افزایش دهیم.می‌توانیم برای سال ۹۸، اتفاقات بزرگتری را رقم بزنیم.ویدیوی آمار مخاطبین من را ببینید: https://cdn.virgool.io/annual-report-97/nn1rfrypdthj-D542.mp4 </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Wed, 27 Mar 2019 13:14:46 +0430</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت هفتم(آخر)</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud</link>
                <description>سایر قسمت ها: https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k سلام دوستان ??امروز آخرین قسمت دوره مقدماتی توسعه اپلیکیشن های مدرن اندروید را آماده کردم و از طریق آپارات می توانید ویدیو را ببینید. https://www.aparat.com/v/UMkwX کد های این پروژه هم در گیتهاب بنده آپلود شده: https://github.com/moeindev/KotlinMVVMToturial داکیومنت های قسمت های آخر دوره هم به زودی نوشته میشه و در آدرسی که در ابتدای دوره در اختیار شما گذاشتم، قرار خواهد گرفت! https://moeindeveloper.gitbook.io/maad/ خبر خوووب: دوره پیشرفته به زودی آماده می شود!نظر شما راجب به این دوره چی بود و هرگونه پیشنهادی برای دوره پیشرفته دارید در بخش کامنت ها بیان کنید حتما جواب میدم!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Mon, 25 Feb 2019 12:52:29 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت ششم</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k</link>
                <description>سایر قسمت ها: https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnxhttps://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz قسمت ششم https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud با سلامبابت تاخیر عذرخواهی میکنم!قسمت ششم آپلود شده در آپارات https://www.aparat.com/v/XOI8S در این قسمت از rxjava ، live data و viewModel صحبت می کنیم و کد قدیمی خود را بروزرسانی خواهیم کرد.خوشحال می شوم نظرات و پیشنهادات خود را در بخش کامنت ها بیان کنید! </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Mon, 18 Feb 2019 19:22:44 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت پنجم</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz</link>
                <description>سایر قسمت ها: https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k در این قسمت مثالی ساده از معماری MVVM خواهیم زد. نکته: در این مرحله، مشکلاتی که در حال حاضر در برنامه نویسی اندروید وجود دارد را بررسی می کنیم و در قسمت های بعدی، این مشکلات را حل می کنیم.ویدیو در آپارات https://www.aparat.com/v/8O1NG خوشحال می شوم نظرات و پیشنهادات شما را در بخش کامنت ها بیان کنید.</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 16 Nov 2018 11:09:15 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت چهارم</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx</link>
                <description>در این قسمت پایه معماری نرم افزار MVVM به زبانی ساده توضیح داده می شود!قسمت های قبلی: https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud لینک دوره در گیت بوک: https://moeindeveloper.gitbook.io/maad/  ویدیو قسمت چهارم در اپارات https://www.aparat.com/v/UYuIe خوشحال میشم نظرات و پیشنهادات خود را در بخش کامنت ها بنویسید!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 02 Nov 2018 14:26:43 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت سوم</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv</link>
                <description>https://twitter.com/brijeshmasrani/status/901291501870751745در این قسمت روی پوشه بندی و سایر اجزای پروژه کار می کنیم!قسمت های قبل: https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud صفحه اصلی دوره در گیت بوک: https://moeindeveloper.gitbook.io/maad/ ویدیوی این قسمت در آپارات https://www.aparat.com/v/Um3bd خوشحال می شوم نظرات و پیشنهادات خود را در بخش کامنت ها مطرح کنید!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Thu, 01 Nov 2018 00:35:59 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت دوم</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv</link>
                <description>خب در این قسمت میریم که پروژه را در اندروید استدیو ایجاد کنیم و برای کار خود کانفیگ کنیم.نکته مهم: تصمیم گرفتم که در گیت بوک همزمان با ویدیوها، نسخه داکیومنت را هم آماده کنم!قسمت اول در ویرگول: https://virgool.io/@moeinDeveloper/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud لینک داکیومنت در گیت بوک: https://moeindeveloper.gitbook.io/maad/ پی نوشت: بنده از شبیه ساز اندروید استفاده نمیکنم و این باعث شد که نمایش صفحه گوشیم با نرم افزار vysor امکان پذیر نبود و با خطا مواجه می شد! اما برای قسمت سوم این مشکل حل شده!ویدیوی قسمت دوم در آپارات: https://www.aparat.com/v/i7B98 لطفا پیشنهادات و نظرات خود را در بخش کامنت ها بنویسید! ☺️</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Tue, 30 Oct 2018 17:12:12 +0330</pubDate>
            </item>
                    <item>
                <title>توسعه اپلیکیشن های مدرن اندرویدی قسمت اول</title>
                <link>https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk</link>
                <description>امروز تصمیم گرفتم که یک دوره آموزشی اندروید ساده را طراحی کنم. در این دوره شما یاد خواهید گرفت که از معماری MVVM و زبان کاتلین در اندروید، و با استفاده از ابزار ها و فریمورک های قدرتمندی مانند RxJava, LiveData,Dagger اپلیکیشنی قدرتمند تر و بهینه تر طراحی کنید!نکته: در این دوره سعی می شود که به صورت خیلی ساده و ابتدایی این مباحث تقریبا پیچیده، برای افراد مبتدی توضیح داده شود و امکان دارد برای سادگی کار، بعضی از مباحث پوشش داده نشود! https://www.aparat.com/v/avRuU قسمت اول در آپارات☝?خوشحال می شوم اگر پیشنهادی دارید در بخش نظرات مطرح کنید! https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-gehfdldz7qsk  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-qp2vaxbugrgv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-gmkn5clbh0wv  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-ezhfnqexosnx  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-qzsywt5pomzz  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%B4%D8%B4%D9%85-scsim5sfaq7k  https://virgool.io/MobileLab/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%AF%D8%B1%D9%86-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D9%87%D9%81%D8%AA%D9%85%D8%A2%D8%AE%D8%B1-xu62cbbyj7ud </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Sun, 28 Oct 2018 12:46:48 +0330</pubDate>
            </item>
                    <item>
                <title>مشکلی که شاید با آن برخورد کنید!</title>
                <link>https://virgool.io/MobileLab/%D9%85%D8%B4%DA%A9%D9%84%DB%8C-%DA%A9%D9%87-%D8%B4%D8%A7%DB%8C%D8%AF-%D8%A8%D8%A7-%D8%A2%D9%86-%D8%A8%D8%B1%D8%AE%D9%88%D8%B1%D8%AF-%DA%A9%D9%86%DB%8C%D8%AF-qof8ilbg8d9l</link>
                <description>دیشب هنگام خروجی گرفتن از اَپَمْ، به مشکل عجیبی بر خوردم اونم این بود که دِیتابایندینگ(DataBinding) ویومدل(ViewModel) را نمی شناخت و خیلی عجیب بود که خطای type mismatch از کد من میگرفت در حالی که همین کد در پروژه قبلیم کار میکرد!مطمئنأ الان می گویید که یک بار پروژه را Clean کن و دوباره پروژه را  rebuild کن! Build &gt; Clean Project‌Build &gt; Rebuild Projectاما متاسفانه در این مورد جوابگو نبود! راه حلی دومی که به ذهنم رسید این بود که کَشِ اندروید استدیو را خالی کنم!File &gt; Invalidate Caches / Restartاما باز هم ناموفق بود! راه حل بعدی، اِسْتَک اٌوِرْفِلْو(StackOverFlow):گشتم، نبود، نگرد،نیست!☹️بعد از اینکه حسابی جستجو کردم، به این نتیجه رسیدم که یک تاپیک ایجاد کنم و مشکلم را بیان کنم: https://stackoverflow.com/questions/53013130/type-mismatch-inferred-type-is-but-was-expected بعد از دو الی سه دقیقه، جواب های بی ربطی دریافت میکردم! بعضی ها میگفتن که ممکنه نال باشه مقدار ویومدلت و... . ولی مشکل من این نبود! مشکل من این بود که اندروید استدیو را آپدیت کرده بودم! الان لابد می پرسید که چه ربطی به آپدیت داره! ربطش این بود که در اندروید استدیوی جدید، از ورژن دوم DataBinding استفاده می شود و به صورت پیشفرض، مقدار آن  true می باشد! و بالاخره، بعد از سه ساعت و نیم جستجو و تاپیک زدن و... مشکلم حل شد.راه حل نهایی:در فایل gradle.properties، این خط را برای غیر فعال کردن DataBinding اضافه کنید:android.databinding.enableV2=falseسورس کد پروژه در گیتهاب: https://github.com/moeindev/KotlinRoomAAC </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Sat, 27 Oct 2018 16:47:20 +0330</pubDate>
            </item>
                    <item>
                <title>لیست کشویی در سویفت</title>
                <link>https://virgool.io/MobileLab/%D9%84%DB%8C%D8%B3%D8%AA-%DA%A9%D8%B4%D9%88%DB%8C%DB%8C-%D8%AF%D8%B1-%D8%B3%D9%88%DB%8C%D9%81%D8%AA-qvtqoxnvtcpf</link>
                <description>در این آموزش کوتاه یاد خواهیم گرفت که چگونه یک لیست با آیتم و زیر مجموعه بسازیم.قبل از اینکه شروع کنیم شما می توانید مطالب قبلی را بخوانید: http://vrgl.ir/HOR1C  http://vrgl.ir/gfdiCایجاد پروژه در ایکس کد:در اینجا اطلاعات خود را تکمیل کنید:بعد از تکمیل اطلاعات، در صفحه بعدی single view application را انتخاب کنید و مسیر ذخیره پروژه را تعیین کنید؛ حالا اپلیکیشن شما آماده کدنویسی است:به اِستوریبٌرد اصلی خود بروید:از منوی پایین سمت راست، Table View را انتخاب کرده و به صورت دِرَگ و دِراپْ به داخل ویٌوکٌنْتٌرٌلِرْ خود بکشید:بعد از تغییر اندازه و ست کردن constraint ها، تِیبِل ویو را انتخاب کنید و در منوی سمت راست، Prototype cells را از ۰ به عدد ۲ تغییر بدید.حالا در تِیبِل ویو دو آیتم را مشاهده می کنید:در قدم بعدی هر سِل را انتخاب کنید و به آن identifier بدهید: در قدم بعدی استایل سِل ها را به basic تغییر بدهید:نکته: در اینجا میتوان فقط از یک سِل هم استفاده کرد!در قدم بعدی، با انتخاب کردن تِیبِل ویو، دیتاسورس و دلیگیت را با استفاده از دِرَگ و دِراپْ به ویٌوٌکٌنْتٌرٌلِرْ ارتباط بدهیم.پس از انجام دادن این کار، با استفاده از دِرَگ و دِراپْ، تِیبِل ویوی خود را به ViewController.swift متصل می کنیم:حال، با افزودن دلیگیت و دیتاسورس در ویوکنترلر کنترل تِیبِل ویو خود را به دست بگیرید!متوجه اخطار ایکس کد می شوید که با افزودن متود های زیر، اخطار رفع می شود:در اینجا ما دونوع داده داریم، یکی آیتم ها و یکی زیر مجموعه آیتم ها که می خواهیم آن ها را به صورت کشویی باز و بسته و نشان بدهیم!پیش از هرکاری متود زیر را نیز اضافه کنید:حالا نوبت این است که اطلاعات را نمایش بدهیم، در اینجا ممکن است اطلاعات مورد نظر ما هرچیزی باشد، اما برای ساده کردن، کلاسی برای دیتامٌدل خود می سازیم و اطلاعات را درون آن قرار می دهیم:هر expandDataModel یک آیتم است.هر آیتم دارای مقدار isExpanded می باشد که وضعیت باز بودن و یا بسته بودن آیتم را به ما نشان می دهد.هر آیتم دارای یک عنوان است که آن را با sectionTitle مشخص می کنیم.هر آیتم دارای تعدادی زیر مجموعه است که برای ساده کردن از رشته استفاده شده که آن را با sectionRows مشخص می کنیم.در متود init، به هر پراپرتی یک مقدار می دهیم.بر می گردیم به کلاس ویٌوکٌنْتٌرٌلِرْ خود و یک آرایه از دیتامٌدل خود به مقدار دلخواه می سازیم:حالا در این قسمت ما می خواهیم تعداد زیر مجموعه ها در یک آیتم را مشخص کنیم:در اینجا ما مقدار آیتم ها را برگشت می دهیم در صورتی که آن ها باز باشند.نکته: برای جلوگیری از fatal error: Array index out of range در سویفت، ما مقدار برگشتی را همیشه در صورت باز بودن بعلاوه ۱ می کنیم!در متود numberOfSections، مقدار آیتم های خودرا برمی گردانیم:در متود cellForRowAt، مقادیر را در آیتم ها و زیر مجموعه ها پر می کنیم:در اینجا ما ابتدا چک خواهیم کرد که آیا این یک section است یا row، در قدم بعدی اگر section بود با استفاده از indexPath.section مقدار section مورد نظر را بگیرد و اطلاعات را نمایش دهد! و اگر row بود، مقدار را با استفاده از indexPath.row -1 از section بگیرد و نمایش دهد!نکته: در قسمت قبلی ما مقدار ایندکس را بعلاوه ۱ کردیم و حالا آن را در indexRow برای زیر مجموعه ها کم می کنیم.حالا باید مشخص کنیم که وقتی یک آیتم انتخاب شد، در صورت باز بودن بسته و در صورت بسته بودن باز شود! و در این حال اگر زیر مجموعه انتخاب شد، عملی صورت نگیرد! به نظر خیلی پیچیده است اما در واقعیت نیست:توضیحات: در این قسمت ابتدا نوع را تعیین کردیم که آیا section است یا row، در صورت section یا همان آیتم بودن وضعیت باز بودن و یا بسته بودن را با استفاده از isExpanded بررسی کند؛ در صورت باز یا بسته بودن با تغییر مقدار isExpanded آن را کنترل کند و در آخر، با دستور reloadSections، مقدار تغییر یافته را اعمال کند!پروژه رو اجرا کنید:?همانطور که می بینید، برنامه به درستی کار می کند!جمع بندی:‌ این نوع از آیتم ها بسیار کاربردی هستند و در مواردی مانند نمایش پست ها و نظرات مربوط به آن ها و... به کار می روند. تِیبِلْ ویو یکی از عناصر حیاتی در برنامه نویسی آی او اس می باشد و عملکرد آن همانند ریسایکِلِر ویو در برنامه نویسی اندروید می باشد. و هر دو دارای ویژگی ها و ضعف های خاص خود می باشند. در آینده به مقایسه این دو عنصر خواهیم پرداخت!کد پروژه در گیتهاب ?: https://github.com/moeindev/ExpandableCell </description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Fri, 19 Oct 2018 22:03:27 +0330</pubDate>
            </item>
                    <item>
                <title>مروری بر طراحی اِسْکِچ دیزاین در آی او اس</title>
                <link>https://virgool.io/MobileLab/%D9%85%D8%B1%D9%88%D8%B1%DB%8C-%D8%A8%D8%B1-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%A7%D9%90%D8%B3%D9%92%DA%A9%D9%90%DA%86-%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D8%AF%D8%B1-%D8%A2%DB%8C-%D8%A7%D9%88-%D8%A7%D8%B3-kxqwkkujhesz</link>
                <description>بعد از دوماه تجربه شیرین آی او اس، تصمیم گرفتم که بعضی از عناصر موجود برای طراحی یو آی(UI) در آی او اس را با اندروید به صورت کلی مقایسه کنم.عناصر طراحی کلی اندروید و آی او اس:عنصر آی او اس = معادل تقریبی در اندرویداِستوریبُرد(StoryBoard) = لایه ایکس ام ال (XML Laout)ویٌوکٌنتٌرِلِر(ViewController) = اَکْتیویتی (Activity)سِگْوِی(Segue) = معادل تقریبی برای اجرای اکتیویتی دیگر از طریق اینتِنت(Intent)اِستوریبٌرد(StoryBoard):چیزی نیست جز یک نمایش دهنده طراحی کلی برنامه و روابط بین ویٌوکٌنتٌرٌلِر ها و سِگوِی هایی که با ایکس ام ال نوشته شده است! شما می توانید ویٌوکٌنتٌرٌلِر های خود را از طریق اِستوریبٌرد به یک دیگر ارتباط بدهید و از کٌد نویسی بیشتر برای اجرای صفحات اَپ خود خودداری کنید!نمای کلی یک اِستوریبٌرد:مزیت نسبت به اندروید: شما می توانید کل صفحات خود را در یک اِستوریبٌرد طراحی کنید و ارتباطات بین آن ها را نیز تعریف کنید بدون اینکه لازم باشد یک خط کٌد بنویسید! جالبه نه؟ اما انیمیشین بین صفحات را چگونه تعریف کنیم؟ جواب بسیار ساده است! درون اِستوریبٌرد به سادگی میتوان نوع انیمیشن را برای هر صفحه تعیین کرد و دیگر نگران کِرَش کردن اَپ خود هنگام اجرا نباشیم(خطاهای مربوط به اجرا نشدن بعضی از انیمیشن ها در نسخه های مختلف اندروید). در آینده نیز مطالبی در مورد اُتولایٌوت در آی او اس خواهم نوشت!ویٌوکٌنتٌرٌلِر(ViewController):یکی از اجزای اِستوریبٌرد می باشد که وظیفه نمایش اطلاعات و هَنْدِلِرْ برای حرکات کاربر روی صفحه مورد نظر می باشد. چیزی مانند اکتیویتی در اندروید. شما در هر اِستوریبٌرد می توانید n ویٌوکٌنتٌرٌلِر داشته باشید. همچنین می توانید برای هر ویٌوکٌنتٌرٌلِر یک فایل دیزاین مجزا داشته باشید درست مانند اندروید! ?نمای کلی یک ویٌوکٌنتٌرٌلِر:نمای پیشفرضنمای یک نمونه تکمیل شدهسِگوِی(segue): یکی از اجزای اِستوریبٌرد و یک نشان دهنده جریان و ارتباطات بین صفحات هست که به سیستم مبدأ و مقصد را نشان می دهد و باعث می شود که شما نیازی به کٌدنویسی بیشتر برای اجرای نمایش صفحات نخواهید داشت! نمای کلی یک سِگوِی بین دو ویٌوکٌنتٌرٌلِر:نمای کلی یک اِستوریبٌرد با چندین ویٌوکٌنْتٌرٌلِر و چندین سِگوِی:جمع بندی کلی:برنامه نویسی آی او اس به مراتب از برنامه نویسی اندروید آسان تر و لذت بخش تر می باشد! در این آموزش سعی شد فقط عناصر اصلی را مورد بررسی قرار بدهیم و در آینده عناصر دیگر مانند NavigationController و TabBarController را نیز مورد بررسی قرار می دهیم!پی نوشت: در این مقاله سعی شد از مفاهیم ساده برای توضیح عناصر استفاده شود اگر کمی و کاستی را در این مقاله مشاهده نمودید لطفا در بخش کامِنت ها بنده را مطلع بفرمایید!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Thu, 11 Oct 2018 11:50:11 +0330</pubDate>
            </item>
                    <item>
                <title>مهاجرت از اندروید به ای او اس</title>
                <link>https://virgool.io/MobileLab/%D9%85%D9%87%D8%A7%D8%AC%D8%B1%D8%AA-%D8%A7%D8%B2-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A8%D9%87-%D8%A7%DB%8C-%D8%A7%D9%88-%D8%A7%D8%B3-dgginerimhb1</link>
                <description>مدت ها بود که به فکر این بودم در کنار برنامه نویس اندروید، برنامه نویسی آی او اس را هم یاد بگیرم ولی هیچوقت زمان یادگیری را نداشتم! بعد از اینکه قسمت اندروید یک پروژه را تمام کردم، توانستم یک ریزه با آی او اس کار کنم و بعد از چند دقیقه ای سِرچ در گوگل، توانستم یک منبع خوب برای یادگیری برنامه نویسی ای او اس پیدا کنم.لینک دوره در یودِمی: https://www.udemy.com/ios-11-app-development-bootcamp/ این یک دوره کامله برای دوستان مبتدی و همه نکات رو ریز به ریز با زبان انگلیسی ساده برای شما توضیح داده!متاسفانه امکان شرکت در دوره و پرداخت برای ما ایرانی ها وجود نداره! ولی خب همیشه میگن راه های رسیدن به خدا زیاده  :d لینک دانلود دوره در پی سی دانلود: http://p30download.com/fa/entry/74117/180919-%D8%AF%D8%A7%D9%86%D9%84%D9%88%D8%AF-udemy-ios-11-swift-4-the-comple نکته: دوره در سایت اپدیت نیست با توجه به اینکه الان آی او اس ۱۲ اومده و برنامه ایکس کد هم به نسخه ۱۰ ارتقا یافته البته برای یادگیری اولیه مشکلی نیست!در آینده مطالب بیشتری درباره ای او اس مینویسم.xCode:خب به بخش شیرین برنامه نویسی ای او اس یعنی xCode رسیدیم.ایکس کد ادیتور رسمی اپل برای برنامه نویسی ای او اس هست که ابزارهای متعددی برای برنامه نویسای ای او اس در اون قرار داده شده؛ شما با xCode میتونید برای دستگاه های دلخواه از قبیل آیفون،آی پد، واچ او اس(watch os) و سیستم عامل مک و... برنامه ی خودتان را توسعه بدهید.برای نصب برنامه میتوانید به AppStore مراجعه کنید!حداقل سیستم عامل مورد نیاز برای نصب : macOS 10.13.6 و نسخه های به روز تر! ادیتور های غیر رسمی: https://www.jetbrains.com/objc/  مشکلات برنامه: ۱.بعضی وقتا خطای syntax کُدی که می نویسید را با تاخیر تشخیص، یا اصلا تشخیص نمیده! راه حل پیشنهادی:‌ هر چند خط کُدی که می نویسید، چند ثانیه مکث کنید که بررسی کنه یا اینکه با زدن کلید های ترکیببی commmand+s مشکل رو حل کنید.۳. اُتوسِیو(Auto save) در اکثر اوقات کار نمیکنه و مجبورید به زدن کلید های command+save عادت کنید!(در اندروید استدیو همچنین مشکلی نداشتیم تاحالا) ۲.بعضی وقتا هم که فورس کلوز میده و نمیشه کاریش کرد اما اونقدرا هم اذیت نمیکنه!Swift:سال ۲۰۱۴ توسط اپل توسعه داده شد و برای جایگزین کردن سویفت با objective-c در برنامه نویسی ای او اس به کار گرفته شد! البته هنوز هم از objective-c در Xcode استفاده میشه و میتونید با اون برنامه خودتون رو توسعه بدید!اگر توسعه دهنده اندروید هستید با کاتلین کار کردید، تبریک میگم شما تقریبا با سویفت آشنایی دارید! در واقع کاتلین شباهت زیادی به syntax سویفت داره!برای مطالعه بیشتر میتونید به این لینک مراجعه کنید: https://blog.indoorway.com/swift-v-kotlin-the-differences-that-matter-50b2d393f526 Swift vs objective-c:Objective-Cswiftقضاوت با شما!پ ن : ی غلط توی کد هست! :دی اجرای اپلیکیشن توسعه داده شده:شما می توانید با استفاده از شبیه ساز آیفون، برنامه خود را تست کنید و نیازی نیست که دستگاه فیزیکی داشته باشید! همچنین میتوانید از آیفون خود برای تست استفاده کنید(در آینده صحبت میکنیم)تست فلایت:پلتفرمی برای تست اپلیکیشن روی دستگاه های تیم شما و برای اجرای آزمایشی اپلیکیشن شما قبل از منتشر کردن می باشد!(در آینده بیشتر صحبت میکنیم).برای استفاده از تست فلایت باید اکانت دِوِلُوپِر اپل داشته باشید!منتشر کردن اپلیکیشن:برخلاف اندروید، خروجی گرفتن برنامه برای منتشر کردن آسان نخواهد بود! شما باید یک اکانت دِوِلُوپِر اپل داشته باشید که قیمت اون ۹۹ دلاره! در غیر اینصورت میتونید به صورت sign نشده خروجی بگیرید و در مارکت های ایرانی منتشر کنید!جمع بندی کلیاگر مثل من توسعه دهنده اندروید هستید، پیشنهاد میکنم که برنامه نویسی آی او اس را حتما امتحان کنید و مطمئن هستم که تجربه عالی و لذت بخشی خواهید داشت!پ.ن: از دوستان متخصص در زمینه ای او اس بابت هرگونه کم و کاستی در این مقاله معذرت میخواهم و اگر جایی اشتباه شده در بخش کامنت ها اصلاح کنید!</description>
                <category>محمد معین عبدی</category>
                <author>محمد معین عبدی</author>
                <pubDate>Wed, 10 Oct 2018 22:25:35 +0330</pubDate>
            </item>
            </channel>
</rss>