Errores de Android——DialogFragment.showNow:No se puede realizar esta acción después de onSaveInstanceState

análisis del problema:

1. Cuándo llamar al método onSaveInstanceState()

onSaveInstanceState()Llamado para guardar el estado de cada instancia antes de que se destruya la actividad, de modo que se pueda garantizar que el estado se recupere onCreate(Bundle)o onRestoreInstanceState(Bundle)se restablezca.

El método onSaveInstanceState de la actividad llamará FragmentManager#saveAllStateal método para guardar el estado del fragmento, que se usa 同时设置mStateSaved为truepara indicar que el estado se guardó.

2. ¿Cuándo aparecerá Can not perform this action after onSaveInstanceState?

Hay dos situaciones en las que no se puede realizar esta acción después de la excepción onSaveInstanceState:

1. FragmentTransaction的commit()时出现:
2. Activity/FragmentActivity的onBackPressed时出现:

commitEn ambos casos , los métodos o etc. se llaman después de almacenar el estado onBackPressed, lo que llamará a checkStateLoss(), lanzando una excepción.

private void checkStateLoss() {
    
    
	if (isStateSaved()) {
    
    
		throw new IllegalStateException("Can not perform this action after  onSaveInstanceState");
	}
}

@Override
public boolean isStateSaved() {
    
    
	// See saveAllState() for the explanation of this.  We do this for
    // all platform versions, to keep our behavior more consistent between
    // them.
    return mStateSaved || mStopped;
}

Referencia detallada: https://www.jianshu.com/p/ee58be253a5b
Bien, volvamos al lugar donde informamos el error DialogFragment.showNow, primero mira el código fuente:

public void showNow(@NonNull FragmentManager manager, @Nullable String tag) {
    
    
	mDismissed = false;
    mShownByMe = true;
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commitNow();
}

A partir del código anterior, se puede ver que se ha realizado un envío de transacción Fragmento y se utiliza el método commitNow.Continúe buscando el código fuente:

@Override
public void commitNow() {
    
    
	disallowAddToBackStack();
	mManager.execSingleAction(this, false);
}

Aquí vemos execSingleAction的第二个参数allowStateLoss传值fasle,

private void ensureExecReady(boolean allowStateLoss) {
    
    
	...

    if (!allowStateLoss) {
    
    
    	checkStateLoss();
    }

    if (mTmpRecords == null) {
    
    
    	mTmpRecords = new ArrayList<>();
        mTmpIsPop = new ArrayList<>();
    }
    mExecutingActions = true;
    try {
    
    
    	executePostponedTransaction(null, null);
    } finally {
    
    
    	mExecutingActions = false;
    }
}

Eventualmente se execSingleActionejecutará ensureExecReady, ensureExecReady同样进行了checkStateLoss()状态检查por lo que el motivo del error es evidente, así que hablemos de la solución a continuación.

solución:

Todos sabemos que el envío de transacciones de Fragment tiene dos métodos commit()y commitAllowingStateLoss()si lo usamos commitAllowingStateLoss()就会避免上述报错. Entonces, ¿se puede modificar el método show de DialogFragment de acuerdo con esta idea? La respuesta es sí. Ir directamente al código.

@Override
public void showNow(@NonNull FragmentManager manager, @Nullable String tag) {
    
    
	try {
    
    
    	//由于父类方法中mDismissed,mShownByMe不可直接访问,所以此处采用反射修改他们的值
        Class dialogFragmentClass = DialogFragment.class;
        Field mDismissed = dialogFragmentClass.getDeclaredField("mDismissed");
        mDismissed.setAccessible(true);
        mDismissed.set(this, false);

        Field mShownByMe = dialogFragmentClass.getDeclaredField("mShownByMe");
        mShownByMe.setAccessible(true);
        mShownByMe.set(this, true);

        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commitNowAllowingStateLoss();
    } catch (Exception e)  {
    
    
        e.printStackTrace();
    }
}

Supongo que te gusta

Origin blog.csdn.net/u012230055/article/details/129573315
Recomendado
Clasificación