আপনার টুকরা ডিবাগ করুন

এই নির্দেশিকাটি এমন সরঞ্জামগুলিকে কভার করে যা আপনি আপনার টুকরোগুলি ডিবাগ করতে ব্যবহার করতে পারেন৷

ফ্র্যাগমেন্ট ম্যানেজার লগিং

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

আপনি নিম্নলিখিত adb shell কমান্ড ব্যবহার করে লগিং সক্ষম করতে পারেন:

adb shell setprop log.tag.FragmentManager DEBUG

বিকল্পভাবে, আপনি নিম্নরূপ ভার্বোজ লগিং সক্ষম করতে পারেন:

adb shell setprop log.tag.FragmentManager VERBOSE

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

ডিবাগ লগিং

DEBUG স্তরে, FragmentManager সাধারণত লাইফসাইকেল স্টেট পরিবর্তনের সাথে সম্পর্কিত লগ বার্তা নির্গত করে। প্রতিটি লগ এন্ট্রিতে Fragment থেকে toString() ডাম্প থাকে। একটি লগ এন্ট্রি নিম্নলিখিত তথ্য নিয়ে গঠিত:

  • Fragment ইনস্ট্যান্সের সহজ ক্লাস নাম।
  • Fragment ইনস্ট্যান্সের আইডেন্টিটি হ্যাশ কোড
  • Fragment ইনস্ট্যান্সের ফ্র্যাগমেন্ট ম্যানেজারের অনন্য আইডি। এটি কনফিগারেশন পরিবর্তন এবং প্রক্রিয়া মৃত্যু এবং বিনোদন জুড়ে স্থিতিশীল।
  • যে কন্টেইনারে Fragment যোগ করা হয়েছে তার আইডি, কিন্তু শুধুমাত্র সেট করলে।
  • Fragment ট্যাগ, কিন্তু শুধুমাত্র যদি সেট করা থাকে।

নিম্নলিখিত একটি নমুনা DEBUG লগ এন্ট্রি:

D/FragmentManager: moveto ATTACHED: NavHostFragment{92d8f1d} (fd92599e-c349-4660-b2d6-0ece9ec72f7b id=0x7f080116)
  • Fragment ক্লাস হল NavHostFragment
  • আইডেন্টিটি হ্যাশ কোড হল 92d8f1d
  • অনন্য ID হল fd92599e-c349-4660-b2d6-0ece9ec72f7b
  • কন্টেইনার আইডি হল 0x7f080116
  • ট্যাগটি বাদ দেওয়া হয়েছে কারণ কোনোটিই সেট করা হয়নি৷ উপস্থিত হলে, এটি tag=tag_value ফরম্যাটে আইডি অনুসরণ করে।

সংক্ষিপ্ততা এবং পঠনযোগ্যতার জন্য, নিম্নলিখিত উদাহরণগুলিতে UUID গুলি ছোট করা হয়েছে।

এখানে একটি NavHostFragment আরম্ভ করা হচ্ছে এবং তারপর FirstFragment টাইপের স্টার্ট startDestination Fragment তৈরি করা হচ্ছে এবং RESUMED অবস্থায় রূপান্তরিত হচ্ছে:

D/FragmentManager: moveto ATTACHED: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager:   mName=null mIndex=-1 mCommitted=false
D/FragmentManager:   Operations:
D/FragmentManager:     Op #0: SET_PRIMARY_NAV NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATED: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager:   mName=null mIndex=-1 mCommitted=false
D/FragmentManager:   Operations:
D/FragmentManager:     Op #0: REPLACE FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager:     Op #1: SET_PRIMARY_NAV FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto ATTACHED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATE_VIEW: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATE_VIEW: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto ACTIVITY_CREATED: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESTORE_VIEW_STATE: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto ACTIVITY_CREATED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESTORE_VIEW_STATE: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto STARTED: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto STARTED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESUMED: NavHostFragment{92d8f1d} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESUMED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)

ব্যবহারকারীর মিথস্ক্রিয়া অনুসরণ করে, বিভিন্ন জীবনচক্র অবস্থার বাইরে FirstFragment স্থানান্তরিত হয়। তারপর SecondFragment ইনস্ট্যান্ট করা হয় এবং RESUMED অবস্থায় ট্রানজিশন হয়:

D/FragmentManager:   mName=07c8a5e8-54a3-4e21-b2cc-c8efc37c4cf5 mIndex=-1 mCommitted=false
D/FragmentManager:   Operations:
D/FragmentManager:     Op #0: REPLACE SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager:     Op #1: SET_PRIMARY_NAV SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: movefrom RESUMED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: movefrom STARTED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: movefrom ACTIVITY_CREATED: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto ATTACHED: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATED: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: moveto CREATE_VIEW: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: moveto ACTIVITY_CREATED: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESTORE_VIEW_STATE: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: moveto STARTED: SecondFragment{84132db} (<UUID> id=0x7f080116)
D/FragmentManager: movefrom CREATE_VIEW: FirstFragment{ccd2189} (<UUID> id=0x7f080116)
D/FragmentManager: moveto RESUMED: SecondFragment{84132db} (<UUID> id=0x7f080116)

সমস্ত Fragment দৃষ্টান্ত একটি শনাক্তকারী দ্বারা প্রত্যয়িত হয় যাতে আপনি একই Fragment শ্রেণীর বিভিন্ন দৃষ্টান্ত ট্র্যাক করতে পারেন।

ভার্বোস লগিং

VERBOSE স্তরে, FragmentManager সাধারণত তার অভ্যন্তরীণ অবস্থা সম্পর্কে লগ বার্তা নির্গত করে:

V/FragmentManager: Run: BackStackEntry{f9d3ff3}
V/FragmentManager: add: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: Added fragment to active set NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto ATTACHED: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: Commit: BackStackEntry{5cfd2ae}
D/FragmentManager:   mName=null mIndex=-1 mCommitted=false
D/FragmentManager:   Operations:
D/FragmentManager:     Op #0: SET_PRIMARY_NAV NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto CREATED: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: Commit: BackStackEntry{e93833f}
D/FragmentManager:   mName=null mIndex=-1 mCommitted=false
D/FragmentManager:   Operations:
D/FragmentManager:     Op #0: REPLACE FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager:     Op #1: SET_PRIMARY_NAV FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: Run: BackStackEntry{e93833f}
V/FragmentManager: add: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: Added fragment to active set FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto ATTACHED: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto CREATED: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 1 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto CREATE_VIEW: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 2 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto CREATE_VIEW: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 2 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 2 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto ACTIVITY_CREATED: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto RESTORE_VIEW_STATE: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto ACTIVITY_CREATED: FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto RESTORE_VIEW_STATE: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: SpecialEffectsController: Enqueuing add operation for fragment FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: SpecialEffectsController: For fragment FirstFragment{886440c} (<UUID> id=0x7f080130) mFinalState = VISIBLE -> VISIBLE.
V/FragmentManager: SpecialEffectsController: Container androidx.fragment.app.FragmentContainerView{7578ffa V.E...... ......I. 0,0-0,0 #7f080130 app:id/nav_host_fragment_content_fragment} is not attached to window. Cancelling pending operation Operation {382a9ab} {mFinalState = VISIBLE} {mLifecycleImpact = ADDING} {mFragment = FirstFragment{886440c} (<UUID> id=0x7f080130)}
V/FragmentManager: SpecialEffectsController: Operation {382a9ab} {mFinalState = VISIBLE} {mLifecycleImpact = ADDING} {mFragment = FirstFragment{886440c} (<UUID> id=0x7f080130)} has called complete.
V/FragmentManager: SpecialEffectsController: Setting view androidx.constraintlayout.widget.ConstraintLayout{3968808 I.E...... ......I. 0,0-0,0} to VISIBLE
V/FragmentManager: computeExpectedState() of 4 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: SpecialEffectsController: Enqueuing add operation for fragment NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: SpecialEffectsController: For fragment NavHostFragment{86274b0} (<UUID> id=0x7f080130) mFinalState = VISIBLE -> VISIBLE.
V/FragmentManager: SpecialEffectsController: Container androidx.fragment.app.FragmentContainerView{2ba8ba1 V.E...... ......I. 0,0-0,0 #7f080130 app:id/nav_host_fragment_content_fragment} is not attached to window. Cancelling pending operation Operation {f7eb1c6} {mFinalState = VISIBLE} {mLifecycleImpact = ADDING} {mFragment = NavHostFragment{86274b0} (<UUID> id=0x7f080130)}
V/FragmentManager: SpecialEffectsController: Operation {f7eb1c6} {mFinalState = VISIBLE} {mLifecycleImpact = ADDING} {mFragment = NavHostFragment{86274b0} (<UUID> id=0x7f080130)} has called complete.
V/FragmentManager: SpecialEffectsController: Setting view androidx.fragment.app.FragmentContainerView{7578ffa I.E...... ......I. 0,0-0,0 #7f080130 app:id/nav_host_fragment_content_fragment} to VISIBLE
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: Run: BackStackEntry{5cfd2ae}
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 4 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto STARTED: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto STARTED: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 5 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
D/FragmentManager: moveto RESUMED: NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for FirstFragment{886440c} (<UUID> id=0x7f080130)
D/FragmentManager: moveto RESUMED: FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for FirstFragment{886440c} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)
V/FragmentManager: computeExpectedState() of 7 for NavHostFragment{86274b0} (<UUID> id=0x7f080130)

এই উদাহরণটি শুধুমাত্র FirstFragment এ লোডিং কভার করে। SecondFragment রূপান্তর সহ লগ এন্ট্রিগুলিকে যথেষ্ট পরিমাণে বৃদ্ধি করে। VERBOSE লেভেলের অনেক লগ মেসেজ অ্যাপ ডেভেলপারদের জন্য খুব কম কাজে লাগে। যাইহোক, ব্যাক স্ট্যাকের পরিবর্তন কখন ঘটে তা দেখা কিছু সমস্যা ডিবাগ করতে সাহায্য করতে পারে।

খণ্ডের জন্য কঠোর মোড

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

একটি কাস্টম Policy নির্ধারণ করে যে কোন লঙ্ঘনগুলি সনাক্ত করা হবে এবং লঙ্ঘন শনাক্ত হলে কোন শাস্তি প্রয়োগ করা হবে তা নির্দিষ্ট করে৷

একটি কাস্টম StrictMode নীতি প্রয়োগ করতে, এটি FragmentManager এ বরাদ্দ করুন৷ যত তাড়াতাড়ি সম্ভব এটি করুন। এই ক্ষেত্রে, আপনি এটি একটি init ব্লকে বা জাভা কনস্ট্রাক্টরে করেন:

কোটলিন

class ExampleActivity : AppCompatActivity() {

    init {
        supportFragmentManager.strictModePolicy =
            FragmentStrictMode.Policy.Builder()
                .penaltyDeath()
                .detectFragmentReuse()
                .allowViolation(FirstFragment::class.java,
                                FragmentReuseViolation::class.java)
                .build()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ...
   }
}

জাভা

class ExampleActivity extends AppCompatActivity() {

    ExampleActivity() {
        getSupportFragmentManager().setStrictModePolicy(
                new FragmentStrictMode.Policy.Builder()
                        .penaltyDeath()
                        .detectFragmentReuse()
                        .allowViolation(FirstFragment.class,
                                        FragmentReuseViolation.class)
                        .build()
        );
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)

        ActivityExampleBinding binding =
            ActivityExampleBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        ...
   }
}

যে ক্ষেত্রে আপনাকে স্ট্রিকমোড সক্ষম করতে হবে কিনা তা নির্ধারণ করার জন্য Context জানতে হবে, যেমন একটি বুলিয়ান রিসোর্সের মান থেকে, আপনি একটি OnContextAvailableListener ব্যবহার করে FragmentManager একটি কঠোর মোড নীতি নির্ধারণ করা পিছিয়ে দিতে পারেন:

কোটলিন

class ExampleActivity : AppCompatActivity() {

    init {
        addOnContextAvailableListener { context ->
            if(context.resources.getBoolean(R.bool.enable_strict_mode)) {
                supportFragmentManager.strictModePolicy = FragmentStrictMode.Policy.Builder()
                    .penaltyDeath()
                    .detectFragmentReuse()
                    .allowViolation(FirstFragment::class.java, FragmentReuseViolation::class.java)
                    .build()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ...
   }
}

জাভা

class ExampleActivity extends AppCompatActivity() {

    ExampleActivity() {
        addOnContextAvailableListener((context) -> {
            if(context.getResources().getBoolean(R.bool.enable_strict_mode)) {
                getSupportFragmentManager().setStrictModePolicy(
                        new FragmentStrictMode.Policy.Builder()
                                .penaltyDeath()
                                .detectFragmentReuse()
                                .allowViolation(FirstFragment.class, FragmentReuseViolation.class)
                                .build()
                );
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)

        ActivityExampleBinding binding = ActivityExampleBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        ...
   }
}

সর্বশেষ বিন্দু যেখানে আপনি সমস্ত সম্ভাব্য লঙ্ঘন ধরার জন্য StrictMode কনফিগার করতে পারেন তা হল onCreate() , super.onCreate() এ কল করার আগে :

কোটলিন

class ExampleActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.strictModePolicy = FragmentStrictMode.Policy.Builder()
            .penaltyDeath()
            .detectFragmentReuse()
            .allowViolation(FirstFragment::class.java, FragmentReuseViolation::class.java)
            .build()

        super.onCreate(savedInstanceState)

        val binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ...
   }
}

জাভা

class ExampleActivity extends AppCompatActivity() {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getSupportFragmentManager().setStrictModePolicy(
                new FragmentStrictMode.Policy.Builder()
                        .penaltyDeath()
                        .detectFragmentReuse()
                        .allowViolation(FirstFragment.class, FragmentReuseViolation.class)
                        .build()
                );

        super.onCreate(savedInstanceState)

        ActivityExampleBinding binding = ActivityExampleBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        ...
   }
}

এই উদাহরণগুলিতে ব্যবহৃত এই নীতি শুধুমাত্র টুকরো পুনঃব্যবহারের লঙ্ঘন শনাক্ত করে এবং যখনই একটি ঘটে তখন অ্যাপটি বন্ধ হয়ে যায়। penaltyDeath() ডিবাগ বিল্ডে সহায়ক হতে পারে কারণ এটি যথেষ্ট দ্রুত ব্যর্থ হয় যে আপনি লঙ্ঘন উপেক্ষা করতে পারবেন না।

এটি নির্বাচিতভাবে নির্দিষ্ট লঙ্ঘনের অনুমতি দেওয়াও সম্ভব। পূর্ববর্তী উদাহরণে ব্যবহৃত নীতি, যাইহোক, এই লঙ্ঘনটি অন্যান্য সমস্ত টুকরো ধরনের জন্য প্রয়োগ করে৷ এটি এমন ক্ষেত্রে উপযোগী যেখানে তৃতীয় পক্ষের লাইব্রেরি উপাদানে StrictMode লঙ্ঘন থাকতে পারে।

এই ধরনের ক্ষেত্রে, লাইব্রেরি তাদের লঙ্ঘন ঠিক না করা পর্যন্ত আপনি অস্থায়ীভাবে সেই লঙ্ঘনগুলিকে আপনার স্ট্রিক্টমোডের অনুমোদিত তালিকায় যোগ করতে পারেন যেগুলি আপনার মালিকানাধীন নয়।

অন্যান্য লঙ্ঘনগুলি কীভাবে কনফিগার করবেন সে সম্পর্কে বিশদ বিবরণের জন্য, FragmentStrictMode.Policy.Builder এর ডকুমেন্টেশন দেখুন।

পেনাল্টি তিন প্রকার।

  • penaltyLog() Logcat এ লঙ্ঘনের বিবরণ ডাম্প করে।
  • penaltyDeath() লঙ্ঘন সনাক্ত করা হলে অ্যাপটি বন্ধ করে দেয়।
  • penaltyListener() আপনাকে একটি কাস্টম শ্রোতা যোগ করতে দেয় যা যখনই লঙ্ঘন সনাক্ত করা হয় তখন বলা হয়।

আপনি আপনার Policy জরিমানার যেকোন সমন্বয় প্রয়োগ করতে পারেন। যদি আপনার নীতি স্পষ্টভাবে একটি পেনাল্টি নির্দিষ্ট না করে, penaltyLog() এর একটি ডিফল্ট প্রয়োগ করা হয়। আপনি যদি আপনার কাস্টম Policy penaltyLog() ছাড়া অন্য কোনো শাস্তি প্রয়োগ করেন, তাহলে penaltyLog() নিষ্ক্রিয় করা হবে যদি না আপনি এটি স্পষ্টভাবে সেট করেন।

penaltyListener() উপযোগী হতে পারে যখন আপনার কাছে তৃতীয় পক্ষের লগিং লাইব্রেরি থাকে যেখানে আপনি লঙ্ঘন লগ করতে চান। বিকল্পভাবে, আপনি রিলিজ বিল্ডগুলিতে নন-ফ্যাটাল লঙ্ঘন ক্যাচিং সক্ষম করতে এবং একটি ক্র্যাশ রিপোর্টিং লাইব্রেরিতে লগ করতে চাইতে পারেন। এই কৌশল লঙ্ঘন সনাক্ত করতে পারে অন্যথায় মিস.

একটি বিশ্বব্যাপী StrictMode নীতি সেট করতে, একটি ডিফল্ট নীতি সেট করুন যা FragmentStrictMode.setDefaultPolicy() পদ্ধতি ব্যবহার করে সমস্ত FragmentManager দৃষ্টান্তে প্রযোজ্য:

কোটলিন

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        FragmentStrictMode.defaultPolicy =
            FragmentStrictMode.Policy.Builder()
                .detectFragmentReuse()
                .detectFragmentTagUsage()
                .detectRetainInstanceUsage()
                .detectSetUserVisibleHint()
                .detectTargetFragmentUsage()
                .detectWrongFragmentContainer()
                .apply {
                    if (BuildConfig.DEBUG) {
                        // Fail early on DEBUG builds
                        penaltyDeath()
                    } else {
                        // Log to Crashlytics on RELEASE builds
                        penaltyListener {
                            FirebaseCrashlytics.getInstance().recordException(it)
                        }
                    }
                }
                .build()
    }
}

জাভা

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        FragmentStrictMode.Policy.Builder builder = new FragmentStrictMode.Policy.Builder();
        builder.detectFragmentReuse()
                .detectFragmentTagUsage()
                .detectRetainInstanceUsage()
                .detectSetUserVisibleHint()
                .detectTargetFragmentUsage()
                .detectWrongFragmentContainer();
        if (BuildConfig.DEBUG) {
            // Fail early on DEBUG builds
            builder.penaltyDeath();
        } else {
            // Log to Crashlytics on RELEASE builds
            builder.penaltyListener((exception) ->
                    FirebaseCrashlytics.getInstance().recordException(exception)
            );
        }
        FragmentStrictMode.setDefaultPolicy(builder.build());
    }
}

নিম্নলিখিত বিভাগগুলি লঙ্ঘনের ধরন এবং সম্ভাব্য সমাধানগুলি বর্ণনা করে৷

খণ্ড পুনঃব্যবহার

detectFragmentReuse() ব্যবহার করে ফ্র্যাগমেন্ট পুনঃব্যবহার লঙ্ঘন সক্ষম করা হয়েছে এবং একটি FragmentReuseViolation নিক্ষেপ করে।

এই লঙ্ঘনটি FragmentManager থেকে অপসারণের পরে একটি Fragment উদাহরণের পুনঃব্যবহারের নির্দেশ করে৷ এই পুনঃব্যবহার সমস্যা সৃষ্টি করতে পারে কারণ Fragment তার আগের ব্যবহার থেকে অবস্থা ধরে রাখতে পারে এবং ধারাবাহিকভাবে আচরণ করতে পারে না। আপনি যদি প্রতিবার একটি নতুন উদাহরণ তৈরি করেন, FragmentManager এ যোগ করার সময় এটি সর্বদা প্রাথমিক অবস্থায় থাকে।

ফ্র্যাগমেন্ট ট্যাগ ব্যবহার

ফ্র্যাগমেন্ট ট্যাগ ব্যবহার লঙ্ঘন detectFragmentTagUsage() ব্যবহার করে সক্ষম করা হয়েছে এবং একটি FragmentTagUsageViolation নিক্ষেপ করে।

এই লঙ্ঘনটি নির্দেশ করে যে একটি XML লেআউটে <fragment> ট্যাগ ব্যবহার করে একটি Fragment স্ফীত হয়েছে। এটি সমাধান করার জন্য, আপনার Fragment <fragment> ট্যাগের পরিবর্তে <androidx.fragment.app.FragmentContainerView> এর ভিতরে স্ফীত করুন। একটি FragmentContainerView ব্যবহার করে স্ফীত টুকরাগুলি Fragment লেনদেন এবং কনফিগারেশন পরিবর্তনগুলি নির্ভরযোগ্যভাবে পরিচালনা করতে পারে। আপনি যদি পরিবর্তে <fragment> ট্যাগ ব্যবহার করেন তবে এটি প্রত্যাশিত হিসাবে কাজ নাও করতে পারে।

দৃষ্টান্ত ব্যবহার বজায় রাখুন

detectRetainInstanceUsage() ব্যবহার করে রিটেন ইনস্ট্যান্স ব্যবহার লঙ্ঘন সক্ষম করা হয়েছে এবং একটি RetainInstanceUsageViolation নিক্ষেপ করে।

এই লঙ্ঘনটি একটি ধরে রাখা Fragment ব্যবহার নির্দেশ করে, বিশেষত, যদি setRetainInstance() বা getRetainInstance() এ কল করা হয়, যেগুলি উভয়ই বাতিল করা হয়েছে৷

রক্ষিত Fragment দৃষ্টান্তগুলি নিজে পরিচালনা করার জন্য এই পদ্ধতিগুলি ব্যবহার করার পরিবর্তে, একটি ViewModel রাজ্য সংরক্ষণ করুন যা আপনার জন্য এটি পরিচালনা করে।

ব্যবহারকারীর দৃশ্যমান ইঙ্গিত সেট করুন

সেট ব্যবহারকারী দৃশ্যমান ইঙ্গিত লঙ্ঘন detectSetUserVisibleHint() ব্যবহার করে সক্ষম করা হয়েছে এবং একটি SetUserVisibleHintViolation নিক্ষেপ করে।

এই লঙ্ঘন setUserVisibleHint() -এ একটি কল নির্দেশ করে, যা অবহেলিত।

আপনি যদি ম্যানুয়ালি এই পদ্ধতিতে কল করেন, তাহলে এর পরিবর্তে setMaxLifecycle() কল করুন। আপনি যদি এই পদ্ধতিটি ওভাররাইড করেন, তাহলে আচরণটিকে true পাস করার সময় onResume() এবং false পাস করার সময় onPause() এ সরান।

টার্গেট ফ্র্যাগমেন্ট ব্যবহার

টার্গেট ফ্র্যাগমেন্ট ব্যবহার লঙ্ঘন detectTargetFragmentUsage() ব্যবহার করে সক্ষম করা হয় এবং একটি TargetFragmentUsageViolation নিক্ষেপ করে।

এই লঙ্ঘনটি setTargetFragment() , getTargetFragment() , বা getTargetRequestCode() এ একটি কল নির্দেশ করে, যেগুলি সবই বাতিল করা হয়েছে৷ এই পদ্ধতিগুলি ব্যবহার করার পরিবর্তে, একটি FragmentResultListener নিবন্ধন করুন। পাস করা ফলাফল সম্পর্কে আরও তথ্যের জন্য, খণ্ডের মধ্যে ফলাফল পাস দেখুন।

ভুল খণ্ড ধারক

ভুল খণ্ড কন্টেইনার লঙ্ঘন detectWrongFragmentContainer() ব্যবহার করে সক্ষম করা হয়েছে এবং একটি WrongFragmentContainerViolation নিক্ষেপ করে।

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