فرگمنت اندروید چیست؟

فرگمنت چیست؟ چگونه یک فرگمنت اندروید بسازیم؟

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


فرگمنت چیست؟

fragment چیست

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


یک مقدار فنی تر، فرگمنت دقیقا چیست؟

قبل از هر چیز باید بدانید که Fragment یک کلاس جاوا در اندروید است. یعنی اگر کلاسی داشته باشید که از این کلاس ارث بری (یا به اصطلاح آن را extend) کرده باشد، تبدیل به یک فرگمنت میشود. این کلاس دارای متدهای خاص خود میباشد که به تعدادی از آنها متدهای چرخه عمر یا LifeCycle گفته میشود. با استفاده از این متدها میتوانید عملکرد Fragment را در مرحله های مختلف زندگی آن، کنترل کنید. با متدهای LifeCycle فرگمنت ها در قسمت های بعدی همین مقاله آشنا میشویم.

تعریف فنی فرگمنت

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

فرگمنت ها برای ساخت یک رابط کاربری ماژولار مورد استفاده قرار میگیرند. آنها به شما این قابلیت را میدهند که در یک صفحه اپلیکیشن، چندین Fragment داشته باشید که عملکرد های متفاوتی دارند. یعنی می توانید چندین Fragment را درون یک اکتیویتی داشته باشید.

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

تعریف دقیق فرگمنت

وقتی که فرگمنت را به عنوان یکی از اجزای رابط کاربری اکتیویتی به آن اضافه میکنید، این فرگمنت در یک ViewGroup در ساختار اکتیویتی زندگی خواهد کرد. اما این فرگمنت فایل Layout یا ظاهر مربوط به خود را خواهد داشت که این فایل در اکتیویتی نشان داده می شود. برای این که یک Fragment درون یک اکتیویتی نشان داده شود، باید مکان آن را در فایل Layout اکتیویتی (دقت کنید، اکتیویتی) مشخص کنیم، بعد با استفاده از کدهای جاوا مشخص میکنیم که کدام فرگمنت در آنجا نمایش داده شود.

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


برای درک بهتر Fragment

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


تفاوت فرگمنت و اکتیویتی

تفاوت فرگمنت و اکتیویتی
  1. اکتیویتی میزبان فرگمنت است: هر Fragment حتما باید توسط یک اکتیویتی میزبانی شود، و هیچ فرگمنتی نمیتواند بصورت مستقل اجرا شود.
  2. فرگمنت مانند اکتیویتی مستقل نیست: اکتیویتی ها میتوانند تقریبا بدون نیاز و وابستگی به دیگر کامپوننت های اپلیکیشن، اجرا شوند و شروع به کار کنند. اما فرگمنت ها این قابلیت را ندارند.
  3. چندین فرگمنت میتواند در صفحه وجود داشته باشد: Fragment ها میتوانند در کنار هم، در یک صفحه از نرم افزار قرار بگیرند.
  4. برای ارسال اطلاعات به فرگمنت از Bundle استفاده میشود: روند های ارسال پیام در اکتیویتی و فرگمنت با هم تفاوت دارند. در اکتیویتی ها از Intent و برای Fragment ها از Bundle استفاده میشود.
  5. برای شروع کردن فرگمنت از Fragment Manager استفاده میشود: فرگمنت ها با استفاده از Intent ها شروع میشوند اما Fragment ها برای اینکار نیازمند Fragment Manager هستند.

شباهت های فرگمنت و اکتیویتی

شباهت فرگمنت و اکتیویتی
  1. هردو دارای یک فایل کلاس و فایل Layout هستند: اکتیویتی و فرگمنت از دو قسمت تشکیل شده اند، یک فایل ظاهری با پسوند xml و یک کلاس جاوا.
  2. هردو دارای متدهای چرخه عمر هستند: اکتیویتی و Fragment دارای متدهای گوناگونی برای مدیریت چرخه عمر خود هستند.
  3. هردو میتوانند یک صفحه از اپلیکیشن باشند: هم اکتیویتی و هم Fragment میتوانند یک صفحه کامل از اپلیکیشن را به خود اختصاص بدهند.
  4. هردو کلاس های اندروید هستند: هردوی آنها دارای فایل های کلاس جاوا هستند که درون آنها هم متد ها و کلاس های دیگری قرار دارد که در زمان اجرا، فراخوانی میشوند.
  5. هردو ساختاری برای انتقال اطلاعات دارند: هردوی این موارد، از یک ساختار برای انتقال اطلاعات و پیام استفاده میکنند. یکی Intent برای اکتیوتی و دیگری Bundle برای فرگمنت.

تاریخچه و فلسفه طراحی فرگمنت

تاریخچه فرگمنت

فرگمنت ها در نسخه ۳٫۰ (API Level 11) به اندروید اضافه شدند. هدف طراحی و معرفی این جزء از برنامه های اندرویدی، توانایی ساخت رابط های کاربری منعطف تر در دستگاه هایی با صفحه های بزرگ، مانند تبلت ها بود. چون در صفحه هایی مانند تبلت ها، فضای زیادی وجود دارد و یک اپلیکیشن باید بتواند از این فضای اضافه، نهایت استفاده را داشته باشد. همچنین این اتفاق باید بدون نیاز به اعمال تغییرات پیچیده و اساسی در سلسه مراتب View اندروید رخ می داد.

به همین دلیل اجزایی طراحی و ساخته شدند که وقتی آنها را به اکتیویتی اضافه میکنید، میتوانید صفحه را به چندین قسمت تقسیم کنید که هرکدام عملکرد خاص خودشان را دارند. بدون اینکه نیاز داشته باشید عملکرد های پیچیده ای که در Back Stack اکتیویتی رخ میدهد را کنترل و مدیریت کنید. همه این امکانات امروزه با استفاده از Fragment Support Library در دسترس شما قرار دارند.

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

شمای اکتیویتی و فرگمنت

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

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

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


کجا باید از فرگمنت استفاده کنیم؟

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

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

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

ساختار fragment

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

  1. فایل ظاهر یا Layout با پسوند xml: هر فرگمنت دارای یک فایل Layout است که در پوشه res در مسیر پروژه قرار میگیرد. این فایل شامل همه المان هایی است که در رابط کاربری، روی صفحه نمایش داده میشود. این فایل با استفاده از ساختار XML نوشته میشود. در این فایل همه المان ها، استایل ها، اندازه ها، فونت ها، جاگذاری ها و بقیه مواردی که در رابط کاربری باید تنظیم شوند، وجود دارند.
  2. فایل کلاس جاوا با پسوند class: این فایل در اصل مسئول همه عملیات ها، اتفاق ها و عملکرد هایی است که در فرگمنت رخ میدهد. درون این فایل کدهایی به زبان جاوا وجود دارد که عملکرد فرگمنت را مشخص میکنند. یعنی بدون این کلاس جاوا، Fragment فقط یک پوسته خالی است که هیچ واکنشی ندارد و هیچ کاری را نمیتواند انجام بدهد. همه متدها، متدهای چرخه عمر، کلاس ها، ارتباط با سرور ها، ذخیره سازی داده و همه و همه در این کلاس انجام میشوند.

چرخه عمر فرگمنت

فرگمنت یکی از کلاس های جاوا است که میتواند بارها مورد استفاده دوباره قرار بگیرد. این کلاس دارای متدهایی است که به آنها متدهای چرخه عمر یا Life Cycle Method گفته میشود. این متد ها برای مدیریت و کنترل مراحلی است که یک Fragment در مدت زمانی که وجود دارد (زنده است) استفاده میشود.

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

چرخه عمر فرگمنت

یعنی یک فرگمنت دارای مراحل مختلفی در زمان اجرای خود میباشد. برنامه نویس هم با استفاده از متدهای مدیریت چرخه عمر Fragment، میتواند مشخص کند که در هرکدام از این مرحله ها، فرگمنت چه رفتاری از خودش نشان بدهد. به مجموعه این مراحل Life Cycle گفته میشود.

نکته مهمی که باید بدانید، این است که چرخه عمر یک فرگمنت به چرخه عمر اکتیویتی میزبان آن وابسته است. هرچند این متدها در Fragment و اکتیویتی با یکدیگر تفاوت دارند و تعداد آنها هم متفاوت است، اما متدهای Life Cycle فرگمنت به متدهای چرخه عمر اکتیویتی متصل میشوند و با وابستگی به آنها اجرا میشوند. در ادامه با همه این متدها، وضایف آنها و همچنین نحوه و ترتیب اجرای آنها آشنا خواهیم شد.


متدهای چرخه عمر Fragment

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


متد onAttach

این متد اولین مرحله از چرخه عمر فرگمنت میباشد و زمانی اجرا میشود که Fragment به اکتیویتی متصل میشود. یعنی اولین مرحله در چرخه عمر یک Fragment، اتصال آن به اکتیویتی می باشد. در این مرحله نباید کاری انجام بدهید و معمولا این متد را Override نمیکنند.


متد onCreate

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

نکته مهمی که در این متد باید مورد توجه قرار بدهید، این است که بر خلاف متدهای چرخه عمر اکتیویتی، شما نمیتوانید به اجزای View یا مواردی که در فایل Layout تعریف کرده اید دسترسی داشته باشید. زیرا در این متد هنوز View ساخته نشده است.


متد onCreateView

این متد جایی است که باید Layout فرگمنت را بسازید. به این کار به اصطلاح Inflate کردن گفته میشود. یعنی سیستم این متد را برای ساختن UI فرگمنت صدا میزند. این متد یک مقدار بازگشتی از نوع View را بر میگرداند. این مقدار باید فایل Layout را درون خود داشته باشد که با استفاده از کلاس Inflater باید آن را بسازید.

نکته مهم درباره این متد این است که اجزای رابط کاربری میتوانند در این مرحله از چرخه عمر، مقداردهی اولیه شوند. اما معمولا برای این کار از متد بعدی استفاده میشود. وظیفه این متد ساختن رابط کاربری Fragment است. (برای این کار در اکتیویتی، از متد setContentView استفاده میشود.


متد onViewCreated

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


متد onActivityCreated

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


متد onStart

این متد زمانی صدا زده میشود که اکتیویتی شروع به نمایش روی صفحه کند. در این زمان متد onStart صدا زده می شود.


متد onResume

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


متد onPause

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


متد onStop

این مرحله بعد از onPause اجرا میشود و در این مرحله فعالیت های فرگمنت متوقف میشود. اما هنوز ظاهر Fragment وجود دارد و تخریب نشده است.


متد onDestroyView

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


متد onDestroy

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


متد onDetach

وقتی این متد اجرا شود، فرگمنت از اکتیویتی جدا می شود و کاملا از بین میرود.


چگونه یک فرگمنت بسازیم؟

برای ساختن یک فرگمنت باید دو کار را به طور کلی انجام بدهیم:

  1. ساخت کلاس فرگمنت
  2. ساخت فایل لایوت Fragment
  3. اضافه کردن فرگمنت به اکتیویتی

بیایید با جزئیات همه این مراحل را با یکدیگر بررسی کنیم.


۱- ساخت کلاس فرگمنت

 برای ساخت کلاس فرگمنت، باید در درخت پروژه روی پکیج خاصی که نیاز داریم Fragment درون آن وجود داشته باشد، کلیک راست میکنیم و از منوی New، گزینه Class را انتخاب میکنیم.

ساخت کلاس فرگمنت در اندروید استودیو
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

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

انتخاب اسم کلاس فرگمنت
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

برای اینکه یک کلاس به فرگمنت تبدیل شود، باید یکی از کلاس های فرگمنت موجود در پلتفرم اندروید را extend کنیم. با این کار کلاس ما تبدیل به یک Fragment میشود و همه ویژگی های آن را ارث بری میکند. بعد از این کار میتوانید متدهای چرخه عمر فرگمنت را به همراه متدهایی که خودتان برای مدیریت Fragment نیاز دارید را به آن اضافه کنید. (متدهای چرخه عمر را میتوانید override کنید زیرا مربوط به کلاس پدر، یعنی Fragment هستند).

extend کردن کلاس فرگمنت
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

بعد از ساختن این کلاس، باید فایل Layout فرگمنت را بسازیم. اما کارهای ما با این فایل هنوز تمام نشده است و بعد از ساختن فایل xml، باید دوباره به این کلاس برگردیم تا ارتباط کلاس و فایل ظاهر را برقرار کنیم.


۲- ساخت Layout فرگمنت

برای ساخت فایل ظاهری، باید از پنجره فایل های پروژه، پوشه res را باز کنیم. بعد روی فایل layout کلیک راست میکنیم و گزینه New Android Resource File را انتخاب میکنیم.

برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

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

انتخاب نام فاِیل layout فرگمنت
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

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

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Hello World!"
android:textColor="@android:color/black"
android:textSize="18sp" />

</androidx.constraintlayout.widget.ConstraintLayout>
فایل layout برای فرگمنت
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

قدم بعدی این است که ارتباط میان کلاس اکتیویتی و فایل ظاهر آن را برقرار کنیم.


۳- برقراری ارتباط میان فایل کلاس و فایل Layout

بعد از ساختن هر دو فایل، باید ارتباط میان آنها را برقرار کنید تا فرگمنت کامل شده باشد. برای این کار باید به کلاس فرگمنت برویم. اولین کاری که باید انجام بدهید این است که یکی از متدهای چرخه عمر را override کنید که مسئول ساخته شدن View در Fragment است. یعنی ابتدا باید متد onCreateView را پیاده سازی کنیم. این متد باید شبیه به نمونه کدهای زیر باشد:

متد oncreateview در فرگمنت ها
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.
public class TestFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
}
}

درون این متد باید با استفاده از یک کلاس جاوا به نام Inflater، عمل Inflate کردن ظاهر فرگمنت را انجام بدهیم. اینکار باعث میشود که فایل Layout ساخته شده به عنوان ظاهر فرگمنت شناخته شود و هنگام شروع Fragment، روی صفحه نمایش داده بشود. درون این متد ابتدا باید یک آبجکت از کلاس View بسازیم. سپس با استفاده از کلاس Inflater و مانند مثالی که در زیر مشاهده میکنید، باید آدرس فایل xml را مشخص کنید و آن را درون آبجکت View بریزید. سپس به عنوان خروجی متد، Instance ساخته شده از کلاس View را برگردانید.

کلاس inflater در فرگمنت ها
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.
public class TestFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
}
}

۴- اضافه کردن فرگمنت به اکتیویتی

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

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

بنابراین در فایل Layout متعلق به اکتیویتی میزبان (که در اینجا MainActivity است)، یک FrameLayout اضافه میکنیم و یک id برای آن مشخص میکنیم. از این id در کدهای جاوا استفاده خواهیم کرد.

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

میتوانید از این کد برای اضافه کردن FrameLayout به اکتیویتی استفاده کنید (مخصوص فایل xml):

<FrameLayout
        android:id="@+id/test_fragment_container_fl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white" />

برای اینکار باید از یک متد به نام getSupportFragmentManager استفاده میکنیم. این متد توانایی شروع کردن یک فرگمنت را در اختیار ما قرار میدهد و همچنین یک نمونه از کلاس SupportFragmentManager را برمیگرداند. یعنی میتوانید متدهای این کلاس را، روی آن مستقیما صدا بزنید.

استفاده از کلاس fragmentmanager
برای دیدن عکس با کیفیت بالا، روی آن کلیک کنید.

برای اینکه بتوانید یک فرگمنت را به صفحه اضافه کنید، باید یک تراکنش بسازید. برای اینکار باید متد beginTransaction را روی نمونه ای که از کلاس SupportFragmentManager داریم، صدا بزنیم. یعنی چیزی مانند کد زیر.

public class MainActivity extends AppCompatActivity {
private FrameLayout frameLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().add(R.id.test_fragment_container_fl, new TestFragment(),null).commit();


}
}

این تراکنش میتواند فرگمنت ها را به صفحه اضافه کرده و آنها را نمایش بدهد. به عنوان آخرین قدم برای نمایش Fragment روی صفحه، باید با استفاده از متدهای add یا replace اقدام به اضافه کردن فرگمنت در مکانی که برای آن روی صفحه اکتیوتی مشخص کرده اید، بکنید. اما تفاوت این دو متد کجاست؟

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


باز کردن فرگمنت از یک فرگمنت دیگر

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

باز کردن فرگمنت از یک فرگمنت دیگر

برای شروع کردن یک فرگمنت از یک فرگمنت دیگر دو راه کلی و معمولی پیش روی شما قرار دارد. شما میتوانید مستقیما این کار را درون Fragment انجام بدهید، یا اینکه میتوانید متد مربوط برای استارت کردن فرگمنت مورد نظر را درون اکتیویتی بسازید و آن را از درون Fragment اجرا صدا بزنید. (روش دوم رو استفاده کنین، چون بهتره اکتیویتی همه چیز رو کنترل کنه). مثال ها رو با هم بررسی میکنیم:

برای باز کردن فرگمنت از یک فرگمنت دیگر:

FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.container,YOUR_FRAGMENT_NAME,YOUR_FRAGMENT_STRING_TAG);
transaction.addToBackStack(null);
transaction.commit();

برای باز کردن Fragment از یک اکتیویتی دیگر:

FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.container,YOUR_FRAGMENT_NAME,YOUR_FRAGMENT_STRING_TAG);
transaction.addToBackStack(null);
transaction.commit();

انواع فرگمنت ها

انواع فرگمنت ها

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


فرگمنت تک صفحه (Single Frame Fragment)

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


کاربرد Single Frame Fragment

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

دیالوگ فرگمنت (Dialog Fragment)

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


کاربرد های دیالوگ فرگمنت:

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

BottomSheet Fragment

فرگمنت های BottomSheet از پایین صفحه ظاهر میشوند و میتوانند گزینه های بیشتری را برای کاربر نمایش بدهند. یکی از ویژگی های خوب این مدل از Fragment ها، این است که در موقعیت خوبی برای دسترسی کاربر قرار گرفته اند و تجربه کاربری خوبی را ارائه میدهند. میتوانید از این فرگمنت ها برای نشان دادن گزینه های بیشتر، اطلاعات اضافه، گرفتن گزینه ها یا اطلاعات دیگر از کاربر استفاده کنید. دو مدل مختلف از این Fragment ها وجود دارد که میخواهیم با آنها آشنا شویم:


Modal BottomSheet Fragment

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


Persistent BottomSheet Fragment

این مدل در محتوای اپلیکیشن نشان داده میشود. یعنی اگر این فرگمنت را در یک اکتیویتی پیاده سازی کرده باشید، همیشه یک کادر در پایین صفحه نشان داده خواهد شد که با کشیدن آن به سمت بالا، همه محتوای خود را نشان میدهد. ارتفاع این مدل در نسبت با Modal BottomSheet کمتر است.


فرگمنت Headless (برای پردازش های پس زمینه)

بعضی از فرگمنت ها هستند که میتوانید آنها را بدون تعریف کردن رابط کاربری هم استفاده کنید. به این فرگمنت ها، Headless Fragment گفته میشود. بعضی از پردازش ها و عملیات ها هستند که گاهی نیاز دارید جلوی چشم کاربر نباشند. به اصطلاح گفته میشود که این عملیات ها در Background یا پس زمینه انجام میشوند. میتوانید برای این موارد از Fragment های بدون رابط کاربری استفاده کنید. برای پیاده سازی این مدل، باید در متد onCreateView مقدار null را برگردانید.

پیشنهاد میشود برای عملیات های پس زمینه، بهترین کار این است که از سرویس ها در اندروید استفاده کنید. اما اگر میخواهید این کار را با استفاده از فرگمنت ها انجام بدهید، رتبه دوم بهترین راه حل ها، به Headless Fragment داده میشود. برای اینکار، باید تنظیمات Headless Fragment را طوری مشخص کنید که محافظت شده (یا به اصطلاح Retained) باشد. یک فرگمنت Retained در طول زمان و وقتی که وضعیت ها تغییر میکند، از بین نمی رود.

Headless Fragement ها معمولا برای کپسوله کردن یک حالت خاص در طول تغییر هایی که اتفاق می افتند، یا یک وظیفه که باید در پس زمینه انجام شود به کار میروند. برای این منظور باید Headless Fragment را بصورت محافظت شده یا Retained در بیاورید. یک فرگمنت Retained در طول زمان و وقتی که وضعیت ها تغییر میکند، از بین نمی رود.

فرگمنت های retained

برای اینکه یک فرگمنت را محافظت شده کنید، باید متد setRetainInstance را درون آن صدا بزنید.

اضافه کردن این Fragment، به اکتیویتی کار پیچیده ای نیست. باید از متد add در کلاس FragmentManager استفاده کنید. اگر میخواهید بعدا به این فرگمنت ارجاع بدهید، باید برای add کردن آن، از یک تگ استفاده کنید. این کار شما را قادر میکند که برای پیدا کردن آنها متد findFragmentByTag که مربوط به کلاس FragmentManager را صدا بزنید.


انتقال داده بین فرگمنت ها

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


انتقال داده بین فرگمنت ها با Fragment Manager

بعد از فرگمنت ورژن ۱٫۳ هر کدام از FragmentManager ها، عضوی به نام FragmentResultOwner را درون خود دارند و آن را implement میکند. یعنی FragmentManager ها میتوانند نتیجه هایی که از دیگر Fragment ها گرفته شده را درون خود نگهداری کنند و انتقال بدهند. این ساختار به شما اجازه میدهد بین فرگمنت های مختلف ارتباط مستقیم برقرار کنید، بدون اینکه نیاز باشد یک نمونه از آنها را ساخته باشید.

فرض کنید دو Fragment داریم که آنها را A و B نام گذاری میکنیم. برای اینکه بتوانیم داده ها را از فرگمنت A به فرگمنت B انتقال بدهیم، باید ابتدا یک Result Listener در فرگمنت A، یعنی همان فرگمنتی که قرار است نتیجه ها را دریافت کند، تعریف کنیم. برای اینکار باید یک API به نام setFragmentResultListener را روی FragmentManger متعلق به فرگمنت A صدا بزنیم. میتوانید نمونه این کد را در ادامه مشاهده کنید:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getParentFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) {
// We use a String here, but any type that can be put in a Bundle is supported
String result = bundle.getString("bundleKey");
// Do something with the result…
}
});
}
ارسال داده بین فرگمنت ها با FragmentManager

در فرگمنت B، یعنی فرگمنتی که نتیجه ها را تولید میکند، باید نتیجه ها را درون همان FragmentManager بریزیم و از همان requestKey استفاده کنیم. میتوانید این کار را با استفاده از یک API به نام setFragmentResult انجام بدهید. نمونه کدهای زیر را مشاهده کنید:

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle result = new Bundle();
result.putString("bundleKey", "result");
getParentFragmentManager().setFragmentResult("requestKey", result);
}
});

بعد از این کار، فرگمنت A نتیجه ها را دریافت میکند و وقتی که در حالت STARTED قرار گرفت، Listener اجرا میشود. شما میتوانید فقط یک Listener و یک Result برای یک کلید خاص تعریف کنید. یعنی اگر متد setResults را بیشتر از یکبار صدا بزنید، آخرین نتیجه ای که درون آن قرار بدهید به Fragment پدر برگردانده خواهد شد. اگر هم این متد را بدون اینکه Listener مورد نیاز برای آن را ساخته باشید صدا بزنید، نتیجه ها درون FragmentManager باقی خواهند ماند تا زمانی که این Listener صدا زده بشود.

توجه داشته باشید که فرگمنتی که Listener درون آن قرار دارد باید حتما شروع شده باشد تا بتواند نتیجه ها را دریافت کند. هنگامی که یک Listener نتیجه ای را دریافت میکند و متد onFragmentResult صدا زده میشود، آن نتیجه پاک خواهد شد. این رفتار دو پیامد خواهد داشت:

  • فرگمنت های موجود در Back Stack نتیجه را تا زمانی که نشان داده شوند و در حالت STARTED قرار گیرند، دریافت نمیکنند.
  • اگر فرگمنتی که منتظر نتیجه است از قبل در حالت STARTED قرار گرفته باشد، متد Listener بلافاصله اجرا خواهد شد.

نکته: زمانی که یک Fragment به حالت DESTROYED رسیده باشد، دیگر نمیتوانید Listener برای آن تعریف کنید.


ارسال Result میان فرگمنت پدر و فرگمنت فرزند

ارسال داده بین فرگمنت پدر و فرزند

برای اینکه نتیجه ها را از فرگمنت فرزند به Fragment والد ارسال کنید، فرگمنت پدر، باید وقتی که متد setFragmentResultListener را صدا میزنیم، از getChildFragmentManager به جای getParentFragmentManager استفاده کنید. نمونه کد زیر را مشاهده کنید:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// We set the listener on the child fragmentManager
getChildFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() {
@Override
public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) {
String result = bundle.getString("bundleKey");
// Do something with the result..
}
});
}
ارسال داده بین فرگمنت والد و فرزند

فرگمنت فرزند نتیجه ها را درون FragmentManager خودش تنظیم میکند. سپس Fragment پدر وقتی که در حالت STARTED قرار گرفت، میتواند این نتیجه ها را دریافت کند. مثال زیر را مشاهده کنید:

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle result = new Bundle();
result.putString("bundleKey", "result");
// The child fragment needs to still set the result on its parent fragment manager
    getParentFragmentManager().setFragmentResult("requestKey", result);
}
});

تست کردن Result های گرفته شده

برای اینکه نتیجه های گرفته شده از setFragmentResult و setFragmentResultListener باید از FragmentScenario استفاده کنید. شما باید برای فرگمنتی که زیر تست قرار دارد، یک سناریو درست کنید. برای اینکار میتوانید از launchFragmentInContainer یا launchFragment استفاده کنید و سپس متدهای که در حال تست شدن نیستند را بصورت دستی صدا بزنید.

برای تست کردن setResultListener، یک سناریو با استفاده فرگمنتی که متد setResultListener را صدا میزند بسازید. بعد از آن باید setResult را مستقیما صدا بزنید و نتیجه ها را بررسی نمایید. مثال را در زیر مشاهده کنید:

@Test
fun testFragmentResultListener() {
val scenario = launchFragmentInContainer&amp;amp;lt;ResultListenerFragment>()
scenario.onFragment { fragment ->
val expectedResult = "result"
fragment.parentFragmentManagager.setResult("requestKey", bundleOf("bundleKey" to expectedResult))
assertThat(fragment.result).isEqualTo(expectedResult)
}
}

class ResultListenerFragment : Fragment() {
var result : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact
setResultListener("requestKey") { key, bundle ->
result = bundle.getString("bundleKey")
}
}
}

برای تست کردن setResult، باید یک سناریو با استفاده از فرگمنتی که متد setResult را صدا میزند بسازید. بعد از آن باید مستقیما متد setResultListener را صدا بزنید و نتیجه ها را بررسی کنید. مثال زیر را مشاهده کنید:

@Test
fun testFragmentResult() {
val scenario = launchFragmentInContainer<ResultFragment>()
lateinit var actualResult: String?
scenario.onFragment { fragment ->>
fragment.parentFragmentManagager.setResultListener("requestKey") { key, bundle ->>
actualResult = bundle.getString("bundleKey")
}
}
onView(withId(R.id.result_button)).perform(click())
assertThat(actualResult).isEqualTo("result")
}

class ResultFragment : Fragment(R.layout.fragment_result) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById(R.id.result_button).setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
}
}

سوالات خودتان را بپرسید

نظر شما درباره فرگمنت ها

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


منابع بیشتر برای مطالعه

میتوانید از منابع زیر برای مطالعه بیشتر درباره Fragment های اندروید استفاده کنید:

دیدگاه‌ خود را بنویسید

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

اسکرول به بالا