آموزش کامل ساخت فرگمنت(fragment) در اندروید

ساخت فرگمنت در اندروید

یک فرگمنت نشان دهنده یک رفتار یا بخشی از رابط کاربری در یک اکتیویتی است. شما می توانید چندین فرگمنت را تنها در یک اکتیویتی ترکیب کنید تا یک UI چند پنجره ای ایجاد کنید و یک fragment را دوباره در چندین اکتیویتی استفاده کنید.

شما می توانید فکر کنید که یک fragment بخشی مدولار (پیمانه ای) از یک اکتیویتی است که دارای چرخه حیات است، رویدادهای ورودی را دریافت می کند و می توانید در حالی که اکتیویتی در حال اجراست آن را اضافه یا حذف کنید (مانند ” sub activity ” که می توانید در اکتیویتی های مختلف استفاده کنید).

فرگمنت همیشه باید در یک اکتیویتی جاسازی شود و چرخه حیات فرگمنت به طور مستقیم تحت تاثیر چرخه حیات میزبان است. به عنوان مثال، زمانی که اکتیویتی متوقف می شود، همه ی فرگمنت ها در آن وجود دارد، و وقتی اکتیویتی از بین می رود، همه فرگمنت ها نیز از بین می روند. با این حال، در حالی که یک اکتیویتی در حال اجرا است (چرخه حیات آن در حالت متوقف باقی مانده است)، شما می توانید هر fragment را به صورت جداگانه دستکاری کنید، مانند افزودن یا حذف کردن آنها. هنگامی که شما یک فرگمنت را انجام می دهید، می توانید آن را به یک پشته بازگشتی که توسط اکتیویتی مدیریت می شود اضافه کنید. هر ورودی پشته بازگشتی در اکتیویتی، یک رکورد فرگمنت است که رخ داده است. پشته بازگشتی به کاربر اجازه می دهد به یک فرگمنت با فشار دادن دکمه Back (حرکت به عقب) بازگردد .

هنگامی که یک فرگمنت را به عنوان بخشی از لایوت اکتیویتی خود اضافه می کنید، آن را در داخل سلسله مراتب ViewGroup می بینید و می توانید فرگمنت را در لایوت خود تعریف کنید. شما می توانید یک فرگمنت را به لایوت اکتیویتی خود با عنصر  <fragment>  یا با استفاده از کد برنامه خود به ViewGroup اضافه کنید. با این حال، fragment لازم نیست که بخشی از لایوت اکتیویتی باشد؛ شما همچنین می توانید یک فرگمنت را بدون استفاده از رابط کاربر خود به عنوان یک ایجاد کننده نامرئی برای اکتیویتی بکار ببرید.

این مقاله نحوه ساخت برنامه با استفاده از fragment را شرح می دهد، از جمله اینکه چگونه فرگمنتها می توانند حالت خودشان را هنگامی که به پشته بازگشتی اضافه می شوند حفظ کنند، چگونگی به اشتراک گذاری رویدادها با اکتیویتی و سایر فرگمنتها در اکتیویتی، کمک به action bar اکتیویتی و غیره.

برای اطلاعات بیشتر در مورد بررسی چرخه حیات، از جمله راهنمایی در مورد بهترین شیوه ها، به  چرخه حیات مراجعه کنید.

فلسفه طراحی

آندروید fragment ها را در آندروید 3.0 (API level 11) معرفی کرد، که عمدتاً برای حمایت از طرح های UI پویا و انعطاف پذیر بر روی صفحه نمایش های بزرگ مانند تبلت ها است. از آنجا که صفحه نمایش تبلت ها  بسیار بزرگتر از گوشی است، فضای بیشتری برای ترکیب و تعویض اجزای رابط کاربری وجود دارد. fragment ها اجازه می دهند که چنین طرح هایی بدون نیاز به مدیریت تغییرات پیچیده بصورت سلسله مراتب قابل مشاهده باشند. با تقسیم بندی یک اکتیویتی به فرگمنت، شما قادر به تغییر ظاهر اکتیویتی در زمان اجرا می باشید و این تغییرات را در پشته بازگشتی نگه می دارید که توسط اکتیویتی مدیریت می شود.

به عنوان مثال، یک برنامه خبری می تواند از یک fragment برای نشان دادن لیستی از مقالات در سمت چپ استفاده کند و یک fragment دیگر برای نمایش یک مقاله در سمت راست – هر دو فرگمنت در یک اکتیویتی به صورت یک طرفه ظاهر می شوند و هر فرگمنت دارای چارچوب زندگی خودش است و روش های فراخوانی و رویدادهای ورودی کاربر خود را مدیریت می کنند. بنابراین، به جای استفاده از یک اکتیویتی برای انتخاب یک مقاله و اکتیویتی دیگری برای خواندن مقاله، کاربر می تواند یک مقاله را انتخاب کند و همه آن را تنها در یک اکتیویتی بخواند، همانطور که در طرح تبلت در شکل 1 نشان داده شده است.

شما باید هر فرگمنت را به عنوان یک اکتیویتی مدولار (پیمانه ای) و قابل استفاده مجدد طراحی کنید. به این دلیل است که هر فرگمنت طرح و رفتار خود را با بازخورد چرخه حیات خود تعریف می کند، شما باید برای استفاده مجدد از طراحی و جلوگیری از دستکاری مستقیم یک فرگمنت از دیگر فرگمنت، یک بخش را در اکتیویتی های گوناگون اضافه کنید. این مهم است، زیرا یک fragment مدولار به شما امکان می دهد ترکیب های فرگمنت خود را برای اندازه های مختلف صفحه نمایش ها تغییر دهید. هنگام طراحی برنامه برای پشتیبانی از تبلت و گوشی، شما می توانید fragment خود را در پیکربندی های مختلف طراحی و مجدد استفاده کنید تا بهینه سازی تجربه کاربری بر اساس فضای صفحه در دسترس باشد. به عنوان مثال، بر روی یک گوشی ممکن است لازم باشد فرگمنت های جداگانه را برای تنها در یک UI نمایش دهید زمانی که بیش از یکی نمی تواند در یک اکتیویتی مشابه قرار بگیرد.

فرگمنت ها در اندروید

شکل 1: یک مثال از اینکه چگونه دو ماژول UI تعریف شده توسط fragment را می توان در یک اکتیویتی برای یک طراحی تبلت ترکیب کرد، اما برای طراحی گوشی جدا شده است.

برای مثال – ادامه برنامه اخبار – برنامه می تواند دو قسمت را در اکتیویتی A جاسازی کند، در حالیکه روی دستگاهی با اندازه تبلت اجرا می شود. با این حال، اندازه صفحه گوشی، برای هر دو fragment کافی نیست، بنابراین اکتیویتی A تنها فرگمنت لیست مقالات را شامل می شود و زمانی که کاربر یک مقاله را انتخاب می کند اکتیویتی B مقاله را که شامل بخش دوم است، شروع می کند. بنابراین همانطور که در شکل 1 نشان داده شده است، برنامه با استفاده مجدد از فرگمنت ها در تبلت و گوشی از ترکیب های مختلف پشتیبانی می کند.

ساخت یک فرگمنت

چرخه حیات فرگمنت اندروید

شکل 2. چرخه ی یک فرگمنت (در حالی که اکتیویتی در حال اجرا است).

برای ایجاد یک فرگمنت، شما باید یک زیر کلاس از Fragment (یا یک زیر کلاس موجود از آن) ایجاد کنید. کلاس Fragment دارای کد است که بسیار شبیه یک اکتیویتی است. این روش ها شامل فراخوانی یک اکتیویتی مانند onCreate ()، onStart ()، onPause() و onStop() است. در حقیقت، اگر شما یک برنامه اندرویدی موجود را برای استفاده از fragment تبدیل کنید، ممکن است به سادگی کد را از روش های بازخورد اکتیویتی ها به روش های بازخورد مربوط به فرگمنت تغییر دهید.

معمولاً، شما باید روش های چرخه حیات زیر را اجرا کنید:

onCreate()

سیستم هنگام فراخوانی فرگمنت، onCreate() را فرامی خواند. در پیاده سازی خود، باید اجزای ضروری فرگمنت را حفظ کنید، هنگامی که فرگمنت متوقف شده یا متوقف می شود راه اندازی کنید و سپس آن را دوباره ادامه دهید.

onCreateView()

سیستم زمانیکه وقت آن رسیده باشد onCreateView() را فرا می خواند تا برای اولین بار رابط کاربری خود را طراحی کند. برای رسم یک فرگمنت UI شما باید یک View از این روش، که  لایوت اصلی fragment شما است، بازگردانید. اگر فرگمنت UI را ارائه ندهد، می توانید مقدار خالی را بازگردانید.

onPause()

سیستم این روش را به عنوان اولین نشانه ای که کاربر از آن خارج می شود، فرا می خواند (هر چند که این بدان معنی نیست که فرگمنت از بین می رود). این معمولاً جایی است که شما باید هرگونه تغییری را انجام دهید تا خارج از جلسه فعلی کاربر ادامه یابد (زیرا ممکن است کاربر نتواند باز گردد).

اکثر برنامه های کاربردی حداقل باید این سه روش را برای هر فرگمنت پیاده سازی کنند، اما چند روش فراخوان دیگر نیز وجود دارد که باید برای رسیدن به مراحل مختلف چرخه حیات فرگمنت استفاده کنید. تمام روشهای فراخوانی چرخه حیات با جزئیات بیشتر در ” مدیریت چرخه حیات فرگمنت ” توضیح داده شده است.

همچنین چند زیر کلاس وجود دارد که ممکن است بخواهید به جای کلاس اصلی Fragment گسترش دهید:

DialogFragment

یک گفتگوی شناور را نمایش می دهد. استفاده از این کلاس برای ایجاد یک گفتگو، جایگزین خوبی برای استفاده از روش های کمک رسانی گفتگو در کلاس اکتیویتی است، زیرا شما می توانید یک گفتگوی fragment را در پشته بازگشتی مدیریت شده توسط اکتیویتی قرار دهید و به کاربر اجازه می دهد به یک فرگمنت رها شده بازگردد.

ListFragment

لیستی از مواردی را که توسط یک آداپتور (مانند یک SimpleCursorAdapter) مدیریت می شود، شبیه به ListActivity نمایش می دهد. این روش های متعددی برای مدیریت نمایش لیست، مانند فراخوانی onListItemClick()  برای اداره رویدادهای کلیک، فراهم می کند.

PreferenceFragment

Preference یک سلسله مراتب از اشیاء را مانند یک لیست، شبیه به PreferenceActivity نمایش می دهد. این هنگام ایجاد یک اکتیویتی “تنظیمات” برای برنامه شما مفید است.

اضافه کردن یک رابط کاربری

fragment معمولاً به عنوان بخشی از یک رابط کاربری اکتیویتی استفاده می شود و طرح خود را به اکتیویتی می دهد.

برای ارائه یک طرح فرگمنت، شما باید متد onCreateView() را فراخوانی کنید، که سیستم اندروید زمانی که وقت آن فرا رسیده باشد فرگمنت را برای آن طرح صدا می زند. پیاده سازی شما از این روش باید نمایی از طرح بندی اصلی fragment شما را بازگرداند.

توجه: اگر fragment شما یک زیر کلاس از ListFragment باشد، اجرای پیش فرض، یک ListView را از inCreateView() باز می کند، بنابراین شما نیازی به پیاده سازی آن ندارید.

برای بازگشت به یک طرح از ()onCreateView ، شما می توانید آن را از یک منبع لایوت تعریف شده در XML بخواهید. برای کمک به این کار، ()onCreateView   یک شی LayoutInflare را فراهم می کند.

به عنوان مثال، در زیر یک زیر کلاس از fragment است که یک طرح را از فایل example_fragment.xml بارگذاری می کند:

پارامتر container  که به inCreateView() منتقل شد، ViewGroup پدر (از طرح اکتیویتی) است که در آن طرح فرگمنت شما وارد می شود. پارامتر savedInstanceState یک Bundle (بسته نرم افزاری) است که اگر فرگمنت بازگردانده شود داده های مربوط به نمونه قبلی از fragment را فراهم می کند.

ایجاد طرح (layout)

در مثال بالا، R.layout.example_fragment مرجع یک منبع طرح به نام example_fragment.xml است که در منابع برنامه ذخیره شده است. برای اطلاعات در مورد چگونگی ایجاد طرح در XML، مقاله رابط کاربر را ببینید.

سه دلیل استفاده از روش inflate():

–  inflate شناسه (ID) منبع طرح مورد نظر شما  را می خواهد.

– ViewGroup به عنوان پدر inflate می شود. عبور از container  مهم است به این منظور که سیستم پارامترهای طرح را به View اصلی از طرح inflate  شده که توسط View پدر در آن قرار دارد، اعمال می کند.

– یک boolean که نشان می دهد که آیا طرح inflate  شده به ViewGroup (پارامتر دوم) در طول inflate  متصل شده. (در این مورد، این اشتباه است زیرا سیستم قبلاً طرح  را در container قرار داده است- درست عبور کردن یک افزونه در view group در لایوت نهایی ایجاد می کند.

حالا شما دیده اید که چگونه یک فرگمنت ایجاد کنید که یک طرح را ایجاد می کند. بعد، شما نیاز به اضافه کردن فرگمنت به اکتیویتی خود دارید.

اضافه کردن یک fragment به یک اکتیویتی

معمولاً یک fragment به بخشی از UI در اکتیویتی میزبان کمک می کند، که به طور کلی به عنوان بخشی از سلسله مراتب view اکتیویتی جاسازی شده است. دو روش برای اضافه کردن یک fragment به طرح اکتیویتی وجود دارد:

– فرگمنت را در داخل فایل طرح بندی اکتیویتی اعلام کنید.

در این مورد، شما می توانید خواص لایوت را برای فرگمنت، مانند یک view مشخص کنید. به عنوان مثال، در اینجا فایل لایوت برای یک اکتیویتی با دو فرگمنت نشان داده شده است:

ویژگی android:name  در عنصر <fragment>  از کلاس Fragment در لایوت معرفی شده است.

هنگامی که سیستم این طرح اکتیویتی را ایجاد می کند، آن هر fragment مشخص شده در طرح را ایجاد می کند و هر فرگمنت را بطور مشخص در لایوت معرفی می کند و متد () onCreateView را برای بازیابی فرگمنتها در لایوت صدا می زند. سیستم بوسیله فرگمنت view را در بطور مستقیم  در مکانی که عنصر <fragment> قرار دارد، درج می کند.

توجه: هر fragment نیاز به یک شناسه ی(ID) منحصر به فرد دارد که سیستم می تواند برای بازگرداندن فرگمنت، اگر اکتیویتی مجدداً راه اندازی شود، استفاده کند (و شما می توانید از آن برای گرفتن فرگمنت استفاده کنید مانند انجام تراکنش حذف). سه راه برای ارائه شناسه برای یک فرگمنت وجود دارد:

– ویژگی android:id یک ID منحصر بفرد عرضه می کند.

–  ویژگی Android: tag  یک رشته منحصر به فرد عرضه می کند.

–  اگر شما هیچ یک از دو راه قبلی را ارائه نکنید، سیستم از شناسه container view استفاده می کند.

یا، به صورت برنامه نویسی، فرگمنت را به ViewGroup موجود اضافه کنید.

در هر زمانی که اکتیویتی شما در حال اجرا است، می توانید فرگمنت را به طرح اکتیویتی خود اضافه کنید. شما فقط باید یک ViewGroup را تعیین و در فرگمنت قرار دهید.

برای انجام تراکنش های فرگمنت در اکتیویتی خود (مانند افزودن، حذف یا جایگزینی فرگمنت)، شما باید از API ها از FragmentTransaction استفاده کنید. شما می توانید نمونه ای از FragmentTransaction  را در اکتیویتی ببینید:

سپس می توانید یک fragment را با استفاده از روش add() اضافه کنید، فرگمنتی را که می خواهید اضافه کنید و مشخصات آن را وارد کنید. مثلاً:

اولین پارامتر منتقل شده به ViewGroup، add() است که باید در فرگمنت قرار داده شود، که توسط ID منبع مشخص شده است، و پارامتر دوم فرگمنت برای اضافه کردن است.

هنگامی که تغییرات خود را با FragmentTransaction انجام می دهید، باید commit() برای اعمال تغییرات اجرا کنید.

اضافه کردن یک فرگمنت بدون رابط کاربری (UI)

مثال های بالا نشان می دهد که چگونه یک fragment را به اکتیویتی خود اضافه کنید تا UI سفارشی شما فراهم شود. با این حال، شما می توانید یک فرگمنت را  برای ارائه یک رفتار پس زمینه برای یک اکتیویتی بدون ارائه UI استفاده کنید.

برای اضافه کردن یک fragment بدون یک رابط کاربری، فرگمنت را با استفاده از اکتیویتی با add(Fragment, String)  اضافه کنید. (یک رشته منحصر بفرد “tag” برای فرگمنت تهیه کنید و به شناسه View نسبت دهید). این فرگمنت را اضافه می کند، اما به دلیل اینکه همراه با یک View در طرح اکتیویتی مرتبط نیست، نمی تواند inCreateView()  را صدا بزند. بنابراین شما نیازی به پیاده سازی این روش ندارید.

تامین تگ رشته ای برای فرگمنت به طور جدی برای فرگمنت های غیر UI نیست – شما همچنین می توانید تگ های رشته را به فرگمنت هایی که یک UI دارند عرضه کنید، اما اگر فرگمنت UI ندارد، تنها راه شناسایی آن تگ رشته است اگر بخواهید قسمت دیگری از اکتیویتی را بعداً دریافت کنید، باید از findFragmentByTag() استفاده کنید.

برای مثال اکتیویتی که از یک fragment به عنوان یک ایجاد کننده در پس زمینه استفاده می کند بدون یک رابط کاربری، نمونه ای از FragmentRetainInstance.java را که در مثال های  SDK (از طریق Android SDK Manager در دسترس است) مشاهده می کند و در سیستم شما به عنوان <sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java قرار داده شده است.

مدیریت فرگمنت ها

برای مدیریت فرگمنت های موجود در اکتیویتی شما نیاز دارید تا از FragmentManager استفاده کنید. برای دریافت آن، getFragmentManager() را در اکتیویتی خود صدا بزنید.

برخی از چیزهایی که می توانید با FragmentManager انجام دهید عبارتند از:

– دریافت فرگمنت هایی که در اکتیویتی وجود دارد با findFragmentById() (برای فرگمنت هایی که UI را در طرح اکتیویتی فراهم می کنند) یا findFragmentByTag()  (برای فرگمنت هایی که UI را ارائه می دهند یا نمی دهند).

– قطعه های حذف شده از پشته بازگشتی، با popBackStack()  (شبیه سازی فرمان Back توسط کاربر).

– ثبت نام یک listener برای تغییر در پشته بازگشتی با addOnBackStackChangedListener() .

همانطور که در بخش قبلی نشان داده شده است، شما می توانید از FragmentManager برای باز کردن FragmentTransaction استفاده کنید، که به شما امکان انجام تراکنش هایی مانند اضافه کردن و حذف فرگمنت ها را می دهد.

انجام تراکنش های فرگمنت

یک ویژگی عالی در مورد استفاده از فرگمنتها در اکتیویتی ، توانایی اضافه کردن، حذف، جایگزینی و انجام عملیات دیگر، در پاسخ به تعامل کاربر است. هر مجموعه تغییراتی که شما در اکتیویتی مرتکب می شوید، یک تراکنش نامیده می شود و شما می توانید با استفاده از یکی از API ها در FragmentTransaction انجام دهید. همچنین شما می توانید هر تراکنش را که توسط اکتیویتی اجرا می کنید در پشته بازگشتی ذخیره کنید، به کاربر اجازه دهید که از طریق تغییرات fragment به عقب حرکت کند (مانند حرکت به عقب از طریق اکتیویتی ها).

شما می توانید نمونه ای از FragmentTransaction را از FragmentManager بدست آورید مثل این:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

هر تراکنش مجموعه ای از تغییرات است که می خواهید در همان زمان انجام دهید. شما می توانید تمام تغییراتی که می خواهید برای یک تراکنش انجام دهید را با استفاده از روش هایی مانند add ()، remove()   و replace() تنظیم کنید. سپس، برای اعمال تراکنش به اکتیویتی، باید commit() را صدا بزنید.

با این حال، قبل از صدا زدن commit() ، ممکن است بخواهید addToBackStack() را صدا بزنید تا تراکنش را به پشته بازگشتی از تراکنش های فرگمنت اضافه کند. این پشته توسط اکتیویتی مدیریت می شود و اجازه می دهد تا کاربر با فشار دادن دکمه بازگشت به حالت قبلی فرگمنت بازگردد.

به عنوان مثال، در اینجا چگونگی جایگزینی یک fragment با دیگری و حفظ وضعیت قبلی در پشته بازگشتی را نشان می دهد:

در این مثال، newFragment هر فرگمنت (در صورت وجود) جایگزین شده در حال حاضر در container لایوت با شناسه R.id.fragment_container شناسایی شده است. با فراخوانی addToBackStack() ، تراکنش جایگزین به پشته برگشت داده می شود، بنابراین کاربر می تواند تراکنش را معکوس کند و با فشار دادن دکمه برگشت، فرگمنت قبلی را بازگرداند.

برای بازیابی فرگمنتها از پشت بازگشتی، باید onBackPressed() را در کلاس اکتیویتی اصلی override  کنید:

اگر شما onBackPressed() را override   نکنید اکتیویتی قبلی پشته بازگشتی وجود دارد، با فشار دادن دکمه برگشت، برنامه را مجدداً به آن اکتیویتی باز می گردد؛ اگر هیچ اکتیویتی قبلی وجود نداشته باشد، فشار دادن Back بستگی به برنامه دارد.

اگر چندین تغییر را به تراکنش اضافه کنید (مثل add() یا remove() ) و addToBackStack() را صدا بزنید، همه تغییرات قبل از صدا زدن commit() به پشته بازگشتی اعمال می شود و به عنوان یک تراکنش واحد اضافه می شود و دکمه بازگشت همه آنها را با هم عوض می کند.

دستوراتی که  شما به FragmentTransaction  اضافه می کنید مهم نیست، به جز:

– شما باید در آخر commit() را صدا بزنید.

– اگر چند فرگمنت را به یک container اضافه می کنید، سپس به ترتیبی که آنها را اضافه کرده اید، به همان ترتیب در سلسله مراتب view ظاهر می شوند.

اگر هنگام انجام تراکنشی که یک fragment را حذف می کند، addToBackStack() را صدا نزنید، زمانی که تراکنش انجام شود، آن قطعه از بین می رود و کاربر نمی تواند به آن بازگردد. در حالی که اگر هنگام حذف یک فرگمنت، addToBackStack() را فراخوانی کنید، فرگمنت متوقف می شود و در صورتی که کاربر به عقب برگردد، از سر گرفته خواهد شد.

نکته: برای هر تراکنش فرگمنت، شما می توانید یک انیمیشن را با فراخوانی setTransition()  اعمال کنید.

با صدا زدن ()commit تراکنش بلافاصله انجام نمی شود. بلکه، آن را در thread اکتیویتی UI برنامه ریزی (thread “main”)و اجرا می شود، چون thread  قادر به انجام آن است. در صورت لزوم، شما می توانید  executePendingTransactions()    از thread   رابط کاربری خود صدا بزنید تا بلافاصله تراکنش توسط commit() انجام و اجرا شود. معمولاً انجام چنین کاری لازم نیست مگر اینکه تراکنش وابسته به مشاغل دیگر در thread   باشد.

احتیاط: شما می توانید یک تراکنش را با استفاده از commit()انجام دهید، فقط قبل از اینکه اکتیویتی در این حالت ذخیره شود (زمانی که کاربر اکتیویتی را ترک می کند). اگر بعد از آن تلاش کنید، این استثناء برداشته خواهد شد. اگر اکتیویتی نیاز به بازگردانی داشته باشد، این حالت پس از commit می تواند از بین برود. برای مواقعی که در آن خوب است که commit را از بین ببرید از  commitAllowingStateLoss() استفاده کنید.

ارتباط با اکتیویتی

اگر چه فرگمنت به عنوان یک شیء مستقل از یک اکتیویتی عمل می کند و می تواند در داخل چند اکتیویتی استفاده شود، و یک نمونه از یک فرگمنت مستقیماً به اکتیویتی که حاوی آن است مرتبط می شود.مشخصاً، fragment می تواند به اکتیویتی با getActivity() دسترسی داشته باشد و به راحتی وظایف را انجام دهد مانند یافتن یک View در طرح اکتیویتی:

به همین ترتیب، اکتیویتی شما می تواند متد ها را بوسیله دستیابی به یک مرجع  به Fragment از FragmentManager، با استفاده از findFragmentById() یا findFragmentByTag()، فراخوانی کند. مثلاً:

ایجاد رویداد فراخوان برای اکتیویتی

در برخی موارد ممکن است برای اشتراک رویدادها با اکتیویتی، یک فرگمنت داشته باشید. یک راه خوب برای انجام آن اینست که یک رابط فراخوان داخل فرگمنت تعریف کنید،که نیاز به اکتیویتی میزبان برای پیاده سازی دارید. هنگامی که اکتیویتی یک فراخوان را از طریق رابط دریافت می کند، می تواند اطلاعات را در صورت لزوم با سایر فرگمنتها در لایوت به اشتراک بگذارد.

به عنوان مثال، اگر یک برنامه خبری دارای دو قسمت در یک اکتیویتی باشد، یک لیست برای نمایش مقالات (فرگمنت A) و دیگری برای نمایش یک مقاله (فرگمنت B) -پس از آن وقتی که یک آیتم لیست انتخاب شود فرگمنت B می تواند مقاله را نمایش دهد. در این مورد، رابط OnArticleSelectedListener داخل فرگمنت A اعلام شده است:

سپس اکتیویتی که میزبان این fragment است رابط OnArticleSelectedListener را اجرا می کند و onArticleSelected()  را override  می کند تا فرگمنت B رویداد را از فرگمنت A دریافت کند. برای اطمینان از اینکه عملکرد میزبان این رابط را اجرا می کند، روش فراخوانی فرگمنت A در onAttach() (که سیستم هنگام اضافه کردن فرگمنت به اکتیویتی صدا می زند). نمونه ای از OnArticleSelectedListener را با ریختن اکتیویتی، که به onAttach() منتقل شده است، معرفی می کند:

اگر اکتیویتی این رابط را اجرا نکند، پس فرگمنت ClassCastException را اجرا می کند. موفقیت عضو mListener اشاره به پیاده سازی اکتیویتی دارد به طوری که فرگمنت A می تواند OnArticleSelectedListener را با فراخوانی اکتیویتی  با روش های تعریف شده توسط رابط OnArticleSelectedListener به اشتراک بگذارد. برای مثال، اگر فرگمنت A از ListFragment گسترش یافته باشد، در هر زمان که کاربر یک آیتم از لیست را کلیک کند، سیستم onListItemClick() را در فرگمنت صدا می زند، که پس از آن صدا زدن ()onArticleSelected  این رویداد با اکتیویتی به اشتراک گذاشته می شود:

پارامتر id به onListItemClick() ارسال شده است، ID ردیف آیتم کلیک شده است که اکتیویتی (یا اکتیویتی دیگر) برای جمع آوری مقاله در برنامه از ContentProvider  استفاده می کند.

اطلاعات بیشتر در مورد استفاده از ارائه دهنده محتوا (content provider) در مقاله content provider موجود است.

اضافه کردن آیتم به نوار برنامه

fragment می تواند با قرار دادن OptionsMenu در منوی تنظیمات اکتیویتی (و در نتیجه نوار برنامه) آیتم های منو را بوسیله onCreateOptionsMenu() اشتراک بگذارد. بدین ترتیب در هنگام onCreate() باید با استفاده از setHasOptionsMenu() این متدها را صدا بزنی، تا نشان دهد که فرگمنت می خواهد آیتم ها را به Options Menu اضافه کند (در غیر این صورت فرگمنت inCreateOptionsMenu()  را دریافت نخواهد کرد ).

هر آیتمی که به Options Menu اضافه کنید به آیتم های فرگمنت موجود نیز اضافه می شود. فرگمنت بازخوردها را با متد onOptionsItemSelected() هنگامی که انتخاب می شوند، دریافت می کند.

شما همچنین می توانید یک View را در طرح فرگمنت خود ثبت کنید تا یک context menu  را با registerForContextMenu() فراخوانی کند. هنگامی که کاربر context menu را باز می کند، فرگمنت onCreateContextMenu() را صدا می زند. هنگامی که کاربر یک آیتم را انتخاب می کند، فرگمنت onContextItemSelected() را دریافت می کند.

توجه: اگرچه fragment شما یک فراخوانی انتخاب شده- بر روی آیتم- را برای هر آیتم منو اضافه می کند، اکتیویتی ابتدا فراخوان را دریافت و پاسخ را برای آیتم منوی انتخاب شده بر می گرداند. اگر پیاده سازی اکتیویتی روی آیتم انتخاب شده انجام نشود، رویداد به فراخوان فرگمنت منتقل می شود. این برای Options Menu و context menus صادق است.

مطلب مرتبط: انواع منو در اندروید

بررسی چرخه حیات فرگمنت

چرخه حیات fragment

شکل 3: مفهوم چرخه حیات اکتیویتی بر چرخه حیات fragment را نشان می دهد

مدیریت چرخه حیات یک فرگمنت بسیار شبیه مدیریت چرخه حیات یک اکتیویتی است. مانند یک اکتیویتی، یک فرگمنت می تواند در سه حالت وجود داشته باشد:

Resumed

فرگمنت در اکتیویتی در حال اجرا قابل مشاهده است.

Paused

اکتیویتی دیگری در پیش زمینه  دارای تمرکز است، اما اکتیویتی که در این فرگمنت زندگی می کند هنوز هم قابل مشاهده است (اکتیویتی ابتدایی تا حدی شفاف است یا تمام صفحه را پوشش نمی دهد).

Stopped

فرگمنت قابل مشاهده نیست هر دو اکتیویتی میزبان متوقف شده اند و یا fragment از اکتیویتی حذف شده است و به پشته بازگشتی داده شده است. فرگمنت متوقف شده هنوز زنده است (تمام اطلاعات عضو  و حالت توسط سیستم حفظ می شود). با این حال، این دیگر برای کاربر قابل مشاهده نیست و اگر اکتیویتی از بین برود، از بین خواهد رفت.

همچنین مانند یک اکتیویتی، شما می توانید حالت یک فرگمنت را با استفاده از Bundle حفظ کنید، در صورتی که روند اکتیویتی از بین برود و شما نیاز به بازگرداندن حالت فرگمنت هنگامی که اکتیویتی بازسازی می شود، دارید. شما می توانید در حین کار با فراخوانی onSaveInstanceState()  حالت فرگمنت را ذخیره کنید و آن را با onCreate() ، onCreateView() یا onActivityCreated() برگردانید. برای کسب اطلاعات بیشتر در مورد ذخیره حالت، به مقاله  اکتیویتی ها مراجعه کنید.

مهمترین تفاوت در چرخه حیات بین یک اکتیویتی و یک فرگمنت، این است که چگونه در پشته بازگشتی مربوطه ذخیره می شود. یک اکتیویتی در یک پشته بازگشتی از اکتیویتی قرار داده شده است، زمانی که متوقف می شود بطور پیش فرض توسط سیستم مدیریت می شود (به طوری که کاربر می تواند با دکمه Back، همانطور که در کارها و پشته بازگشتی بحث شده است). با این حال، تنها زمانی یک فرگمنت در پشته بازگشتی مدیریت شده توسط اکتیویتی میزبان قرار می گیرد که شما به صراحت درخواست آنرا با فراخوانی addToBackStack() در طی تراکنشی که fragment را حذف می کند درخواست می کنید.

در غیر این صورت، مدیریت چرخه حیات fragment بسیار شبیه به مدیریت چرخه حیات اکتیویتی است. بنابراین، شیوه های مشابه برای مدیریت چرخه حیات اکتیویتی نیز برای فرگمنت نیز استفاده می شود. با این حال آنچه که شما باید درک کنید، این است که چگونه حیات اکتیویتی بر حیات فرگمنت تاثیر می گذارد.

احتیاط: اگر شما در یک Fragment به یک شی Context نیاز دارید، می توانید getActivity() را فراخوانی کنید. با این حال، مراقب فراخوانی getActivity() زمانی که فرگمنت به یک اکتیویتی متصل است، باشید. هنگامی که فرگمنت متصل نیست یا در حین پایان چرخه حیات خود جدا شده است، getActivity() مقدار صفر برمی گرداند.

مطلب مرتبط: آشنایی با چرخه حیات اکتیویتی در اندروید

هماهنگی با چرخه حیات اکتیویتی

چرخه حیات اکتیویتی که در آن fragment زندگی می کند به طور مستقیم بر چرخه حیات فرگمنت تاثیر می گذارد، به طوری که هر فراخوان چرخه حیات برای این اکتیویتی در یک فراخوان مشابه برای هر فرگمنت نیز انجام می شود. برای مثال، هنگامی که اکتیویتی onPause() را دریافت می کند، هر فرگمنت در اکتیویتی نیز onPause() را دریافت می کند.

چرخه حیات فرگمنتها دارای چند فراخوان اضافی است، با این حال، بررسی تعامل منحصر به فرد با اکتیویتی برای انجام اقداماتی مانند ساخت و نابود کردن رابط کاربری فرگمنت. این روش های فراخوان اضافی عبارتند از:

onAttach()

فراخوان زمانی است که fragment با اکتیویتی مرتبط است (اکتیویتی در اینجا منتقل می شود).

onCreateView()

برای ایجاد سلسله مراتبی از view همراه با fragment فراخوانده می شود.

onActivityCreated()

زمانی که اکتیویتی متد onCreate() را بر می­گرداند فراخوانی می شود.

onDestroyView()

هنگامی که سلسله مراتب View مربوط به فرگمنت حذف می شود، فراخوانی می شود.

onDetach()

زمانی که fragment از اکتیویتی جدا می شود، فراخوانی می شود.

در شکل 3 روند چرخه حیات یک فرگمنت، که بر اکتیویتی میزبان تأثیر می گذارد، نشان داده شده است. در این شکل، می توانید ببینید که چگونه هر حالت متوالی اکتیویتی، کدام روش فراخوانی را که یک fragment ممکن است دریافت کند، تعیین می کند. به عنوان مثال، هنگامی که اکتیویتی onCreate() را فراخوانی می کند، یک فرگمنت در اکتیویتی، فراخوانی بیشتر از onActivityCreated() دریافت نمی کند.

هنگامی که اکتیویتی به حالت از سر گرفتن می رسد، شما می توانید آزادانه فرگمنت ها را به اکتیویتی اضافه و حذف کنید. بنابراین، تنها در حالی که اکتیویتی در حالت از سر گرفتن است می تواند چرخه حیات یک fragment به طور مستقل تغییر کند.

با این حال، هنگامی که اکتیویتی از سر گرفته می شود، fragment دوباره از طریق چرخه حیات خود به اکتیویتی اضافه می شود.

مثال

برای به دست آوردن همه چیز در این مقاله با هم بحث می کنیم، در اینجا یک مثال از اکتیویتی با استفاده از دو fragment برای ایجاد یک لایوت دو تکه ای آورده شده است. اکتیویتی زیر شامل یک فرگمنت برای نشان دادن لیستی از بازی های شکسپیر است و دیگری برای نشان دادن خلاصه ای از بازی، هنگام انتخاب از لیست. همچنین چگونگی تنظیمات مختلف فرگمنتها را بر اساس پیکربندی صفحه نمایش نشان می دهد.

نکته: سورس کامل این اکتیویتی در برنامه نمونه نمایش داده شده است که از کلاس FragmentLayout استفاده می کند.

یک لایوت به طور معمول به main activity در حین  onCreate() اعمال می شود:

کد زیر در لایوت fragment_layout.xml قرار داده شده است:

با استفاده از این لایوت، سیستم به تدریج TitlesFragment (که عناوین بازی را فهرست می کند) را به محض بارگذاری طرح اکتیویتی، ترسیم می کند، در حالی که FrameLayout (جایی که فرگمنت خلاصه بازی را نمایش می دهد) در ابتدا فضای اشغال شده را در سمت راست صفحه برده و در انجا باقی می ماند. همانطور که در زیر مشاهده خواهید کرد، تا زمانی که کاربر یک مورد را از لیست انتخاب نکند، یک فرگمنت در FrameLayout قرار می گیرد.

با این وجود، تمام پیکربندی های صفحه نمایش به اندازه کافی گسترده نیستند تا لیست بازی و خلاصه آن را کنار یکدیگر نشان دهند. بنابراین، طرح بندی بالا فقط برای پیکربندی صفحه نمایش افقی (landscape)، بوسیله ذخیره آن در res / layout-land / fragment_layout.xml استفاده می شود.

بنابراین، هنگامی که صفحه نمایش در جهت عمودی است، سیستم طرح زیر را اعمال می کند، که در res / layout / fragment_layout.xml ذخیره می شود:

این طرح فقط TitlesFragment را شامل می شود. این بدان معنی است که هنگامی که دستگاه در جهت عمودی قرار دارد، فقط لیستی از بازی ها قابل مشاهده است. بنابراین، هنگامی که کاربر یک آیتم لیست را کلیک کند، برنامه به جای بارگیری فرگمنت دوم، یک اکتیویتی جدید را برای نمایش خلاصه آغاز می کند.

سپس، شما می توانید ببینید که چگونه در کلاس های fragment انجام شده است. اول TitlesFragment است، که لیستی از بازی های شکسپیر را نشان می دهد. این فرگمنت ListFragment را گسترش می دهد و به آن متکی است تا اکثریت کار نمایش لیست را مدیریت کند.

همانطور که شما این کد را بررسی می کنید، متوجه می شوید که دو رفتار احتمالی ممکن است با انتخاب یک آیتم از لیست رخ دهد: بسته به اینکه کدام طرح اکتیویتی فعال است است، می تواند یک فرگمنت جدید ایجاد و نمایش داده شود تا جزئیات را در یک اکتیویتی مشابه نشان دهد (اضافه کردن فرگمنت به FrameLayout) یا شروع یک اکتیویتی جدید (جایی که فرگمنت را می توان نشان داد).

fragment دوم، DetailsFragment خلاصه بازی را برای آیتم انتخاب شده از لیست از TitlesFragment نشان می دهد:

کلاس TitlesFragment را به یاد بیاورید، که اگر کاربر یک آیتم را از لیست کلیک کند، R.id.details لایوت فعلی را شامل نمی شود (آن جایی که به DetailsFragment وابسته است)، سپس اکتیویتی برنامه DetailsActivity را برای نمایش محتوای آیتم نشان می دهد.

در اینجا DetailsActivity ، به سادگی DetailFragment را جاسازی می کند تا خلاصه بازی انتخاب شده را هنگامی که صفحه نمایش در جهت عمودی است، نمایش دهد:

توجه داشته باشید که اگر پیکربندی افقی باشد این اکتیویتی خود را به پایان می رساند، به طوری که اکتیویتی اصلی می تواند DetailsFragment را همراه با TitlesFragment به دست بیاورد و نمایش دهد. این اتفاق می افتد، اگر کاربر در جهت عمودی شروع به DetailsActivity کند و سپس به جهت افقی بچرخاند(که اکتیویتی فعلی را مجددا فعال می کند).

برای نمونه های بیشتر با استفاده از فرگمنت (و سورس کامل برای این مثال)، نمونه API Demos موجود در ApiDemos (برای دانلود Samples SDK component  در دسترس است) را ببینید.

منبع: https://developer.android.com/guide/components/fragments.html#Example

درباره ShopDroid

فروشگاه توسعه دهندگان موبایل شاپ دروید با بیش از 7 سال سابقه مفتخر است که اولین و بهترین فروشگاه سورس می باشد

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *