<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های فرشته ناجی</title>
        <link>https://virgool.io/feed/@fereshtehnaji</link>
        <description>برنامه نویس اندروید @NeshanMap</description>
        <language>fa</language>
        <pubDate>2026-06-16 13:35:30</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/10951/avatar/ps3h2f.jpg?height=120&amp;width=120</url>
            <title>فرشته ناجی</title>
            <link>https://virgool.io/@fereshtehnaji</link>
        </image>

                    <item>
                <title>مودیفایر transient چی هست و چه کاربردی داره؟</title>
                <link>https://virgool.io/@fereshtehnaji/%D9%85%D9%88%D8%AF%DB%8C%D9%81%D8%A7%DB%8C%D8%B1-transient-%DA%86%DB%8C-%D9%87%D8%B3%D8%AA-%D9%88-%DA%86%D9%87-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-%D8%AF%D8%A7%D8%B1%D9%87-k4m7l3ppqvcu</link>
                <description>در جاوا transient با تلفظ تِرَن زی اِنت یک Non-Access Modifier هست مثل abstract، final، static و .. که قبل از یک متغیر عضو کلاس قرار میگیره و به جاوا می‌گه هنگام سریالایز این متغیر رو مستثنی کنه (ازینجا میتونید با سریالایز در جاوا آشنا بشید). به این معنی که در زمان تبدیل مقدار یک آبجکت به جریان بایت‌ها مقدار این متغیر در نظر گرفته نمی‌شه و زمان دی سریالایز از یک مقدار پیش فرض براش استفاده می‌شه (معمولا برای نوع داده‌های اولیه مقدار پیش‌فرض صفر یا false هست و برای نوع داده‌های دیگه Null). چه دردی از من دوا می‌کنه؟معمولا اینطور پیش می‌ره که من یک چیز جدید رو توی کدها می‌بینم میرم داکیومنتش رو می‌خونم و احتمالا هم متوجه می‌شم چیه و پایان و احتمالا فراموشی. انقدر داکیومنتی که خوندم تئوری هست که خیلی اوقات باعث نمیشه کاربردش رو درک کنم و وقتی نیاز داشتم بعنوان یک راه‌حل تو ذهنم بیاد.در همین مورد اخیر، میگیم اوکی باشه من الان فهمیدم transient چیه و وقتی قبل متغیر بذارنش چه اتفاقی می‌افته اما به چه درد من می‌خوره؟ چه مواقعی باید ازش استفاده کنم؟بیایید یک مثال بزنیم. به آبجکت User فکر کنید و خصوصیاتش مانند نام، نام خانوادگی، ایمیل، آدرس، پسورد و غیره. حالا این آبجکت سریالایز میشه و توی شبکه منتقل میشه. ممکنه یک دغدغه امنیتی برامون پیش بیاد که نمی‌خوام فیلد پسورد کنار بقیه فیلدهای آبجکت قرار بگیره و ارسال بشه و یک مقدار نگرانم می‌کنه. اینجاست که علامت گذاری این فیلد با transient می‌تونه مشکل امنیتی رو حل کنه.public class User implements Serializable {
    private String firstName;
    private String lastName;
    private String address;
    private String email;
    private transient String password;
   @Override
    public String toString() {
   
  }
}وقتی فیلدی می‌تونه از روی فیلد دیگه تولید بشهاین هم می‌تونه یک کاربرد دیگه از transient باشه. فرض کنید ما یک کلاس GalleryImage داریم که دو تا فیلد Image و thumbnailImage داره. که فیلد thumbnailImage از روی Image ساخته می‌شه بهمین خاطر ما می‌تونیم فیلد thumbnailImage رو transient کنیم و باعث بشیم کدمون efficient بشه.public class GalleryImage implements Serializable {
    private static final long serialVersionUID = 123456789L;

    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail() {
        // This method will derive the thumbnail from the main image
    }

    private void readObject(ObjectInputStream inputStream)
        throws IOException, ClassNotFoundException {
        inputStream.defaultReadObject();
        generateThumbnail();
    }
}نکته مهمفیلدهای استاتیک بطور غیرمستقیم transient هستند و لازم نیست دوباره transient تعریف بشوند. چرا که فرآیند سریالایز شدن روی نمونه‌ای از کلاس(آبجکت‌ها) اعمال میشه نه خود کلاس‌ ولی فیلدهای استاتیک متعلق به خود کلاس هستند بنابراین قابل سریالایز شدن نیستند.تفاوت transient با volatileاین سوالیه که شاید تو یه مصاحبه ازتون بپرسن ولی در واقع این دو تا هیچ ربطی به هم ندارن ! تنها ارتباطشون این هست که هردوشون modifier هستند اما transient برای جلوگیری از سریالایز شدن مقدار یک متغیر در پروسه سریالایز شدن یک آبجکت استفاده می‌شه و volatile به visibility متغیرهایی که توسط تردهای مختلف دستکاری میشن مربوط هست.بقیه Non-Access Modifierها چی هستند؟مودیفایر Abstractبرای کلاس ها و متدها استفاده می‌شه.مودیفایر finalاین کلمه کلیدی میتونه متغیرها و متدها و کلاس ها رو غیرقابل تغییر کند و برای نگهداری یک مقدار ثابت ازش استفاده می‌شه.مودیفایر nativeفقط برای متدها استفاده می‌شه و نشون میده که اون متد با JNI (Java Native Interface) پیاده سازی شده است.مودیفایر staticبرای متدها و متغیرهایی استفاده می‌شه که میخوایم بدون ساخت آبجکت از کلاس بهشون دسترسی داشته باشیم.مودیفایر strictfpیک کلمه کلیدی در جاوا است که برای محدود کردن محاسبات ممیز شناور و حصول اطمینان از نتیجه یکسان در هر پلتفرم در حین انجام عملیات در متغیر ممیز شناور استفاده می شود. البته الان در برنامه نویسی جاوا این کلمه کلیدی بی استفاده هست.مودیفایر synchronizedدر دنیای چندنخی یا مالتی تردینگ، چند ترد همزمان تلاش میکنن که به یک منبع اشتراکی دست پیدا کنن و نتایج ناسازگاری ایجاد کنند. Synchronization یا همزمانی برای ارتباطات قابل اعتماد در مالتی تردینگ لازم است.مودیفایر volatileمفهومی برای visibility متغیرهاست. بدون volatile یک متغیر رو ممکنه تردهای مختلف بصورت آپدیت نشده ببینند اما با استفاده از این مودیفایر تردها بعد از اتمام عملیات نوشتن در حافظه مقدار متغیر را خواهند دید. نکته آخروقتی داده‌های حساسی در آبجکت دارید که نمی‌خواهید transmit بشه یا یک فیلد میتونه از فیلد دیگه استخراج بشه از transient استفاده کنید.</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Sat, 08 Apr 2023 14:42:29 +0330</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگر در برنامه اندرویدی (7-Scoping SubComponent)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-7-scoping-subcomponent-clj3yqtztm84</link>
                <description>این نوشتار مربوط به بخش هفتم از کُدلب آموزشی استفاده از Dagger در پروژه اندرویدی به زبان کاتلین هست و می‌تونید بخش قبلی رو از اینجا بخونید.در بخش‌های قبلی کُدلَب یک subcomponent ساختیم به نام RegistrationComponentچرا؟چون یک instance از ویومدل داشته باشیم که بین اکتیویتی و فرگمنت هاش مشترک باشه نه در کل برنامه.قبلا دیدیدم که اگر ما کامپوننت و کلاس های داخلی اش رو با scope annotation یکسانی مشخص کنیم. باعث میشه که تایپ مون مثلا اینجا ویو مدل مون ، instance یکسانی در اون کامپوننت داشته باشه.امانمی تونیم دوباره از اسکوپ انوتیشن Singleton استفاده کنیم. چون یکبار توسط کامپوننت اصلی برنامه استفاده شده است.پسباید یک Scope Annotation جدید بسازیم!اسمش چی باشه؟آیا اسم @RegistrationScope خوبه؟ نه ! اسم Scope Annotation نباید مستقیما هدف رو مشخص کنه. اسمش باید وابسته به لایف تایم اش باشه تا بتونه توسط کامپوننت‌های هم رده‌ی خودش استفاده مجدد بشه (مثل LoginComponent و غیره)قوانین Scopingوقتی یک تایپ مثل یک ویومدل با Scope Annotation مشخص میشه فقط توسط کامپوننت‌هایی که با همون scope مشخص شده اند قابل استفاده است.وقتی یک کامپوننت رو با یک Scope Annotation مشخص می‌کنیم، ایشون می‌تونه فقط تایپ‌هایی که با اون انوتیشن مشخص شده‌اند یا اون‌هایی که هیچ انوتیشنی ندارند رو provide کنه.یک ساب کامپوننت نمی‌تونه از Scope Annotation که توسط پدرش بکار رفته، استفاده کنهیک فایل ActivityScope.ktبه نام در پکیج di بسازید و ActivityScopeرو اینطوری تعریف کنین:ActivityScope.ktبرای اسکوپ کردن RegistrationViewModelبه RegistrationComponentباید این کلاس و اینترفیس هر دو با @ActivityScopeحاشیه نویسی بشن.RegistrationViewModel.ktRegistrationComponent.ktدر نتیجه این تغییرات دیگه همیشهRegistrationComponent یک نمونه از RegistrationViewModelتامین خواهد کرد.لایف سایکل SubComponent هامیخواهیم ببینیم لایف سایکل این subcomponent که ساختیم باید چی باشه. AppComponent که به لایف سایکل اپلیکیشن متصل شده بود چون می خواستیم تا وقتی برنامه در حافظه است فقط یک instance از گراف برنامه داشته باشیم. از طرفی گفتیم میخواهیم subcomponent بین اکتیویتی و فرگمنت هاش به اشتراک گذاشته بشه و هر وقت اکتیویتی عوض شد یک نمونه جدید ازش ساخته شه ، بنابراین باید به لایف سایکل اکتیویتی متصل بشه. برای رسیدن به این هدف یک رفرنس به آن در اکتیویتی می سازیم همان طور که instance کامپوننت AppComponent را در کلاس اپلیکیشن ساختیم.RegistrationActivity.ktسپس یک instance از RegistrationComponentدر متدonCreate قبل از super.onCreateمی سازیم و اکتیویتی را بهregistrationComponentبجای appComponentتزریق می‌کنیم. یادتونه یک متد در AppComponent گذاشتیم که RegistrationComponentفکتوری رو برمیگردوند؟ اون متد رو فراخوانی میکنیم و بعد هم متد create رو تا از RegistrationComponentنمونه بسازیمبا استفاده از این instance اکتیویتی رو به این ساب کامپوننت inject میکنیم.حالا دیگه فیلدهایی که تو این اکتیویتی هستن و با @Injectمشخص شده اند توسطRegistrationComponent تامین وابستگی خواهند شد. اگر گیج شدید تصویر زیر رو نگاه کنید.RegistrationActivity.ktاگر دقت کرده باشید متغیر registrationComponentبا@Inject انوتیت نشده است. چون انتظار نداریم این متغیر توسط Dagger پرواید شود.حالا نوبت فرگمنت هاست:یک نمونه از RegistrationComponent در اکتیویتی داریم و از همون برای Inject فرگمنت ها به RegistrationComponent استفاده میکنیم. یادتونه که ! در متد on Attach.EnterDetailsFragment.ktهمین مراحل رو برای فرگمنت TermsAndConditionsهم برید.TermsAndConditionsFragment.ktپروژه را اجرا کنید.مثل قبل از register خارج و دوباره register کنید. خواهید دید که روند ثبت نام به درستی انجام می‌شود ولی Setting باعث میشه که برنامه دچار کرش شود چون هنوز از دگر استفاده نمی کند که در ادامه انجام خواهد شد.گراف اپلیکیشن تا این لحظه به صورت زیر درآمده است:تفاوت این گراف با گراف بخش قبل این است که RegistrationViewModelبهRegistrationComponent اسکوپ شده است که این موضوع با یک دایره قرمز کوچک روی RegistrationViewModelمشخص شده است.افزودن فیچر Login به Daggerجدا از قضیه scope کردن آبجکت‌ها به لایف سایکل‌های متفاوت، ساختن subcomponent یک عادت خوب برنامه نویسی است که بخش‌های مختلف برنامه رو از هم encapsulate می کند.اینکه طوری برنامه رو طراحی کنید که یک sub graph برای هر فیچر یا جریان برنامه بسازید باعث میشه از نظر حافظه و زمان باز شدن، برنامه پرفرمنس بیشتری پیدا کنه و مقیاس پذیر بشه. از اینکه یک گراف کلی داشته باشید که تمام آبجکت ها رو بسازه به شدت اجتناب کنید چون باعث میشه کامپوننت Dagger ناخوانا بشه و قابلیت ماژولار کردن نداشته باشه.با این توضیحات بیایید جریان Login رو ریفکتور کنیم تا این بخش هم به دگر اضافه بشه. برای اینکار میخواهیم یک subcomponent جدید برای جریان Login بسازیم.یک فایل به نام LoginComponent.ktدر پکیج loginبسازید. LoginComponentرا همان طور که کامپوننت RegistrationComponentرا ساختیم، تعریف کنید و کلاس های مربوط به لاگین را به آن اضافه کنید.login/LoginComponent.ktیادتونه برای Annotation Scope ای که ساختیم یک نام جامع گذاشتیم تا کامپوننت های مشابه اش بتونن ازش استفاده کنن؟ حالا LoginComponentرو باActivityScope انوتیت میکنیم.بعد LoginViewModelرا با روش constructor Inject به Dagger معرفی می‌نماییم.LoginViewModel.kt?از این بعد حواسمون هست که کدوم کلاسها باید با انوتیشتن @ActivityScope مشخص بشن. اما LoginViewModelقرار نیست توسط کلاس دیگه ای reuse بشه پس لازم نیست با این Annotation مشخص بشه.همچنین باید این SubComponent جدید را به لیست subcomponentهای کامپوننت AppComponentدر کلاس AppSubcomponentsاضافه نماییم.AppSubcomponents.ktمثل اکتیویتی قبلی، برای اینکه LoginActivityبتونه به فکتوری این ساب کامپوننت جدید دسترسی داشته باشه، باید یک متد در AppComponentبذاریم که فکتوری اونو برگردونه.AppComponent.ktحالا دیگه همه چی فراهم شده تا یک instance از LoginComponentبسازیم و در LoginActivityآن را inject کنیم.مثل ابرای اینکه del را @Injectکنید و ساخت آن را حذف کنید تا این وظیفه روی دوش Dقرار بگیرد.2. فکتوری LoginComponentرا ازappComponent با فراخوانی متد loginComponent()بدست بیاورید و یک نمونه از LoginComponentبا متد create بسازید و injectرا با ارسال اکتیویتی انجام دهید.3. ساخت دستی loginViewModelرا حذف کنید.LoginActivity.ktحالا پروژه را اجرا کنید.جریان Login باید به درستی کار کند.? با LoginComponentجدید گراف برنامه به صورت زیر خواهد بود:سولوشن کُدلب تا این لحظه در 2_subcomponents برنچ قرار دارد.در بخش بعدی کُدلب قراره Setting به دگر معرفی شود و داشتن چندین اکیتیوتی با Scope یکسان را خواهید آموخت.بعدیکُدلَب استفاده از دَگِر در برنامه اندرویدی(8-داشتن چند اکتیویتی در یک Scope) بزودی...قبلیکُدلَب استفاده از دَگر در برنامه اندرویدی (6-SubComponent)کُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)کُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشن‌ها)کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Mon, 11 Apr 2022 16:17:06 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگر در برنامه اندرویدی (6-SubComponent)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-6-subcomponent-nk2tqat1h5lx</link>
                <description>این نوشتار مربوط به بخش ششم از کُدلب آموزشی استفاده از Dagger در پروژه اندرویدی به زبان کاتلین هست و می‌تونید بخش قبلی رو از اینجا بخونید.جریان Registrationبیایید در ادامه جریان Registration رو کامل کنیم، هنوز فرگمنت‌های این فیچر از DI دستی استفاده می‌کنند. دو تا فرگمنت EnterDetailsFragmentو TermsAndConditionsFragmentرو هم مانند اکتیویتی‌ها به متدهای کلاس AppComponent اضافه می‌کنیم.AppComponent.ktفرگمنت EnterDetailsFragmentرو باز کنید تا ببینیم چه فیلدهایی رو می‌خواهیم به دگر معرفی کنیم؟ دو تا ویومدل داره. از طریق فیلد اینجکشن این دو ویو مدل را به دگر معرفی می کنیم و مودیفایر private را هم حذف می کنیم.EnterDetailsFragment.ktو باید مقدار دهی دستی ویومدل ها را هم از کد حذف کنیم.EnterDetailsFragment.ktحالا وقتشه که از نمونه appComponent که در کلاس اپلیکیشن قراره داره برای Inject فرگمنت ها استفاده کنیم. در فرگمنت متد on Attach را اضافه کنید و کد مربوط به Inject را در این متد بعد از super.onAttach قرار دهید.EnterDetailsFragment.ktعادت خوب کدنویسیدر اکتیویتی، درخواست Inject به Dagger در متد on Create و قبل از super نوشته می‌شود.در فرگمنت، درخواست Inject به Dagger در متد on Attach و بعد از super نوشته می‌شود.فقط ویومدل مربوط به این فرگمنت یعنی RegistrationViewModelمونده که از قبل به دَگِر معرفی شده.RegistrationViewModel پس کارمون با فرگمنت EnterDetailsFragmentتمومه! همین کارها رو با فرگمنتTermsAndConditionsFragment هم انجام می‌دهیم:1- فیلدهایی که قراره توسط دگر تامین وابستگی بشوند رو با @Inject انوتیت می کنیم (مثلا registrationViewModel) و مودیفایر private رو حذف می‌کنیم.2. ساخت نمونه از registrationViewModelرو حذف می‌کنیم.چون این کار وظیفه Dagger هست.3. درخواست Inject به دَگِر را در متد onAttach ارسال می‌کنیم.TermsAndConditionsFragment.ktپروژه را اجرا کنید.چه اتفاقی افتاد؟ بعد از ثبت نام برنامه کرش کرد! مشکل اینه که instanceهای متفاوتی از RegistrationViewModelبه RegistrationActivityو EnterDetailsFragmentو TermsAndConditionsFragmentتزریق شده است. اما این آرمان ما نبود! ما می‌خواستیم یک instance یکسان از این ویومدل بین اکتیویتی و فرگمنت‌هاش به اشتراک گذاشته بشه!چقدر شبیه مشکلی که با UserManager داشتیمه نه؟ پس بیاییم ویومدل رو Singleton کنیم چطوره؟خب در این لحظه مشکلمون حل میشه اما در آینده مشکلاتی بوجود میاد.ما نمی خواهیم که instance ویومدل تا وقتی برنامه در حال اجراست در حافظه بمونه حتی وقتی روند ثبت نام یک یوزر به پایان رسید و دیگه ویو مدل رو لازم نداریم!برای هر جریان ثبت نام یک instance متفاوت از ویومدل میخوایم. اگر کاربر ثبت نام و بعد لغو ثبت نام کنه نمی خوایم اطلاعات ثبت نام قبلی در ثبت نام جدید در دسترس باشه.پس چی میخوایم؟میخواهیم فرگمنت‌های مربوط به Registration از  ویومدل یکسانی که از اکتیویتی میاد استفاده کنند و همونو reuse کنند اما اگر اکتیویتی تغییر کرد، instance ویومدل هم عوض بشه.پس باید instance ویومدل به لایف سایکل اکتیویتی scope بشه نه کل برنامه!می‌تونیم یک کامپوننت جدید برای Register بسازیم و ویومدل رو به اون scope کنیم. برای اینکار از Dagger subcomponents استفاده می‌کنیم.معرفی Dagger subcomponents ساب کامپوننت ها کامپوننت هایی هستند که گراف Dagger رو از کامپوننت والد ارث بری می کنند.بنابراین همه ی آبجکت‌هایی که در کامپوننت والد provide شدند در این ساب کامپوننت ها provide خواهند شد. با این روش آبجکتی که در ساب کامپوننت هست می تونه به آبجکتی که در کامپوننت والد provide شده، وابستگی داشته باشد.برای ایجاد subComponent مراحل زیر را می رویم:یک فایل جدید به نام RegistrationComponent.ktدر پکیج registration بسازیدیک اینترفیس به نام RegistrationComponent در آن ایجاد و با @Subcomponent حاشیه نویسی‌اش می‌کنیم.registration/RegistrationComponent.ktهمه مواردی که به Registration ربط داره از AppComponent به این subComponent  منتقل می‌کنیم.یک اینترفیس فکتوری در این subComponent بسازید تا بتوانیم از آن instance بسازیم.RegistrationComponent.ktبجای آنکه RegistrationActivity یک instance از RegistrationComponentبسازه، یه متد به AppComponent اضافه می‌کنیم تا فکتوری، ساب کامپوننت RegistrationComponentرو برگردونه.AppComponent.kt?به این فکر کنید اگر اینکارو نمی کردیم چی می‌شد و راه حل چی بود؟ آیا این روش کد تمیز تری بهمون میده؟یادآوریدو تا راه متفاوت برای ارتباط با گراف Dagger وجود داره:1- متدی داشته باشیم که خروجی اش unit باشه(در جاوا void) و پارامتر ورودی اش کلاسی باشد که می‌خواهیم فیلد اینجکشن را در آن فعال کنیم. (مثل fun inject(activity: MainActivity))2- متدی داشته باشیم که خروجی اش تایپی باشه که میخواهیم از گراف بدست بیاریم (مثل fun registrationComponent(): RegistrationComponent.Factoryکه تایپ RegistrationComponentرو بهمون میده )از راه دوم استفاده کردیم تاRegistrationActivityبتونه از فکتوری    RegistrationComponentاستفاده کنه و ازش instance بسازه. در واقع این متد تایپ RegistrationComponent رو از گراف در اختیارمون قرار داد.چالش ?چطور به AppComponent بگیم که RegistrationComponent یکی از subcomponentهای توست و براش کدهای لازم رو تولید کن؟از طریق DaggerModule!تو پکیج di یک ماژول به نام AppSubcomponentsمی‌سازیم و با @Module حاشیه نویسی‌اش می کنیم. تو همین @Module در بخش پارامتر subcomponentsنام ساب کامپوننتی که ساختیم یعنی RegistrationComponentرو اضافه میکنیم. AppSubcomponents.ktهمچنین اسم این ماژول جدید رو تو لیست ماژول‌های AppComponentاضافه می‌کنیم.AppComponent.ktحالا دیگه AppComponent از ساب کامپوننت‌اش خبر داره!تصویر گراف برنامه تا این لحظههمان طور که در پایین سمت چپ گراف می بینید کلاس های ویو (دو فرگمنت و یک اکتیویتی) توسط RegistrationComponentاینجکت شده اند. از آنجا که RegistrationViewModelو EnterDetailsViewModelفقط توسط کلاس‌هایی که از RegistrationComponentاستفاده می‌کنند درخواست شده‌اند، بخشی از این subcomponent هست بجای AppComponent.در بخش بعدی کُدلب Scope کردن SubComponent ها را خواهید آموخت.بعدیکُدلَب استفاده از دَگر در برنامه اندرویدی (7-Scoping SubComponent) قبلیکُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)کُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشن‌ها)کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Sat, 09 Apr 2022 16:02:35 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D9%90%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-5-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-scope-nyaxyqe2fefr</link>
                <description>این نوشتار مربوط به بخش پنجم از کُدلب آموزشی استفاده از Dagger در پروژه اندرویدی به زبان کاتلین هست و می‌تونید بخش قبلی رو از اینجا بخونید. استفاده از  Scoping یا محدودهIce cream scoop or annotation scope?گاهی اوقات شما به چند دلیل می‌خواهید که از یک وابستگی در کامپوننت instance یکسانی داشته باشید:1- تایپی دارم که چندتا کلاس ازش استفاده می‌کنند و نمی‌خوام هی ساخته بشه و لازمه که instance یکسانی توسط این کلاس‌ها به اشتراک گذاشته بشه.(در این جا UserManager)2- آبجکتی دارم مثل JSON Parser که ساختش هزینه زیادی داره و نمی‌خوام هربار که به عنوان وابستگی اعلان میشه، هی دوباره ساخته شهاین جور مواقع از مفهومی به نام scope استفاده می‌کنیم تا instance یکسانی از یک تایپ در یک کامپوننت داشته باشیم. به اینکار اسکوپ کردن یک تایپ به لایف سایکل کامپوننت هم گفته می‌شه. تا وقتی اون کامپوننت در حافظه هست، ما هم همین یک دونه instance از اون کلاس رو داریم و از بین نمی‌ره و دوباره هم ساخته نمی‌شه.چطوری اسکوپ کنم؟ بیشتر توضیح بده اصلا نمی فهمم این اسکوپ چی هست!با سینگلتون که آشنایی دارید؟ جواب شما : البته که داریم !!?خب اینجا یک انوتیشن اسکوپ داریم به نام @Singleton. بالای سر اسم AppComponent و اون کلاسی که میخوایم یک بار ازش ساخته بشه در طول زندگی این کامپوننت  (اینجا UserManager) یک انوتیشن سینگلتون می ذاریم. تمام!سینگلتون که از قبل داشتیم ولی اگر لازم باشه خودمونم می تونیم انوتیشن اسکوپ بسازیم خیلی جالب و راحت که در ادامه یادتون می‌دم.سینگلتون تنها انوتیشن اسکوپی هست که در پکیج  javax.inject قرار داره.پس چی شد؟وقتی ما یک کامپوننت رو با Singleton انوتیت کنیم، همه کلاس‌هایی که با این انوتیشن مشخص بشن، به لایف سایکل اون کامپوننت وصل می‌شن یا اسکوپ می‌شن یا محدود می‌شن.حالا AppComponent.ktرو باز کنید و با سینگلتون اون رو انوتیت کنید.حالا هر کلاسی که با سینگلتون انوتیت بشه به AppComponent اسکوپ خواهد شد! پس بیایید اینکارو برای UserManager انجام بدیم:در این مرحله دوباره پروژه رو اجرا کنید. مجددا ثبت نام انجام بدید و ببینید چی میشه؟وقتی ثبت نام رو انجام می دید وارد جریان main می‌شید. مشکل حل شد!راه حل پروژه که در تا اینجا بهش رسیدید در برنچ 1_registration_main کد گیتهاب وجود داره.و باز بیایید ببینیم گراف برنامه تا اینجا چه شکلی شده؟Current state of the graph with a unique instance of UserManager in AppComponentدر بخش بعدی قراره با SubComponent ها آشنا بشیم.بعدیکُدلَب استفاده از دَگر در برنامه اندرویدی (6-SubComponent) قبلیکُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشن‌ها)کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Thu, 07 Apr 2022 11:16:11 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-4-%D8%AA%D8%B2%D8%B1%DB%8C%D9%82-%DA%AF%D8%B1%D8%A7%D9%81-%D8%A8%D9%87-%D8%A7%DA%A9%D8%AA%DB%8C%D9%88%D8%AA%DB%8C-ymxgv9lnnemh</link>
                <description>چطور گرافی که ساختیم به اکتیویتی اینجکت کنیم؟معمولا در اندروید گراف دَگر در کلاس اپلیکیشن زندگی می‌کند، چون می‌خواهیم تا وقتی که برنامه در حال اجراست گراف در حافظه باشه.این طوری گراف به لایف سایکل اَپ وصل میشه. تو این مثال، می‌خواستیم Application Context در گراف در دسترس باشه. نتیجه مثبت این امر اینه که گراف در دسترس سایر کلاس‌های اندروید که می‌تونن به کانتکست دسترسی داشته باشند هم هست و چون توی تست می‌تونیم از کلاس اپلیکیشن کاستوم استفاده کنیم، برای تست هم خوبه.حالا بیایین تا AppComponent رو توی کلاس Application بسازیم.همانطور که گفتیم، وقتی پروژه رو بیلد می‌کنیم دگر کلاس  DaggerAppComponentکه شامل پیاده‌سازی گراف AppComponent هست رو می‌سازه.ساخت نمونه از AppComponent در کلاس اپلیکیشناز جایی که برای گراف یک فکتوری ساختیم با انوتیشن خاص خودش، اینجا می‌تونیم متد استاتیک فکتوری از کلاس DaggerAppComponentرو فراخوانی کنیم.بعد هم متد create اون رو و applicationContextرو بعنوان کانتکست بهش ارسال کنیم.همه این کارهارو با Kotlin lazy initialization کردیم، پس متغیر ایجاد شده immutable هست و هروقت لازم باشه ساخته می‌شه.این نمونه ای از گراف که در اینجا ساخته شد، در اکتیوتی به کارمون میاد. تو اکتیویتی از این نمونه استفاده می‌کنیم تا متد inject اش رو فراخوانی کنیم و اکتیوتی رو به عنوان پارامتر براش بفرستیم.با این کار اکتیوتی درخواست فیلد اینجکشن خودش را به دگر ارسال می‌کنه. اکتیوتی به این صورت در میاد:درخواست تزریق به دگر توسط اکتیویتیتغییرات:قبل از تعریف ویو مدل @Inject میاد.خط زیر به متد on create و قبل از فراخوانی super اضافه میشه.(application as MyApplication).appComponent.inject(this)خط مربوط به ساخت ویومدل حذف میشه.فراخوانی appComponent.inject(this)فیلدهای کلاس اکتیوتی که با Inject انوتیت شدن رو پر می‌کنه.یادآوری:درخواست اکتیوتی از دَگِر برای تزریق وابستگی‌هایش را در متد on create قبل از super on create بذارید تا از مشکلات بازیابی فرگمنت جلوگیری بشه.پروژه رو اجرا کنید. باگی دیدید؟ بعد از ثبت نام باید وارد صفحه اصلی بشید اما به صفحه لاگین  می روید، چون نمونه‌ی یوزرمنیجری که در MainActivity استفاده میشه داره در کلاس اپلیکیشن ساخته میشه اما Registration داره از نمونه‌ای از یوزرمنیجر استفاده می‌کنه که توسط دَگِر پرواید می‌شه.افزودن Main flow به دَگِر1- اول اکتیویتی MainActivity رو به AppComponent مشابه قبل اضافه کنید.2- به ویو مدل و وابستگی‌هاش انوتیشن Inject رو اضافه کنید.3- در اکتیوتی فیلدهای وابستگی رو پیدا کنید و انوتیشن Inject رو اضافه کنید و خطوط مربوط به تعریف اون فیلد هارو از اکتیوتی حذف کنید.افزودن متد اینجکت MainActivity به AppComponentما دوباره اسم این متد رو هم inject گذاشتیم چون اسم متد مهم نیست و پارامتر ارسالی مهمه.1- حالا باید MainActivity رو هم تغییرات بدیم. مثلا یوزر منیجر رو بیاید گلوبال تعریف کنید و قبلش انوتیشن Inject بذارید، برای ویومدل هم همین طور.2- سپس مقداردهی این دو فیلد رو حذف کنید چون قراره توسط دگر پر بشن.3- کلاس MainActivity رو در AppComponent اینجکت کنید.کلاس UserManager همین الان در گراف هست و دَگِر می‌دونه چطور ازش نمونه بسازه اما در مورد ساخت MainViewModel اطلاع نداره که باید توسط روش Inject سازنده اونو به دگر معرفی کنیم.همان طور که می بینید MainViewModel  به UserDataRepositoryوابستگی دارد. پس اونو هم با Inject انوتیت می‌کنیم:از جایی‌که UserManager از قبل در گراف بوده، دَگِر تمام اطلاعات لازم برای بیلد موفق گراف در اختیار دارد.وضعیت فعلی گراف در این نقطه از زمانپروژه رو بیلد کنید . دوباره خطا گرفتید درسته؟error: Dagger does not support injection into private fieldsاین خطا به یکی از بدی‌های دَگِر مربوط میشه. در هنگام فیلد اینجکشن، این فیلدها نمی‌تونن private باشنمودیفایر private رو بردارید و مجدد پروژه رو بیلد کنید.با موفقیت بیلد شد درسته؟ حالا می‌تونید پروژه رو اجرا کنید.برای شروع مجدد، دکمه Unregister رو بزنید و دوباره رجیستر کنید. بعد از رجیستر باز هم به صفحه main نرفتید؟ دوباره وارد Login شدید؟پس باز هم باگ داریم !! اما چرا؟! جریان رجیستر و جریان main هردو دارن از UserManager که از گراف اپلیکیشن تزریق شده استفاده می‌کنند. مشکل اینه که دگر به طور دیفالت همیشه  یک نمونه جدید از تایپ ها(در مورد ما UserManager) پرواید می‌کنه!آها پس مشکل ساخته شدن مجدد UserManager و از دست رفتن اطلاعات ثبت نامه! ما باید دگر رو وادار کنیم از همون نمونه قبلی UserManager دوباره استفاده کنه. اما چطور؟با Scoping !بعدیکُدلَب استفاده از دَگِر در برنامه اندرویدی (5-استفاده از Scope)قبلیکُدلَب استفاده از دَگر در برنامه اندرویدی (3-انوتیشن‌ها)کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Thu, 07 Apr 2022 10:06:13 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگِر در برنامه اندرویدی (3-انوتیشن‌ها)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-3-%D8%A7%D9%86%D9%88%D8%AA%DB%8C%D8%B4%D9%86-%D9%87%D8%A7-s3mtimytibtv</link>
                <description>در دو بخش قبل با DI و فریمورک Dagger آشنا شدید. هم چنین پروژه‌ای که قراره روش کار کنیم رو از گیتهاب کلون کردید و با پکیج ها و فیچرهاش آشنا شدید. در این بخش قراره Dagger رو روی فیچر یا جریان Registration پیاده‌سازی کنیم.آشنایی با انوتیشن هادگر همه‌ی کار رو با استفاده از انوتیشن‌ها پیش می بره، به همین دلیل باید باهاشون آشنا بشیم. اولین انوتیشنی که باهاش آشنا می‌شیم اسمش Inject !انوتیشن اینجکت - @Injectاز ریفکتور کردن جریان رجیستر کار رو آغاز می‌کنیم. بارها گفتیم که دگر قراره برامون گراف برنامه رو بسازه که توش مشخصه کی به چی ربط داره. برای این که بتونه اینکارو بکنه باید بدونه از کلاس‌هایی که تو گراف هستند چطور نمونه بسازه؟پس میاییم با یک انوتیشن @Injectسازنده اون کلاس‌ها رو علامت گذاری می‌کنیم. وقتی اینکارو می‌کنیم:1- دگر می فهمه چطور از آن کلاس نمونه بسازه2- اگر کلاس پارامتر ورودی داره، دگر می‌فهمه این کلاس مثلا آرگومان ایکس رو به عنوان وابستگی دریافت کرده.کلاس RegistrationViewModel.kt رو باز کنید. یادتونه که RegistrationActivityاین ویومدل رو می ساخت؟ واسه همین میخوایم طرز ساخت این ویومدل رو به دگر معرفی کنیم. RegistrationViewModel.ktهمون طور که می بینید در کاتلین حتما باید کی ورد constructorرو قبل از انوتیشن @Injectبیاریم. ویومدل کلاسUserManagerرو بعنوان وابستگی می‌گیره اما هنوز دگر خبر نداره چطور باید از روش نمونه بسازه و تو گراف بذاره، بهمین دلیل فایل UserManager رو هم باز کنید و انوتیشن @Injectرو برای سازنده کلاس بذارید.UserManager حالا دیگه دگر می‌فهمه که چطور از روی این دو تا کلاس نمونه بسازه. همون طور که می بینیدUserManager هم یک وابستگی داره که کلاس Storageهست اما Storageیک اینترفیسه و باید یه طور متفاوت به دگر یاد بدیم که چطور از روی اون نمونه بسازه. بعدا بهش می رسیم.ویوها و جایگاه شون در گراف! (اکتیویتی‌ها و فرگمنت‌ها)می دونید که اکتیوتی‌ها و فرگمنت‌ها توسط سیستم ساخته می‌شن و دگر نمی تونه از روشون نمونه بسازه. در اکتیویتی ها هرکدی که مربوط به مقدار دهی اولیه هست در متد on create قرار داره و ما نمی تونیم مثل قبل از از انوتیشین @Injectدر سازنده استفاده کنیم.پس چه کنیم؟فیلد اینجکشندر فیلد اینجکشن که عموما در اکتیویتی و فرگمنت استفاده می‌شه، فیلدهایی که وابستگی هستن و میخواهیم از دگر درخواست کنیم اونارو برامون بسازه رو با انوتیشین @Injectمشخص میکنیم. یادتونه که RegistrationActivityقرار بود ویومدل رو بسازه. پس بیایید با فیلد اینجکشن به دگر بگیم اونو برامون بسازه و این وظیفه رو از روی دوش اکتیویتی برداریم.برای رسیدن به این هدف دو تا کار می کنیم.1- در اکتیویتی جایی که یک فیلد از جنس ویومدل ایجاد کرده رو با انوتیشن @Injectمشخص میکنیم.2- خطی که مربوط به ساخت ویومدل هست رو از متد on create حذف میکنیم.یادآوریوقتی از @Injectدر سازنده یک کلاس استفاده می‌کنیم به دگر اطلاع می‌دهیم چطور از روی کلاس نمونه بسازه و وقتی از @Injectدر یک فیلد استفاده می‌کنیم به دگر اطلاع می دهیم که چطور فیلد رو با ساخت یک نمونه از آن تایپ پر کنه.بریم سراغ شناخت یک انوتیشن دیگه.انوتیشن کامپوننت - Componentدگر قراره گراف نیازمندی‌های پروژه رو بسازه و طوری اونو مدیریت کنه که ما بتونیم نیازمندی‌ها رو از این گراف بگیریم.برای رسیدن به این هدف یک اینترفیس می سازیم و با انوتیشن @Componentاون رو انوتیت یا حاشیه نویسی می‌کنیم. این کار باعث می‌شه دگر یک container بسازه همون کاری که در حالت دستی خودمون انجام می‌دادیم.  این کلاس قراره یک سری متد داشته باشه که دگر قراره نیازمندی های پارامترهای این متدها رو تامین کنه.این انوتیشن باعث می‌شه دگر کدهایی تولید کنه تا نیازمندی ها رو تامین یا پرواید کنه.برای شروع یک متد به این اینترفیس اضافه می‌کنیم که به دگر بگه RegistrationActivityدرخواست تزریق یا  اینجکشن داره.در کنار پکیج registrationیک پکیج به نام di بسازید. درون این پکیج یک کاتلین فایل به نام ایجاد AppComponent.kt و درون این فایل یک اینترفیس به همین نام بسازید. مسیر اینترفیس:app/src/main/java/com/example/android/dagger/di/AppComponent.ktبا متدی که به اینترفیس اضافه کردیم به دگر میگیم که اکتیوتی درخواست اینجکشن داره و تو باید فیلدهای که با انوتیشن @Injectدر اکتیویتی مشخص شده رو براش پرواید کنی.خطای مشکل در تامین یک نیازمندی در زمان کامپایلدیدیم که دگر باید از روی ویومدل نمونه بسازه، برای این کار باید نیازمندی های کلاس ویومدل رو تامین کنه، پس باید از روی UserManagerهم نمونه بسازه و بهمین ترتیب ...اگر در طی این فرآیند تو در تو، دگر به جایی برسه که ندونه چطور از روی یک کلاس نمونه بسازه و وابستگی رو تامین کنه خطا میده و میگه نمیتونم.اپ را بیلد کنید. این کار باعث میشه که پردازنده انوتیشن دگر فعال بشه و کدهای مدیریت وابستگی هارو تولید کنه. با بیلد کردن شما خطای زیر رو در پنجره بیلد خواهید دید:dagger/app/build/tmp/kapt3/stubs/debug/com/example/android/dagger/di/AppComponent.java:7:
 error: [Dagger/MissingBinding] com.example.android.dagger.storage.Storage cannot be provided without an @Provides-annotated methodاولین چیزی که می فهمیم اینه که در AppComponent به خطا خورده است. دومین چیز اینه که خطا از نوع [Dagger/MissingBinding]است و معنیش اینه که دگر نمیدونه چطور یک تایپ خاص رو پرواید کنه؟اگر به خواندن ادامه بدیم می فهمیم که گفته Storage نمیتونه بدون انوتیشن@Providesتامین وابستگی بشه.دلیلش مشخصه! ما هنوز به دگر نگفتیم چطور یک آبجکت از تایپ Storage بسازه.انوتیشن‌های Binds، Module و BindsInstanceباید از راه متفاوتی ساخت آبجکت از Storageرو به دگر بفهمونیم چون اینترفیسه و مستقیما نمیشه از روش نمونه ساخت. باید به دگر بگیم چه پیاده‌سازی از این اینترفیس رو لازم داریم که در اینجا SharedPreferencesStorageاست.ساخت دگر ماژولبرای اینکار باید ماژول بسازیم. چطوری؟ یک کلاس مثلا به نام StorageModule می سازیم و با انوتیشین @Moduleمشخص اش می‌کنیم.مانند کامپوننت‌ها، ماژول‌ها هم مشخص می‌کنند چطور Dagger نیازمندی یک تایپ خاص رو تامین کنه؟ نیازمندی ها توسط @Provides و @Binds مشخص می‌شوند.پس یک کلاس به نام StorageModuleمی‌سازیم و با انوتیشن @Moduleحاشیه نویسی اش می‌کنیم.ساخت ماژول برای معرفی اینترفیس به دَگِرانوتیشن Bindsانوتیشن @Binds برای تامین وابستگی‌های اینترفیسی هست و پیاده سازی اینترفیسمون رو مشخص می‌کنه و همراه یک متد abstract استفاده می‌شه.بنابراین درون ماژول یک فانکشن ابسترکت با نام دلخواه می‌سازیم مثلا provideStorageو با @Binds نشانه‌گذاریش می کنیم. و تایپ فانکشن هم میشه همون اینترفیسی که میخواهیم پیاده سازی شو فراهم کنیم که در این جا Storageهست.پیاده سازی اینترفیس چطور تعیین میشه؟یک پارامتر از جنس پیاده‌سازی اینترفیس به اون متد abstarct می فرستیم که در این‌جا SharedPreferencesStorageهست.با کد بالا به دَگِر می‌گیم هر موقع به آبجکت Storageنیاز داشتی از SharedPreferencesStorage استفاده کن.چون متد ابسترکت هست، مجبوریم کلاس رو هم ابسترکت تعریف کنیم.یادآوریماژول‌ها روشی برای Encapsulate کردن تامین وابستگی‌ آبجکت‌ها به یک روش معنایی هستند.تا این‌جا به دگر گفتیم هروقت یک آبجکت Storageدرخواست شد، یک نمونه از SharedPreferencesStorage بساز اما نگفتیم چطوری؟! برای اینکار از همان روش constructor Inject که یاد گرفتیم استفاده کنید. کلاس SharedPreferencesStorage  را باز کنید و تغییرش دهید.تغییر AppComponentگراف برنامه باید از این ماژول خبردار بشه. پس AppComponent رو باز کنید و داخل انوتیشین @Componentاسم این ماژول جدید را توی پارامتر modules اضافه کنید.به این ترتیب AppComponent می تونه به اطلاعات درون ماژول دسترسی داشته باشه. در برنامه‌های بزرگتر باید یک NetworkModule برای تامین نیازمندی های OkHttpClient هم داشته باشیم یا برای کانفیگ Gson و Moshi.پروژه رو بیلد کنید. دوباره یک ارور مشابه ارور قبلی خواهید دید که این دفعه می گه Context رو نمیتونم پیدا کنم. Context نیازمندی کدوم کلاس بود؟؟؟انوتیشن BindsInstanceمیدونیم Context توسط سیستم اندروید provide می‌شه و خارج از گراف برنامه است. چون موقع ساخت گراف، Context از قبل وجود داره باید اونو به گراف پاس بدیم.چطور؟برای AppComponent یک فکتوری می‌نویسیم و از انوتیشن BindsInstance استفاده می‌کنیم.1- یک اینترفیس به نام Factory می سازیم و براش انوتیشن Component.Factory میذاریم.2- درون اینترفیس یک متد به نام create تعریف میکنیم که تایپ خروجی آن AppComponent است و یک پارامتر از جنس Context می‌گیرد که با انوتیشن BindsInstance انوتیت شده است.انوتیشن BindsInstance برای آبجکت‌هایی هست که خارج گراف ساخته می‌شوند مانند Context .دوباره پروژه رو بیلد کنید. با موفقیت بیلد میشه و دَگر گراف برنامه رو خواهد ساخت. ساخت گراف اپلیکیشن به طور اتوماتیک توسط پراسسور انوتیشن انجام می‌گیرد. نام کلاس تولید شده Dagger{ComponentName} است و شامل پیاده سازی گراف است.از کلاس DaggerAppComponentتولید شده در قسمت بعدی استفاده خواهیم کرد. توجه کنید تا وقتی که کد با موفقیت بیلد نشود این کلاس را نخواهید داشت.تا ایجا گراف برنامه این شکلیه:وضعیت گراف اپلیکشن تا این لحظههمانگونه که می‌بینید AppComponent شامل StorageModule است، همراه با اطلاعاتی که می‌داند چطور از روی Storage آبجکت بسازد. Storage به Context وابسته است اما چون Context موقع ایجاد گراف ارسال می‌شود، همه وابستگی‌های Storage تامین شده است.یک instance از Context به متد create فکتوری AppComponent ارسال شده است، بنابراین هرآبجکتی در گراف که به Context نیاز داشته باشد، نمونه مشترکی در اختیارش قرار میگیرد. این موضوع با یک نقطه سفید در کنار مستطیل Context در تصویر مشخص شده است.بعدیکُدلَب استفاده از دَگر در برنامه اندرویدی (4-تزریق گراف به اکتیوتی)قبلیکُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Wed, 06 Apr 2022 23:23:21 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگِر در برنامه اندرویدی (2-شروع)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D9%90%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C-2-%D8%B4%D8%B1%D9%88%D8%B9-ljdlukaj5uyq</link>
                <description>در بخش قبل با مفهوم DI و فریمورک Dagger برای رسیدن به اون آشنا شدید. و توضیح دادیم که اینجا یک کُدلب هست که قراره قدم به قدم روی یک پروژه اندرویدی به زبان کاتلین کار کنید و DI رو در آن پیاده کنید.در پایان آموزش چه بدست خواهید آورد؟وقتی کُدلَب تموم بشه شما یک گراف اپلیکیشن تست شده به صورت زیر خواهید داشت:گراف اپلیکیشن که همه کلاس های اپ و وابستگی هاشونو نشون میدهاز ظاهر پیچیده این گراف نگران نشید. این فقط یک تصویر کلی هست که قدم به قدم باهاش آشنا خواهید شد.کدی که قراره روش کار کنیم رو از این آدرس بگیرید:$ git clone  https://github.com/googlecodelabs/android-daggerاین پروژه گیتهاب رو در اندروید استودیو کلون کنید. با سه تا برنچ مواجه میشید:برنچ Main : برنچ اولیه که باهاش مواجه می‌شید و Manual DI در آن پیاده شده و شما قراره کتابخونه دگر رو بهش اضافه کنید و قدم به قدم به سمت راه‌حل نهایی حرکت کنیدبرنچ 1_registration_main و 2_subcomponents و 3_dagger_appبرنچ‌های میانی برای رسیدن به راه حلبرنچ راه‌حل نهایی کُدلب حالا کد رو اجرا کنید و ببینید اپ شامل چی هست؟جریان رجیستریشن - Registration flowجریان  لاگین - Login flowجریان هوم - Home flowجریان ستینگ - Setting flowیکم وقت بذارید و با کد و پکیج هاش آشنا بشید:فلش ها وابستگی های بین آبجکتها رو نشون میدن برنامه شامل معماری MVVM هست که در اون پیچیدگی ویوها روی دوش ویو مدل هست. عکس بالا رو ببینید. بالا سمت چپ در مستطیل سبز RegistrationActivity رو ببینید. این اکتیویتی باید ویومدلش که RegisterationViewModel هست رو بسازه. ویو مدل باید UserManager رو بسازه و UserManager باید Storage رو بسازه. این فقط یک خط وابستگی تو برنامه بود که مربوط به جریان Registration هست و ما از همین خط برای جایگیزینی دگر با حالت منوآل شروع می‌کنیم.می‌خواهیم دگر رو مسئول ساخت گراف برنامه و تزریق وابستگی به فیلدهای تو اکتیویتی هامون کنیم.افزودن کتابخانه دَگِر به پروژهفایل app/build.gradle رو باز کنید و دو تا dependency زیر رو اضافه کنید هم‌چنین پلاگین Kapt رو هم بالای فایل اضافه کنید و sync now رو بزنید.build.gradleسوال پیش میاد این چیزایی که به فایل گردل اپ اضافه کردیم چین؟دگر با استفاده از مدل انوتیشنی که تو جاوا هست پیاده‌سازی شده و یک پردازنده انوتیشن در زمان کامپایل کدها رو تولید می کنهدر کاتلین، پردازنده‌های انوتیشن توسط یک پلاگین کامپایلر به نام kapt پشتیبانی می‌شهاین پلاگین چطور فعال میشه؟ با id که اون بالای فایل اضافه کردیم یعنی id &#x27;kotlin-kapt&#x27; و id &#x27;kotlin-android-extensionsکتابخونه دگر که اضافه کردیم هرچی انوتیشن برای ادامه کار لازم داریم تو خودش داره.یک دونه کامپایلر دگر هم اضافه کردیم که همون پردازنده انوتیشینی هست که کدهای لازم برای تولید گراف برنامه رو تولید می‌کنه اما نگران نباشید این کدها در نهایت در اپ قرار نمی‌گیرن و حجم برنامه رو زیاد نمی‌کنند.بعدی کُدلَب استفاده از دَگر در برنامه اندرویدی (3-انوتیشن‌ها)قبلیکُدلَب استفاده از دَگر در برنامه اندرویدی(1-معرفی)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Wed, 06 Apr 2022 22:59:40 +0430</pubDate>
            </item>
                    <item>
                <title>کُدلَب استفاده از دَگِر در برنامه اندرویدی(1-معرفی)</title>
                <link>https://virgool.io/@fereshtehnaji/%DA%A9%D9%8F%D8%AF%D9%84%D9%8E%D8%A8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%AF%D9%8E%DA%AF%D8%B1-%D8%AF%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF%DB%8C1-%D9%85%D8%B9%D8%B1%D9%81%DB%8C-erdpa4nkby78</link>
                <description>طی چند تا پُست قراره به زبان روان و خودمانی بیاموزیم چطور دَگِر رو در پروژه اندروید خودمون بیاریم؟تزریق وابستگیزبان استفاده شده در این آموزش کاتلین هست و همه چیز در این آموزش از این کُدلب گوگل اومده! پس اگر زبانتون خوبه پیشنهاد می‌کنم کُدلب اصلی رو بخونید وگرنه همین پست رو ادامه بدید.بهتره اشاره کنم که بیشتر بخش‌ها ترجمه مستقیم نیست و برداشت خود من از مفاهیمه.پس با من همراه بشید.دَگِر چی هست؟قبل از آنکه بخواهید با دَِگر آشنا بشید باید با مفهوم تزریق وابستگی یا دِپندِنسی اینجکشن-Dependency Injection  آشنا بشید، سپس در مورد یکی از ابزارهای این کار که دَگِر - Dagger هست صحبت خواهیم کرد. ازین پس بجای عبارت تزریق وابستگی(Dependency Injection) از اختصار آن یعنی DI در این نوشتار استفاده خواهم کرد.وابستگی - Dependencyدر دنیای نرم افزار، وابستگی به این معنی هست که کلاس A داره از کلاس B استفاده می‌کنه. همین!کلاس A به کلاس B وابسته است در نتیجه کلاس B میشه وابستگیه کلاس A و هروقت کلاس A به کلاس B نیاز داشته باشه باید اون رو  بسازه.مثلا یک کلاس داریم به نام User که یک فیلد داره از جنس کلاس Address. پس کلاس User به کلاس Address وابسته است و User باید کلاس Address رو بسازه تا بتونه ازش استفاده کنه. در دنیای شی‌گرایی معمولا کلاس‌ها برای انجام دادن وظایفشون به کلاس‌های دیگه وابسته هستن.تا اینجا فهمیدیم وابستگی معنیش چیه. حالا بریم سراغ تزریق اون.تزریق وابستگی (DI)دیگه چیه؟ چه اسم عجیبی!فرض کنید شما انسانی هستید که می خواید تو یک خونه مستقل زندگی کنید و کار زیادی به آدم ها نداشته باشید. اما انسان موجودی اجتماعی هست با کلی نیازمندی. یعنی نمی تونیم بگیم مستقل باش و هیچ نیازمندی نداشته باش. برای مثال میخوایم غذا بخوریم و احتیاج به نان داریم. آیا منطقیه یک نانوا توی خونمون بیاریم و کلی هزینه کنیم برای ایجاد نانوایی یا بهتره زنگ بزنیم اسنپ برامون نون بفرسته؟آیا منطقیه برای تهیه پوشاک تو خونه خیاط بیاریم و چرخ خیاطی و دنگ و فنگ یا آنلاین برامون لباس بیارن؟ و بهمین ترتیب بقیه نیازمندی ها... غیرمنطقیه که بخواهیم خودمون وسایل رفع نیازمندی ها رو فراهم کنیم، چون کار هزینه‌بر و پیچیده‌ای هست. اگر من بخواهم فردا برم یه خونه دیگه زندگی کنم برام سخته ! راه‌حل منطقی اینه که نیازمندی‌ها از بیرون برامون تامین بشه و ما فقط استفاده کنیم ! حالا تامین نیازمندی‌ها می‌تونه حتی ساده ترم بشه. به این صورت که خودمون زنگ نزنیم به این و اون تا برامون تامین کنن، یکی رو استخدام کنیم که کار تامین نیازمندی‌ها رو برامون انجام بده.خیلی زندگی زیبا میشه مگه نه؟?تو دنیای نرم افزار هم، میشه همینقدر زندگی رو قشنگ کرد. شما یک کلاس هستید با چند تا وابستگی: تزریق وابستگی یعنی این وابستگی‌ها خارج از کلاس شما ایجاد بشه و به شما پاس داده بشه. ایده اینه که کلاس‌ها مسئول ساخت وابستگی‌هاشون نباشن.درک بهتر با یک مثالفرض کنید شما یک کلاس Car هستید که دو تا فیلد Engine و Wheels دارید. اگر خود کلاس Car مسئول ساخت این دو تا وابستگی باشه، موقع نیاز باید Engine رو بسازه. ساخت موتور یک ماشین هم که کاری راحتی نیست، خودش کلی نیازمندی و ملاحظات داره و در واقع کار پر هزینه‌ای هست. ساخت چرخ‌ها هم به همین ترتیب. اما وقتی تزریق وابستگی داشته باشیم موتور و چرخ ها خارج از کلاس Car ساخته می‌شن و براش ارسال می‌شن و کلاس Car دیگه دغدغه ساخت موتور، چرخ ها و هزینه شونو نداره.کی این وابستگی‌ها رو بسازه؟هنگام تامین وابستگی‌ها، می تونید دستی از روی  وابستگی‌ها نمونه بسازید و به کلاس نیازمند بفرستید (منوآل DI ) یا از یک ابزاری بخواید این کارو براتون انجام بده!کدوم بهتره؟منوآل DI رو می‌تونید برای پروژه‌های کوچک استفاده کنید و حتما یکبار این تست رو انجام بدید! اما وقتی پروژه بزرگ میشه، راستش تامین وابستگی‌ها سخت میشه :)از این‌جا منوآل رو امتحان کنید.چرا دَگِر استفاده کنیم؟وقتی پروژه بزرگ می‌شه مجبورید کلی کد بویلرپلیت (بویلرپلیت چیه؟ اینجا رو بخون) مثلا فکتوری‌ها رو بنویسید که مستعد خطا میشه و کلی مدیریت‌ها رو دستی انجام بدید و ....خب چه کاریه؟ بیاییم از فریمورک دَگِر درخواست کنیم اینکارو برامون انجام بده.دگر شما رو از شر نوشتن کلی کد بویلرپلیت خطا خیز خلاص می‌کنه.?کد گراف اپلیکیشن (بعدا می فهمید چیه) رو براتون می‌نویسه، چیزی که مجبور بودید تو حالت دستی خودتون بنویسیدش تحت عنوان AppContainerبرای کلاس‌هایی که تو گراف اپلیکیشن هستن فکتوری می‌نویسه.تصمیم می‌گیره چه وقت از روی یک تایپ نمونه جدید بسازه یا نمونه قبلی رو مجدد استفاده کنه?در نهایت برای هر جریانی تو برنامه مثلا جریان لاگین یک کانتینر جدا می‌سازه و اینجوری می‌تونه آبجکت‌هایی که لازم نیستن رو از حافظه خارج کنه و پرفرمنس رو بهتر کنه.یه چیز مهم هم تو ذهنتون داشته باشید که DI به چه درد میخوره؟استفاده مجدد از کد راحت میشهریفکتور کد راحت میشهکدمون قابلیت تست نوشتن پیدا می‌کنهبرای شروع این کُدلَب چی لازم دارید؟کاتلین بلد باشید و مفهوم DI و مزایای استفاده از Dagger در برنامه اندرویدی رو بدونیدبرای شروع به بخش دوم کُد لب بروید:بعدیکُدلَبِ استفاده از دَگر در برنامه اندرویدی (2-شروع)</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Wed, 06 Apr 2022 22:39:19 +0430</pubDate>
            </item>
                    <item>
                <title>مجموعه‌ای از سوالات مصاحبه‌های اندروید (بخش اول)</title>
                <link>https://virgool.io/cheyab-blog/%D9%85%D8%AC%D9%85%D9%88%D8%B9%D9%87-%D8%A7%DB%8C-%D8%A7%D8%B2-%D8%B3%D9%88%D8%A7%D9%84%D8%A7%D8%AA-%D9%85%D8%B5%D8%A7%D8%AD%D8%A8%D9%87-%D9%87%D8%A7%DB%8C-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-j9ugw3olcthh</link>
                <description>آنچه که در ادامه می‌آید ترجمه ای از مقاله‌ی یک برنامه نویس اندروید به نام خانم Anitaa Murthy است. ایشان طی سال‌ها مجموعه‌ای از سوالات مصاحبه‌های اندروید را جمع آوری کردند که  در ادامه با هم خواهیم خواند. بر خلاف اصل مقاله، تعدادی از سوال‌ها را اول آورده‌ام. دوست دارم این سوال‌ها را پیش خودتان پاسخ دهید (سعی کنید واقعا با جملات به آنها پاسخ دهید، نه اینکه در ذهنتان به آن فکر کنید) و به این وسیله دانش خود را به چالش بکشید.اپلیکیشن چیست؟کانتکست (Context) چیست؟می‌دانید ArmV7 چیست؟چرا bytecode نمی‌تواند در اندروید اجرا شود؟بیلد تایپ در گردل چیست؟ و برای چه چیزی استفاده می‌شود؟پروسه بیلد شدن در اندروید را توضیح دهید.سناریویی را توضیح دهید که در آن ()on Destroy بدون ()on Pause و on Stop در اکتیویتی فراخوانی شود.چند تای آن‌ها را پاسخ دادید؟خب اجازه بدهید به سراغ پاسخ‌ها و ادامه سوالات برویم:1. اپلیکیشن چیست؟کلاس اپلیکیشن، کلاسی پایه در برنامه اندروید است که شامل همه کامپوننت‌های دیگر مانند اکتیویتی‌ها و سرویس‌ها می‌شود. کلاس اپلیکیشن و یا هر زیر کلاسی از آن قبل از هر کلاس دیگری شروع می‌شوند.2. کانتکست (Context) چیست؟کانتکست روح زندگی برنامه اندرویدی است و بدون آن برنامه شما یک کد جاوای ساده است.کانتکست مهم ترین چیز در توسعه اندروید است و از طریق آن می‌توان اطلاعاتی راجع به اپلیکیشن و اکتیویتی بدست آورد.با کانتکست می‌توان به ریسورس‌ها، دیتابیس و پرفرنس‌ها و غیره دسترسی پیدا کرد.کانتکست مثل یک نقطه دسترسی به محیطی هستش که برنامه شما در حال حاضر روی آن در حال اجراست.کلاس اکتیویتی و کلاس اپلیکیشن هر دو از Context اکستند شده‌اند.دو نوع کانتکست مهم UI Context و Non-UI Context در دنیای اندروید داریم. بسیار مهمه که تفاوت این دو رو بدونید و اینکه چه موقع از هرکدام استفاده کنید که دچار مشکلات حافظه نشید.3. می دانید ARMv7 چیست؟در اندروید سه نوع معماری CPU داریم. ARMv7 بهینه‌ترین آن‌هاست که در مصرف باتری بهینه‌سازی شده است. ARM64 نسخه تکامل یافته‌تری است که از پردازش 64 بیتی برای محاسبات قدرتمندتری استفاده می‌کند. پردازنده ARMx86 از دوتای دیگر قدرتمندتر است اما استفاده کمتری دارد چون اصلا مصرف باتری خوبی ندارد.4. چرا bytecode نمی تواند در اندروید اجرا شود؟زیرا اندروید بجای JVM (ماشین مجازی جاوا) تا اندروید ۴.۴ ازDVM  (ماشین مجازی Dalvik) استفاده می کرد و از اندروید ۵ از ART (android runtime) استفاده میکند. برای آشنایی بیشتر با دالویک و ART می‌توانید این مقاله را مطالعه بفرمایید.5. در گردلBuildType چیست؟بیلد تایپ پراپرتی هایی را تعریف می کند که Gradle هنگام بیلد کردن و پکیج‌بندی کردن برنامه اندروید شما از آن استفاده می‌کند .    1. بیلد تایپ تعریف می‌کند که چگونه یک ماژول بیلد شود، برای مثال ProGuard اجرا شود یا خیر.    2. و  Flavour محصول تعریف می کند که چه چیزی بیلد شود، مثلا اینکه چه ریسورس‌های در بیلد وجود داشته باشد.    3. گردل یک خصوصیت بیلد برای هر ترکیب ممکن از بیلد تایپ‌ها و Flavourهای محصول ایجاد می‌کند.6. فرآیند بیلد در اندروید را توضیح دهید؟1. اولین قدم پوشه ریسورس‌ها (/res) را با استفاده از ابزار aapt  (android asset packaging tool) کامپایل می‌کند. همه‌ی این ریسورس ها به یک دونه فایل کلاس R.java کامپایل می‌شوند. این کلاس فقط شامل یک سری ثابت است.2. قدم دوم همه‌ی سورس کدهای جاوا توسط javac به فایل‌های .class کامپایل می‌شوند. سپس این کلاس‌ها توسط ابزار &quot;dx&quot; که در SDK tools قراردارد، به بایت کد Dalvik تبدیل می‌گردند، و خروجی آن کلاس .dex است.3. مرحله‌ی آخر ساخت apk است که همه این ورودی‌ها تبدیل به یک فایل apk(android packaging key) می‌شود.7. معماری یک اپلیکیشن اندروید چیست؟معماری اپلیکیشن اندروید شامل کامپوننت‌های زیر است:1. سرویس‌ها: برای انجام عملیات بکگراند استفاده می‌شود.2. اینتنت: کانکشن داخلی بین اکتیویتی‌ها برقرار می‌کند و همچنین برای ارسال داده بکار می‌رود.3. ریسورس‎ها: مانند استرینگ‌ها و تصاویر4. ابزارهای آگاه‌سازی: شامل نور، صدا، آیکون، نوتیفیکیشن، دیالوگ و تست5. کانتنت پروایدر: برای اشتراک گذاری داده بین اپلیکیشن ها کاربرد دارد.8. اکتیویتی در اندروید را توصیف کنید؟اکیتیویتی ها اساسا کانتینر یا پنجره ای برای رابط کاربری (UI) هستند.9. چرخه حیات یک اکتیویتیشامل متدهای زیر است: متد onCreate : این متد مربوط به زمانی ست که view برای اولین بار ایجاد می‌شود. در این متد ما view ها را ایجاد می‌کنیم و داده‌ها را از باندل می‌خوانیم.متد on Start : وقتی اکتیوتی در معرض دید کاربر قرار می‌گیرد فراخوانی می‌شود. حالا اگر اکتیویتی روی صفحه گوشی کاربر قابل مشاهده شود یعنی در فورگراند باشد بعد از آن on Resume فراخوانی میشه اما اگر اکتیویتی hide شود آنگاه متد on Stop فراخوانی خواهد‌ شد.متد on Resume: وقتی اکتیوتی قابل تعامل با کاربر باشد، فراخوانی می‌شود. در این مرحله اکتیویتی بالای استک اکتیویتی قرار می‌گیرد.متد on Pause: وقتی اکتیویتی به بکگراند برود فراخوانی می‌شود اما توجه کنید که اکتیویتی هنوز زنده است.متد on Stop: وقتی اکتیویتی دیگر برای کاربر قابل مشاهده نیست، فراخوانی می‌شود.متد on Destroy: وقتی اکتیویتی در حال به پایان رسیدن و مرگ است، فراخوانی می‌شود.متد on Restart: بعد از اینکه اکتیوتی stop شد، درست قبل از شروع مجدد، این متد فراخوانی می‌گردد.10.  تفاوت متد onCreate و on start چیست؟متد onCreate در طول چرخه حیات اکتیویتی فقط یکبار فراخوانی می‌شود. هنگام شروع برنامه یا زمانیکه اکیتیوتی destroy شده و از بین رفته و حالا دوباره ساخته شده است مثلا در زمان تغییر configuration.متد on Start: هر وقتی که اکتیویتی توسط کاربر قابل دیدن شود، فراخوانی می‌شود. معمولا بعد از onCreate و on Restart.11. یک سناریو بگویید که در آن بدون فراخوانی on Pauseو on Stop فقط onDestroy اکتیویتی کال شود؟اگر متد finish در تابع onCreate اکتیویتی فراخوانی شود سیستم متد onDestroy را مستقیماً فراخوانی می‌کند.12. چرا شما setContentView را در متد onCreate اکتیویتی انجام می‌دهید؟از آنجایی که متد onCreate اکتیویتی فقط یکبار فراخوانی می‌شود، باید بیشتر مقداردهی های اولیه نیز همین جا انجام شود. اصلا کار بهینه ای نیست که setContentView را در توابع on Resume یا on Start انجام دهیم، چون این توابع چندین بار فراخوانی می‌شوند و setContentView عمل سنگینی است.13.  متدهای onRestoreInstanceState و onSaveInstanceState در اکتیویتی چه کاری انجام می‌دهند؟متد onRestoreInstanceState: وقتی اکتیویتی نابود شده مجددا ساخته می شود، می‌توانیم وضعیت ذخیره شده را از باندلی که به این متد پاس داده شده است، بازیابی نماییم. هر دو متد onCreate و onRestoreInstanceState باندل مشابهی دریافت می‌کنند، اما چون متد onCreate هر وقت که سیستم نمونه‌ی جدیدی از اکتیویتی شما می‌سازد و یا وقتی که نمونه‌ی قبلی را بازسازی می‌کند فراخوانی می‌شود باید قبلا از خواندن داده ها از باندل، نال نبودن آن‌ها را چک کنید. اگر باندل نال بود مشخص می‌شود که سیستم نمونه‌ی جدید از اکتیویتی ساخته است و این فراخوانی بخاطر بازسازی نمونه قبلی که destroy شده، نبوده است.متد onSaveInstanceState : این متد برای ذخیره‌ی داده‌ها قبل از pause شدن اکتیویتی استفاده می‌شود.14.  از Launch مود در اندروید چی می‌دانید؟وقتی یک اکتیویتی قرار است اجرا شود، سیستم از روی لانچ مود می‌فهمد که باید نمونه‌ی جدید بسازد یا از نمونه قبلی استفاده کند و یا حتی برای نمونه‌های دیگر موجود در Stack اکتیویتی چه اتفاقی خواهد افتاد.بیاییم با استفاده از تصاویر برگرفته از این مقاله ببینیم لانچ مودها چه تفاوت‌هایی باهم دارند. و در ابتدا یک تصویر راهنما ببینیم:رنگ سبز یعنی نمونه‌ای از اکتیوتی به تازگی ایجاد شده است و رنگ زرد به این معنی ست که نمونه اکتیویتی قبلا وجود داشته و فقط متد onNewIntent فراخوانی شده است.مود Standard: مود استاندارد، نمونه ای از اکتیویتی در Taskای که از آن شروع شده است، ایجاد می‌کند. می‌تواند چند نمونه از اکتیوتی ایجاد شود و به تسک‌های مشابه یا متفاوت افزوده شود.مثال : فرض کنید که استک اکتیویتی به این صورت باشد: A-&gt;B-&gt;C-&gt;D حالا ما اکتیویتی B را با لانچ مود استاندارد، لانچ می کنیم. اکتیویتی B با لانچ مود استاندارد در مانیفست تعریف شده است. بعد از اجرای آن با اینکه یک نمونه از آن قبلا در استک وجود داشته است، یک نمونه‌ی جدید ساخته شده است.مود SingleTop: مود SingleTop مشابه مود Standard است بجز اینکه اگر یک نمونه از اکتیویتی بالای استک وجود داشته باشد، آنگاه نمونه ای جدیدی از آن اکتیویتی ساخته نخواهد شد و intent به نمونه اکتیویتی که بالای استک است ارسال خواهد شد، در غیر اینصورت نمونه‌ی جدیدی از اکتیویتی در بالای استک قرار خواهد گرفت.مثال 1: فرض کنید استکی به این صورت داریم: A-&gt;B-&gt;C-&gt;Dاکتیویتی D با لانچ مود SingleTop در مانیفست تعریف شده است. چون قبلا یک نمونه از اکتیویتی D در بالای استک وجود داشته است، نمونه‌ی جدیدی ایجاد نمیشود و متد onNewIntent در اکتیویتی D فراخوانی می‌شود. مثال 2: استک اکتیویتی به این صورت است: A-&gt;B-&gt;C اکتیویتی D با لانچ مود SingleTop در مانیفست تعریف شده است. نمونه‌ی جدیدی از اکتیویتی D در استک قرار می‌گیرد.مثال 3: استک اکتیویتی به این صورت است: A-&gt;B-&gt;D-&gt;C اکتیویتی D با لانچ مود SingleTop در مانیفست تعریف شده است. یک نمونه از اکتیویتی D قبلا در استک وجود داشته اما چون بالای استک نبوده است یک نمونه جدید از اکتیویتی D ایجاد می‌شود.مود SingleTask: مود تک وظیفه‌ای یا SingleTask به این صورت است که فقط یک نمونه از اکتیویتی می‌تواند وجود داشته باشد مشابه الگوی سینگلتون. سه حالت خواهیم داشت. حالت اول) نمونه‌ای از این اکتیویتی در استک نداشته باشیم، که نمونه ی جدید بالای استک ایجاد خواهد شد. حالت دوم) نمونه از این اکتیویتی از قبل بالای استک وجود دارد، نمونه‌ی جدید ساخته نمی‌شود و فقط Intent به تابع onNewIntent تحویل داده خواهد شد. حالت سوم) نمونه‌ای از این اکتیویتی وجود داشته باشد اما بالای استک نباشد. در این حالت همه نمونه های بالای این نمونه نابود خواهند شد تا این نمونه بالای استک باشد و Intent به تابع onNewIntent تحویل داده خواهد شد.مثال 1: فرض کنید یک استک داریم به این صورت: A-&gt;B-&gt;C-&gt;Dاکتیویتی C با لانچ مود SingleTask در مانیفست تعریف شده است. همان گونه که انتظار داشتیم اکتیویتی D نابود شده است و متد onNewIntent در نمونه قدیمی اکتیویتی C فراخوانی شده است.(حالت سوم)مثال 2: استک اکتیویتی به این صورت است: A-&gt;Bچون قبلا نمونه‌ای از اکتیویتی C در استک نداشتیم، یک نمونه‌ی جدید از آن ساخته می‌شود.مود SingleInstance: مود تک نمونه‌ای یا SingleInstance مشابه تک وظیفه‌ای است اما سیستم، اکتیویتی با لانچ مود SingleInstance را در Task موجودی که اکتیویتی دیگری در آن وجود دارد، قرار نمی‌دهد. چنین اکتیویتی همیشه در یک Task جداگانه اجرا خواهد شد.مثال: فرض کنید یک استک اکتیویتی به این صورت داریم: A-&gt;B-&gt;C-&gt;Dاگر اکتیویتی E را با لانچ مود SingleInstance اجرا کنید استک اکتیویتی جدید به این صورت خواهد بود:Task 1: A-&gt;B-&gt;C-&gt;DTask 2: Eاکتیویتی E با لانچ مود SingleInstance در مانیفست تعریف شده است. همان طور که می‌بینیم نمونه‌ی اکتیویتی E در task دیگری ایجاد شده است.مثال 2: اکتیویتی F بعد از اکتیویتی E اجرا خواهد شد. استک اکتیویتی به صورت زیر خواهد بود.همان طور که می‌بینیم نمونه‌ی اکتیویتی F وارد تسک دیگر شد و نمونه‌ی اکتیویتی E هنوز در تسک خود تنهاست.مثال3:استک اولیه به این صورت است که دو Task داریم. Task اول شامل A-&gt;B و Task دوم شامل Eحالا دوباره اکتیویتی E اجرا می‌شود. چه اتفاقی خواهد افتاد؟متد onNewIntent در نمونه‌ی اکتیویتی E فراخوانی شده است و نمونه‌ی جدیدی ایجاد نشده است.برای مشاهده مثال‌های تصویری و جا افتادن بهتر موضوع می توانید این مقاله و این مقاله را مطالعه نمایید.15. وقتی کاربر اسکرین را rotate می‌کند، اکتیویتی چگونه پاسخ می‌دهد؟وقتی اسکرین rotate می‌شود، نمونه فعلی اکتیویتی نابود می‌شود و نمونه‌ی جدیدی از اکتیویتی در rotation جدید ایجاد خواهد شد. و متد onRestart فراخوانی می‌شود. بقیه متدهای لایف سایکل اکتیویتی مشابه زمانی ‌که اکتیویتی جدید ساخته می‌شود، اجرا خواهند شد.16. در زمان rotate صفحه چگونه از reloading و resetting داده جلوگیری کنیم؟اساسی‌ترین رویکرد استفاده از ترکیب ویو مدل ها و تابع onSaveInstanceState خواهد بود. چگونه؟می دانیم ویومدل‌ها LifeCycle-Aware (از لایف سایکل آگاهی دارند) هستند. یعنی اگر اکتیویتیِ صاحب ویومدل بخاطر تغییر تنظیمات نابود شود، ویو مدل نابود نخواهد شد و فقط به نمونه‌ی جدید اکتیویتی دوباره متصل می‌شود. به عبارت دیگر اگر اسکرین سه بار rotate شود و اکتیویتیِ صاحب ویومدل سه بار نابود شود، سه نمونه‌ی جدید از اکتیویتی ایجاد خواهد شد اما فقط یک نمونه از ویومدل ایجاد شده است.بنابراین بهترین رویکرد این است که داده‌ها را در کلاس ویومدل ذخیره کنیم و می‌توانیم از متد onSaveInstanceState اکتیویتی برای حفظ داده‌های کوچک Uiای استفاده کنیم.برای مثال، فرض کنید یک صفحه جستجو داریم و کاربر یک عبارت را برای جستجو در ادیت تکست وارد کرده است. نتایج جستجو در یک ریسایکلر ویو نمایش داده می‌شود. کاربر صفحه را rotate می‌کند. برای حفظ داده‌های لیست و عبارت درون ادیت تکست چه خواهید کرد؟بهترین روش برای جلوگیری از ریست شدنِ لیست، ذخیره‌ی داده‌های لیست در ویو مدل و عبارت جستجو شده در تابع onSaveInstanceState می‌باشد.17. وقتی یک اکتیویتی جدید از طریق Intent  ایجاد می‌شود، دو راه برای پاک کردن بک استک اکتیویتی پیشنهاد کنید.راه اول) استفاده از فلگ FLAG_ACTIVITY_CLEAR_TOP راه دوم) استفاده از ترکیب فلگ‌های FLAG_ACTIVITY_CLEAR_TASK و FLAG_ACTIVITY_NEW_TASK18.  چه تفاوتی بین FLAG_ACTIVITY_CLEAR_TASK  و FLAG_ACTIVITY_CLEAR_TOP وجود دارد؟فلگ FLAG_ACTIVITY_CLEAR_TASK: همان طور که از نامش پیداست تمام نمونه‌های درون تسک را پاک خواهد کرد حتی اگر از اکتیویتی فعلی نمونه‌هایی وجود داشته باشد، آن‌ها هم پاک خواهد شد. خلاصه همه چی پاک می‌شود و نمونه‌ی جدید، روت تسک خواهد بود و به همین دلیل حتما باید این فلگ با ترکیب فلگ FLAG_ACTIVITY_NEW_TASK استفاده شود.فلگ FLAG_ACTIVITY_CLEAR_TOP : هنگام ست شدن این فلگ برای اجرای اکتیویتی دو حالت خواهیم داشت. حالت 1) نمونه‌ی قدیمی از این اکتیویتی در لیست تسک وجود دارد، بنابراین تمام نمونه های روی آن حذف خواهد شد و نمونه قدیمی root لیست خواهد شد. حالت 2) اگر نمونه‌ی قدیمی وجود نداشته باشد، یک نمونه‌ی جدید ایجاد می شود و root لیست خواهد شد. استفاده از ترکیب این فلگ با FLAG_ACTIVITY_NEW_TASK ضروری نیست اما یک good practice محسوب می‌گردد.19.  کانتنت پروایدرها را شرح دهید.کانتنت پروایدر همان طور که از نامش پیداست فراهم کننده کانتنت(داده) از یک اپلیکیشن برای دیگری در صورت درخواست  آن اپلیکیشن می‌باشد. کانتنت پروایدر، تسهیلات دسترسی به مجموعه‌ای ساختار یافته از داده و همچنین امنیت آن داده‌ها را فراهم می‌کند. کانتنت پروایدر اینترفیسی استانداردی ست که داده ها را از یک پراسس به کد در حال اجرا در پراسس دیگری متصل می‌کند. برای دسترسی به داده‌های درون کانتنت پروایدر باید از یک شی ContentResolver درون کانتکست اپلیکیشن خودتان استفاده کنید تا با ارائه دهنده داده ارتباط برقرار نمایید.20. دسترسی به داده از طریق کانتنت پروایدر چگونه است؟اول مطمئن شوید که مجوز لازم برای خواندن داده را دارید. سپس متد getContentResolver در شی کانتکست را برای دسترسی به شی ContentResolver فراخوانی نمایید.با ContentResolver.query یک کوئری برای دسترسی به داده‌ها ایجاد کنید.این متد یک cursor را برمی‌گرداند و می‌توانید داده‌ها را از این کرسر بخوانید.در این جا بخش اول سوالات مصاحبه‌های اندرویدی به پایان رسید. انشالله در بخش‌های بعدی این مقاله ادامه سوالات را باهم خواهیم دید و پاسخ خواهیم داد.در بخش دوم سوالاتی در خصوص سرویس و ناهمزمانی در اندروید مطرح خواهد شد.</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Sat, 05 Jun 2021 23:46:22 +0430</pubDate>
            </item>
                    <item>
                <title>13 استاندارد برای code review (الهام گرفته شده از گوگل)</title>
                <link>https://virgool.io/@fereshtehnaji/13-%D8%A7%D8%B3%D8%AA%D8%A7%D9%86%D8%AF%D8%A7%D8%B1%D8%AF-%D8%A8%D8%B1%D8%A7%DB%8C-code-review-%D8%A7%D9%84%D9%87%D8%A7%D9%85-%DA%AF%D8%B1%D9%81%D8%AA%D9%87-%D8%B4%D8%AF%D9%87-%D8%A7%D8%B2-%DA%AF%D9%88%DA%AF%D9%84-gxrjzlpaxct8</link>
                <description>code review comicدر این مقاله ، به طور خلاصه 13 استاندارد بررسی کد را بررسی خواهیم کرد که به طور چشمگیری به بهبود سلامت نرم افزار شما کمک می‌کند و توسعه دهندگان را خوشحال نگه می‌دارد.مرور کد یا code review اصلا چیه؟فرآیندی که در اون یک یا چند تا برنامه‌نویس، کد نوشته شده توسط برنامه‌نویس‌های دیگر رو review می‌کنند و حالا چرا ؟ به دلایل زیر:کد خطا و باگی نداشته باشد.کد کیفیت و استانداردهایی که برای استایل کد تعریف کردیم رو رعایت کرده باشد.کد دقیقا همون چیزی که قرار بوده را انجام می‌دهد.کدی که مرج شده، سلامت کد اصلی رو از وضعیت قبلی بهتر کرده است.این‌ها دلایلی بود برای اینکه چرا کد ریویو یکی از بخش‌های مهم توسعه نرم‌افزار است.کد ریویو مثل دروازه‌بانی عمل می‌کنه که تصمیم می‌گیره، این بخش از کد به کد اصلی اضافه بشه و به محصول نهایی برسد یا خیر.شرکت گوگل به برتری تکنولوژی خود مشهور است. برنامه‌نویسان گوگل  استانداردهایی را تعریف کردند که نکات خوبی را در مورد کد ریویو بیان می کنه و بهتر است آن‌ها را هنگام کد ریویو بخاطر بسپارید:هدف اولیه بررسی کد این است که مطمئن شویم  سلامت کد پایه‌ی گوگل در طول زمان بهبود پیدا کرده است.در ادامه با هم ۱۳ استاندارد کد ریویو رو می‌خونیم.استانداردهای کد ریویو:１. کد کامیت شده، باید سلامت کلی سیستم را بهبود داده باشدوقتی یک پول ریکوئست را می‌گیریم باید بررسی شود که سلامت کلی سیستم بهبود پیدا کرده است.  ایده اصلی اینست که در نتیجه بهبودهای کوچک، سلامتی کد اصلی بعد از هر مرج بهبود پیدا کند.２. کد ریویو، پاسخ و فیدبک دادن سریعدر کد ریویو، مرج کردن کد رو به تأخیر نیاندازید. هنگام مرور کد، انتظار کد کامل یا پرفکت رو نداشته باشیم. اگر کد دریافتی سلامت کلی سیستم رو بهبود می‌بخشه آن را ادغام کنید.&quot;نکته کلیدی ای که در این‌جا وجود داره اینه که چیزی به نام پرفکت کد وجود ندارد و همیشه کد بهتر در میان است&quot;اگر وسط یک تسک نیازمند به تمرکز نیستید، کد ریویو رو کمی پس از دریافت آن، انجام دهید. با این حال، یک روز کاری  حداکثر زمانیه که می‌تونید به یک پول ریکوئست پاسخ دهید. پیش بینی می‌شه یک پول ریکوئست در طول یک روز چند دور کد ریویوی جزئی یا کلی شود.３. در طول کد ریویو  آموزش بدهید و الهام‌بخش باشیددر هنگام مرور کد سعی کنید مانند یک منتور با اشتراک‌گذاری دانش و تجربه در هرکجا که امکان دارد راهنمایی کنید.４. هنگام مرور کد استانداردها را رعایت کنیدهمیشه بخاطر داشته باشید که راهنمای استایل، استانداردهای کدنویسی و چنین مستنداتی در مرور کد اقتدار مطلق را دارند. برای مثال، اگر بین استفاده از تب و اسپیس مانده بودید به استانداردهای کدنویسی رجوع کنید.اگر از زبان جاوا استفاده می‌کنید، لینک زیر خلاصه‌ای از بهترین روش‌های برنامه‌نویسی جاوا در کمپانی‌های غول تکنولوژی است(اگر در ایران هستید برای مشاهده این مقاله احتمالا نیاز به تغییر آدرس IP دارید).A short summary of Java coding best practices５. حل تعارضات ناشی از بررسی کدوقتی کدِ یک برنامه نویس دیگه رو بررسی می‌کنید و سپس کامنتی در مورد کد به او ارائه می‌دید با توجه به کامنتی که دادید ممکنه واکنش‌های مختلفی دریافت کنید. طرف مقابل ممکن خیلی خوشحال و سپاسگزار شود یا ناراحت و تدافعی. شما باید این تعارضات رو بر اساس روش‌های توافق شده در استایل‌ها و استانداردهای کدنویسی حل کنید. همچنین راهنمایی و پیشنهادات برنامه نویسان دیگری که تجربه و دانش بیشتری بر روی محصول دارند دنبال کنید.نموداری را می‌بینید که توسط خانم Alex Hill در مقاله‌ی هنرِ دریافت و ارسال بررسی کد، ترسیم شده است.این نمودار دو تا محور داره: ارزشمند بودن کامنت و میزان تعارضات بر اساس کامنت‌هایی که فرد بررسی کننده کد ارائه می‌دهد. هنگامی که برنامه‌نویس کدی رو می نویسه و ریویو کننده، فیدبک و کامنتی به نویسنده کد می‌دهد، چون نویسنده به کدش حس مالکیت داره با توجه به میزان این حس مالکیت و نوع نظراتی که دریافت می‌کنه، ممکنه مقداری درگیری به وجود بیاد.هندل کردن تعارضات ناشی از کامنت های بررسی کننده کد. از مقاله Alex Hillدر قسمت بالا سمت چپ کامنت‌هایی رو می بینید که کم ارزش هستند و همچنین درگیری بالایی رو هم پیش میارن مثل کامنت در مورد تنظیمات دلخواه، استفاده از فضاهای خالی در کد و غیره که  ارزش ندارند در کد ریویو  بررسی شوند و می‌تونیم خیلی راحت یک استاندارد مشخص کنیم و به آن بچسبیم تا همه همان را رعایت کنند یا اینکه کلی ابزارهای اتوماتیک برای این کار وجود دارد و دیگر لازم نیست که یک انسان خودش رو درگیر این موارد کند. همانطور که گفته شد این موارد چون با حس مالکیت رابطه مستقیم دارند،باعث درگیری بالا میشن و به دلایلی که گفته شد کامنت‌های کم ارزشی هستند.در بخش پایین نمودار شما نقص‌ها رو می‌بینید. نقص‌هایی مثل اشکال در رفتار تابع، باگ‌ها و یا تست‌های نوشته نشده. این موارد هیچ ارتباطی با مالکیت کد ندارند چرا که فرد هرگز از عمد این مشکلات را به وجود نمیاره.  پس این نوع از کامنت‌ها حس تدافعی در نویسنده ایجاد نمی‌کنند.در بخش بالایی نمودار مواردی ان که نسبتاً غیر قابل ارزیابی هستند اما شامل نظرات ارزشمندی مانند نظر در مورد خوانایی کد، استفاده از الگوهای طراحی، انتخاب نام‌های مناسب در این بخش قرار دارد.  این نوع از نظرات  نمی‌توانند توسط یک ابزار خودکار سازی ارائه شوند و حتما باید توسط یک انسان انجام شود، بازدهی بالایی دارند و همچنین نظر مستقیمی روی انتخاب‌های مالک کد می‌دهند. در واقع این نظرات خیلی ارزشمندند با اینکه ممکنه درگیری ای بین مالک کد و ریویو کننده ایجاد کنند. اگر ما سعی کنیم کامنت‌هایی که در دسته‌بندی‌های کم ارزش هستند رو ارائه ندیم و کامنتهامون از این دسته‌ی با ارزش باشه آنگاه می‌تونیم مشکلات کامنت‌های این دسته بندی رو مدیریت کنیم تا بتونیم همکاری رو بالا ببریم و مرور کد ارزشمندی داشته باشیم.اگر کامنتی در کد ریویو می‌دین که خیلی جزئی یا اختیاری ست به روشنی بیان کنید و اجازه بدید که نویسنده‌‌ی کد تصمیم بگیره که به اون توجه کنه یا خیر.به عنوان یک بررسی کننده، اگر که استانداردی برای استایل ها و کد نویسی ندارید، می‌تونید حداقل پیشنهاداتی ارائه کنید تا پایداری کد اصلی حفظ بشه.６. بررسی تغییرات UI به عنوان بخشی از کد ریویواگر تغییرات پول ریکوست، شامل تغییرات ظاهری هم میشه پس سعی کنید علاوه بر کد ریویو حتماً دموی تغییرات ظاهری رو هم ببینید تا بررسی کنید آیا چیزی که مشاهده میشه همون چیزیه که انتظار میره یا خیر؟７. بررسی کنید که ایا همه تست‌ها وجود دارندباید حتما بررسی کنید که کد همراه با همه تست‌ها مثل یونیت تست، integration تست و غیره باشه مگر اینکه در شرایط خیلی خاص و اضطراری باشید.شرایط خاص هم یعنی یک باگ یا رخنه امنیتی وجود داشته باشه که بخواد به سرعت حل بشه و تست می‌تونه بعداً اضافه بشه. در چنین موارد مطمئن شوید که تسکی براش ایجاد شده و یک نفر مسئولیت آن رو به عهده بگیره که بعد از اینکه شرایط بحرانی رد شد، تست‌ها رو اضافه کنه.هیچ دلیل خوبی برای تست ننوشتن وجود ندارد!  اگر محدودیت زمانی دارید  و ممکن است برخی از اهداف به دمو یا ریلیز نرسند، راه حل آن فرار از تست‌نویسی نیست  بلکه موارد قابل تحویل را کاهش دهید.Ethan Vincent تست نویسی جان ما را نجات خواهد داد. کپی رایت توسط آقای   ８. وقتی روی تسکی فوکوس کردید، بخاطر کد ریویو آن را به تعویق نیندازیدوقتی وسط یک تسک متمرکز هستید، وقفه ایجاد نکنین به این خاطر که زمان زیادی طول میکشه که به جایگاهی که بودید برگردید. هزینه وقفه انداختن در کار برنامه نویسی که فوکوس کرده خیلی بیشتر از منتظر ماندن یک برنامه‌نویس دیگه به خاطر کد ریویو است.  کد ریویو رو بعد از یک استراحت کوتاه برنامه‌ریزی شده مثل ناهار یا قهوه و چیزهایی از این دست انجام بدید.کپی رایت توسط آقای Jason Heerisانتظار نمیره که کل فرایند  بررسی کد و مرج کردن در یک روز اتفاق بیفتد. چیزی که مهمه اینه که به نویسنده کد خیلی سریع فیدبکی بدید. مثلاً ممکنه شما فرصت نکنید که کل کد ریویو رو انجام بدید اما می‌تونید با یک بررسی سریع به چند مورد اشاره کنید.９. همه چیز را ریویو کنید و مفروضاتی را قائل نشویدتمام خطوطی رو که برای کد ریویو به شما سپرده شده، بررسی کنید  و هیچ فرضی در مورد کلاس‌ها و متدهای نوشته شده توسط یک انسان انجام ندهید و مطمئن بشید که دقیقا انچه کد انجام می‌دهد را فهمیده‌اید.مفروضات قائل نشید. کپی رایت توسط Manuمطمئن شوید کدی که درحال بررسی آن هستید را می‌فهمید در غیر این صورت از نویسنده کد توضیح بخواهید.اگر صلاحیت بررسی بخشی از کد را ندارید مطمئن شوید که برنامه‌نویسی که صلاحیت آن را دارد حتماً آن بخش را بررسی کند.１０. کد را با داشتن یک تصویر کلی در ذهن بررسی کنیداغلب بررسی تغییرات با یک وسعت دید بیشتر خیلی کمک کننده است.  مثلاً فرض کنید که یک فایل تغییر کرده و چهار (4) خط کد به آن اضافه شده. فقط آن چهار (4) خط کد را ریویو نکنید بلکه بررسی کل فایل را در نظر بگیرید و چک کنید چه چیزهایی به آن اضافه شده. آیا کیفیت کد موجود را کاهش داده یا باعث شده که توابع موجود نیاز به ریفکتور پیدا کند؟اگر چنین تغییرات ساده‌ای در چارچوب کلاس یا متد بررسی نشود در طول زمان شاهد کلاسی خواهیم بود که غیر قابل نگهداری، پیچیده و غیرقابل تست است. کلاسی که همه کار انجام می دهد و گسترش و تغییر آن مشکل است. کلاسی که اصل تک مسئولیتی را نقض می‌کند.(مطمئنم همتون تجربه کار با چنین کلاسی رو داشتید)به یاد داشته باشیم همانطور که پیشرفت‌های اندک در طول زمان جمع می‌شوند و منجر به تولید یک محصول عالی با کمترین نقص می‌شوند، به همین ترتیب هم، تخریب جزئی کد و بدهی‌های فنی با گذشت زمان منجر به محصولی می‌شوند که نگهداری و تغییر آن چالش برانگیز است.１１. تشخیص و تشویق کد خوب در طول بررسی کداگر در حین کد ریویو مورد خوبی رو دیدید نویسنده کد را با اشتیاق صدا کنید و او را تشویق کنید. هدف کد ریویو فقط پیدا کردن اشتباهات نیست بلکه تشویق و راهنمایی توسعه‌دهندگان برای کار فوق‌العاده‌ای که انجام می دهند نیز هست.１２. در مرور کد، هوشیار، محترم، مهربان و صریح باشیدبسیار حیاتی است که در هنگام بازبینی کد صریح، مودب و محترم باشید و در عین حال در رفتار با نویسنده روشنگر و رهنما باشید. هنگام مرور کد حتما نظرتان را درباره‌ی کد و نه توسعه‌دهنده بیان کنید.(لطفا شخصیت برنامه نویس را تخریب نکنید و صدای خود را بالا نبرید!)در لینک زیر راهنمای گوگل در مورد چگونگی احترام گذاشتن در زمان مرور کد وجود دارد:بررسی کد محترمانه１３. نظرات مربوط به بررسی کد خود را توضیح دهید و یک محدوده در ذهن خود داشته باشیدهرگاه نظری که در کد ریویو ارائه می‌دهید، روش دیگری را بیان می‌کند مهم است که دلیل خود را توضیح دهید و بر اساس دانش و تجربه خود مثالی بزنید تا توسعه‌دهنده درک کند، چگونه پیشنهاد شما به کیفیت کد او کمک خواهد کرد.هنگام پیشنهاد اصلاح یا تغییر به نویسنده کد، تعادل درستی را پیدا کنید تا نویسنده را در اصلاح کدش راهنمایی کنید. به عنوان مثال من از روش راهنمایی، توضیح  و ارائه برخی نکات و پیشنهادات استفاده می‌کنم و هرگز راه حل کامل را ارائه نمی دهم.مطالعه بیشتربرای عمیق‌تر شدن در مبحث استانداردهای کد ریویو گوگل، لینک زیر را مطالعه کنید و همچنین من بیشتر برایتان خواهم نوشت.چطور یک کد ریویو انجام دهیم.هزینه ایجاد وقفه در کار برنامه نویسی که تمرکز کرده در مقایسه با اینکه یک توسعه دهنده منتظر بماند تا شما کد خود را در بازه زمانی مناسب مرور کنید ، بسیار زیاد است. برای اطلاعات بیشتر در این باره ، به لینک زیر مراجعه کنید:هزینه ایجاد وقفه برای توسعه دهندگانمقاله بسیار مفید خانم Alex Hill با نام هنر ارسال و دریافت کد ریویو را در اینجا بخوانید.منابع استانداردها و روش های گوگلمقاله آقای Rafiullah Hamedyمقاله خانوم Alex Hillجمع بندیبه‌ عنوان برنامه‌نویسی که مدتی است در حال کد ریویو کد همکاران خود است و خودش هم همیشه تجربه ریویو شدن کدهایش را دارد توصیه می‌کنم حتما بررسی کد را امری جدی تلقی کنید. با بررسی کد به همکارانتان کمک می‌کنید از دانش و تجربه‌ی شما بهره‌مند شوند، کد خود را از نگاه شخص دیگری ببینند، ایده بگیرند و بسیار زیاد جلوی اشتباهات سهوی را خواهید گرفت.لطفا نظرات و پیشنهاد خود را در مورد این مطلب با من در میان بگذارید.</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Thu, 22 Oct 2020 21:12:15 +0330</pubDate>
            </item>
                    <item>
                <title>چرخه حیات و ارتباطات فرگمنت</title>
                <link>https://virgool.io/coderlife/%DA%86%D8%B1%D8%AE%D9%87-%D8%AD%DB%8C%D8%A7%D8%AA-%D9%88-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7%D8%A7%D8%AA-%D9%81%D8%B1%DA%AF%D9%85%D9%86%D8%AA-klseco6bs56o</link>
                <description>چرخه حیات فرگمنت و اکتیویتی و ارتباط آن‌ها در این نوشتار می‌خواهم مفاهیم مربوط به چرخه حیات و ارتباطات فرگمنت را توضیح دهم، آنچه در این نوشتار خواهید آموخت:درک چرخه حیات فرگمنتکاربرد کال بک‌های چرخه حیات فرگمنتارتباطات بین فرگمنت و اکتیویتیشناخت بک استک فرگمنتارسال داده بین فرگمنت و اکتیویتیمقدمه :خب اول بیایین ببینیم اصلا چرخه حیات چی هست؟لایف سایکل یا چرخه حیات، دوره‌های زندگی یک فرگمنت یا اکتیویتی ست که از هنگام تولد تا مرگ در اون دوره ها قرار می‌گیره و سیستم هم با استفاده از یک رخدادی به نام callBack بهمون خبر میده که الان فرگمنت یا اکتیویتی توی اون قسمت از چرخه حیات افتاده. ما هم با شناختن این callBack ها و اینکه کی فراخوانی میشن، میتونیم کارهای جالبی انجام بدیم. شکل بالا هم داره callBackهای چرخه حیات اکتیویتی و فرگمنت رو بهمون نشون می‌ده.مثلاً وقتی اکتیویتی برای اول بار متولد می‌شه، سیستم، کال بک onCreate رو صدا میزنه. و وقتی زمان مرگ اکتیویتی برسه سیستم کال بک onDestroy را فراخوانی می کنه که دیگه آخرین تعاملمون رو با اکتیویتی داشته باشیم. مثلا اگر هنوز منابعی مونده که در کال بک‌های قبلی مثل  &quot;آن استاپ&quot; آزادشون نکردیم، اینجا آزادش کنیم. (متاسفانه نام بعضی از توابع در این بستر حذف می‌شود و من مجبورم به فارسی آن‌ها را بنویسم)هدف این مقاله:وقتی ما به عنوان یک برنامه‌نویس کال بک‌های چرخه حیات رو درست نشناسیم باعث میشه از مزیت‌ آن‌ها بی‌بهره بمونیم یا حتی گاهی چیزهایی رو درست مدیریت نکنیم. مانند اکتیویتی، فرگمنت هم چرخه حیات خودشو داره. اگر ارتباط بین چرخه حیات فرگمنت و اکتیویتی رو درک کنید، اون موقع می‌تونید فرگمنت‌هایی طراحی کنید که متغیرها رو ذخیره و بازیابی کنند و با اکتیویتی‌ها ارتباط برقرار کنند.یک اکتیویتی که میزبان یک فرگمنت هست، میتونه اطلاعات رو به فرگمنت ارسال کنه و اطلاعات رو از فرگمنت دریافت کنه. در این نوشتار، فرآیندهایی برای ارسال داده از فرگمنت به اکتیویتی و بلعکس رو یاد می‌گیرید و اینکه چطور چرخه حیات فرگمنت رو مدیریت کنیم، توضیح داده خواهد شد.درک چرخه حیات فرگمنتاستفاده از چرخه حیات فرگمنت خیلی شبیه استفاده از چرخه حیات اکتیویتی ست. در callbackهای چرخه حیاتِ فرگمنت می‌تونیم تعیین کنیم که فرگمنتمون در یک وضعیت مشخص چه رفتاری داشته باشه؟ وضعیت هایی مثل Active، مثل paused یا stopped.وضعیت‌های چرخه حیات فرگمنتفرگمنت توسط اکتیویتی میزبان‌اش add می‌شود. بعد از اینکه فرگمنت add شد، در طول چرخه حیاتش می‌تونه سه وضعیت زیر رو داشته باشه:اکتیو یا رزیوم (active یا resume)پاز شده (paused)استاپ شده (stopped)وضعیت‌های فرگمنت در طول چرخه حیاتچطور وضعیت اکتیویتی روی فرگمنت تاثیر می‌گذارد؟از جایی‌که یک فرگمنت همیشه مهمون یک اکتیویتی هست، چرخه حیات فرگمنت مستقیماً از چرخه حیات میزبانش یعنی اکتیویتی تاثیر می‌پذیرد. مثلاً وقتی یک اکتیویتی پاز می‎شود، تمام فرگمنت‌هایی که توش هستند هم پاز می‌شوند و وقتی اکتیویتی destroy می‌شود، همه فرگمنتهاشم نابود می‌شوند.هر callbackای که در چرخه حیات اکتیویتی فراخوانی می‌شه در callback مشابه‌اش در فرگمنت هم اثر می‌گذارد. مثلاً وقتی یک اکتیویتی &quot;آن پاز&quot; رو می‌گیره، متد &quot;آن پاز&quot; برای هر فرگمنت این اکتیویتی هم فراخوانی می‌شه. برای فهم بیشتر جدول زیر رو ببینید:همانند اکتیویتی، variable assignments را می‌توانید در فرگمنت هم ذخیره کنید. از آنجا که داده‌های فرگمنت معمولا به اکتیویتی میزبانش مربوط هستند، کد اکتیویتی میتونه از یک callback برای بازیابی داده از فرگمنت استفاده کنه و بعد از دوباره ساخته شدن فرگمنت هم، داده ها رو بازیابی کنه. که در ادامه راجع به ارتباط بین اکتیویتی و فرگمنت بیشتر خواهید خواند. کاربرد callback های چرخه حیات فرگمنتمانند کاری که با متدهای چرخه حیات اکتیویتی می‌تونستید انجام بدید، در فرگمنت هم می‌تونید متدهای چرخه حیاتش رو override کنید و  وقتی فرگمنت در وضعیت‌های معینی قرار می‌گیره، کارهای مهمی رو انجام بدهیم. پر کاربردترین کال بک هایی که معمولا override میشن در زیر اومدن:متد ()onCreate: کامپوننت‌های مهم و متغیرهای فرگمنت را در این تابع مقداردهی اولیه کنید، چونکه وقتی اکتیویتی ساخته می‌شود این متد فراخوانی میشه. هرچیزی که در این متد، مقداردهی اولیه شود، اگر فرگمنت پاز و رزیوم شود، محفوظ خواهد ماند.متد ()onCreateView:  لایه XML فرگمنت در این متد inflate می‌شود (یعنی اندروید با ایجاد آبجکت های ویو در حافظه، لایه XML را رندر می‌کند.). سیستم در این متد برای اولین بار  ظاهر فرگمنت را ترسیم می‌کند و فرگمنت در اکتیویتی قابل دیدن می‌شه. برای ترسیم شدن ظاهر فرگمنت، شما باید ویو اصلی یا همون ویو روتِ لایه فرگمنت رو return کنید. اگر هم فرگمنتتون UI نداره باید null رو return کنید. متد &quot;آن پاز&quot; :  اگر می‌خواهید هر داده و وضعیتی در طول تخریب فرگمنت در امان بمونه در این متد ذخیره کنید. این متد در شرایط زیر توسط سیستم صدا زده میشه:     1. کاربر back بزنه.     2. فرگمنت replace یا removed بشه یا هر عملیات دیگه‌ای که فرگمنت رو تغییر بده.      3. اکتیویتی میزبان پاز بشه. یک فرگمنت پاز شده، فرگمنتیه که هنوز زنده است! (همه اطلاعات member ها و state ها توسط سیستم حفظ می‌شود) و اگر کاربر دکمه بک را بزند و فرگمنت از بک استک برگردد، آنگاه چرخه حیات فرگمنتی که پاز شده بود با فراخوانی متد ()onCreateView از سر گرفته می‌شود. . اما اگر اکتیویتی destroy بشه(از بین بره)، فرگمنت هم از بین خواهد رفت. فرگمنت Callback‌های کاربردی دیگر مانند موارد زیر هم دارد:متد ()onAttach: وقتی فرگمنت به اکتیویتی میزبان افزوده می‌شود، فراخوانی می‌شود. در این متد می‌توانید چک کنید که اکتیویتی اینترفیس تعریف شده در فرگمنت را پیاده‌سازی کرده یا خیر.(مثالی از این مورد را در ادامه خواهید دید) بعد از این متد ()onCreate فراخوانی می‌شود.(در بالا تعریف شد) متد  &quot;آن رزیوم&quot; :  اکتیویتی این متد را فراخوانی می‌کنه تا فرگمنتی که فعال و قابل مشاهده ست را از سرگیری کند.متد ()onActivityCreated: وقتی متد onCreate اکتیوتی تمام می‌شود، این کال بک فراخوانی میشه و بهمون اطلاع میده که اکتیویتی ساخته شده ست. از این متد برای مقداردهی های اولیه‌ی نهایی استفاده کنید، مانند بازیابی viewها و stateها. همچنین این متد برای فرگمنت‌هایی که از ()setRetainInstance برای حفظ instance خود می‌کنند، مفید است، چون وقتی این متد اجرا شود به فرگمنت می‌گوید که چه وقت با instance اکتیویتی جدید مرتبط شده است. این متد بعد از ()onCreateView و قبل از ()onViewStateRestored فراخوانی می‌شود.متد ()onDestroyView: وقتی viewای که توسط ()onCreateView ساخته شده بود از فرگمنت حذف می‌شود، فراخوانی خواهد شد. این متد وقتی اکتیویتی میزبان استاپ می‌شود یا فرگمنت را حذف می‌کند، نیز فراخوانی می‌شود. از این متد برای انجام کارهایی مثل log کردن یک پیام استفاده کنید و توجه کنید که فرگمنت دیگر قابل مشاهده نیست و بار بعدی که فرگمنت بخواد نمایش داده بشه یک view جدید ساخته می‌شه. این متد بعد &quot;آن استاپ&quot; از  و قبل از ()onDestroy فراخوانی میشه.ارتباطات فرگمنت و اکتیویتیاکتیویتی می‌تونه با گرفتن یک رفرنس از فرگمنت، از متدهای فرگمنت استفاده کنه، و به همین ترتیب فرگمنت هم می‌تونه با گرفتن یک رفرنس اکتیویتی (getActivity) از ریسورس‌هاش، مثلاً از یک ویو استفاده کنه که در ادامه با مثال این دو مورد را خواهید آموخت. استفاده از کانتکست اکتیویتی در یک فرگمنتوقتی فرگمنت در وضعیت فعال یا resume هست، فرگمنت می تونه با ()getActivity یک رفرنس به instance اکتیویتی میزبان خودش بگیره. همچنین می‌تونه از این طریق ویوهای درون لایه اکتیویتی را find کند:View listView = getActivity().findViewById(R.id.list);توجه کنید اگر فرگمنت هنوز به اکتیویتی attach نشده باشد، ()getActivity نال برمی‌گرداند.فراخوانی توابع فرگمنت در اکتیویتی میزبانشبه همین ترتیب، اکتیویتی شما می‌تونه رفرنس به فرگمنت رو از FragmentManager با استفاده از ()findFragmentById بدست بیاره. مثال زیر متد  ()getSomeData فرگمنت رو فراخوانی می‌کنه:ExampleFragment fragment = (ExampleFragment)
getFragmentManager().findFragmentById(R.id.example_fragment);
// ...
mData = fragment.getSomeData();شناخت back stack فرگمنتیک تفاوت مهم بین فرگمنت و اکتیویتی اینه که چطور اکتیویتی‌ها و فرگمنت‌ها از back stack خودشون استفاده می‌کنند. با شناخت بک استک فرگمنت می‌تونید بک زدن کاربر در فرگمنت رو مدیریت کنید.در اکتیویتی، سیستم به طور خودکار back stack اکتیویتی‌ها رو نگه می‌داره.در فرگمنت، اکتیویتیِ میزبان back stack رو نگه می‌داره و شما در طول هر عملیاتی که فرگمنت رو اضافه میکنه، مستقیماً با متد ()addToBackStack، فرگمنت رو باید به بک استک اضافه کنی. (یعنی خودکار نیست)اینو تو ذهنتون داشته باشید که وقتی برنامه شما یک فرگمنت رو replace یا remove می‌کنه، کار مناسب اینه که این شانس رو به کاربر بدیم که بک بزنه و دوباره فرگمنت رو ببینه. برای اینکار باید متد ()addToBackStack رو قبل از کامیت کردنِ FragmentTransaction فراخوانی کنید.fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();توجه: متد ()addToBackStack یک رشته ورودی اختیاری می‌گیره که یک نام یکتا برای تراکنش جاری هست. ما می‌تونیم به جای اون null ارسال کنیم، چون بهش نیازی نداریم، مگر اینکه بخوایم عملیات فرگمنتیه پیشرفته‌ای با استفاده از اینترفیس FragmentManager.BackStackEntry انجام بدیم.هنگام حذف یک فرگمنت بخاطر داشته باشید که اگر از روش بالا استفاده کرده باشید، اکتیویتی میزبانش یک back stack برای فرگمنت نگه می‌داره. به این صورت، فرگمنت نابود نمیشه و اگر کاربر بک بزنه، ریستارت می‌شه.ارسال داده بین یک فرگمنت و اکتیویتی اکتیویتی که میزبان یک فرگمنته، می‌تونه اطلاعاتی رو براش بفرسته و اطلاعاتی رو ازش بگیره. و به این صورته که یک فرگمنت نمی‌تونه مستقیماً با یک فرگمنت دیگه ارتباط داشته باشه، همه ارتباطات فرگمنت به فرگمنت از طریق اکتیویتی میزبان اون‌ها انجام می‌شه. یعنی فرگمنت با اکتیویتی‌اش ارتباط برقرار می‌کنه و اکتیویتی با فرگمنت دیگه. در ادامه این ارتباط رو به روشنی توضیح خواهم داد.ارتباط دو فرگمنت از طریق اکتیویتی میزبان آن‌هاارسال داده از اکتیویتی به فرگمنت:فرض کنید کاربر قبلاً در فرگمنت انتخابی انجام داده است و حالا شما می‌خواهید وقتی فرگمنت رو در اکتیویتی start می‌کنید این انتخاب رو برای فرگمنت ارسال کنید.بهترین روش برای مقداردهی اولیه داده در یک فرگمنت، استفاده از متد فکتوری فرگمنت می‌باشد. همان طور که می‌دانید، می‌تونید instance فرگمنت رو با متد ()newInstance درون فرگمنت بسازید.public static SimpleFragment newInstance() {
        return new SimpleFragment();
}سپس با صدا زدن این تابع ()newInstance در اکتیویتی، از فرگمنت نمونه بسازید. SimpleFragment fragment = SimpleFragment.newInstance();برای مثال، اگر بخواهید فرگمنت رو با انتخاب قبلی کاربر باز کنید، در اکتیویتی مانند زیر عمل می‌کنید:SimpleFragment fragment = SimpleFragment.newInstance(mRadioButtonChoice);حالا فکتوری متد ()newInstance در فرگمنت می‌تونه از باندل و setArgument استفاده کنه تا قبل از اجرای فرگمنت، آرگومان هارو ست کنه. public static SimpleFragment newInstance(int choice) {
        SimpleFragment fragment = new SimpleFragment();
        Bundle arguments = new Bundle();
        arguments.putInt(CHOICE, choice);
        fragment.setArguments(arguments);
        return fragment;
}در ادامه کد کامل تری از ساخت فرگمنت در اکتیویتی می بینیم:// Get the FragmentManager and start a transaction.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
                                          .beginTransaction();
// Instantiate the fragment.
SimpleFragment fragment =
                SimpleFragment.newInstance(mRadioButtonChoice);
// Add the fragment.
fragmentTransaction.add(R.id.fragment_container, fragment).commit();قبل از اینکه ظاهر فرگمنت ترسیم شود، در متد ()onCreate یا ()onCreateView با استفاده از ()getArguments ، آرگومان های ارسالی را از باندل بخوانید و عملیات لازم را انجام دهید.if (getArguments().containsKey(CHOICE)) {
    // A choice was made, so get the choice.
    mRadioButtonChoice = getArguments().getInt(CHOICE);
    // Check the radio button choice.
    if (mRadioButtonChoice != NONE) {
         radioGroup.check
             (radioGroup.getChildAt(mRadioButtonChoice).getId());
    }
}ارسال داده از فرگمنت به اکتیویتی برای ارسال داده از فرگمنت به اکتیویتی‌اش مراحل زیر را در فرگمنت طی کنید:یک اینترفیس لیسنر با یک یا چند متد، برای ارتباط با اکتیویتی تعریف کنید.تابع ()onAttach را override کنید تا در آن چک کنید اکتیویتی میزبان، اینترفیس را پیاده سازی کرده است یا خیر. متدی که برای اینترفیس تعریف کردید را صدا کنید و داده‌هایی که میخواهید رو به عنوان پارامتر برایش ارسال کنید.در اکتیویتی میزبان مراحل زیر را طی کنید:اینترفیس تعریف شده در فرگمنت را پیاده‌سازی کنید.(همه اکتیویتی هایی که از این فرگمنت استفاده می‌کنند باید اینترفیس را پیاده سازی کنند)بعد از پیاده سازی اینترفیس، از شما خواهد خواست تا متدهای اینترفیس را پیاده‌سازی کنید.لطفا متدها را برای گرفتن داده، پیاده‌سازی کنید.در مثال زیر اینترفیس OnFragmentInteractionListener  را در فرگمنت تعریف می‌کنیم. اینترفیس یک متد به نام ()onRadioButtonChoice دارد. اکتیویتی باید این اینترفیس را پیاده‌سازی کند. متد ()onAttach فرگمنت اگر اکتیویتی این اینترفیس را پیاده سازی کرده باشد یک رفرنس به آن تعریف می‌کند وگرنه یک Exception برمی‌گرداند. // Interface definition and onFeedbackChoice() callback.
interface OnFragmentInteractionListener {
    void onRadioButtonChoice(int choice);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new ClassCastException(context.toString()
                    + &amp;quot must implement OnFragmentInteractionListener&amp;quot);
    }
}در ادامه می بینید که چطور متد ()onCheckedChanged درون فرگمنت وضعیت رادیو باتن‌ها را بررسی می‌کند و از طریق متد ()onRadioButtonChoice داده‌های دریافتی را برای اکتیویتی ارسال می‌کند.public void onCheckedChanged(RadioGroup group, int checkedId) {
    View radioButton = radioGroup.findViewById(checkedId);
    int index = radioGroup.indexOfChild(radioButton);
    switch (index) {
        case YES: // User chose &amp;quotYes.&amp;quot
            textView.setText(R.string.yes_message);
            mRadioButtonChoice = YES;
            mListener.onRadioButtonChoice(YES);
            break;
        case NO: // User chose &amp;quotNo.&amp;quot
            textView.setText(R.string.no_message);
            mRadioButtonChoice = NO;
            mListener.onRadioButtonChoice(NO);
            break;
        default: // No choice made.
            mRadioButtonChoice = NONE;
            mListener.onRadioButtonChoice(NONE);
            break;
    }
}برای استفاده از متدهای اینترفیس، برای بازیابی داده‌های ارسالی، اکتیویتی باید آن(ها) را پیاده‌سازی کرده باشد. public class MainActivity extends AppCompatActivity
                implements SimpleFragment.OnFragmentInteractionListener {
   //...
}و در نهایت می‌بینیم اکتیویتی از متد ()onRadioButtonChoice برای دریافت داده استفاده می‌کند.@Override
public void onRadioButtonChoice(int choice) {
    mRadioButtonChoice = choice;
    Toast.makeText(this, &amp;quotChoice is &amp;quot + Integer.toString(choice),
                                            LENGTH_SHORT).show();
}ممکن است برخی داده‌های فرگمنت در اکتیویتی میزبانش لازم شوند. اکتیویتی می‌تواند از متدهای اینترفیس فرگمنت برای بازیابی داده‌های مرتبط استفاده کند(همین روش گفته شده). اکتیویتی می‌تونه بعداً موقع بازسازی (recreating) فرگمنت داده‌ها رو برای فرگمنت ارسال کنه. آنچه خواندید ترجمه‌ای از مرجع مفاهیمِ توسعه اندروید پیشرفته بود که یک دوره آموزشی است و توسط تیم آموزشی توسعه دهندگان گوگل ایجاد شده است. می‌توانید محتوای کامل دوره را ازینجا مطالعه بفرمایید.</description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Sat, 26 Sep 2020 08:15:02 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی با مبحث شیرین Serialization در جاوا</title>
                <link>https://virgool.io/MobileLab/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D9%85%D8%A8%D8%AD%D8%AB-%D8%B4%DB%8C%D8%B1%DB%8C%D9%86-serialization-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-vkfz2ilcnvye</link>
                <description>فرض کنید که شما در برنامه خود یک آبجکت از یک کلاس دارید که یک سری داده هم در اون آبجکت ذخیره کردید و حالا می خواهید این داده ها رو دریک فایل ذخیره کنید چه می کنید؟زبان جاوا یک مکانیزم جذاب به نام object serialization در اختیار ما قرار می‌دهد، در این مکانیزم می‌تونیم آبجکت رو به شکل دنباله‌ای از بایت‌ها در جریان خروجی بنویسیم و بعدا برش گردونیم. دنباله بایت ها شامل داده‌های آبجکت، نوع آبجکت چیه و نوع داده‌های ذخیره شده در آبجکت چی هست، می‌باشد.پس از اینکه آبجکت سریال‌سازی شده در یک فایل نوشته شد، می توانیم از فایل اونو بخونیم و deserialize اش کنیم یعنی با استفاده از اطلاعاتی که در بایت‌ها ذخیره شده مثل نوع داده و داده های درون آبجکت، آن آبجکت را در حافظه بازسازی کنیم.(خیلی ساده و آسون!)جذاب‌ترین بخش این فرآیند آن است که به ماشین مجازی جاوا (JVM) وابسته نیست به طوری‌که می‌تونه در یک پلتفرم serialized شود و سپس در پلتفرم کاملاً متفاوت دیگری deserialized گردد.حالا می‌خواهم دو تا کلاس مهم رو بهتون معرفی کنم که با استفاده از اون‌ها بتونید خیلی راحت و ساده سریالایز و دی سریالایز رو انجام بدید! کلاس‌های ObjectInputStream و ObjectOutputStream جریان‌های سطح بالایی هستند که در خودشون توابعی برای سریالایز و دی سریالایز کردن آبجکت ها دارند.کلاس ObjectOutputStream توابع نوشتن زیادی برای نوشتن نوع داده‌های مختلف دارد. اما تابع زیر از همه برجسته‌تر است: public final void writeObject(Object x) throws IOException تابعی که در بالا می‌بینید یک آبجکت را در ورودی می‌گیرد و اون آبجکت رو سریالایز کرده و به جریان خروجی (output stream) ارسال‌اش می‌کند. خُب پس به طور مشابه کلاس  ObjectInputStream هم تابع زیر را برای دی سریالایز کردن آبجکت دارد.public final Object readObject() throws IOException, ClassNotFoundExceptionاین تابع آبجکت رُ از جریان ورودی (فایلی که قبلا آبجکت توش ذخیره شده) بازیابی و دی سریالایز می‌کند. خروجی این تابع یک آبجکت است که شما باید آن را به کلاس موردنظرتان cast کنید.حالا این که سریالایز چطور در جاوا کار می کند را از طریق یک مثال با کمک از کلاس Employee نشان می‌دهیم. کلاس Employee زیر را داریم که اینترفیس Serializable را پیاده‌سازی کرده است:public class Employee implements java.io.Serializable {
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   
   public void mailCheck() {
      System.out.println(&amp;quotMailing a check to &amp;quot + name + &amp;quot &amp;quot + address);
   }
}توجه کنید برای آن که یک کلاس با موفقیت سریال سازی شود باید دو تا شرط مهم را رعایت کند:شرط اول: کلاس باید اینترفیس java.io.Serializable را پیاده‌سازی کرده باشد.شرط دوم: همه ی فیلدهای کلاس باید قابل سریال‌سازی باشند. اگر فیلدی قابل سریال‌سازی نباشد باید توسط transient نشانه گذاری گردد.اگر براتون جالب بود که یک کلاس استاندارد در جاوا قابل سریال سازی هست یا خیر، داکیومنت آن را مطالعه کنید. تست آن هم بسیار ساده است، اگر کلاس java.io.Serializable  را پیاده‌سازی کند قابل سریال سازی است و اگرنه نیست.معرفی دی سریالایز (Deserialize)کردن یک آبجکت:همون طور که گفتیم کلاس ObjectOutputStream برای سریالایز کردن آبجکت استفاده می‌شه. مثالی می‌زنیم از برنامه SerializeDemo که یک آبجکت از Employee می‌سازد و آن را درون یک فایل سریال‌سازی می‌کند. وقتی اجرای برنامه تمام می‌شود یک فایل employee.ser ایجاد شده است. توجه: وقتی که یک آبجکت را به یک فایل سریالایز می‌کنید، استاندارد جاوا این است که به فایل پسوند .ser بدهد.import java.io.*;
public class SerializeDemo {

   public static void main(String [] args) {
      Employee e = new Employee();
      e.name = &amp;quotReyan Ali&amp;quot
      e.address = &amp;quotPhokka Kuan, Ambehta Peer&amp;quot
      e.SSN = 11122333;
      e.number = 101;
      
      try {
         FileOutputStream fileOut =
         new FileOutputStream(&amp;quot/tmp/employee.ser&amp;quot);
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf(&amp;quotSerialized data is saved in /tmp/employee.ser&amp;quot);
      } catch (IOException i) {
         i.printStackTrace();
      }
   }
}خُب حالا یک FileOutputStream رو برای نوشتن بایت های خروجی باز می کنیم و یک مسیر ذخیره فایل هم در سازنده بهش می‌دهیم.سپس یک شی از کلاس دوست داشتنی ObjectOutputStream می‌گیریم و جریان داده خروجی رو بهش می‌دهیم. حالا وقتی چیه؟ بله متد نوشتن آبجکت در فایل رو فراخوانی کنیم. (متد writeObject )حالا اگر یادتون باشه، کار این متد، گرفتن آبجکت (نمونه از کلاس Employee) و سریالایز کردن اون و ارسالش به جریان خروجی هست. بعدم که تابع کلوز شی های ساخته شده رو فراخوانی می کنیم که بندگان خدا سرگردون نباشن. (منابع آزاد بشن)از سریال خارج کردن (Deserializing) آبجکت:  برنامه زیر آبجکت Employee که در برنامه قبلی سریال سازی شده بود را deserialize می‌کند. import java.io.*;
public class DeserializeDemo {

   public static void main(String [] args) {
      Employee e = null;
      try {
         FileInputStream fileIn = new FileInputStream(&amp;quot/tmp/employee.ser&amp;quot);
         ObjectInputStream in = new ObjectInputStream(fileIn);
         e = (Employee) in.readObject();
         in.close();
         fileIn.close();
      } catch (IOException i) {
         i.printStackTrace();
         return;
      } catch (ClassNotFoundException c) {
         System.out.println(&amp;quotEmployee class not found&amp;quot);
         c.printStackTrace();
         return;
      }
      
      System.out.println(&amp;quotDeserialized Employee...&amp;quot);
      System.out.println(&amp;quotName: &amp;quot + e.name);
      System.out.println(&amp;quotAddress: &amp;quot + e.address);
      System.out.println(&amp;quotSSN: &amp;quot + e.SSN);
      System.out.println(&amp;quotNumber: &amp;quot + e.number);
   }
}خروجی برنامه بالا به صورت زیر است:Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101نکات زیر قابل توجه است:بلاک try/catch تلاش می‌کند ClassNotFoundException که در تابع (readObject) اعلان شده است را catch کند. برای آنکه ماشین مجازی جاوا (JVM) بتواند یک آبجکت را deserialize کند باید بایت کد مربوط به کلاس را پیدا کند، و اگر نتواند بایت کد را پیدا کند این اکسپشن را ایجاد می‌کند.توجه کنید که خروجی تابع readObject به رفرنسی به  Employee ، فرم دهی (cast) خواهد شد.مقدار ابتدایی فیلد SSN برابر با 11122333 بود، ولی اگر یادتان باشد ما آن را با transient نشانه گذاری کردیم بهمین دلیل در زمان سریال سازی به جریان خروجی ارسال نشد و مقدار آن در آبجکت deserialize شده برابر صفر شد. این نوشته ترجمه‌ی آزادی از اینجا بود و اگر می‌خواهید در این مطلب عمیق شوید. همین فصل از کتاب Core Java جلد دوم را در اینجا بخوانید. </description>
                <category>فرشته ناجی</category>
                <author>فرشته ناجی</author>
                <pubDate>Thu, 24 Sep 2020 22:48:15 +0330</pubDate>
            </item>
            </channel>
</rss>