ফ্র্যাগমেন্ট ম্যানেজার

FragmentManager হল এমন ক্লাস যা আপনার অ্যাপের ফ্র্যাগমেন্টে অ্যাকশন পারফর্ম করার জন্য দায়ী, যেমন সেগুলি যোগ করা, সরানো বা পরিবর্তন করা এবং ব্যাক স্ট্যাকে যোগ করা।

আপনি Jetpack Navigation লাইব্রেরি ব্যবহার করলে, FragmentManager-এর সাথে সরাসরি ইন্টার‍্যাক্ট নাও করতে পারেন, কারণ এটি আপনার হয়ে FragmentManager-এর সাথে কাজ করে। তবে, ফ্র্যাগমেন্ট ব্যবহার করে এমন যেকোনও অ্যাপ কোনও না কোনও লেভেলে FragmentManager ব্যবহার করে, তাই এটি কী এবং কীভাবে কাজ করে তা বোঝা গুরুত্বপূর্ণ।

এই পৃষ্ঠায় নিম্নলিখিত বিষয়গুলি কভার করা হয়েছে:

  • কীভাবে FragmentManager অ্যাক্সেস করবেন।
  • আপনার অ্যাক্টিভিটি ও ফ্র্যাগমেন্টের সাথে সম্পর্কিত FragmentManager-এর ভূমিকা।
  • FragmentManager-এর মাধ্যমে কীভাবে ব্যাক স্ট্যাক ম্যানেজ করবেন।
  • আপনার ফ্র্যাগমেন্টে কীভাবে ডেটা ও ডিপেন্ডেন্সি প্রদান করবেন।

FragmentManager অ্যাক্সেস করা

আপনি কোনও অ্যাক্টিভিটি বা ফ্র্যাগমেন্ট থেকে FragmentManager অ্যাক্সেস করতে পারবেন।

FragmentActivity এবং এর সাবক্লাস, যেমন AppCompatActivity, getSupportFragmentManager() পদ্ধতির মাধ্যমে FragmentManager-এ অ্যাক্সেস আছে।

ফ্র্যাগমেন্ট এক বা একাধিক চাইল্ড ফ্র্যাগমেন্ট হোস্ট করতে পারে। ফ্র্যাগমেন্টের মধ্যে, আপনি FragmentManager-এর রেফারেন্স পেতে পারেন যা getChildFragmentManager()-এর মাধ্যমে ফ্র্যাগমেন্টের চাইল্ড ম্যানেজ করে। আপনাকে যদি এর হোস্ট FragmentManager অ্যাক্সেস করতে হয়, তাহলে আপনি getParentFragmentManager() ব্যবহার করতে পারবেন।

ফ্র্যাগমেন্ট, তাদের হোস্ট এবং প্রতিটির সাথে যুক্ত FragmentManager ইনস্ট্যান্সের মধ্যে সম্পর্ক দেখার জন্য এখানে কয়েকটি উদাহরণ দেওয়া হল।

দুটি UI লেআউটের উদাহরণ যা ফ্র্যাগমেন্ট এবং তাদের হোস্ট অ্যাক্টিভিটির মধ্যে সম্পর্ক দেখায়
ছবি ১. দুটি UI লেআউটের উদাহরণ যা ফ্র্যাগমেন্ট এবং তাদের হোস্ট অ্যাক্টিভিটির মধ্যে সম্পর্ক দেখায়।

ছবি ১-এ দুটি উদাহরণ দেখানো হয়েছে, যার প্রতিটিতে একটি করে অ্যাক্টিভিটি হোস্ট আছে। এই দুটি উদাহরণের হোস্ট অ্যাক্টিভিটি ব্যবহারকারীকে টপ-লেভেল নেভিগেশন দেখায় BottomNavigationView হিসেবে যা অ্যাপে বিভিন্ন স্ক্রিনের সাথে হোস্ট ফ্র্যাগমেন্ট সোয়্যাপ করার জন্য দায়ী। প্রতিটি স্ক্রিন আলাদা ফ্র্যাগমেন্ট হিসেবে প্রয়োগ করা হয়।

উদাহরণ ১-এ হোস্ট ফ্র্যাগমেন্ট দুটি চাইল্ড ফ্র্যাগমেন্ট হোস্ট করে যা একটি স্প্লিট-ভিউ স্ক্রিন তৈরি করে। উদাহরণ ২-এ হোস্ট ফ্র্যাগমেন্ট একটি সিঙ্গেল চাইল্ড ফ্র্যাগমেন্ট হোস্ট করে যা সোয়াইপ ভিউ-এর ডিসপ্লে ফ্র্যাগমেন্ট তৈরি করে।

এই সেট-আপের ক্ষেত্রে, আপনি প্রতিটি হোস্টকে এমনভাবে ভাবতে পারেন যার সাথে একটি FragmentManager যুক্ত আছে যা তার চাইল্ড ফ্র্যাগমেন্ট ম্যানেজ করে। এটি ছবি ২-এ supportFragmentManager, parentFragmentManager ও childFragmentManager-এর মধ্যে প্রপার্টি ম্যাপিংয়ের সাথে দেখানো হয়েছে।

প্রতিটি হোস্টের সাথে নিজস্ব FragmentManager যুক্ত থাকে
            যা তার চাইল্ড ফ্র্যাগমেন্ট ম্যানেজ করে
ছবি ২. প্রতিটি হোস্টের নিজস্ব FragmentManager আছে যা এর সাথে যুক্ত এবং এর চাইল্ড ফ্র্যাগমেন্ট ম্যানেজ করে।

রেফারেন্সের জন্য উপযুক্ত FragmentManager প্রপার্টি নির্ভর করে ফ্র্যাগমেন্ট হায়ারার্কিতে কলসাইট কোথায় আছে এবং আপনি কোন ফ্র্যাগমেন্ট ম্যানেজার অ্যাক্সেস করার চেষ্টা করছেন তার উপর।

FragmentManager-এর রেফারেন্স পেয়ে গেলে, ব্যবহারকারীকে দেখানো ফ্র্যাগমেন্ট ম্যানিপুলেট করতে আপনি এটি ব্যবহার করতে পারবেন।

চাইল্ড ফ্র্যাগমেন্ট

সাধারণত, আপনার অ্যাপে একটি বা অল্প সংখ্যক অ্যাক্টিভিটি থাকে, যেখানে প্রতিটি অ্যাক্টিভিটি সম্পর্কিত স্ক্রিনের একটি গ্রুপকে প্রতিনিধিত্ব করে। অ্যাক্টিভিটি টপ-লেভেল নেভিগেশন প্লেস করার জন্য একটি পয়েন্ট এবং ফ্র্যাগমেন্টের মধ্যে ViewModel অবজেক্ট ও অন্যান্য ভিউ-স্টেট স্কোপ করার জন্য একটি জায়গা প্রদান করতে পারে। ফ্র্যাগমেন্ট আপনার অ্যাপে একটি স্বতন্ত্র গন্তব্যকে দেখায়।

আপনি যদি একসাথে একাধিক ফ্র্যাগমেন্ট দেখাতে চান, যেমন স্প্লিট-ভিউ বা ড্যাশবোর্ডে, তাহলে আপনি চাইল্ড ফ্র্যাগমেন্ট ব্যবহার করতে পারেন যা আপনার ডেস্টিনেশন ফ্র্যাগমেন্ট এবং এর চাইল্ড ফ্র্যাগমেন্ট ম্যানেজার দ্বারা ম্যানেজ করা হয়।

চাইল্ড ফ্র্যাগমেন্টের অন্যান্য ব্যবহারের ক্ষেত্রগুলি নিচে দেওয়া হল:

  • স্ক্রিন স্লাইড, চাইল্ড ফ্র্যাগমেন্ট ভিউয়ের সিরিজ ম্যানেজ করতে পেরেন্ট ফ্র্যাগমেন্টে ViewPager2 ব্যবহার করা।
  • সম্পর্কিত স্ক্রিনের সেটের মধ্যে সাব-নেভিগেশন।
  • Jetpack Navigation, চাইল্ড ফ্র্যাগমেন্টকে আলাদা আলাদা গন্তব্য হিসেবে ব্যবহার করে। একটি অ্যাক্টিভিটি একটি সিঙ্গেল পেরেন্ট NavHostFragment হোস্ট করে এবং ব্যবহারকারীরা আপনার অ্যাপের মাধ্যমে নেভিগেট করার সাথে সাথে বিভিন্ন চাইল্ড ডেস্টিনেশন ফ্র্যাগমেন্ট দিয়ে এর স্পেস পূরণ করে।

FragmentManager ব্যবহার করুন

FragmentManager ফ্র্যাগমেন্ট ব্যাক স্ট্যাক ম্যানেজ করে। রানটাইমে, FragmentManager ব্যবহারকারীর ইন্টার‌্যাকশনের উত্তরে ফ্র্যাগমেন্ট যোগ করা বা সরানোর মতো ব্যাক স্ট্যাক অপারেশন পারফর্ম করতে পারে। পরিবর্তনের প্রতিটি সেট একক ইউনিট হিসেবে একসাথে কমিট করা হয়, যাকে FragmentTransaction বলা হয়। ফ্র্যাগমেন্ট ট্রানজ্যাকশন সম্পর্কে আরও বিস্তারিত আলোচনার জন্য, ফ্র্যাগমেন্ট ট্রানজ্যাকশন সংক্রান্ত নির্দেশিকা দেখুন।

ব্যবহারকারী তার ডিভাইসে ফিরে যাওয়ার বোতামে ট্যাপ করলে অথবা আপনি FragmentManager.popBackStack() কল করলে, সবচেয়ে উপরের ফ্র্যাগমেন্ট ট্রানজ্যাকশন স্ট্যাক থেকে পপ-অফ হয়ে যায়। স্ট্যাকে আর কোনও ফ্র্যাগমেন্ট ট্রানজ্যাকশন না থাকলে এবং আপনি চাইল্ড ফ্র্যাগমেন্ট ব্যবহার না করলে, Back ইভেন্ট অ্যাক্টিভিটিতে বাবল আপ করে। আপনি চাইল্ড ফ্র্যাগমেন্ট ব্যবহার করলে, চাইল্ড ও সিবলিং ফ্র্যাগমেন্টের জন্য বিশেষ বিবেচনার বিষয় দেখুন।

আপনি কোনও ট্রানজ্যাকশনে addToBackStack() কল করলে, ট্রানজ্যাকশনে যেকোনও সংখ্যক অপারেশন অন্তর্ভুক্ত থাকতে পারে, যেমন একাধিক ফ্র্যাগমেন্ট যোগ করা বা একাধিক কন্টেনারে ফ্র্যাগমেন্ট পরিবর্তন করা।

ব্যাক স্ট্যাক পপ করা হলে, এইসব অপারেশন একটি একক অ্যাটমিক অ্যাকশন হিসেবে রিভার্স হয়ে যায়। তবে, আপনি যদি popBackStack() কল করার আগে অতিরিক্ত ট্রানজ্যাকশন করে থাকেন এবং ট্রানজ্যাকশনের জন্য addToBackStack() ব্যবহার না করে থাকেন, তাহলে এইসব অপারেশন আগের অবস্থায় ফিরে যাবে না। তাই, একটি FragmentTransaction-এর মধ্যে, ব্যাক স্ট্যাককে প্রভাবিত করে এমন ট্রানজ্যাকশন এবং ব্যাক স্ট্যাককে প্রভাবিত করে না এমন ট্রানজ্যাকশন ইন্টারলিভ করা এড়িয়ে চলুন।

ট্রানজ্যাকশন করা

লেআউট কন্টেনারের মধ্যে ফ্র্যাগমেন্ট দেখাতে, FragmentTransaction তৈরি করতে FragmentManager ব্যবহার করুন। ট্রানজ্যাকশনের মধ্যে, আপনি কন্টেনারে add() বা replace() অপারেশন করতে পারবেন।

যেমন, একটি সাধারণ FragmentTransaction এইরকম দেখতে হতে পারে:

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack("name") // Name can be null
}

জাভা

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack("name") // Name can be null
    .commit();

এই উদাহরণে, ExampleFragment ফ্র্যাগমেন্টকে প্রতিস্থাপন করে, যদি থাকে, যা বর্তমানে R.id.fragment_container আইডি দ্বারা শনাক্ত করা লেআউট কন্টেনারে রয়েছে। replace() মেথডে ফ্র্যাগমেন্টের ক্লাস প্রদান করলে, FragmentManager-কে তার FragmentFactory ব্যবহার করে ইনস্ট্যান্টিয়েশন ম্যানেজ করতে দেয়। আরও তথ্যের জন্য, আপনার ফ্র্যাগমেন্টে ডিপেন্ডেন্সি প্রদান করুন বিভাগ দেখুন।

setReorderingAllowed(true) ট্রানজ্যাকশনে জড়িত ফ্র্যাগমেন্টের স্টেট পরিবর্তন অপ্টিমাইজ করে যাতে অ্যানিমেশন ও ট্রানজিশন সঠিকভাবে কাজ করে। অ্যানিমেশন ও ট্রানজিশন ব্যবহার করে নেভিগেট করার ব্যাপারে আরও তথ্য পেতে, ফ্র্যাগমেন্ট ট্রানজ্যাকশন এবং অ্যানিমেশন ব্যবহার করে ফ্র্যাগমেন্টের মধ্যে নেভিগেট করা দেখুন।

addToBackStack() কল করলে ট্রানজ্যাকশন ব্যাক স্ট্যাকে জমা হয়। ব্যবহারকারী পরে ট্রানজ্যাকশনটি বাতিল করতে পারেন এবং 'ফিরে যান' বোতামে ট্যাপ করে আগের ফ্র্যাগমেন্টে ফিরে যেতে পারেন। আপনি যদি একটি ট্রানজ্যাকশনের মধ্যে একাধিক ফ্র্যাগমেন্ট যোগ করেন বা সরিয়ে দেন, তাহলে ব্যাক স্ট্যাক পপ করা হলে সেইসব অপারেশন আগের অবস্থায় ফিরে যায়। addToBackStack() কলে দেওয়া ঐচ্ছিক নাম আপনাকে popBackStack() ব্যবহার করে নির্দিষ্ট ট্রানজ্যাকশনে ফিরে যাওয়ার সুবিধা দেয়।

আপনি কোনও ট্রানজ্যাকশন করার সময় addToBackStack()-এ কল না করলে, ফ্র্যাগমেন্ট সরিয়ে দেওয়া হয়, তারপর ট্রানজ্যাকশন সম্পূর্ণ হলে সরিয়ে দেওয়া ফ্র্যাগমেন্ট নষ্ট হয়ে যায় এবং ব্যবহারকারী আর সেখানে নেভিগেট করে ফিরে যেতে পারেন না। ফ্র্যাগমেন্ট সরানোর সময় আপনি addToBackStack() কল করলে, ফ্র্যাগমেন্টটি শুধুমাত্র STOPPED হয় এবং পরে ব্যবহারকারী ফিরে এলে RESUMED হয়। এই ক্ষেত্রে এর ভিউ নষ্ট হয়ে যায়। আরও তথ্যের জন্য, ফ্র্যাগমেন্ট লাইফসাইকেল দেখুন।

আগে থেকে থাকা ফ্র্যাগমেন্ট খুঁজুন

আপনি findFragmentById() ব্যবহার করে লেআউট কন্টেনারের মধ্যে বর্তমান ফ্র্যাগমেন্টের রেফারেন্স পেতে পারেন। XML থেকে ইনফ্লেট করা হলে প্রদত্ত আইডি দ্বারা অথবা FragmentTransaction-এ যোগ করা হলে কন্টেনার আইডি দ্বারা ফ্র্যাগমেন্ট খুঁজতে findFragmentById() ব্যবহার করুন। এখানে একটি উদাহরণ দেওয়া হল:

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack(null)
}
...
val fragment: ExampleFragment =
        supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment

জাভা

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();
...
ExampleFragment fragment =
        (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);

এছাড়াও, আপনি কোনও ফ্র্যাগমেন্টে একটি অনন্য ট্যাগ অ্যাসাইন করতে পারেন এবং findFragmentByTag() ব্যবহার করে রেফারেন্স পেতে পারেন। আপনি android:tag XML অ্যাট্রিবিউট ব্যবহার করে ফ্র্যাগমেন্টে ট্যাগ অ্যাসাইন করতে পারেন যা আপনার লেআউটে বা FragmentTransaction-এর মধ্যে add() বা replace() অপারেশন চলাকালীন সংজ্ঞায়িত করা হয়।

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container, "tag")
   setReorderingAllowed(true)
   addToBackStack(null)
}
...
val fragment: ExampleFragment =
        supportFragmentManager.findFragmentByTag("tag") as ExampleFragment

জাভা

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null, "tag")
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();
...
ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");

চাইল্ড ও সিবলিং ফ্র্যাগমেন্টের জন্য বিশেষ বিবেচনা

যেকোনও সময় শুধুমাত্র একটি FragmentManager ফ্র্যাগমেন্ট ব্যাক স্ট্যাক কন্ট্রোল করতে পারে। আপনার অ্যাপ স্ক্রিনে একই সময়ে একাধিক ফ্র্যাগমেন্ট দেখালে অথবা আপনার অ্যাপ চাইল্ড ফ্র্যাগমেন্ট ব্যবহার করলে, একটি FragmentManager আপনার অ্যাপের প্রাথমিক নেভিগেশন ম্যানেজ করার জন্য নির্দিষ্ট করা হয়।

ফ্র্যাগমেন্ট ট্রানজ্যাকশনের মধ্যে প্রাথমিক নেভিগেশন ফ্র্যাগমেন্ট সংজ্ঞায়িত করতে, ট্রানজ্যাকশনে setPrimaryNavigationFragment() মেথড কল করুন, ফ্র্যাগমেন্টের ইনস্ট্যান্স পাস করুন যার childFragmentManager-এর প্রাথমিক কন্ট্রোল আছে।

নেভিগেশন স্ট্রাকচারকে একাধিক লেয়ারের সিরিজ হিসেবে বিবেচনা করুন, যেখানে অ্যাক্টিভিটি সবচেয়ে বাইরের লেয়ার হিসেবে কাজ করে এবং এর নিচে চাইল্ড ফ্র্যাগমেন্টের প্রতিটি লেয়ারকে র‍্যাপ করে। প্রতিটি লেয়ারে একটিই প্রাথমিক নেভিগেশন ফ্র্যাগমেন্ট থাকে।

ফিরে যাওয়ার ইভেন্ট ঘটলে, সবচেয়ে ভিতরের লেয়ার নেভিগেশন আচরণ নিয়ন্ত্রণ করে। সবচেয়ে ভিতরের লেয়ারে আর কোনও ফ্র্যাগমেন্ট ট্রানজ্যাকশন না থাকলে, কন্ট্রোল পরবর্তী লেয়ারে ফিরে আসে এবং আপনি অ্যাক্টিভিটিতে না পৌঁছানো পর্যন্ত এই প্রসেস চলতে থাকে।

একই সময়ে দুই বা তার বেশি ফ্র্যাগমেন্ট দেখানো হলে, সেগুলির মধ্যে শুধুমাত্র একটিই প্রাইমারি নেভিগেশন ফ্র্যাগমেন্ট হয়। একটি ফ্র্যাগমেন্টকে প্রাথমিক নেভিগেশন ফ্র্যাগমেন্ট হিসেবে সেট করলে আগের ফ্র্যাগমেন্ট থেকে ডেজিগনেশন সরিয়ে দেওয়া হয়। আগের উদাহরণ ব্যবহার করে, আপনি যদি ডিটেল ফ্র্যাগমেন্টকে প্রাথমিক নেভিগেশন ফ্র্যাগমেন্ট হিসেবে সেট করেন, তাহলে মূল ফ্র্যাগমেন্টের ডেজিগনেশন সরিয়ে দেওয়া হয়।

একাধিক ব্যাক স্ট্যাক কাজ করে

কিছু ক্ষেত্রে, আপনার অ্যাপে একাধিক ব্যাক স্ট্যাকের প্রয়োজন হতে পারে। একটি সাধারণ উদাহরণ হল, আপনার অ্যাপ যদি নিচের দিকে নেভিগেশন বার ব্যবহার করে। FragmentManager-এর মাধ্যমে আপনি saveBackStack() ও restoreBackStack() পদ্ধতির সাহায্যে একাধিক ব্যাক স্ট্যাক সাপোর্ট করতে পারবেন। এইসব পদ্ধতি আপনাকে একটি ব্যাক স্ট্যাক সেভ করে এবং অন্য একটি রিস্টোর করে ব্যাক স্ট্যাকের মধ্যে অদলবদল করতে দেয়।

saveBackStack(), ঐচ্ছিক name প্যারামিটার সহ popBackStack() কল করার মতোই কাজ করে: নির্দিষ্ট ট্রানজ্যাকশন এবং স্ট্যাকে এর পরে থাকা সব ট্রানজ্যাকশন পপ করা হয়। পার্থক্য হল যে saveBackStack() পপ-আপ করা ট্রানজ্যাকশনে সব ফ্র্যাগমেন্টের স্টেট সেভ করে।

যেমন, ধরুন আপনি আগে addToBackStack() ব্যবহার করে FragmentTransaction কমিট করার মাধ্যমে ব্যাক স্ট্যাকে ফ্র্যাগমেন্ট যোগ করেছেন, নিচের উদাহরণে যেমন দেখানো হয়েছে:

Kotlin

supportFragmentManager.commit {
  replace<ExampleFragment>(R.id.fragment_container)
  setReorderingAllowed(true)
  addToBackStack("replacement")
}

জাভা

supportFragmentManager.beginTransaction()
  .replace(R.id.fragment_container, ExampleFragment.class, null)
  // setReorderingAllowed(true) and the optional string argument for
  // addToBackStack() are both required if you want to use saveBackStack()
  .setReorderingAllowed(true)
  .addToBackStack("replacement")
  .commit();

সেক্ষেত্রে, আপনি saveBackStack()-এ কল করে এই ফ্র্যাগমেন্ট ট্রানজ্যাকশন এবং ExampleFragment-এর স্ট্যাটাস সেভ করতে পারবেন:

Kotlin

supportFragmentManager.saveBackStack("replacement")

জাভা

supportFragmentManager.saveBackStack("replacement");

আপনি একই নামের প্যারামিটার সহ restoreBackStack() কল করতে পারেন যাতে পপ-আপ করা সব ট্রানজ্যাকশন এবং সেভ করা সব ফ্র্যাগমেন্ট স্টেট ফিরিয়ে আনা যায়:

Kotlin

supportFragmentManager.restoreBackStack("replacement")

জাভা

supportFragmentManager.restoreBackStack("replacement");

আপনার ফ্র্যাগমেন্টে ডিপেন্ডেন্সি প্রদান করুন

ফ্র্যাগমেন্ট যোগ করার সময়, আপনি ম্যানুয়ালি ফ্র্যাগমেন্ট ইনস্ট্যান্টিয়েট করতে এবং FragmentTransaction-এ যোগ করতে পারবেন।

Kotlin

fragmentManager.commit {
    // Instantiate a new instance before adding
    val myFragment = ExampleFragment()
    add(R.id.fragment_view_container, myFragment)
    setReorderingAllowed(true)
}

জাভা

// Instantiate a new instance before adding
ExampleFragment myFragment = new ExampleFragment();
fragmentManager.beginTransaction()
    .add(R.id.fragment_view_container, myFragment)
    .setReorderingAllowed(true)
    .commit();

আপনি ফ্র্যাগমেন্ট ট্রানজ্যাকশন কমিট করলে, আপনার তৈরি করা ফ্র্যাগমেন্টের ইনস্ট্যান্সই ইনস্ট্যান্স হিসেবে ব্যবহার করা হয়। তবে, কনফিগারেশন পরিবর্তন করার সময়, আপনার অ্যাক্টিভিটি এবং এর সব ফ্র্যাগমেন্ট নষ্ট হয়ে যায় এবং তারপর সবচেয়ে উপযুক্ত Android রিসোর্স দিয়ে আবার তৈরি করা হয়। FragmentManager আপনার জন্য এই সব কিছু ম্যানেজ করে: এটি আপনার ফ্র্যাগমেন্টের ইনস্ট্যান্স আবার তৈরি করে, সেগুলিকে হোস্টের সাথে অ্যাটাচ করে এবং ব্যাক স্ট্যাক স্টেট আবার তৈরি করে।

ডিফল্ট হিসেবে, FragmentManager একটি FragmentFactory ব্যবহার করে যা ফ্রেমওয়ার্ক আপনার ফ্র্যাগমেন্টের নতুন ইনস্ট্যান্স ইনস্ট্যান্টিয়েট করার জন্য প্রদান করে। এই ডিফল্ট ফ্যাক্টরি আপনার ফ্র্যাগমেন্টের জন্য কোনও আর্গুমেন্ট নেই এমন কনস্ট্রাক্টর খুঁজে পেতে এবং আহ্বান করতে রিফ্লেকশন ব্যবহার করে। এর অর্থ হল, আপনার ফ্র্যাগমেন্টে ডিপেন্ডেন্সি প্রদান করার জন্য আপনি এই ডিফল্ট ফ্যাক্টরি ব্যবহার করতে পারবেন না। এর অর্থ হল, প্রথমবার ফ্র্যাগমেন্ট তৈরি করার জন্য আপনি যে কাস্টম কনস্ট্রাক্টর ব্যবহার করেছিলেন, ডিফল্ট হিসেবে সেটি আবার তৈরি করার সময় ব্যবহার করা হয় না।

আপনার ফ্র্যাগমেন্টে ডিপেন্ডেন্সি প্রদান করতে অথবা কোনও কাস্টম কনস্ট্রাক্টর ব্যবহার করতে, পরিবর্তে একটি কাস্টম FragmentFactory সাবক্লাস তৈরি করুন এবং তারপরে FragmentFactory.instantiate ওভাররাইড করুন। আপনি FragmentManager-এর ডিফল্ট ফ্যাক্টরি ওভাররাইড করে আপনার কাস্টম ফ্যাক্টরি ব্যবহার করতে পারবেন, যা আপনার ফ্র্যাগমেন্ট ইনস্ট্যান্টিয়েট করতে ব্যবহার করা হয়।

ধরুন, আপনার একটি DessertsFragment আছে যা আপনার হোমটাউনে জনপ্রিয় ডেজার্ট দেখানোর জন্য দায়ী এবং সেই DessertsFragment-এর একটি DessertsRepository ক্লাসের উপর নির্ভরতা আছে যা এটিকে আপনার ব্যবহারকারীকে সঠিক UI দেখানোর জন্য প্রয়োজনীয় তথ্য প্রদান করে।

আপনি হয়ত আপনার DessertsFragment-কে এমনভাবে সংজ্ঞায়িত করতে পারেন যাতে এর কনস্ট্রাক্টরে একটি DessertsRepository ইনস্ট্যান্সের প্রয়োজন হয়।

Kotlin

class DessertsFragment(val dessertsRepository: DessertsRepository) : Fragment() {
    ...
}

জাভা

public class DessertsFragment extends Fragment {
    private DessertsRepository dessertsRepository;

    public DessertsFragment(DessertsRepository dessertsRepository) {
        super();
        this.dessertsRepository = dessertsRepository;
    }

    // Getter omitted.

    ...
}

আপনার FragmentFactory-এর একটি সহজ ইমপ্লিমেন্টেশন নিম্নলিখিতটির মতো দেখতে হতে পারে।

Kotlin

class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment =
            when (loadFragmentClass(classLoader, className)) {
                DessertsFragment::class.java -> DessertsFragment(repository)
                else -> super.instantiate(classLoader, className)
            }
}

জাভা

public class MyFragmentFactory extends FragmentFactory {
    private DessertsRepository repository;

    public MyFragmentFactory(DessertsRepository repository) {
        super();
        this.repository = repository;
    }

    @NonNull
    @Override
    public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
        Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className);
        if (fragmentClass == DessertsFragment.class) {
            return new DessertsFragment(repository);
        } else {
            return super.instantiate(classLoader, className);
        }
    }
}

এই উদাহরণটি FragmentFactory-এর সাবক্লাস, যা DessertsFragment-এর জন্য কাস্টম ফ্র্যাগমেন্ট তৈরির লজিক প্রদান করতে instantiate() পদ্ধতিকে ওভাররাইড করে। অন্যান্য ফ্র্যাগমেন্ট ক্লাস FragmentFactory-এর ডিফল্ট অ্যাকশন দ্বারা super.instantiate()-এর মাধ্যমে ম্যানেজ করা হয়।

এরপর আপনি FragmentManager-এ একটি প্রপার্টি সেট করে আপনার অ্যাপের ফ্র্যাগমেন্ট তৈরি করার সময় ব্যবহার করার জন্য ফ্যাক্টরি হিসেবে MyFragmentFactory-কে মনোনীত করতে পারবেন। আপনার অ্যাক্টিভিটির super.onCreate()-এর আগে আপনাকে অবশ্যই এই প্রপার্টি সেট করতে হবে যাতে আপনার ফ্র্যাগমেন্ট আবার তৈরি করার সময় MyFragmentFactory ব্যবহার করা হয়।

Kotlin

class MealActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance())
        super.onCreate(savedInstanceState)
    }
}

জাভা

public class MealActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        DessertsRepository repository = DessertsRepository.getInstance();
        getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository));
        super.onCreate(savedInstanceState);
    }
}

অ্যাক্টিভিটিতে FragmentFactory সেট করলে, অ্যাক্টিভিটির ফ্র্যাগমেন্ট হায়ারার্কি জুড়ে ফ্র্যাগমেন্ট তৈরি ওভাররাইড করে। অন্যভাবে বলতে গেলে, আপনি যোগ করেন এমন যেকোনও চাইল্ড ফ্র্যাগমেন্টের childFragmentManager, এখানে সেট করা কাস্টম ফ্র্যাগমেন্ট ফ্যাক্টরি ব্যবহার করে, যদি না নিচের লেভেলে ওভাররাইড করা হয়।

FragmentFactory-এর মাধ্যমে টেস্ট করুন

সিঙ্গল অ্যাক্টিভিটি আর্কিটেকচারে, FragmentScenario ক্লাস ব্যবহার করে আইসোলেশনে আপনার ফ্র্যাগমেন্ট টেস্ট করুন। আপনার অ্যাক্টিভিটির কাস্টম onCreate লজিকের উপর নির্ভর করতে পারবেন না বলে, পরিবর্তে আপনি ফ্র্যাগমেন্ট টেস্টের আর্গুমেন্ট হিসেবে FragmentFactory পাস করতে পারবেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

// Inside your test
val dessertRepository = mock(DessertsRepository::class.java)
launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment {
    // Test Fragment logic
}

এই টেস্টিং প্রসেস সম্পর্কে বিস্তারিত তথ্য এবং সম্পূর্ণ উদাহরণের জন্য, আপনার ফ্র্যাগমেন্ট টেস্ট করুন দেখুন।