Bu kılavuz, parçalarınızda hata ayıklamak için kullanabileceğiniz araçları ele alır.
FragmentManager günlük kaydı
FragmentManager
, Logcat'e çeşitli mesajlar gönderebilir. Bu özellik varsayılan olarak devre dışıdır ancak bazen bu günlük mesajları, parçalarınızla ilgili sorunları gidermenize yardımcı olabilir. FragmentManager
, DEBUG
ve VERBOSE
günlük düzeylerinde en anlamlı çıkışı verir.
Günlük kaydını aşağıdaki adb shell
komutunu kullanarak etkinleştirebilirsiniz:
adb shell setprop log.tag.FragmentManager DEBUG
Alternatif olarak, ayrıntılı günlük kaydını aşağıdaki şekilde etkinleştirebilirsiniz:
adb shell setprop log.tag.FragmentManager VERBOSE
Ayrıntılı günlük kaydını etkinleştirirseniz Logcat penceresinde bir günlük düzeyinde filtre uygulayabilirsiniz. Ancak bu sayede yalnızca FragmentManager
günlükleri değil, tüm günlükler filtrelenir. FragmentManager
günlük kaydını yalnızca ihtiyaç duyduğunuz günlük düzeyinde etkinleştirmek genellikle en iyi seçenektir.
HATA AYIKLAMA günlük kaydı
DEBUG
düzeyinde, FragmentManager
genellikle yaşam döngüsü durumu değişiklikleriyle ilgili günlük mesajları yayınlar. Her günlük girişi, Fragment
aracındaki toString()
dökümünü içerir.
Günlük girişi aşağıdaki bilgilerden oluşur:
Fragment
örneğinin basit sınıf adı.Fragment
örneğinin kimlik karma kodu.Fragment
örneğinin parça yöneticisinin benzersiz kimliği. Bu, yapılandırma değişiklikleri ve süreç ölümü ve yeniden oluşturma açısından sabittir.- Yalnızca ayarlanmışsa
Fragment
öğesinin eklendiği kapsayıcının kimliği. Fragment
etiketi (yalnızca ayarlanmışsa).
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 karma kodu:
92d8f1d
. - Benzersiz kimlik:
fd92599e-c349-4660-b2d6-0ece9ec72f7b
. - Kapsayıcı kimliği:
0x7f080116
. - Herhangi bir etiket ayarlanmadığından etiket atlandı. Mevcut olduğunda,
tag=tag_value
biçimindeki kimliği izler.
UUID'ler, kısa ve anlaşılır olması için aşağıdaki örneklerde kısaltılmıştır.
Burada, başlatılmakta olan NavHostFragment
ve ardından FirstFragment
türündeki startDestination
Fragment
öğesinin oluşturulup RESUMED
durumuna geçirilmesini görebilirsiniz:
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 çıkar. Daha sonra SecondFragment
örneklenir ve RESUMED
durumuna geçer:
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)
Tüm Fragment
örneklerine bir tanımlayıcı tarafından sonek getirilir. Böylece aynı Fragment
sınıfının farklı örneklerini izleyebilirsiniz.
AYRINTILI günlük kaydı
VERBOSE
düzeyinde, FragmentManager
genellikle dahili durumuyla ilgili günlük mesajları yayınlar:
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
sitesindeki yükleme işlemi ele alınmaktadır. SecondFragment
ürününe geçişin dahil edilmesi, günlük girişlerini önemli ölçüde artırır.
VERBOSE
düzeyindeki günlük mesajlarının çoğu, uygulama geliştiricilerine pek fayda sağlamaz. Bununla birlikte, arka yığında değişikliklerin ne zaman gerçekleştiğini görmek bazı sorunların hatalarını ayıklamaya yardımcı olabilir.
Parçalar için StrictMode
Jetpack Fragment kitaplığının 1.4.0 ve sonraki sürümleri, parçalar için StrictMode özelliğini içerir. Bu özellik, uygulamanızın beklenmedik şekilde davranmasına
neden olabilecek bazı yaygın sorunları yakalayabilir. StrictMode
ile çalışma hakkında daha fazla bilgi için StrictMode konusuna bakın.
Özel Policy
hangi ihlallerin tespit edildiğini ve ihlaller tespit edildiğinde hangi cezanın uygulanacağını belirtir.
Özel bir StrictMode politikası uygulamak için politikayı FragmentManager
'a atayın.
Bunu mümkün olduğunca erken yapın. Bu durumda, bunu bir init
bloğunda veya Java kurucusinde yaparsınız:
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()); ... } }
StrictMode'un etkinleştirilip etkinleştirilmeyeceğini belirlemek için Context
bilmeniz gereken durumlarda (ör. bir boole kaynağının değeri) OnContextAvailableListener
kullanarak FragmentManager
öğesine StrictMode politikası atamayı erteleyebilirsiniz:
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()); ... } }
Olası tüm ihlalleri yakalamak için StrictMode'u yapılandırabileceğiniz en son nokta, super.onCreate()
çağrısından önce onCreate()
içindedir:
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 böyle bir ihlal olduğunda uygulama sonlandırılır. penaltyDeath()
, ihlalleri yoksayamayacağınız kadar hızlı bir şekilde başarısız olduğundan hata ayıklama derlemelerinde faydalı olabilir.
Belirli ihlallere seçerek de izin verebilirsiniz. Ancak önceki örnekte kullanılan politika, bu ihlali diğer tüm parça türleri için uygular. Bu, üçüncü taraf bir kitaplık bileşeninin StrictMode ihlalleri içerebileceği durumlarda yararlıdır.
Bu tür durumlarda, sahip olmadığınız bileşenler, söz konusu ihlaller tarafından düzeltilene kadar StrictMode izin verilenler listesine geçici olarak ekleyebilirsiniz.
Diğer ihlalleri yapılandırma hakkında ayrıntılı bilgi için FragmentStrictMode.Policy.Builder
belgelerini inceleyin.
Üç ceza türü vardır.
penaltyLog()
, ihlallerin ayrıntılarını Logcat'e gönderir.penaltyDeath()
, ihlaller tespit edildiğinde uygulamayı sonlandırır.penaltyListener()
, ihlaller tespit edildiğinde çağrılan özel bir işleyici eklemenize olanak tanır.
Policy
içinde istediğiniz ceza kombinasyonunu uygulayabilirsiniz. Politikanız açıkça bir ceza belirtmiyorsa varsayılan olarak penaltyLog()
uygulanır. Özel Policy
öğenizde penaltyLog()
dışında bir ceza uygularsanız penaltyLog()
açıkça ayarlamadığınız sürece devre dışı bırakılır.
İhlalleri günlüğe kaydetmek istediğiniz bir üçüncü taraf günlük kaydı kitaplığınız varsa penaltyListener()
yararlı olabilir. Alternatif olarak, sürüm derlemelerinde önemli olmayan ihlal yakalamayı etkinleştirebilir ve bunları bir kilitlenme raporlama kitaplığına kaydedebilirsiniz. Bu strateji, diğer durumlarda gözden kaçan ihlalleri tespit edebilir.
Genel bir StrictMode politikası ayarlamak için FragmentStrictMode.setDefaultPolicy()
yöntemini kullanarak tüm FragmentManager
örneklerinde geçerli olacak varsayılan bir politika belirleyin:
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ı geçici çözümler açıklanmaktadır.
Parça yeniden kullanımı
Parça yeniden kullanım ihlali detectFragmentReuse()
ile etkinleştirilir ve FragmentReuseViolation
hatası verir.
Bu ihlal, bir Fragment
örneğinin FragmentManager
ürününden kaldırıldıktan sonra yeniden kullanıldığını belirtir. Fragment
, önceki kullanımından kalan durumunu koruyabilir ve tutarlı davranamayabilir. Bu yeniden kullanım, sorunlara yol açabilir. Her defasında yeni bir örnek oluşturursanız bu örnek, FragmentManager
öğesine eklendiğinde her zaman ilk durumunda olur.
Parça etiketi kullanımı
Parça etiketi kullanım ihlali detectFragmentTagUsage()
ile etkinleştirilir ve FragmentTagUsageViolation
hatası verir.
Bu ihlal, XML düzeninde <fragment>
etiketi kullanılarak bir Fragment
değerinin şişirildiğini gösterir. Bu sorunu çözmek için Fragment
öğenizi <fragment>
etiketi yerine <androidx.fragment.app.FragmentContainerView>
içinde şişirin. FragmentContainerView
kullanılarak genişletilen parçalar Fragment
işlemi ve yapılandırma değişikliklerini güvenilir bir şekilde işleyebilir. Bunun yerine <fragment>
etiketini kullanırsanız bunlar beklendiği gibi çalışmayabilir.
Örnek kullanımını koru
Örnek kullanma ihlali, detectRetainInstanceUsage()
kullanılarak etkinleştirilir ve RetainInstanceUsageViolation
hatası verir.
Bu ihlal, özellikle her ikisi de kullanımdan kaldırılan setRetainInstance()
veya getRetainInstance()
çağrıları varsa saklanan Fragment
kullanımını belirtir.
Saklanan Fragment
örneklerini yönetmek için bu yöntemleri kullanmak yerine, durumu sizin için halleden bir ViewModel
içinde depolayın.
Kullanıcı tarafından görülebilen ipucunu ayarla
Kullanıcı tarafından görülebilir ipucu ihlali, detectSetUserVisibleHint()
ile etkinleştirilir ve SetUserVisibleHintViolation
hatası verir.
Bu ihlal, kullanımdan kaldırılan bir setUserVisibleHint()
çağrısına işaret eder.
Bu yöntemi manuel olarak çağırıyorsanız bunun yerine setMaxLifecycle()
yöntemini çağırın. Bu yöntemi geçersiz kılarsanız true
içinde geçerken davranışı onResume()
, false
içinde geçerken onPause()
değerine taşıyın.
Hedef parça kullanımı
Hedef parça kullanımı ihlali, detectTargetFragmentUsage()
ile etkinleştirilir ve bir TargetFragmentUsageViolation
döndürür.
Bu ihlal, setTargetFragment()
, getTargetFragment()
veya getTargetRequestCode()
için yapılan ve kullanımdan kaldırılan bir çağrı olduğunu gösterir. Bu yöntemleri kullanmak yerine bir FragmentResultListener
kaydedin. Sonuçları geçirme hakkında daha fazla bilgi için Parçalar arasında sonuçları geçirme bölümüne bakın.
Yanlış parça kapsayıcısı
Yanlış parça kapsayıcısı ihlali, detectWrongFragmentContainer()
kullanılarak etkinleştirildi ve WrongFragmentContainerViolation
hatasına neden oluyor.
Bu ihlal, FragmentContainerView
dışında bir kapsayıcıya Fragment
eklendiğini gösterir. Fragment
etiket kullanımında olduğu gibi, bir FragmentContainerView
içinde barındırılmadıkça parça işlemleri beklendiği gibi çalışmayabilir. Kapsayıcı görünümü kullanmak, View
API'deki çıkış animasyonlarını kullanan parçaların, diğer tüm parçaların üzerine çizilmesine neden olan bir sorunun giderilmesine de yardımcı olur.