Android配置变更后Activity恢复时Fragment重叠问题求助
配置变更后Activity恢复时Fragment重叠问题排查
我的Android应用包含一个Activity和一个Fragment,配置变更(比如横竖屏切换)后Activity恢复时,会创建两个Fragment并出现重叠现象,我没有使用ViewPager,看过相关问题但没理解解决方案,附上关键代码求排查线索。
ContinuarInformeActivity 关键代码
public class ContinuarInformeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_continuar_informe); // get fragment manager myChildToolbar = findViewById(R.id.toolbarinf); setSupportActionBar(myChildToolbar); // Get a support ActionBar corresponding to this toolbar ActionBar ab = getSupportActionBar(); // Enable the Up button ab.setDisplayHomeAsUpEnabled(true); // add nviewModel = new ViewModelProvider(this).get(NuevoinformeViewModel.class); loadData(savedInstanceState); //reviso si es edicion y ya tengo info en temp ultimares=dViewModel.getUltimoTemp(); if(ultimares!=null) //is edition { preguntaAct=dViewModel.inftempToReac(ultimares); if(preguntaAct.getTabla().equals(ultimares.getTabla())){ //si es la misma FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); Bundle args = new Bundle(); args.putInt(DetalleProductoFragment.ARG_PREGACT,preguntaAct.getId() ); args.putBoolean(DetalleProductoFragment.ARG_ESEDI,true); DetalleProductoFragment nvofrag = new DetalleProductoFragment(); nvofrag.setArguments(args); ft.add(R.id.continf_fragment,nvofrag); ft.commit(); }else{ buscarPreguntas(); dViewModel.getReactivos().observe(this, new Observer<List<Reactivo>>() { @Override public void onChanged(List<Reactivo> reactivos) { Log.d(TAG, "reactivo:" + reactivos.get(0).getLabel()); Bundle args = new Bundle(); args.putInt(DetalleProductoFragment.ARG_PREGACT,reactivos.get(0).getId() ); args.putBoolean(DetalleProductoFragment.ARG_ESEDI,false); DetalleProductoFragment nvofrag = new DetalleProductoFragment(); nvofrag.setArguments(args); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.continf_fragment, nvofrag); ft.commit(); } }); } }else { //is new buscarPreguntas(); dViewModel.getReactivos().observe(this, new Observer<List<Reactivo>>() { @Override public void onChanged(List<Reactivo> reactivos) { Log.d(TAG, "2reactivo:" + reactivos.get(0).getLabel()); Bundle args = new Bundle(); args.putInt(DetalleProductoFragment.ARG_PREGACT,reactivos.get(0).getId() ); args.putBoolean(DetalleProductoFragment.ARG_ESEDI,false); DetalleProductoFragment nvofrag = new DetalleProductoFragment(); nvofrag.setArguments(args); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.continf_fragment, nvofrag); ft.commit(); } }); } } public void loadData(Bundle savedInstanceState) { Bundle datosRecuperados = getIntent().getExtras(); if(datosRecuperados!=null) { idinformeSel = datosRecuperados.getInt(INFORMESEL); //es la visita id }else { //lo recupero if (savedInstanceState != null) { // Restore value of members from saved state Constantes.CLAVEUSUARIO = savedInstanceState.getString(KEY_USUARIO); Constantes.ETAPAACTUAL = savedInstanceState.getInt(KEY_ETAPAACT); Constantes.INDICEACTUAL=savedInstanceState.getString(KEY_INDICEACT); Intent intento1 = new Intent(this, NavigationDrawerActivity.class); startActivity(intento1); finish(); return; } } mBinding.setSdf(Constantes.sdfsolofecha); .... } @Override public boolean onSupportNavigateUp() { onBackPressed(); return false; } boolean salir; @Override public void onBackPressed() { DetalleProductoFragment fragment = (DetalleProductoFragment) getSupportFragmentManager().findFragmentById(R.id.continf_fragment); numpreg = fragment.getNumPregunta(); salir=true; if(numpreg==4||numpreg==3||numpreg==5||numpreg==43||numpreg==7) { return; //no puedo regresar } DetalleProductoFragment fragment = (DetalleProductoFragment) getSupportFragmentManager().findFragmentById(R.id.continf_fragment); fragment.atras(); return; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_continuar, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { noSalir=false; switch (item.getItemId()) { case R.id.csalir: int numpreg=0; if(nviewModel.clienteSel==4) if(numpreg==3||numpreg==4||numpreg==5){ noSalir=true; } if(nviewModel.clienteSel==5||nviewModel.clienteSel==7) if(numpreg==53||numpreg==54||numpreg==55){ noSalir=true; } if(nviewModel.clienteSel==6) if(numpreg==73||numpreg==74||numpreg==75){ noSalir=true; } return true; default: break; } return false; } @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can save the view hierarchy state super.onSaveInstanceState(savedInstanceState); savedInstanceState.putInt(KEY_ETAPAACT,Constantes.ETAPAACTUAL ); savedInstanceState.putString(KEY_USUARIO, Constantes.CLAVEUSUARIO ); savedInstanceState.putString(KEY_INDICEACT, Constantes.INDICEACTUAL ); savedInstanceState.putInt("visitasel",idinformeSel ); } }
DetalleProductoFragment 关键代码
public class DetalleProductoFragment extends Fragment { ... public DetalleProductoFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mViewModel = new ViewModelProvider(requireActivity()).get(NuevoinformeViewModel.class); root = inflater.inflate(R.layout.fragment_generic2, container, false); svprin = root.findViewById(R.id.fgllcontentmain); return root; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == REQUEST_CODE_TAKE_PHOTO) && resultCode == RESULT_OK) { if (archivofoto!=null&&archivofoto.exists()) { if(requestCode == REQUEST_CODE_TAKE_PHOTO) { preguntaview.setTextoint(nombre_foto); if(ComprasUtils.getAvailableMemory(getActivity()).lowMemory) { Toast.makeText(getActivity(), "No hay memoria suficiente para esta accion", Toast.LENGTH_SHORT).show(); return; }else { // Bitmap bitmap1 = BitmapFactory.decodeFile(getActivity().getExternalFilesDir(null) + "/" + nombre_foto); ComprasUtils cu = new ComprasUtils(); cu.comprimirImagen(archivofoto.getAbsolutePath()); Bitmap bitmap1 = ComprasUtils.decodeSampledBitmapFromResource(archivofoto.getAbsolutePath(), 100, 100); preguntaview.setImageBitmap(bitmap1); // fotomos.setLayoutParams(new LinearLayout.LayoutParams(350,150)); preguntaview.verBtnRotar(); nombre_foto=null; archivofoto=null; if(preguntaview.getNopermiso()!=null) { preguntaview.getNopermiso().setChecked(false); } preguntaview.aceptarSetEnabled(true); } } } else{ Log.e(TAG,"Algo salió mal???"); } } @Override public void onDestroy() { super.onDestroy(); if(sspeechRecognizer!=null) sspeechRecognizer.destroy(); } @Override public void onPause() { super.onPause(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("picUri", nombre_foto); } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); if(savedInstanceState!=null) nombre_foto= savedInstanceState.getString("picUri"); } @Override public void onDestroyView() { super.onDestroyView(); mViewModel = null; lcviewModel = null; dViewModel=null; preguntaview=null; tomadoDe=null; atributos=null; causas=null; root=null; preguntaAct=null; svprin=null; loadingDialog=null ; lcviewModel=null; nombre_foto=null; archivofoto=null; } }
问题原因及修复方案
核心原因
Android系统在配置变更时,会自动保存并恢复FragmentManager中的Fragment实例。你的onCreate方法没有判断savedInstanceState是否为null,每次重建Activity都会重新执行Fragment的添加逻辑,导致系统恢复的旧Fragment和你新创建的Fragment重叠。
具体修复步骤
在Activity的onCreate中添加状态判断
在执行Fragment添加逻辑前,先检查savedInstanceState是否为null。如果不为null,说明系统已经恢复了之前的Fragment,不需要再创建新的:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_continuar_informe); // ... 其他初始化代码 ... loadData(savedInstanceState); ultimares=dViewModel.getUltimoTemp(); // 关键判断:仅当savedInstanceState为null时才创建Fragment if (savedInstanceState == null) { if(ultimares!=null) //is edition { preguntaAct=dViewModel.inftempToReac(ultimares); if(preguntaAct.getTabla().equals(ultimares.getTabla())){ // ... 原有的Fragment添加代码 ... }else{ buscarPreguntas(); dViewModel.getReactivos().observe(this, new Observer<List<Reactivo>>() { @Override public void onChanged(List<Reactivo> reactivos) { // ... 原有的Fragment添加代码 ... } }); } }else { //is new buscarPreguntas(); dViewModel.getReactivos().observe(this, new Observer<List<Reactivo>>() { @Override public void onChanged(List<Reactivo> reactivos) { // ... 原有的Fragment添加代码 ... } }); } } }可选方案:使用replace替代add
如果业务需要每次重建都创建新Fragment,可以用ft.replace(R.id.continf_fragment, nvofrag)替代ft.add,这样会移除容器中已有的Fragment,避免重叠。但这种方式会丢失之前Fragment的状态,仅适合不需要保留状态的场景。验证Fragment状态恢复逻辑
确保Fragment在onViewStateRestored中正确恢复状态,避免系统恢复的Fragment出现异常显示。
内容的提问来源于stack exchange,提问作者Marisol vega
相关产品推荐
相关产品推荐

