<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های نسرین محمدزاده</title>
        <link>https://virgool.io/feed/@nasrin4672</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 15:55:17</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/195916/avatar/n626Tr.png?height=120&amp;width=120</url>
            <title>نسرین محمدزاده</title>
            <link>https://virgool.io/@nasrin4672</link>
        </image>

                    <item>
                <title>شخصی سازی پیام های Firebase In-App Messaging در اندروید</title>
                <link>https://virgool.io/@nasrin4672/%D8%B4%D8%AE%D8%B5%DB%8C-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%BE%DB%8C%D8%A7%D9%85-%D9%87%D8%A7%DB%8C-firebase-in-app-messaging-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-rpghwdbs1jjy</link>
                <description>سلام به دوستان عزیز تو این مقاله قصد دارم نحوه شخصی سازی رابط کاربری پیام های firebase in-app messaging (به اختصار fiam) رو توضیح بدم. تو مقاله ی قبلی که منتشر کردم نحوه راه اندازی fiam رو توضیح دادم که از این لینک میتونید بهش دسترسی داشته باشید.خب مرحله اول برای اینکار اینه که کلاس زیر رو ایجاد کنید. توی این کلاس قراره پیامی که از فایربیس دریافت کردیم رو بررسی کنیم و براساس نوع پیامی که ارسال شده ui موردنظر خودمون رو نمایش بدیم:*نکته: توی این کد از  dependency injection و Hilt استفاده شده .مرحله ی بعدی اینه که کد زیر رو توی  اکتیویتی اصلیتون قرار بدید. اگر پروژتون single activity هست توی اون اکتیویتی در غیر این صورت یک base activity که سایر activity ها از اون ارث بری میکنند.خب با این کار برای اولین بار که متد  اجرا میشه پیام های از فایربیس دریافت میشن و بسته به ایونتی که برای اون پیام در زمان ارسال درنظر گرفته شده در جای مناسبش نمایش داده میشه به علاوه این پیام ها به کلاس InAppMesssagingHandler ای که از قبل ساختیم ارسال میشه و پیام ها براساس ui ای که ما براش درنظر گرفتیم نمایش داده میشه.مرحله ی بعدی پیاده سازی ui هایی هست که برای پیام ها در نظر گرفتیم.بسته به استایل و تم نرم افزارتون این بخش هارو میتونید خودتون پیاده سازی کنید.در ادامه میریم سراغ کامل کردن کلاس InAppMesssagingHandler. همونطور که بالاتر شمای کلی این کلاس رو دیدید ما میتونیم بر اساس messageType تشخیص بدیم که چه نوع پیامی برامون ارسال شده و براساس اون ui موردنظرمون رو اعمال کنیم به عنوان مثال برای حالتی که پیاممون از نوع Modal هست کد اون بخش به شکل زیر پیاده سازی میشه:مهم ترین نکته ای که پیاده سازی این بخش داره کد زیر هست:توی این تیکه از کد ما زمانی که کاربر پیام رو میبنده با صدا زدن کال بک CLICK در واقع اعلام میکنیم که کاربر این پیام رو مشاهده کرده، اگر این کار رو انجام ندیم هر بار کاربر به نقطه ی دریافت اون پیام میرسه (به عنوان مثال اپ در حالت foreground قرار بگیره) اون پیام دوباره به کاربر نمایش داده میشه.حالا خروجی کدمون رو توی دو حالت با هم میبینیم: حالتی که ui پیش فرض خودت فایربیس هست و  حالتی که ما ui موردنظر خودمون رو اعمال کردیم برای پیام های از نوع Cardحالت پیش فرض فایربیسحالت customize شدهتا اینجا مراحل کلی پیاده سازی توضیح داده شد، جزییات و پیاده سازی کامل کد بالا تو گیت هابم قرارداره میتونید کد رو به طور کامل از این لینک دریافت کنید و جزییات پیاده سازیش رو ببینید.پذیرای نظرات و پیشنهاداتون هستم.</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Sun, 20 Feb 2022 18:04:41 +0330</pubDate>
            </item>
                    <item>
                <title>راه اندازی Firebase In-App Messaging در اندروید</title>
                <link>https://virgool.io/@nasrin4672/%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-firebase-in-app-messaging-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-rp58zpdqnol6</link>
                <description>سلام به دوستان عزیز توی این مقاله میخوام نحوه راه اندازی in-app messaging فایربیس رو توضیح بدم و بعد از اون نحوه کاستومایز کردن ui پیام هاش رو باهم بررسی خواهیم کرد.اول از همه باید ببینیم  FIAM  ( مخفف Firebase In-App Messaging ) چی هست و برای چه کاری استفاده میشه. FIAM سرویس ارسال پیام فایربیس هست و این پیام ها زمانی ارسال میشن که اپلیکشن در حال اجرا هست یا به اصطلاح تو foreground قرار داره و کاربر در حال استفاده از اپلیکیشن هست. علاوه بر اون این قابلیت رو داره که به صورت اختصاصی زمانی ارسال بشه که کاربر داخل اپلیکشن اکشن خاصی رو انجام میده مثلا وقتی کاربر روی دکمه ی خاصی کلیک کرد یک پیام براش ارسال بشه. راه اندازی اولیه FIAM ( مخفف Firebase In-App Messaging ) بسیار کار ساده ای هست که در ادامه با هم میبینیم.نکته۱: تو این مقاله فرض بر این گرفته شده که شما از قبل پروژتون رو داخل کنسول فایربیس اضافه کردید.نکته۲: کدها با زبان کاتلین خواهند بود.مرحله اول برای راه اندازی FIAM اضافه کردن Dependency های موردنیازش تو gradle هست:dependencies {
    implementation platform(&#039;com.google.firebase:firebase-bom:29.0.3&#039;)
    implementation &#039;com.google.firebase:firebase-inappmessaging-display-ktx&#039;
    implementation &#039;com.google.firebase:firebase-analytics-ktx&#039;
}خب بعد از sync کردن اپلیکیشن شما اماده دریافت FIAM هست.حالا نحوه ارسال یه FIAM رو با هم بررسی میکنیم:برای این کار اول وارد کنسول فایربیس بشید و اپلیکیشن مورد نظرتون رو انتخاب کنید و وارد داشبورد اون بشید و از منوی سمت چپ گزینه ی In-App Messaging رو انتخاب کنید.تو این قسمت روی دکمه Create your first campaign کلیک کنید:تو قسمت اول این صفحه میتونید نوع پیامی که در نظر دارید ارسال بشه رو مشخص کنید که چهار حالت مختلف داره: card, modal, image only, top banner به عنوان مثال حالت modal رو انتخاب میکنیم. تو این قسمت میتونیم خصوصیات ظاهری مثل رنگ متن و رنگ پس زمینه و رنگ دکمه و لینک عکس موردنظرمون و موارد دیگه رو مشخص کنیم.مرحله بعدی مشخص کردن تارگت پیاممونه که با شرط های مختلف میتونیم مشخص کنید برای کدون پلتفرم ، کدوم نسخه از اپلیکیشنمون و ... پیام ارسال بشه.تو مرحله بعدی میتونیم مشخص کنید که چه زمانی پیاممون نشون داده بشه. به عنوان مثال زمانی که اپ میاد تو foreground یا هر event خاص دیگه ای که تو اپلیکیشنمون مشخص کردید.در انتها میتونید یا این کمپین رو save as draft کنید یا publish کنید. پیشنهاد میشه در زمانی که مشغول توسعه FIAM توی اپلیکیشنتون هستید از حالت save as draft استفاده کنید و برای تست کردن هم از روشی که در ادامه توضیح میدیم استفاده کنید.اگر کمپین رو پابلیش بکنید فقط یک بار پیام رو داخل اپ مشاهده میکنید ولی در زمان توسعه شما نیاز دارید که چندین بار پیام رو ببینید موارد مختلف رو تست کنید برای این کار ابتدا باید Id مربوط به دیوایستون رو پیدا کنید. برای پیدا کردن این id به قسمت logcat اندروید استودیو برید و متن زیر رو سرچ کنید:I/FIAM.Headless: Starting InAppMessaging runtime with Installation ID YOUR_INSTALLATION_IDمقداری که به جای YOUR_INSTALLATION_ID مشاهده میکنید رو کپی کنید و از منوی زیر گزینه test on device رو انتخاب کنید:حالا id دیوایستون رو اینجا paste کنید و دکمه +  رو بزنید و در اخر دکمه test رو کلیک کنید و برنامه تون رو اجرا کنید تا خروجی کار رو مشاهده کنید.خروجی رو باید  به صورت زیر مشاهده کنید:تو مقاله ی بعدی نحوه ی کاستومایز کردن ui پیام ها رو بررسی خواهیم کرد.</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Sat, 01 Jan 2022 15:12:31 +0330</pubDate>
            </item>
                    <item>
                <title>نحوه استفاده از دستور git bisect</title>
                <link>https://virgool.io/@nasrin4672/%D8%AF%D8%B3%D8%AA%D9%88%D8%B1-git-bisect-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-kiybjsojv6cf</link>
                <description>احتمالا خیلی پیش اومده که یه فیچر یا یه کدی رو پیاده سازی کردید و تست کردید و نهایتا دیدید که همه چی اوکی هست ولی یهو بعد یه مدت دیدید که اون قسمت درست کار نمیکنه، یا اینکه در طول زمان اومدید و یه بخش های دیگه ای رو تغییر دادید و اون تغییرات باعث شدن یه قسمت از کدتون ایراد پیدا کنه.خب پیدا کردن این ایرادات ریز تو پروژه های بزرگ ممکنه خیلی سخت بشه و اینکه گاهی ادم نمیدونه اصلا کدوم قسمت باعث به وجود اومدن این مشکل شده.واسه حل کردن این مشکل تو git یه دستور خیلی کاربردی وجود داره که با چند مرحله به راحتی مارو میرسونه به اون کامیتی که باعث به وجود اومدن ایراد شده.مرحله اول اینه که بیاید اون کامیتی که کدهاتون داشته درست کار میکرده رو پیدا کنید و بعداز اون یه کامیت هم به عنوان کامیتی که کد ایراد داره که این میتونه مثلا اخرین کامیت باشه.هر کامیت هم یه id داره که در ادامه به اون نیاز داریم.خب دستور اولی که میزنیم کامیت زیر هست:git bisect startبا این دستور کار جستجومون شروع میشهمرحله بعدی مشخص کردن کامیت ایراد دار هست که به دو حالت میشه مشخصش کرد: git bisect bad HEAD
یا
git bisect bad efa421e602e29ec557c915bb719879d336ba6bدستور اول میاد اخرین کامیت رو به عنوان کامیت بد در نظر میگیره و با دستور دوم میتونید خودتون یه کامیت مشخص رو به عنوان کامیت بد مشخص کنید. اون id هم که تو دستور دوم استفاده شده id کامیت مورد نظرمون هست که در ادامه میگم چطور میشه به دست اوردش.مرحله بعدی هم مشخص کردن کامیتی هست که همه چی توش درست کار میکرده:git bisect good efa421e602e29ec557c915bb719879d336ba6bحالا تو این مرحله میتونید اپ رو بیلد کنید و ببینید همه چی درسته یا نه. مکانیزم این دستور به این شکله که میاد مثل جستجوی دودویی کامیت وسطی بین کامیت خوب و بد رو انتخاب میکنه و کدها رو میبره تو اون کامیت حالا با توجه به وضعیت شما باید ببینید اگه همه چی درست بود پس باید id کامیت وسطی رو بذارید به عنوان کامیت good  و به جستجو ادامه بدید و اگر هنوز ایراد داشت پس این کامیت میانی میشه کامیت bad . انقد این جابه جایی هارو ادامه میدیم تا نهایتن برسیم به یک کامیت اخر که میشه همون کامیتی که کدمون توش خراب شده.بعد از این که کارمون تموم شد هم باید دستور زیر رو بزنیم تا پروسه تموم شه:git bisect resetبرای به دست اوردن id کامیت هامون هم دستور زیر رو میتونیم استفاده کنیم:git logفقط یادتون باشه که ممکنه تغییراتی تو بازه های مختلف زمانی رو کدتون اجرا کرده باشید که باعث شه کد اجرا نشه و باید قبل از بیلد کردن اونا رو تغییر بدید ، مثلا من توی کدم ادرس سرور رو یه بار تغییر داده بودم و خب ادرس سرور قدیمی دیگه در دسترس نبود پس تو تمام مراحل باید حواسم میبود که قبل از run کردن بیام ادرس سرور فعال رو بذارم تو کدم.امیدوارم این پست بتونه کمکتون کنه.</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Sat, 20 Jun 2020 15:00:01 +0430</pubDate>
            </item>
                    <item>
                <title>Kotlin — Control Flow</title>
                <link>https://virgool.io/@nasrin4672/kotlin-control-flow-mfnmfpb3m46v</link>
                <description>عملگرهای کنترلی میتونن برای انتخاب یک مسیر مناسب بین 2 یا چند مسیر استفاده شن. در این مقاله توضیح مختصری راجع به عملگرهای زیر رو بررسی میکنیم:ifwhenforwhile و do...whilebreakcontinueعملگر if:کاربرد اصلی این عملگر یا همون چک کردن یک شرط:val num1 = 10
val num2 = 20
    
if (num1 &gt; num2) {
    print(&amp;quotnum1 &gt; num2)
} else if (num1 &lt; num2) {
    print(&amp;quotnum1 &lt; num2&amp;quot)
} else {
    print(&amp;quotnum1 == num2&amp;quot)
}
// Output: num1 &lt; num2تو کاتلین شرط های یک خطی مشابه ساختاری که تو جاوا بود رو نداریم دیگه (Java--&gt; condition ? val1:val2)به جاش میشه به حالت زیر تو کاتلین پیادشون کرد:val num = 0
val isZero = if (num == 0) true else falseیه خاصیتی که if توی کاتلین داره اینه که میتونه یه مقدار رو برگردونه به عنوان خروجی، در نتیجه میتونیم تو قسمت return توابعمون هم ازش استفاده کنیم:fun getMinValue(a: Int, b: Int): Int {
    return if (a &lt;= b) {
        a
    } else {
        b
    }
}نکته: وقتی داریم اینجوری از if استفاده میکنیم حتما باید خط اخر از هر بلاک if و else مقدار موردنظر به عنوان خروجی تابع باشه.عملگر when:عملگر when جایگزین عملگر switch case (جاوا) در کاتلین هست. با این تفاوت که خیلی قدرتمندتر از switch case هست. این عملگر هم مثل عملگر if میتونه یه مقدار به عنوان خروجی داشته باشه.استفاده ساده ی این عملگر که مشابه switch case هست به شکل زیر هست:val color = &amp;quotRED&amp;quot
when(color) {
    &amp;quotRED&amp;quot -&gt; print(&amp;quotColor is RED&amp;quot)
    &amp;quotGREEN&amp;quot -&gt; print(&amp;quotColor is GREEN&amp;quot)
    &amp;quotBLUE&amp;quot -&gt; print(&amp;quotColor is BLUE&amp;quot)
    else -&gt; print(&amp;quotColor is Unknown&amp;quot)
}
// Output: Color is REDنقطه ی قدرت عملگر when:fun getValue(input: Any): String {
    return when (input) {
 is String -&gt; &amp;quotInput is a String&amp;quot
 in &#039;A&#039;..&#039;Z&#039; -&gt; &amp;quotInput is between A to Z&amp;quot
 0 -&gt; &amp;quotInput is 0&amp;quot
 1, 2 -&gt; &amp;quotInput is either 1 or 2&amp;quot
 in 3..10 -&gt; &amp;quotInput is between 3 to 10&amp;quot
 !in 11..100 -&gt; &amp;quotInput is not between 11 to 100&amp;quot
 else -&gt; &amp;quotInside else case&amp;quot
    }
}همونطور که میبینید اگر تو ورودی تابع نوع ورودیمون رو any بگذاریم میتونیم هر نوع ورودی رو بهش پاس بدیم. حالا ورودی و خروجی های مختلف رو چک میکنیم:getValue(&quot;Any String&quot;) : خروجی Input is a String.getValue(&#x27;D&#x27;) : خروجی input is between A to Z.getValue(0) : خروجی Input is 0.getValue(5) : خروجی Input is between 3 to 10.getValue(256) : خروجی Input is not between 11 to 100.getValue(55) : خروجی Inside else case.نکته: از is و is! برای چک کردن نوع ورودیمون استفاده میکنیم. از in و in! برای چک کردن بازه استفاده میکنیم.حلقه for:حلقه for برای تکرار یک عملیات به تعداد دفعات مشخص استفاده میشه. برای مشخص کردن بازه ی تکرار عملیات در حلقه ی for چند حالت مختلف داریم :استفاده از کلمه کلیدی in:با این روش حلقه به تعداد اعضای لیست موردنظر اجرا میشه و در هر چرخش هم ما به اون ایتم که نوبتش رسیده دسترسی داریم.val fruits = listOf(&amp;quotApple&amp;quot, &amp;quotBanana&amp;quot, &amp;quotCherries&amp;quot, &amp;quotGuava&amp;quot)
for (fruit in fruits) {
    println(fruit)
}
// Output: Apple, Banana, Cherries, Guavaاستفاده از عملگر .. :با این عملگر میتونیم بازه مشخص کنیم. نکته این عمگر اینه که حد بالا و پایینش رو هم شامل میشه یعنی اگر بگیم از 0 تا 5 هم 0 رو شامل میشه هم 5.for (number in 0..5) {
    println(number)
}
// Output: 0 1 2 3 4 5استفاده از عملگر ()withIndex :این تابع در هر چرخش یه ایندکس به هر ایتم میده.val fruits = listOf(&amp;quotApple&amp;quot, &amp;quotBanana&amp;quot, &amp;quotCherries&amp;quot, &amp;quotGuava&amp;quot)
for ((index, fruit) in fruits.withIndex()) {
    println(&amp;quot$index - $fruit&amp;quot)
}
// Output: 0 - Apple, 1 - Banana, 2 - Cherries, 3 - Guavaاستفاده از کلمه کلیدی until:این عملگر هم مثل .. برای مشخص کردن بازه استفاده میشه با این تفاوت که حد بالا رو شامل نمیشه ینی اگر بگیم از 0 تا 5 فقط 0 رو شامل میشه.for (number in 0 until 5) {
    println(number)
}
// Prints: 0 1 2 3 4استفاده از کلمه کلیدی dwonTo:این عملگر هم برای مشخص کردن بازه استفاده میشه اما به صورت معکوس از اخر به اول و مشابه عملگر .. حد بالا و پایین رو شامل میشه.for (number in 5 downTo 0) {
    println(number)
}
// Prints: 5 to 0استفاده از کلمه کلیدی step:اگر بخواهیم تو هر گام تغییر شمارندمون بیشتر از 1 واحد باشه از این کلمه میتونیم تو حلقمون استفاده کنیم.for (number in 0..10 step 2) {
    println(number)
} 
// Prints: 0, 2, 4, 6, 8, 10
for (number in 10 downTo 0 step 2) {
    println(number)
}
// Prints: 10, 8, 6, 4, 2, 0

val fruits = listOf(&amp;quotApple&amp;quot, &amp;quotBanana&amp;quot, &amp;quotCherries&amp;quot, &amp;quotGuava&amp;quot)
for (index in fruits.indices step 2) {
    println(fruits[index])
}
// Prints: Apple, Cherriesاستفاده از کلمه کلیدی indices:این تابع تعداد گام ها رو براساس تعداد ایتم های لیست در نظر میگره و خب از خصوصیت های list هست.val fruits = listOf(&amp;quotApple&amp;quot, &amp;quotBanana&amp;quot, &amp;quotCherries&amp;quot, &amp;quotGuava&amp;quot)
for (index in fruits.indices) {
    println(fruits[index])
}
// Prints: Apple, Banana, Cherries, Guavaحلقه while و do..while:حلقه while ابتدا شرطی که براش مشخص شده رو چک میکنه و اگر شرط برقرار بود بدنه حلقه رو اجرا میکنه. یعنی ممکنه در صورت برقرار نبودن شرط اصلا بدنه حلقه اجرا نشه.var i = 5 
while (i &gt; 0) {
    println(i)
    i--
}
// Ouput: 5 4 3 2 1حلقه do...while برعکس while اول بدنه رو اجرا میکنه بعد شرط رو چک میکنه به این معنی که در هر صورت حداقل یک بار بدنه حلقمون اجرا میشه.var i = 5
do {
    println(i)
    i--
} while (i &gt; 0)
// Ouput: 5 4 3 2 1عملگر break:این عملگر به طور پیش فرض (بدون برچسب) وظیفه اینو داره که نزدیک ترین حلقه رو بشکونه و از ادامه داده شدنش جلوگیری کنه.همونطور که تو مثال پایین میبینید break حلقه ی for داخلی رو شکسته.for (x in 0..2) {
    for (y in 0..2) {
        if (y &gt; 0) break
        println(&amp;quotx:$x - y:$y&amp;quot)
    }
}
// Output:
x:0 - y:0 
x:1 - y:0 
x:2 - y:0حالا اگر بخواهیم با دستور break حلقه ی خارجی رو بشکونیم نیاز داریم که برای حلقه موردنظرمون برچسب بگذاریم و با استفاده از اون به دستور break بگیم که حلقه ای که مد نظرمونه رو بشکونه نه نزدیک ترین حلقه رو.outer@ for (x in 0..2) {
    for (y in 0..2) {
        if (y &gt; 0) break@outer
        println(&amp;quotx:$x - y:$y&amp;quot)
    }
}
// Output:
x:0 - y:0عملگر continue:این عملگر گامی که توش هستیم رو دیگه ادامه نمیده و مستقیم میره به گام بعدی. مثلا اگر بخواهیم حلقمون فقط اعداد فرد رو چاپ کنه مثل مثال زیر:for (i in 0..10) {
    if (i%2 == 0) continue
    print(&amp;quot$i &amp;quot)
}
// Output: 1 3 5 7 9برای عملگر continue هم میتونیم از برچسب استفاده کنیم و بهش بگیم که برای شروع دوباره برگرده به کدوم خط.outer@ for (x in 0..3) {
    for (y in 0..3) {
        if (y &gt; 1) continue@outer
        println(&amp;quotx:$x - y:$y&amp;quot)
    }
}// Ouput:
x:0 - y:0 
x:0 - y:1 
x:1 - y:0 
x:1 - y:1 
x:2 - y:0 
x:2 - y:1 
x:3 - y:0 
x:3 - y:1منابع:منبع 1منبع 2</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Fri, 05 Jun 2020 16:05:19 +0430</pubDate>
            </item>
                    <item>
                <title>توضیحات مقدماتی kotlin coroutine</title>
                <link>https://virgool.io/@nasrin4672/%D8%AA%D9%88%D8%B6%DB%8C%D8%AD%D8%A7%D8%AA-%D9%85%D9%82%D8%AF%D9%85%D8%A7%D8%AA%DB%8C-kotlin-coroutine-f9jgqaefietn</link>
                <description>کوروتین ها در اندروید روشی جدید برای مدیریت thread ها در پس زمینه هستند. اصولا زمانی از coroutine استفاده میشه که قراره کاری با مدت زمان طولانی در پس زمینه اجرا بشه مثل صدا زدن یک وب سرویس یا کار کردن با دیتابیس.البته باید به این نکته اشاره کنم که coroutineها thread نیستند بلکه یک راه برای مدیریت job ها روی thread ها هستند. یعنی شما میتونید چندین coroutine رو تو یک thread اجرا کنید.یکی از مزایای استفاده از coroutineها مدیریت راحت تر کارهای سریالی هست، به این معنی که به عنوان مثال اگر نیاز باشه از نتیجه ی یک وب سرویس به عنوان ورودی وب سرویس بعدی استفاده کنیم این کار با coroutineها خیلی ساده تر قابل انجام هستن.در ادامه چندتا مثال ساده میزنیم و ارسال یک وب سرویس با استفاده از coroutine رو با هم میبینیم.مرحله اول برای استفاده از coroutineها اضافه کردن dependence مورد نیازش به پروژمونه، برای این کار باید چند خط زیر رو به gradle اضافه کنید:implementation &amp;quotorg.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7&amp;quotimplementation &amp;quotorg.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7&amp;quotکد زیر رو تو اکتیویتیمون قرار میدیمclass Coroutine : AppCompatActivity() {

    privateval RESULT_1 = &amp;quotresult #1&amp;quot
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_coroutine)

        buttom.setListener {
            CoroutineScope(IO).launch {
                fakeApiRequest()
            }
        }
    }

    private suspend fun fakeApiRequest(){ 
        val result = getResult1FromApi()
        println(&amp;quotdebug: $result&amp;quot)
    }

    private suspend fun getResult1FromApi():String{
        logThread(&amp;quotgetResult1FromApi&amp;quot)
        delay(1000)
        return RESULT_1
    }

    private fun logThread(methodName : String){
        println(&amp;quotdebug: $methodName : ${Thread.currentThread().name}&amp;quot)
    }
}حالا ببینیم هر بخش این کد چیکار میکنه:تابع fakeApiRequest همونجور که از اسمش پیداست قراره یه وب سرویس رو شبیه سازی کنه.تابع getResult1FromApi نتیجه وب سرویس رو بعد از 1000 میلی ثانیه برامون ارسال میکنه.تابع logThread هم قراره بهمون بگه که اسم thread ای که کد داره روش اجرا میشه چی هست.نکته اول: چرا از کلید واژه suspend استفاده کردیم؟هر وقت بخوایم یه تابع رو داخل یک coroutine صدا بزنیم باید اون تابع suspend باشه.نکته دوم: تفاوت delay با Thread.sleep چیه؟همونطور که بالاتر توضیح دادیم coroutineها threadهای جداگونه نیستن، وقتی از delay استفاده کنیم صرفا اون کوروتینی که داخلش delay گذاشتیم  با تاخیر اجرا میشه اما thread.sleep باعث میشه که کل اون thread با تاخیر اجرا بشه. مثلا اگر 5 تا coroutine داخل اون thread قرار داشته باشه اون تاخیر روی همشون اعمال میشه.نکته سوم: CoroutineScope(IO).launch:وقتی میخوایم یه coroutine رو اجرا کنیم باید مشخص کنیم که میخوایم تو چه thread ای اجرا بشه. برای این کار 3 تا انتخاب داریم:مورد اول IO: منظور input/output هست، وقتی از این scope استفاده میکنیم که بخوایم به عنوان مثال یک وب سرویس رو صدا بزنیم یا با دیتابیس کار کنیم.مورد دوم Main: وقتی این مورد رو استفاده میکنیم که بخوایم با mainthread کار کنیم و نیاز باشه با ui در ارتباط باشیم.مورد سوم Default: این مورد هم وقتی که قرار باشه یه پردازش خیلی سنگین اجرا بشه ازش استفاده میکنیم.حالا اگر کد بالا رو اجرا کنیم خروجی زیر رو میبینیم:I/System.out: debug: getResult1FromApi : DefaultDispatcher-worker-1I/System.out: debug: result #1که خط اول همونطور که قبلا اشاره شد اسم thread ای که کد در حال اجرا شدن روش هست رو نشون میده و خط دوم هم خروجی وب سرویسمونه.حالا یکم کد بالا رو توسعه میدیم، هدفمون اینه که خروجی وب سرویسمون رو داخل یک textview نشون بدیم.برای اینکار تابع fakeApiRequest رو به شکل زیر تغییر میدیم:private suspend fun fakeApiRequest(){
    val result = getResult1FromApi()
    text.text = result
    println(&amp;quotdebug: $result&amp;quot)
}خب حالا اگه کد رو همینجا اجرا کنیم میبینیم که برنامه crash  میکنه اما چرا؟چون ما داریم کد رو روی IO اجرا میکنیم و همونطور که بالا توضیح دادیم این مورد داره تو پس زمینه اجرا میشه و برای برقراری ارتباط با ui باید روی mainthread باشیم.برای حل کردن این مشکل کد زیر رو استفاده میکنیم:private fun setNewText(input: String){
    val newText = text.text.toString() + &amp;quot\n$input&amp;quot
    text.text = newText
}

private suspend fun setTextOnMainThread(input: String){
    withContext(Main){
        setNewText(input)
    }
}

private suspend fun fakeApiRequest(){
    val result = getResult1FromApi()
    setTextOnMainThread(result)
    println(&amp;quotdebug: $result&amp;quot)
}تیکه کدی که مشکلمونو حل میکنه (withContext(Main هست. با استفاده از withContext میتونیم scope مونو تغییر بدیم. ما هم اینجا از io به main منتقل شدیم تا بتونیم با ui در ارتباط باشیم.خب همونطور که ابتدای مقاله اشاره کردم یکی از مزایای coroutineها این بود که کارای سریالی رو میشه راحت تر انجام داد. حالا در ادامه میبینیم که چطور میشه این کار رو انجام داد.private suspend fun getResult2FromApi():String{
    logThread(&amp;quotgetResult2FromApi&amp;quot)
    delay(1000)
    return RESULT_2
}تابع بالا رو به کدمون اضافه میکنیم و تابع fakeApiRequest رو به شکل زیر تغییر میدیم:private suspend fun fakeApiRequest(){
    val result = getResult1FromApi()
    setTextOnMainThread(result)
    println(&amp;quotdebug: $result&amp;quot)

    val result2 = getResult2FromApi()
    setTextOnMainThread(result2)
}حالا اگر کد رو اجرا کنیم میبینیم که اول result #1 چاپ میشه و بعد یک ثانیه result #2  چاپ میشه.حالا ممکنه یه جا نیاز داشته باشیم که وب سرویس دوم از نتیجه ی وب سرویس اول استفاده کنه، فقط کافیه که تابع getResult2FromApi رو به (getResult2FromApi(input: String تغییر بدیم و به شکل زیر ازش استفاده کنیم:private suspend fun fakeApiRequest(){
    val result = getResult1FromApi()
    setTextOnMainThread(result)
    println(&amp;quotdebug: $result&amp;quot)

    val result2 = getResult2FromApi(result)
    setTextOnMainThread(result2)
}اینجوری داریم نتیجه ی وب سرویس اول رو به وب سرویس دوم پاس میدیم.البته باید اشاره کنم که این بخاطر اینه که جفت این توابع دارن تو یه coroutine صدا زده میشن.خب تا اینجا یه دید مختصری به coroutineها داشتیم و چند تا مثال ساده رو بررسی کردیم.امیدوارم این مقاله کمکتون کنه. این نوشته بر اساس ویدیوی زیر نوشته شد:https://www.youtube.com/watch?v=F63mhZk-1-Y&amp;amp;amp;list=PLgCYzUzKIBE_PFBRHFB_aL5stMQg3smhL&amp;amp;amp;index=2&amp;amp;amp;t=0s</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Sat, 30 May 2020 00:29:23 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از shared elements در اندروید</title>
                <link>https://virgool.io/@nasrin4672/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-shared-elements-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-gpksofnywmbz</link>
                <description>تو این مقاله قصد دارم یه مثال ساده برای استفاده از ویژگی shared elements تو اندروید رو توضیح بدم. همونطور که میدونید این ویژگی از اندروید 5 به بعد به این سیستم عامل اضافه شد و بعد از اون شاهد انیمیشن ها و جابه جایی های قشنگ تری تو نرم افزار ها بودیم.برای این کار مرحله اول اضافه کردن یک ImageView تو اکتیویتی اولمونهactivity_main.xmlچند تا نکته رو باید اینجا بهش توجه کنید:اول اینکه چون این ویژگی از اندروید 5 به بعد اضافه شده اگر شما برای برنامتون minSdkVersion رو روی مقداری کمتر از 21 بگذارید مجبورید tools:targetApi=&quot;lollipop&quot; حتما مقدار دهی کنید.نکته بعدی هم خصوصیت transitionName هست که یه اسم به دلخواهتون بهش میدید و برای بقیه فرایند هم از این اسم استفاده میشه درواقع این خصیصه هست که مشخص میکنه المان مورد نظر تو مبدا باید تبدیل بشه به کدوم المان تو مقصد.در ادامه یه imageView هم تو اکتیویتی مقصدمون قرار میدیمactivity_second.xmlهمونجور که میبینید خصوصیت transitionNameرو هم اینجا دقیقا همون مقداری رو بهش دادیم که تو اکتیویتی اول داده بودیمعلاوه بر این ها باید خط زیر رو هم تو style برنامه باید اضافه کنید:styles.xmlتوجه کنید که مقدار tools:targetApi=&quot;lollipop&quot; رو هم اینجا باید اضافه کنید در صورتی که minSdkVersion رو مقداری کمتر از 21 قرار دادید در غیر این صورت نیازی به اضافه کردنش ندارید.حالا مرحله اخر اضافه کردن کد مربوط به جابه جایی بین دو تا اکتیویتی هست: MainActivity.ktخب اینجا باید تو باکس شماره 1 که مشخص شده اون transitionName که قبلا مشخص کرده بودیم رو بهش پاس بدیم که من مقدار imageرو براش گذاشته بودم.تو باکس شماره 2 هم باید id مربوط به imageView تو اکتیویتی مبدا رو بهش پاس بدیم که من مقدار image_view رو بهش دادم.SecondActivity.ktداخل اکتیویتی دوم هم چیز خاصی نیاز نیست بگذارید.و تمام:) حالا میتونید برنامه رو run کنید و نتیجه رو ببینید.کدهای مربوط به این مثال رو هم تو لینک زیر میتونید بهش دسترسی داشته باشید:https://github.com/NasrinMohammadzadeh/shared-elements</description>
                <category>نسرین محمدزاده</category>
                <author>نسرین محمدزاده</author>
                <pubDate>Mon, 18 May 2020 20:40:48 +0430</pubDate>
            </item>
            </channel>
</rss>