Parçalarınızda hata ayıklama

Bu kılavuz, hatalarda hata ayıklamak için kullanabileceğiniz araçları parçalar.

FragmentManager günlük kaydı

FragmentManager için çeşitli mesajlar yayabilir Logcat. Bu ayar varsayılan olarak devre dışıdır. Ancak bazen bu günlük iletileri, sorun gidermenize parçalarıyla ilgili sorunlar oluşturabilirsiniz. FragmentManager en anlamlı çıktıyı verir DEBUG ve VERBOSE günlük düzeylerinde.

Aşağıdakileri kullanarak günlük kaydını etkinleştirebilirsiniz adb shell komutu:

adb shell setprop log.tag.FragmentManager DEBUG

Alternatif olarak, ayrıntılı günlük kaydını aşağıdaki gibi etkinleştirebilirsiniz:

adb shell setprop log.tag.FragmentManager VERBOSE

Ayrıntılı günlük kaydını etkinleştirirseniz, daha sonra bir günlük kaydı düzeyi uygulayabilirsiniz. filtrenize bakın. Ancak bu yalnızca FragmentManager günlüklerini değil, tüm günlükleri filtreler. Genellikle en iyisi FragmentManager günlük kaydını yalnızca ihtiyacınız olan günlük düzeyinde etkinleştirin.

DEBUG günlük kaydı

DEBUG düzeyinde, FragmentManager genellikle yaşam döngüsü durum değişiklikleri. Her günlük girişi toString() Fragment dosyasından dökümü. Bir günlük girişi aşağıdaki bilgilerden oluşur:

  • Fragment örneğinin basit sınıf adı.
  • Kimlik karması kodu Fragment örneği.
  • Fragment örneğinin parça yöneticisinin benzersiz kimliği. Bu kararlı ve yapılandırma değişiklikleri ile işlem ölümü ve yeniden oluşturma gibi.
  • Fragment öğesinin eklendiği (yalnızca ayarlanmışsa) kapsayıcının kimliği.
  • Yalnızca ayarlanmışsa Fragment etiketi.

Aşağıda örnek bir DEBUG günlük girişi verilmiştir:

D/FragmentManager: moveto ATTACHED: NavHostFragment{92d8f1d} (fd92599e-c349-4660-b2d6-0ece9ec72f7b id=0x7f080116)
  • Fragment sınıfı NavHostFragment.
  • Kimlik karması kodu: 92d8f1d.
  • Benzersiz kimlik: fd92599e-c349-4660-b2d6-0ece9ec72f7b.
  • Kapsayıcı kimliği: 0x7f080116.
  • Hiçbir etiket ayarlanmadığından etiket atlandı. Mevcut olduğunda tag=tag_value biçimindeki kimlik.

Kısa ve okunabilir olması için UUID'ler şu şekilde kısaltılmıştır: örnekler.

Başlatılan bir NavHostFragment ve ardından startDestination FirstFragment türünde Fragment oluşturuluyor ve şuna geçiş yapılıyor: RESUMED durumu:

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, bir kullanıcı etkileşiminin ardından çeşitli yaşam döngüsü durumlarından oluşur. Daha sonra SecondFragment örneklenir ve geçişler yapılır RESUMED durumuna kadar:

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)

Takip edebilmeniz için tüm Fragment örneklerinin son eki bir tanımlayıcı tarafından eklenmiştir. farklı örneklerini aynı Fragment sınıfı.

AYRINTILI günlük kaydı

VERBOSE düzeyinde, FragmentManager genellikle dahili durum:

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)

Bu örnekte yalnızca FirstFragment üzerindeki yükleme ele alınmaktadır. Programa geçiş projesine SecondFragment, günlük girişlerini önemli ölçüde artırıyor. VERBOSE düzeyindeki günlük mesajlarının birçoğu uygulamada pek işe yaramaz birlikte çalışır. Ancak, arka yığında ne zaman değişikliklerin olduğunu görmek, hata ayıklanıyor.

Parçalar için StrictMode

Sürüm 1.4.0 ve Jetpack Parça kitaplığının içeriği Parçalar için StrictMode. Bu da beklenmedik şekillerde davranmasına neden olabilir. Paydaşlarla çalışma hakkında daha fazla StrictMode için StrictMode'a bakın.

Özel Policy hangi ihlallerin tespit edildiğini tanımlar ve hangi cezaların uygulandığını belirtir tespit etmektir.

Özel bir StrictMode politikası uygulamak için bunu FragmentManager. Bu işlemi mümkün olduğunca erken yapın. Bu durumda, bunu init blokunda veya Java kurucusunda:

Kotlin

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)
        ...
   }
}

Java

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());
        ...
   }
}

Belirli durumlarda, Context özelliği hakkında bilgi sahibi olmanız StrictMode'u etkinleştirdiğinizde (ör. bir boole kaynağının değerinden) şunu kullanarak bir StrictMode politikası atamayı ertele: FragmentManager OnContextAvailableListener:

Kotlin

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)
        ...
   }
}

Java

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'u, olası tüm durumları yakalayacak şekilde yapılandırabileceğiniz en son nokta ihlal durumu: onCreate() super.onCreate() adlı kişiye yapılacak aramadan önce:

Kotlin

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)
        ...
   }
}

Java

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());
        ...
   }
}

Bu örneklerde kullanılan bu politika yalnızca parça yeniden kullanım ihlallerini tespit eder. ve bu tür bir durum yaşandığında uygulama sonlandırılır. penaltyDeath() şu olabilir: Öte yandan, göz ardı edemeyeceğiniz kadar hızlı başarısız olduğu için hata ayıklama derlemelerinde faydalıdır ihlal eder.

Belirli ihlallere seçmeli olarak izin vermek de mümkündür. Kullanılan politika ancak önceki örnekte, bu ihlal tüm diğer kısım için bulunur. Bu, bir üçüncü taraf kitaplık bileşeninin StrictMode ihlalleri içerebilir.

Bu gibi durumlarda, söz konusu ihlalleri geçici olarak kitaplığa kadar sahibi olmadığınız bileşenler için StrictMode'unuz düzeltir.

Diğer ihlallerin nasıl yapılandırılacağıyla ilgili ayrıntılar için şuraya bakın: FragmentStrictMode.Policy.Builder.

Üç ceza türü vardır.

  • penaltyLog() ihlallerin ayrıntılarını Logcat'e atar.
  • penaltyDeath() İhlaller tespit edildiğinde uygulamayı sonlandırır.
  • penaltyListener() ihlal tespit edildiğinde çağrılacak özel bir işleyici eklemenizi algılandı.

Policy içinde istediğiniz ceza kombinasyonunu uygulayabilirsiniz. Politikanız: açıkça bir ceza belirtmemişse varsayılan olarak penaltyLog() uygulanır. Şu durumda: özel Policy öğenizde penaltyLog() dışında bir ceza uygular, ardından Siz özellikle ayarlamadığınız sürece penaltyLog() devre dışı bırakılır.

penaltyListener(), aşağıdakileri yapmak için üçüncü taraf günlük kaydı kitaplığınız olduğunda yararlı olabilir: ihlallerini günlüğe kaydetmezsiniz. Alternatif olarak, sürüm derlemelerini yakalama ve bunları kilitlenme raporuna kaydetme kitaplığını açar. Bu strateji, aksi takdirde gözden kaçan ihlalleri tespit edebilir.

Genel bir StrictMode politikası belirlemek için, FragmentManager örneği kullanmak için FragmentStrictMode.setDefaultPolicy() yöntem:

Kotlin

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()
    }
}

Java

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());
    }
}

Aşağıdaki bölümlerde ihlal türleri ve olası çözümler açıklanmaktadır.

Parçanın yeniden kullanımı

Parça yeniden kullanımı ihlali, detectFragmentReuse() ve fırlatarak: FragmentReuseViolation.

Bu ihlal, Fragment örneği kaldırıldıktan sonra yeniden kullanılabileceğini belirtir FragmentManager başlangıç fiyatıyla. Bu yeniden kullanım, Fragment nedeniyle sorunlara yol açabilir. önceki kullanımın durumunu korumak ve tutarlı bir şekilde davranmamaktır. Bir yeni bir örnek üzerinde çalışıyorsa örneğine eklendiğinde her zaman FragmentManager

Parça etiket kullanımı

Parça etiket kullanımı ihlali, detectFragmentTagUsage() ve fırlatarak: FragmentTagUsageViolation.

Bu ihlal, Fragment öğesinin <fragment> kullanılarak şişirildiğini gösterir etiketinin hemen arkasına yerleştirilmesi gerekir. Bu sorunu çözmek için Fragment öğenizi şişirin <fragment> yerine <androidx.fragment.app.FragmentContainerView> kapanış etiketinin hemen öncesine yapıştırın. FragmentContainerView ile şişirilen parçalar güvenilir bir şekilde işlenebilir Fragment işlem ve yapılandırma değişikliği. Bu araçlar farklı yerine <fragment> etiketini kullanırsanız beklenen değeri elde edersiniz.

Örnek kullanımını koru

Örnek saklama ihlali, detectRetainInstanceUsage() ve fırlatarak: RetainInstanceUsageViolation.

Bu ihlal, özellikle aşağıdaki durumlarda, elde tutulan Fragment kullanımını gösterir. çok sayıda paydaşı olan setRetainInstance() veya getRetainInstance(), ve bunların her ikisi de kullanımdan kaldırılmıştır.

Saklanan Fragment örneklerini yönetmek için bu yöntemleri kullanmak yerine mağaza durumunu bir ViewModel bu işi sizin yerinize halleder.

Kullanıcı tarafından görülebilen ipucunu ayarla

Kullanıcı tarafından görülebilen ipucunu ayarlama özelliği detectSetUserVisibleHint() ve fırlatarak: SetUserVisibleHintViolation.

Bu ihlal, setUserVisibleHint() Bu destek sonlandırılmıştır.

Bu yöntemi manuel olarak çağırıyorsanız şunu arayın: setMaxLifecycle() . Bu yöntemi geçersiz kılarsanız davranışı onResume() true ve onPause() false ayında geçerken.

Hedef parça kullanımı

Hedef parça kullanımı ihlali, detectTargetFragmentUsage() ve fırlatarak: TargetFragmentUsageViolation.

Bu ihlal, setTargetFragment() getTargetFragment(), veya getTargetRequestCode() ve bunların hepsi kullanımdan kaldırıldı. Bu yöntemleri kullanmak yerine bir FragmentResultListener Sonuçları iletme hakkında daha fazla bilgi için Sonuçları şu tarihler arasında aktarın: parçalarını kullanın.

Yanlış parça kapsayıcısı

Yanlış parça kapsayıcı ihlali, detectWrongFragmentContainer() ve fırlatarak: WrongFragmentContainerViolation.

Bu ihlal, dışında bir kapsayıcıya Fragment eklendiğini gösterir FragmentContainerView. Fragment etiketi kullanımında olduğu gibi, parça işlemleri, FragmentContainerView. Kapsayıcı görünümü kullanmak, View API'deki şu sorunu çözmeye de yardımcı olur: çıkış animasyonlarını kullanan parçaların, diğer tüm bölümlerin üzerine çizilmesine parçalar.