<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های R Hosseini</title>
        <link>https://virgool.io/feed/@R.Hosseini</link>
        <description>android developer</description>
        <language>fa</language>
        <pubDate>2026-06-10 12:57:35</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/66439/avatar/37AWJ1.png?height=120&amp;width=120</url>
            <title>R Hosseini</title>
            <link>https://virgool.io/@R.Hosseini</link>
        </image>

                    <item>
                <title>یک عکس خوب برای پروفایل!</title>
                <link>https://virgool.io/@R.Hosseini/%DB%8C%DA%A9-%D8%B9%DA%A9%D8%B3-%D8%AE%D9%88%D8%A8-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%BE%D8%B1%D9%88%D9%81%D8%A7%DB%8C%D9%84-ftjrs2zswatr</link>
                <description>شاید اولین گام مهم برای داشتن یک پروفایل در شبکه های اجتماعی از جمله توییتر، لینکدین، اینستاگرام و... داشتن یک عکس پروفایل مناسب است.بعضی از افراد حتی با کسی که عکس پروفایل ندارد ارتباط برقرار نمی کنند.در رزومه های  کاری نیز داشتن یک عکس مناسب برای ایجاد ارتباط اولیه اهمیت بسزایی دارد.یک عکس پروفایل مناسب، باعث می شود افراد با شما احساس صمیمیت کنند و تعداد افرادی که صفحه شما را مشاهده می کنند بیشتر شود.اما سوال اینجاست:چگونه یک عکس حرفه ای بگیریم؟!چگونه یک عکس حرفه ای بگیریم؟!1. عکاس مناسب انتخاب کنیداگر توان مالی شما اجازه می دهد، کمک گرفتن از یک عکاس حرفه ای می تواند کار شما را بسیار راحت کند. با این وجود نیازی به هزینه کردن برای داشتن عکاس حرفه ای نیست.شما می توانید از یک دوست یا یکی از اعضای خانواده بخواهید چندین عکس از شما بگیرد. کسی را برای این کار انتخاب کنید که بتواند لبخند طبیعی شما را خوب به تصویر بکشد. یک لبخند گرم و صمیمی، دیگران را برای ایجاد ارتباط و تعامل با شما ترغیب می کند.از عکاس (و در صورت امکان از چند دوست دیگر) بخواهید به عکسها نگاه کرده و نظر دهند.2. سلفی بگیریداگر کسی برای گرفتن عکس از شما در دسترس نیست، می توانید یک سلفی بگیرید. تعدادی عکس بگیرید و سپس تصمیم بگیرید که کدام یک بهترین است. پس از بارگزاری عکس در صفحه خود نیز حتما آن را بررسی کنید. اگر آنطور که انتظار داشتید بنظر نمی رسد، دوباره این کار را تکرار کنید.3. از یک Headshot استفاده کنیداز آنجا که عکس های پروفایل عموما بسیار کوچک هستند، شما باید فقط از سر و گردن و احتمالا شانه هایتان عکس بگیرید. اگر کل بدنتان در عکس نمایان باشد، سر شما خیلی کوچک بنظر می رسد و احتمالا مخاطبان نمی توانند چهره شما را تشخیص دهند.4. یک لباس رسمی بپوشیدالبته این مورد به محلی که قصد آپلود کردن عکس خود را دارید بستگی دارد. اگر پروفایل شما جنبه پروفایل رسمی و کاری دارد، بهتر است از یک لباس رسمی استفاده کنید. در حقیقت عکس شما باید با رشته شما تناسب داشته باشد.بطور مثال همانطور که همه می دانیم یک لباس گلدار، با طرح های شلوغ برای یک فضای کاری و تجاری مناسب نیست.از پوشیدن لباس بدون بند، تاپ یا هر لباس دیگری که باعث شود برهنه بنظر برسید، خودداری کنید. (دقت داشته باشید که قرار شد از قسمت سروگردن و شانه های خود عکس بگیرید!)داشتن یک پوشش حرفه ای و رسمی همچنین به معنای پرهیز از استفاده بیش از حد از آرایش و زیورآلات می باشد.5. عکس باید ساده باشددر یک عکس حرفه ای باید تمرکز عکس روی شما باشد. پس از اشیا، حیوانات خانگی یا کودکان استفاده نکنید. از پس زمینه های شلوغ بپرهیزید. بهتر است پس زمینه عکس یکدست و رنگ روشن باشد.البته که در عکس های غیر حرفه ای و شغلی، مثل پروفایل اینستاگرام یا فیسبوک جریان متفاوت است.اشتباه نکنید! لینکدین برای مشاغل و شبکه های شغلی طراحی شده است. از عکس های شلوغ در آن استفاده نکنید و عکس خود را حرفه ای نگه دارید. از لباسی که در محل کار یا مصاحبه شغلی می پوشید استفاده کنید.6. عکس جدید بگیریداز یک عکس جدید استفاده کنید تا مردم در ملاقات حضوری با شما متعجب نشوند. روبرو شدن با شخصی که 20 سال از عکس های خود بزرگتر است عجیب بنظر می رسد!عکس پروفایل خود را رها نکنید! بهتر است هر چند وقت یکبار تصویر خود را به روز کنید.7. از یک عکس واحد استفاده کنیدبرای توسعه نام تجاری خود یا به اصطلاح برندینگ خود، سعی کنید از یک عکس واحد برای شبکه های اجتماعی و حرفه ای خود استفاده کنید. این کار باعث می شود شما به راحتی قابل تشخیص باشید.بریم باهم چندتا از این نکات و باید و نباید هارو با مثال ببینیم:نور مناسب، رو به دوربینبرش عکس مناسبپس زمینه ساده، تمرکز روی چهرهاجتناب از پس زمینه شلوغ، لباس و آرایش مناسب، لبخندجمع بندی:به یاد داشته باشید که عکس اولین تاثیر را در مخاطبین شما خواهد گذاشت!1. عکاس مناسب انتخاب کنید2. سلفی بگیرید3. از یک Headshot استفاده کنید4. یک لباس رسمی بپوشید5. عکس باید ساده باشد6. عکس جدید بگیرید7. از یک عکس واحد استفاده کنید</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Tue, 06 Jul 2021 23:53:25 +0430</pubDate>
            </item>
                    <item>
                <title>ویژگی های یک عکس خوب برای لینکدین</title>
                <link>https://virgool.io/@R.Hosseini/%D9%88%DB%8C%DA%98%DA%AF%DB%8C-%D9%87%D8%A7%DB%8C-%DB%8C%DA%A9-%D8%B9%DA%A9%D8%B3-%D8%AE%D9%88%D8%A8-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%84%DB%8C%D9%86%DA%A9%D8%AF%DB%8C%D9%86-qyukx16kudit</link>
                <description>linkedin profile pictureوقتی برای کسب یک موقعیت شغلی، چندین نفر با شما شرایط مساوی داشته باشند، این عکس پروفایل شماست که میتواند در انتخاب نهایی کارفرمایان تاثیر بسزایی داشته باشد!در این مقاله بایدها و نبایدهای عکس پروفایل لینکدین را باهم بررسی میکنیم: https://virgool.io/p/qyukx16kudit/1-%DA%86%D8%B4%D9%85%D8%A7%D9%86%D8%A8%D8%A7%D8%B2%D9%88%D8%AE%DB%8C%D8%B1%D9%87 چشمان باز و خیره می تواند شما را ترسو یا ترسناک جلوه دهد! یک لبخند می تواند از این مورد اجتناب کند.2- صورت خود را بالا بگیریداینکار باعث میشود شما فردی با اعتماد بنفس بنظر برسید.فتوشاپ نیز میتواند در این کار به شما کمک کند تا با ایجاد سایه هایی در قسمت فک به این هدف برسید.3- از عینک آفتابی استفاده نکنیدچشم پنجره روح است!4- لباس معمولی و راحت نپوشیدکارفرمایان انتظار دارند شما را با لباس های رسمی ببینند. بطور باور نکردنی لباس های تیره تاثیر چشمگیری دارند!5- لبخند بزنیدلبخندی که دندان های شما دیده شود تاثیر مثبت زیادی در طرف مقابل دارد. (البته منظور یک لبخند با دهان کاملا باز نیست!!)6- ویرایش زیاداز ویرایش زیاد و استفاده از فیلترهایی که تغییرات اساسی در چهره شما ایجاد میکنند بپرهیزید. ویرایش در حد معقول قابل قبول است، اما چهره شما نباید دستخوش تغییرات فاحشی شود و محصول نهایی هیچ شباهتی به شما نداشته باشد.7- نظرسنجی در مورد عکس هاممکن است اطرافیان بنا به دلایلی نظر واقعی خود را به ما نگویند یا بخاطر شناختی که از ما دارند نظری متفاوت از افراد غریبه داشته باشند. پس بهترین کار استفاده از بازخورد اشخاص غریبه است.یک ابزار مناسب برای اینکار Photofeeler می باشد. هم اکنون به Photofeeler بروید و عکس های خود را تست کنید.</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Tue, 06 Jul 2021 16:42:48 +0430</pubDate>
            </item>
                    <item>
                <title>اتصال به درگاه پرداخت در برنامه های اندرویدی</title>
                <link>https://virgool.io/@R.Hosseini/httpsvirgooliorhosseini%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87-%D8%AF%D8%B1%DA%AF%D8%A7%D9%87-%D9%BE%D8%B1%D8%AF%D8%A7%D8%AE%D8%AA-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-nxyvkzz2krrp</link>
                <description>اتصال به درگاه پرداخت در برنامه های اندرویدیبسیاری از اپلیکیشن ها برای ارائه خدمات یا کالا ساخته می شوند و به همین خاطر شامل بخشی برای پرداخت و اتصال به درگاههای بانکی می باشند.اما همیشه برای برنامه نویسان این ابهام و سوال وجود دارد که مراحل این کار به چه صورت است؟درگاه های پرداخت بسیاری وجود دارد که برخی از آنها مستقیم و برخی دیگر، درگاه واسط می باشند. درگاه های مستقیم از طریق بانک ها قابل ارائه است. اما چون نیاز به مدارک زیادی دارد و مراحل دریافت درگاه، در این بانکها دشوار است، درگاه های واسط ایجاد گردیدند.درگاه های واسط در حقیقت واسطه ای میان ما (خدمات گیرنده) و بانکها (خدمات دهنده) می باشند. مزیت درگاه های واسط عدم نیاز به مدارک زیاد و سریع تر بودن روند دریافت درگاه می باشد.هرکدام از این بانک ها و واسط ها، روال کاری خود را برای پرداخت دارند. اما کلیت کار در همه آن ها مشابه است.در این مطلب من سعی کردم کلیت کار و نحوه پیاده سازی را در یک اپلیکیشن اندرویدی نشان دهم.اتصال به درگاه پرداخت شامل دو بخش نسبتا مجزا است:1. بخش مربوط به اپلیکیشن و برنامه نویس اندروید2. بخش مربوط به عملیات پرداخت و برنامه نویس سروردر این مطلب مراحل مربوط به هر دو بخش اپلیکیشن و سرور توضیح داده خواهد شد، اما تمرکز اصلی روی اپلیکیشن اندرویدی خواهد بود.(خوشحال میشم اگه کسی مقاله کاملی در مورد بخش سرور نوشته به من اطلاع بده تا لینکش رو همینجا بیارم)نکته: بخش مربوط به اپلیکیشن اندروید می تواند به دو صورت پرداخت در وب ویو و پرداخت در مرورگر انجام شود. اما پرداخت در وب ویو از امنیت لازم برخوردار نیست و لذا برخی از مارکت های داخلی اجازه پرداخت در وب ویو را نمی دهند.مراحل اتصال به درگاه پرداخت:مراحل اتصال به درگاه پرداخت(توضیحات هر بخش بصورت مختصر داخل فلوچارت نوشته شده اما در صورتی که ابهامی وجود داشت لطفا در کامنت اعلام کنید تا بیشتر توضیح بدم.)همانطور که در نمودار مشخص است، دو مرحله 1 و 5 مربوط به اپلیکیشن اندرویدی بوده، پس کدهای این دو بخش را در زیر می بینیم:مرحله 1. وقتی کاربر روی دکمه پرداخت کلیک کرد باید کاربر را به مرورگر و صفحه request  (یا send) که برنامه نویس سرور اعلام کرده هدایت کنیم، و اطلاعات مورد نیاز را پاس دهیم.String uri = Uri.parse(&amp;quothttps://www.mySite.com/payment/request&amp;quot)
.buildUpon()
.appendQueryParameter(&amp;quotparam1&amp;quot, &amp;quotparam1&amp;quot)
.appendQueryParameter(&amp;quotparam2&amp;quot, &amp;quotparma2&amp;quot)
.build().toString();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(browserIntent); https://virgool.io/p/nxyvkzz2krrp/%D8%A8%D8%AC%D8%A7%DB%8Chttps://www.mySite.com/payment/request%D8%A2%D8%AF%D8%B1%D8%B3url%D8%AE%D9%88%D8%AF%D8%B1%D8%A7%D9%88%D8%A7%D8%B1%D8%AF%DA%A9%D9%86%DB%8C%D8%AF. مرحله 5. ما باید در اپلیکیشن مشخص کنیم که کاربر پس از انجام عملیات پرداخت، به کدام اکتیویتی هدایت شود. لذا کدهای زیر را در منیفست و برای اکتیویتی مورد نظر اضافه می کنیم.&lt;intent-filter&gt;
&lt;action android:name=&amp;quotandroid.intent.action.VIEW&amp;quot /&gt;
&lt;category android:name=&amp;quotandroid.intent.category.DEFAULT&amp;quot /&gt;
&lt;category android:name=&amp;quotandroid.intent.category.BROWSABLE&amp;quot /&gt;
&lt;data android:scheme=&amp;quotyourScheme&amp;quot /&gt;
&lt;/intent-filter&gt;توجه کنید که بجای yourScheme میتوانید هر عنوان دلخواهی را وارد کنید، با این شرط که در آدرسی که در مرحله 4 برای هدایت کاربر از مرورگر به اپلیکیشن استفاده می شود نیز همین عنوان استفاده شده باشد. به این صورت:yourScheme://?data=hello&amp;status=1و سپس در اکتیویتی مقصد می توانید دیتای ارسالی را دریافت کرده و طبق آن عملیات متناسبی انجام دهید:final Uri data = getIntent().getData();
final String tmpData = data.getQueryParameter(&amp;quotdata&amp;quot);
final String tmpState = data.getQueryParameter(&amp;quotstatus&amp;quot);</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Thu, 04 Feb 2021 15:42:52 +0330</pubDate>
            </item>
                    <item>
                <title>برای رسیدن به موفقیت چگونه برنامه ریزی کنیم؟ (اینفوگرافی)</title>
                <link>https://virgool.io/@R.Hosseini/%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B1%D8%B3%DB%8C%D8%AF%D9%86-%D8%A8%D9%87-%D9%85%D9%88%D9%81%D9%82%DB%8C%D8%AA-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%B1%DB%8C%D8%B2%DB%8C-%DA%A9%D9%86%DB%8C%D9%85-%D8%A7%DB%8C%D9%86%D9%81%D9%88%DA%AF%D8%B1%D8%A7%D9%81%DB%8C-m62dybz4tdat</link>
                <description>برنامه ریزی برای رسیدن به موفقیت (اینفوگرافی)بعد از مدتها تنبلی اومدم شروع کنم به کار کردن. اما چیزی که همیشه منو عقب مینداخت و میندازه عدم وجود برنامه ریزیه! پس همین شنبه (نه از اون شنبه ها که هیچ وقت نمیادا! :)) شروع کردم به نوشتن. اولین چیزی که باید نوشته میشد قطعا برنامه ریزی بود. اما دیدم چیزی دربارش نمیدونم! :(یه سرچ مختصری زدم و یه مطلب مفید دربارش خوندم. خلاصۀ اون مقاله رو تو یه اینفوگرافی آوردم که شاید به درد بقیه هم بخوره. :)اینفوگرافی برنامه ریزی برای رسیدن به موفقیت بزرگترین اشتباه در برنامه ریزی: 1- مکتوب نکردن 2- مکتوب نکردن 3- مکتوب نکردن&quot;س بنویسید تا اتفاق بیفتد.&quot;این مطلبو به شکل اینفوگرافی آوردم که هم راحت بشه خوندش هم راحت شیرش کرد. پس اشتراک گزاری یادتون نره. ;)</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Mon, 08 Jun 2020 15:24:31 +0430</pubDate>
            </item>
                    <item>
                <title>نحوه افزودن پوش نوتیفیکیشن فایربیس به پروژه های اندرویدی (کاتلین)</title>
                <link>https://virgool.io/@R.Hosseini/httpsvirgooliorhosseini%D9%86%D8%AD%D9%88%D9%87-%D8%A7%D9%81%D8%B2%D9%88%D8%AF%D9%86-%D9%BE%D9%88%D8%B4-%D9%86%D9%88%D8%AA%DB%8C%D9%81%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%81%D8%A7%DB%8C%D8%B1%D8%A8%DB%8C%D8%B3-%D8%A8%D9%87-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%87%D8%A7%DB%8C-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-tgoiogryb90o</link>
                <description>FCMیه سری کارها هستن که تقریبا برای تمام پروژه هامون بصورت تکراری انجام میدیم. اما فاصله زمانی بین این پروژه ها میتونه باعث بشه که مراحل انجام اون کارو فراموش کنیم. به همین خاطر میخوام تو این مقاله چگونگی اضافه کردن پوش نوتیفیکیشن فایربیس به پروژه رو شرح بدم تا هم یه مرجعی باشه برای خودم و هم برای دیگران. تصور بر اینه که شما پروژتونو ساختین و حالا فقط میخواین FCM رو بهش اضافه کنید. مرحله اول: تنظیم فایربیس و FCM SDK1. ابتدا فایربیس را به پروژه اضافه کنید (در این مقاله بصورت کامل شرح دادم)2. دیپندنسی زیر را به فایل build.gradle اپلیکیشن اضافه کنید:implementation &#039;com.google.firebase:firebase-messaging:20.1.5&#039;مرحله دوم: تغییرات لازم در فایل منیفست1. افزودن پرمیشن اینترنت &lt;uses-permission android:name=&amp;quotandroid.permission.INTERNET&amp;quot/&gt;2. افزودن یک سرویس جدید به منیفست (کد این سرویس در مرحله بعد)&lt;service
    android:name=&amp;quot.java.MyFirebaseMessagingService&amp;quot
    android:exported=&amp;quotfalse&amp;quot&gt;
    &lt;intent-filter&gt;
        &lt;action android:name=&amp;quotcom.google.firebase.MESSAGING_EVENT&amp;quot /&gt;
    &lt;/intent-filter&gt;
&lt;/service&gt;(کد بالا را در تگ application کپی کنید)مرحله سوم: ساخت سرویس برای دریافت پیغامهای FCMیک سرویس با عنوان MyFirebaseMessagingService بسازید و کدهای زیر را در آن کپی کنید:class MyFirebaseMessagingService : FirebaseMessagingService() {
    privateval TAG = MyFirebaseMessagingService::class.java.simpleName
    privateval REQUEST_CODE = 0

    override fun onNewToken(s: String) {
        super.onNewToken(s)
        Log.d(TAG, &amp;quotFirebase token: $s&amp;quot)    
FirebaseMessaging.getInstance().subscribeToTopic(&amp;quotall&amp;quot).addOnCompleteListener {
            Log.d(TAG, &amp;quotThis user subscribe in topic: all&amp;quot)
        }
    }

    override fun Received(remoteMessage: RemoteMessage) {
        Log.d(TAG, &amp;quotFrom: $remoteMessage.from&amp;quot)
        sendNotification(remoteMessage.notification, remoteMessage.data)
    }

    private fun sendNotification(
        notification: RemoteMessage.Notification?,
        data: Map&lt;String, String&gt;
    ) {
        val icon = BitmapFactory.decodeResource(Resources.getSystem&#40;&#41;, R.mipmap.ic_launcher)
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent =
            PendingIntent.getActivity(this, REQUEST_CODE, intent, PendingIntent.FLAG_ONE_SHOT)
        val channelId = getString(R.string.default_notification_channel_id)
        var title: String? = &amp;quot&amp;quot
        var body: String? = &amp;quot&amp;quot
        if (notification != null) {
            title =
                if (notification.title == null) getString(R.string.app_name) else notification.title
            body = if (notification.body == null) &amp;quot&amp;quot else notification.body
        }
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setContentTitle(title)
            .setContentText(body)
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentIntent(pendingIntent)
            .setContentInfo(title)
            .setLargeIcon(icon)
            .setColor(Color.GREEN)
            .setLights(Color.RED, 1000, 300)
            .setDefaults(Notification.DEFAULT_VIBRATE)
            .setSmallIcon(R.mipmap.ic_launcher)

        try {
            val pictureUrl = data[&amp;quotpicture_url&amp;quot]
            if (pictureUrl != null &amp;&amp; &amp;quot&amp;quot != pictureUrl) {
                val url = URL(pictureUrl)
                val bigPicture =
                    BitmapFactory.decodeStream(url.openConnection().getInputStream())
                notificationBuilder.setStyle(
                NotificationCompat.BigPictureStyle().bigPicture(bigPicture).setSummaryText(body)
                )
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Notification Channel is required for Android O and above
        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId, &amp;quotinsta tutorial notif channel&amp;quot, NotificationManager.IMPORTANCE_DEFAULT
            )
            channel.description = &amp;quotchannel description&amp;quot
            channel.setShowBadge(true)
            channel.canShowBadge()
            channel.enableLights(true)
            channel.lightColor = Color.BLUE
            channel.enableVibration(true)
            channel.vibrationPattern = longArrayOf(100, 200, 300, 400, 500)
            notificationManager.createNotificationChannel(channel)
        }
        notificationManager.notify(Random().nextInt(), notificationBuilder.build())
    }
}
توجه: این کلاس پیغامهای رسیده را در هر دو حالت اپلیکیشن یعنی Foreground و Background هندل میکند. و همچنین همه کاربران را به تاپیکی بنام all اضافه میکند.در هر قسمت از برنامه که قصد دارید کاربر را به تاپیک خاصی اضافه کنید کافیست کد زیر را با نام تاپیک دلخواه خود کپی کنید:FirebaseMessaging.getInstance().subscribeToTopic(&amp;quottopic name&amp;quot)      .addOnCompleteListener { task -&gt;
            var msg = getString(R.string.msg_subscribed)
            if (!task.isSuccessful) {
                msg = getString(R.string.msg_subscribe_failed)
            }
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        }
مرحله بعد تست ارسال نوتیفیکیشن و همینطور هندل کردن دیتای دریافتیه که سعی میکنم تو مقاله دیگه ای بصورت کامل شرح بدم.</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Mon, 20 Apr 2020 00:05:16 +0430</pubDate>
            </item>
                    <item>
                <title>افزودن فایربیس به پروژه اندرویدی</title>
                <link>https://virgool.io/@R.Hosseini/httpsvirgooliorhosseini%D8%A7%D9%81%D8%B2%D9%88%D8%AF%D9%86-%D9%81%D8%A7%DB%8C%D8%B1%D8%A8%DB%8C%D8%B3-%D8%A8%D9%87-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-mnllkw9ywxbd</link>
                <description>در این مقاله تصور شده که شما پروژتونو ساختین و حالا فقط قصد دارین فایربیس را به اون اضافه کنید. مرحله اول: ایجاد پروژه جدید در فایربیس1. در سایت فایربیس یک اکانت بسازید یا اگر قبلا این کارو انجام داده اید فقط لاگین کنید.2. در کنسول فایربیس روی Add Project کلیک کرده و یک نام برای پروژه خود انتخاب کنید.3. در این مرحله می توانید گوگل آنالایتیکس را برای پروژه خود فعال یا از آن صرف نظر کنید (بعدا هم میتونید این کار را انجام بدید)مرحله دوم: ثبت مشخصات اپلیکیشن در فایربیس1. وارد کنسول فایربیس شده و پروژه خود را انتخاب کنید.2. روی آیکون اندروید در وسط صفحه کلیک کنید.ثبت مشخصات اپلیکیشن در فایربیس(مرحله 2)3. پکیج نیم، یک نام دلخواه برای اپلیکیشن، و SHA1 را وارد نمایید.(برای یافتن SHA1 از راهنمای موجود در این لینک استفاده کنید)ثبت مشخصات اپلیکیشن در فایربیس (مرحله 3) 4. فایل google-service.json که توسط فایربیس تولید شده را دانلود کنید.ثبت مشخصات اپلیکیشن در فایربیس (مرحله 4)مرحله سوم: افزودن تنظیمات فایربیس به اپلیکیشن1. فایل google-service.json را در مسیر app کپی کنید.افزودن تنظیمات فایربیس به اپلیکیشن (مرحله 1)2 در فایل build.gradle پروژه کدهای زیر را اضافه کنید:buildscript {
    repositories {
        // Check that you have Google&#039;s Maven repository (if not, add it).
        google()
    }
    dependencies {
        // ...
        // Check that you have the Google Services Gradle plugin v4.3.2 or later (if not, add it).
        classpath &#039;com.google.gms:google-services:4.3.3&#039;

        // Add the Crashlytics Gradle plugin.
        classpath &#039;com.google.firebase:firebase-crashlytics-gradle:2.0.0-beta04&#039;
    }
}

allprojects {
    repositories {
        // Check that you have Google&#039;s Maven repository (if not, add it).
        google()
    }
}}3 در فایل  build.gradle اپلیکیشن کدهای زیر را اضافه کنید:apply plugin: &#039;com.android.application&#039;
// Add this line
apply plugin: &#039;com.google.gms.google-services&#039;
// Apply the Crashlytics Gradle plugin
apply plugin: &#039;com.google.firebase.crashlytics&#039;

dependencies {
  // add the Firebase SDK for Google Analytics
  implementation &#039;com.google.firebase:firebase-analytics:17.3.0&#039;
// Add the Firebase SDK for Crashlytics.
implementation &#039;com.google.firebase:firebase-crashlytics:17.0.0-beta04&#039;
}4. پروژه را سینک کنید.5. و در آخر پروژه خود را اجرا کنید.تمامتوجه: در این آموزش Crashlytics نیز همزمان به پروژه اضافه شده است تا بتوانید از این ویژگی فایربیس هم استفاده کنید.</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Sun, 19 Apr 2020 23:00:03 +0430</pubDate>
            </item>
                    <item>
                <title>کاتلین کوروتین در اندروید</title>
                <link>https://virgool.io/@R.Hosseini/%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-%DA%A9%D9%88%D8%B1%D9%88%D8%AA%DB%8C%D9%86-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-kqimlusu9qpx</link>
                <description>کاتلین کوروتین1. مقدمه2. مشکل از کجا شروع شد؟ (چرا کوروتین؟)3. تعریف کوروتین؟3.1 استفاده از کوروتین برای تسک های طولانی3.2 Main-Safty با کوروتین4. ردیابی کوروتین ها4.1 کنسل کردن کار با socps4.2 ردیابی یک کار تا زمانی که در حال اجراست4.3 ارسال خطاها هنگام عدم موفقیت یک کوروتین5. استفاده از structured concurrency6. خلاصه7. منابع1. مقدمهدور هم جمع شدن یک عده از اندروید دولاپرها که تصمیم داشتن با پیاده سازی یک پروژه اوپن سورس موزیک پلیر، مطالب جدیدی رو در اندروید یاد بگیرن و تمرین کنن، باعث شد من در مورد کاتلین کوروتین چندتا مقاله بخونم و ویدئو ببینم.حاصل این مطالعه دو روزه شد این مقاله که پیش روی شماست.اگه مفهوم کوروتین برای شما هم گنگه، یا تازه میخواین شروع به یادگیری این مفهوم نوظهور در کاتلین بکنین در ادامه مقاله با من همراه باشین.توجه: اگرچه کوروتین مفهوم جدیدی در کاتلین ۱.۳ میباشد، اما پیش از این در زبانهای زیادی استفاده میشده. ما برای اشاره به مفهوم کوروتین در کاتلین از عبارت کاتلین کوروتین استفاده خواهیم کرد.2. مشکل از کجا شروع شد؟هر اپ در اندروید شامل یکmain thread یا ترد اصلی می باشد که مسیولیت به روز رسانی های  ui و تعامل با کاربر را بعهده دارد. اگر کارهای بسیار زیاد و یا سنگین روی این ترد انجام شود، اپ بسیار کند شده و یا هنگ خواهد کرد. چنین تسک هایی باید بدون بلاک کردن ترد اصلی انجام شود.به این مثال توجه کنید:همواره کد رویایی ما در برنامه نویسی به این شکل می باشد:The Dream Codeاما ما نمیتوانیم درخواستهای سرور را روی ترد اصلی پیاده کنیم. به همین خاطر در این کد، با NetworkOnMainThreadExeption  مواجه خواهیم شد.حال شاید بگوئید میتوانیم از ترد استفاده کنیم. به این شکل:The Dream code v2اما این کد نیز بخاطر خط دوم دچار CalledFromWrongThreadExeption خواهد شد.اما راه حل چیست؟استفاده از callback!The OK Codeاستفاده از callback ها برای اجتناب از بلاک شدن ترد اصلی بسیار مفید است اما callback ها نیز مشکلات خود را دارند: آنها نمی توانند بدون کار اضافی خطاها را به خوبی هندل کنند. اگر از تعداد callback های زیادی در یک تابع استفاده شود، خوانایی آنها پایین خواهد آمد و میتوانند overloading ایجاد کنند (OutOfMemoryError)برای حل این مشکلات می توان از کوروتین استفاده کرد.3. تعریف کوروتینکوروتین در حقیقت شیوه جدیدی برای ساده کردن کدهای async است. کوروتین کدهای ما را ساده تر و خواناتر می کند. کوروتین ها امکان نوشتن کد غیر همزمان (asynchronous) را به روشی همزمان (synchronous) امکانپذیر می سازد. نوشتن کدها بصورت متوالی در کوروتین به خوانایی کدها کمک می نماید.کوروتین ها مشابه تردها میباشند با این تفاوت که:۱. چندین کوروتین میتواند داخل یک ترد اجرا شود.۲. کوروتین ها بسیار سبکتر از تردها میباشند.۳. تردها توسط os مدیریت می شوند، در حالی که کوروتین ها توسط کاربر.نکته: کوروتین ها جایگزین تردها نیستند، بلکه بیشتر شبیه یک فریم ورک برای مدیریت آنها می باشند.کوروتین ها در اندروید دو مشکل اساسی را حل میکنند:1. کارهای طولانی که main thread را برای مدت طولانی بلاک میکنند.2. Main-safety که به شما این اجازه را میدهد که توابع suspend را در ترد اصلی فراخوانی کنید.(مشابه دریم کد!!?✌️)3.1 استفاده از کاتلین برای تسک های طولانی:ارتباط با یک api، خواندن داده ها از دیتابیس، لود کردن یک عکس از دیسک، چیزهایی هستند که ما به آنها long running task یا تسک های طولانی می گوییم.کوروتین ها در حقیقت راهی برای ساده کردن کدها، برای مدیریت کارهای طولانی هستند.به کد پایین که با کمک کوروتین نوشته شده است دقت کنید:suspend fun fetchDocs() {                               // Dispatchers.Main
    val result = get(&amp;quotdeveloper.android.com&amp;quot)   // Dispatchers.Main
    show(result)                                                 // Dispatchers.Main
} 
suspend fun get(url: String) = withContext(Dispatchers.IO){/*...*/}کوروتین ها این امکان را فراهم میکنند که این کد بدون بلاک کردن ترد اصلی اجرا شود.برای استفاده از کوروتین در کاتلین کافی است کلمه کلیدی suspend را به ابتدای توابع اضافه کنیم. هنگامی که یک کوروتین یک تابع suspend را به حالت تعلیق در می آورد، ترد اصلی را بلاک نکرده، و هنگامی که نتیجه آماده شد، تابع تعلیق شده را از همان نقطه از سر میگیرد (resume).کوروتین ها شامل دو عملیات جدید می باشند: suspend   اجرای کوروتین جاری راpause  کرده و حالت جاری را سیو میکند. resume  کوروتین معلق شده را از محلpause  شده ادامه میدهد.suspend   و resume  با یکدیگر، جایگزین callback ها می شوند.نکته: توابعsuspend تنها از داخل توابع suspend دیگر، و یا یک کوروتین بیلدر مانند launch قابل فراخوانی هستند.در مثال بالا تابع get قبل از نتورک ریکوئست بحالت معلق درخواهد آمد. و پس از دریافت پاسخ از سرور، کار خود را از همان جایی کهpause  شده بود از سر میگیرد.هرگاه یک کوروتین معلق شود، استک فریم جاری (جایی که کاتلین برای نگه داشتن اطلاعات توابع معلق شده استفاده میکند) کپی و ذخیره میگردد. و هنگام resume، استک فریم باز خوانی شده و از همان نقطه معلق شده از سر گرفته خواهد شد.suspend and resume این انیمیشن نحوه suspend و resume شدن تابع را بخوبی نشان میدهد.در اواسط انیمیشن، وقتی همه کوروتین ها در ترد اصلی معلق شدند، ترد اصلی برای انجام سایر کارهای خود، مثل آپدیت ui و هندل کردن User event آزاد خواهد شد.3.2 Main-safety  با کوروتین هادر کاتلین کوروتین، توابعsuspend برای فراخوانی از ترد اصلی، همیشه امن هستند.نکته: عبارت suspend بمعنای اجرای تابع در ترد backgroundنیست، بلکه ممکن است این تابع در ترد اصلی و یا ترد background اجرا شود.در کاتلین همه کوروتین ها باید در یک دیسپچر اجرا شوند. دیسپچر مدیریت اجرای کوروتینها را بر عهده دارد. کوروتین ها میتوانند خود را ساسپند کنند، و دیسپچر آنها را resumeخواهد کرد.یک دیسپچر مدیریت میکند که کدام ترد کوروتین را اجرا کند.در کاتلین سه نوع دیسپچر وجود دارد:1. Dispatchers.Main: ترید اصلی، تعامل با کاربر و انجام کارهای سبک2. Dispatchers.IO: بهینه شده برای ورودی/خروجی دیسک و شبکه، خارج از main thread3. Dispatchers.Default: بهینه شده برای کارهای سنگین cpu، خارج از main threadDispatchersبرای کامل کردن کد بالا بیایید از dispatcher ها استفاده کنیم. داخل تابع get  برای ایجاد یک بلوک که در دیسپچر ioاجرا شود از withContext()استفاده میکنیم.withContext(Dispatchers.IO) یک بلاک کوروتین می باشد که تمامی کدهای داخل این بلاک در دیسپچر ioاجرا خواهد شد. از آنجایی که تابع withContet(Dispatchers.IO) خود یک تابع suspend می باشد، با استفاده از کوروتین main safety را فراهم خواهد کرد.suspend fun fetchDocs() {                                // Dispatchers.Main
      val result = get(&amp;quotdeveloper.android.com&amp;quot)  // Dispatchers.Main
      show(result)                                                // Dispatchers.Main
}                                                                         // Dispatchers.Main
suspend fun get(url: String) =                          // Dispatchers.Main
  withContext(Dispatchers.IO) {
  /* perform blocking network IO here */         // Dispatchers.IO
  }                                                                      // Dispatchers.Mainدر این مثال fetchDocs  در ترد اصلی اجرا می شود، اما می تواند تابع get را که در آن یک درخواست سرور وجود دارد، فراخوانی نماید. زیرا هر دو تابع suspend می باشند.در حقیقت ما با استفاده از suspend، withContext(Dispatchers.IO)توانستیم چنین توابعی را در ترد اصلی فراخوانی کنیم.4. ردگیری کوروتین ها با کمک CoroutineScopeاگرچه کوروتین ها مزایای زیادی دارند، اما نمی توانیم آنها را پیگیری نماییم. شرایطی را در نظر بگیرید که صدها یا حتی هزاران کوروتین داشته باشیم! اگر همه آنها را ردگیری نکرده و به موقع لغو یا کامل نکنیم، برنامه ما ممکن است دچار work leak شود.یک کوروتین رها شده می تواند cpu یا دیسک را هدر داده یا حتی درخواست شبکه ای که دیگر لازم نیست را اجرا کند.برای جلوگیری از این امر کوروتین Structured concurrency را معرفی می نماید.ما از structured concurrency در اندروید برای انجام سه کار استفاده میکنیم:1. کنسل کردن یک کار وقتی دیگر نیازی به آن نداریم2. ردیابی یک کار تا زمانی که در حال اجراست3. ارسال خطاها هنگام عدم موفقیت یک کوروتین4.1 کنسل کردن کار با scopeدر کاتلین، کوروتین ها باید داخل CoroutineScope اجرا شوند. یک CoroutineScope همه کوروتین ها، حتی کوروتین های suspend شده را ردیابی میکند. CoroutineScope  کوروتین ها را اجرا نمیکند، و تنها وظیفه ردگیری آنها را دارد.برای اطمینان از اینکه همه کوروتین ها ردیابی می شوند، کاتلین به شما اجازه شروع یک کوروتین جدید بدونCoroutineScope  را نمیدهد.نکته: یک CoroutineScope تمام کوروتین های ما را ردیابی می کند، و می تواند تمام کوروتین های شروع شده در آن را لغو کند.4.1.1 شروع یک کوروتین جدیددو راه برای شروع کوروتین ها وجود دارد:1. launch کوروتین هایی که این کوروتین بیلدر آغاز میکند نیازی به برگرداندن نتیجه ندارند.2. async  کوروتین هایی که این کوروتین بیلدر آغاز میکند به شما اجازه دریافت نتیجه بازگشتی با کمک await را میدهد.می توان launch را پلی میان توابع عمومی و کوروتین ها دانست.از آنجایی که launch و async تنها در CoroutineScope در دسترس هستند، در نتیجه قابل ردگیری می باشند.4.1.2 شروع در ViewModelدقیقا کجا باید launch را فراخوانی کرده و scope ها را قرار دهیم؟ و چه زمانی باید همه کوروتین های داخل scope را کنسل کنیم؟منطقی است که یک CoroutineScope  را متناظر با یک صفحه کاربری در نظر بگیریم. این امر از نشت کوروتین ها و یا انجام کارهای اضافی برای اکتیویتی و فرگمنتهایی که دیگر نمایش داده نمی شود، جلوگیری میکند. وقتی کاربر از آن صفحه خارج میشود، CoroutineScope   متناظر می تواند همه کارها را کنسل کند.هنگام ادغام کوروتین ها با Android Architecture Componentsمنطقی است که کوروتین ها را در ViewModel راه اندازی کنیم. با این کار دیگر نگران چرخش صفحه موبایل نخواهیم بود.برای استفاده از کوروتین ها در ViewModel میتوانیم از viewModelScope استفاده کنیم.lifecycle-viewmodel-ktx:2.1.0-alpha04.viewModelScopeبه مثال زیر توجه کنید:class MyViewModel(): ViewModel() {
        fun userNeedsDocs() {
               // Start a new coroutine in a ViewModel
               viewModelScope.launch {
                       fetchDocs()
                }
          }
 }4.2 ردیابی کارهاشما می توانید laounch و async را طبق نیاز خود باهم ترکیب و هماهنگ کنید. مثل کد زیر:suspend fun fetchTwoDocs() {
     coroutineScope {
          launch { fetchDoc(1) }
          async { fetchDoc(2) }
     }
 }تفاوت اصلی coroutineScope و supervisorScope در این است که هرگاه هر یک از فرزندان coroutineScope شکست بخورند،coroutineScope  لغو خواهد شد. بنابراین اگر یک درخواست شبکه ناموفق باشد، همه درخواست های دیگر بلافاصله لغو می شوند. اگر در عوض می خواهید درخواست های دیگر را حتی در صورت عدم موفقیت ادامه دهید، می توانید از یک supervisorScope استفاده کنید. در supervisorScope وقتی یکی از فرزندان ناکام باشد، یک supervisorScope مابقی را لغو نخواهد کرد.4.3 ارسال خطاها هنگام شکست خوردن یک کوروتیندر مورد ارسال خطاها، کوروتین مشابه توابع عادی عمل میکند.از آنجا که coroutineScope منتظر تمام فرزندان خود میماند، در صورت شکست هر کدام از آنها مطلع خواهد شد.5. استفاده از structured concurrencyاگر از structured concurrency استفاده کنیم از work leak اجتناب خواهد شد.ما از structured concurrency در اندروید برای انجام سه کار استفاده میکنیم:1. کنسل کردن یک کار وقتی دیگر نیازی به آن نداریم2. ردیابی یک کار تا زمانی که در حال اجراست3. ارسال خطاها هنگام عدم موفقیت یک کوروتینتضمین هایی که structured concurrency به ما میدهد شامل موارد زیر است:1. هنگام کنسل شدن یک scopeهمه کوروتین های آن کنسل می شوند.2. وقتی یک تابع suspendبازگشت داده میشود، تمام کارهای آن انجام شده است.3. وقتی یک کوروتین خطا میدهد، به callerیا scope او اطلاع داده می شود.تضمین هایی که structured concurrency میدهد، کد ما را تمیزتر و امن تر کرده و به ما اجازه میدهد از work leak جلوگیری کنیم.6. خلاصه:کوروتین در حقیقت شیوه جدیدی برای ساده کردن کدهای async است. کوروتین کدهای ما را ساده تر و خواناتر می کند. کوروتین ها امکان نوشتن کد غیر همزمان (asynchronous) را به روشی همزمان (synchronous) امکانپذیر می سازد.کوروتین ها در اندروید دو مشکل اساسی را حل میکنند:1. کارهای طولانی که main thread را برای مدت طولانی بلاک میکنند.2. Main-safety که به شما این اجازه را میدهد که توابع suspend را در ترد اصلی فراخوانی کنید.توابع suspend تنها از داخل توابع suspend دیگر، و یا یک کوروتین بیلدر مانند launch قابل فراخوانی هستند.وقتی همه کوروتین ها در ترد اصلی معلق شدند، ترد اصلی برای انجام سایر کارهای خود آزاد خواهد شد.عبارت suspend بمعنای اجرای تابع در ترد background نیست، بلکه ممکن است این تابع در ترد اصلی و یا ترد background اجرا شود.در کاتلین همه کوروتین ها باید در یک دیسپچر اجرا شوند. دیسپچر مدیریت اجرای کوروتینها را بر عهده دارد. کوروتین ها میتوانند خود را ساسپند کنند، و دیسپچر آنها را resumeخواهد کرد. یک دیسپچر مدیریت میکند که کدام ترد کوروتین را اجرا کند.در کاتلین سه نوع دیسپچر وجود دارد:1. Dispatchers.Main2. Dispatchers.IO3. Dispatchers.Defaultما از structured concurrency در اندروید برای انجام سه کار استفاده میکنیم:1. کنسل کردن یک کار وقتی دیگر نیازی به آن نداریم2. ردیابی یک کار تا زمانی که در حال اجراست3. ارسال خطاها هنگام عدم موفقیت یک کوروتینیک CoroutineScope تمام کوروتین های ما را ردیابی می کند، و می تواند تمام کوروتین های شروع شده در آن را لغو کند.7. منابع:https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb&amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;gt;https://blog.mindorks.com/mastering-kotlin-coroutines-in-android-step-by-step-guidehttps://developer.android.com/kotlin/coroutines&amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;gt;https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#4&amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;gt;https://www.youtube.com/watch?v=BOHK_w09pVA</description>
                <category>R Hosseini</category>
                <author>R Hosseini</author>
                <pubDate>Thu, 12 Mar 2020 18:33:52 +0330</pubDate>
            </item>
            </channel>
</rss>