重新启动活动会创建重复的片段 [英] Restarting Activity creates duplicate fragments
问题描述
当我的活动重新开始时,我会得到彼此重叠的片段,新片段会覆盖旧片段,并且只有最新片段是可编辑的
When my activity restarts i get duplicate fragments on top of each other, the new ones over the old ones, and only the most recent are editable
我的片段看起来像这样,请忽略所有不必要的代码,这时的应用程序已经很大,很难将一件事与另一件事分开
My fragment looks like this, please ignore all unnecessary code, the application at this point is already quite large and it is difficult to separate one thing from another:
package cu.me.cuanto;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class FragmentCambio extends Fragment {
View view;
EditText inputCUC,inputCUP;
TextView exchangeExplain,eraseText,exchangeText;
ImageView rotatingImage; //esta es la imagen que gira en el fragment
ImageView backShadow;
Animation rotate180,fabOpen,fabClose,rotateForward,rotateBackward,shadowIn,shadowOut;
FloatingActionButton exchangeFab,optionsFab,eraseFab;
int exchange=25;
float cuc,cup;
boolean isOptionsOpen=false;
public FragmentCambio(){
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view=inflater.inflate(R.layout.fragment_cambio,container,false);
backShadow = view.findViewById(R.id.back_shadow_2);
backShadow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateFab();
}
});
inputCUC=view.findViewById(R.id.input_cuc);
inputCUP=view.findViewById(R.id.input_cup);
rotatingImage=view.findViewById(R.id.rotating_image);
exchangeExplain=view.findViewById(R.id.exchange_explain_into_cambio);
eraseText=view.findViewById(R.id.erase_text_exchange_frag);
exchangeText=view.findViewById(R.id.exchange_text_exchange_frag);
exchangeFab=view.findViewById(R.id.exchangeFab);
optionsFab=view.findViewById(R.id.optionsFab);
eraseFab=view.findViewById(R.id.eraseFab);
rotate180= AnimationUtils.loadAnimation(getContext(),R.anim.rotate_180);
fabOpen=AnimationUtils.loadAnimation(getContext(),R.anim.fab_open);
fabClose=AnimationUtils.loadAnimation(getContext(),R.anim.fab_close);
rotateForward=AnimationUtils.loadAnimation(getContext(),R.anim.rotate_forward);
rotateBackward=AnimationUtils.loadAnimation(getContext(),R.anim.rotate_backward);
shadowIn=AnimationUtils.loadAnimation(getContext(),R.anim.shadow_in);
shadowOut=AnimationUtils.loadAnimation(getContext(),R.anim.shadow_out);
inputCUP.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
rotatingImage.startAnimation(rotate180); //animación de el icono del centro indicando conversión en sentido contrario
}
});
inputCUC.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(!inputCUC.getText().toString().equals("")){
cuc=Float.valueOf(inputCUC.getText().toString());
cup=cuc*exchange;
inputCUP.setText(String.format("%.2f",cuc*exchange));
}
}
});
optionsFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animateFab();
}
});
eraseFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
inputCUP.setText("");
inputCUC.setText("");
cuc=0;
cup=0;
animateFab();
}
});
exchangeFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (exchange){
case 25:
exchange=24;
exchangeFab.setImageResource(R.drawable.custom24);
exchangeExplain.setText(String.format("Utilizando un cambio de %.0f:1",(float) exchange));
break;
case 24:
exchange=23;
exchangeFab.setImageResource(R.drawable.custom23);
exchangeExplain.setText(String.format("Utilizando un cambio de %.0f:1",(float) exchange));
break;
case 23:
exchange=25;
exchangeFab.setImageResource(R.drawable.custom25);
exchangeExplain.setText(String.format("Utilizando un cambio de %.0f:1",(float) exchange));
break;
default:
break;
}
//to be sure that CUC view is focused
if(inputCUC.hasFocus()){
inputCUP.setText(String.format("%.2f",cuc*exchange));
}
else if(inputCUP.hasFocus()){
Toast.makeText(getContext(),R.string.exchange_change_not_possible,Toast.LENGTH_SHORT).show();
animateFab();
}
if(inputCUC.getText().toString().equals("")){
inputCUP.setText("");
}
}
});
inputCUP.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(inputCUP.isFocused()){
if(!s.toString().equals("")){
cup=Float.valueOf(s.toString());
cuc=cup/25;
inputCUC.setText(String.format("%.2f",cup/25));
}
else
inputCUC.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
inputCUC.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(inputCUC.isFocused()){
if(!s.toString().equals("")){
cuc=Float.valueOf(s.toString());
cup=cuc*exchange;
inputCUP.setText(String.format("%.2f",cuc*exchange));
}
else
inputCUP.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
rotatingImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(inputCUC.isFocused()){
inputCUP.requestFocus();
}
else if(inputCUP.isFocused()){
inputCUC.requestFocus();
}
}
});
return view;
}
void animateFab(){
if(!isOptionsOpen){
optionsFab.startAnimation(rotateForward);
eraseFab.startAnimation(fabOpen);
eraseFab.setClickable(true);
eraseText.setVisibility(View.VISIBLE);
exchangeFab.startAnimation(fabOpen);
exchangeFab.setClickable(true);
exchangeText.setVisibility(View.VISIBLE);
backShadow.startAnimation(shadowIn);
backShadow.setVisibility(View.VISIBLE);
backShadow.setClickable(true);
isOptionsOpen=!isOptionsOpen;
}
else {
optionsFab.startAnimation(rotateBackward);
eraseFab.startAnimation(fabClose);
eraseFab.setClickable(false);
eraseText.setVisibility(View.INVISIBLE);
exchangeFab.startAnimation(fabClose);
exchangeFab.setClickable(false);
exchangeText.setVisibility(View.INVISIBLE);
backShadow.startAnimation(shadowOut);
backShadow.setVisibility(View.INVISIBLE);
backShadow.setClickable(false);
isOptionsOpen=!isOptionsOpen;
}
}
}
我认为问题在于活动重新启动时会再次调用onCreateView方法,因此将创建一个新视图而不会擦除旧视图.问题很烦人,因为在屏幕旋转时会创建新视图,我已经解决了强制肖像的问题,但这并不是真正的解决方案,至少不是一个优雅的解决方案.
I believe the problem is that when activity restarts the onCreateView method is called again so a new view is created without erase the old one. The problem is annoying because the new views are created when the screen rotates, i've solved the problem forcing portrait, but this is not really a solution, at least not an elegant one.
活动中:
package cu.me.cuanto;
import android.Manifest;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.TextView;
public class ActivityMain extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, FragmentHome.FragmentHomeListener {
//Variable Definitions
FragmentTransaction mFragmentTransaction,mDelayedFragmentTransaction;
Animation slideIn,slideOut,fullSlideIn;
FrameLayout homeFragmentContainer,conteoFragmentContainer,exchangeFragmentContainer,debtsFragmentContainer;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mToggle;
NavigationView mNavigationView;
//Other elements like fragments and some other stuff
FragmentHome home = new FragmentHome();
FragmentConteo conteo = new FragmentConteo();
FragmentCambio cambio = new FragmentCambio();
FragmentRecargas deudas = new FragmentRecargas();
@Override
protected void onCreate(Bundle savedInstanceState) {
//Return app to default theme for avoid keep using the one set in manifest
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(!allPermissionsGranted()){
final Dialog grantPermissions = new Dialog(ActivityMain.this);
grantPermissions.setContentView(R.layout.dialog_grant_permissions);
grantPermissions.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
TextView grantPermissionsButton = grantPermissions.findViewById(R.id.main_grant_permissions);
grantPermissionsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
grantPhoneRelatedPermissions();
if(allPermissionsGranted()){
grantPermissions.dismiss();
}
}
});
grantPermissions.show();
}
//para el intercambio de fragments
slideIn= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.slide_in);
slideOut= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.slide_out);
fullSlideIn = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.full_slide_in);
homeFragmentContainer=findViewById(R.id.home_fragment_container);
conteoFragmentContainer=findViewById(R.id.conteo_fragment_container);
exchangeFragmentContainer=findViewById(R.id.exchange_fragment_container);
debtsFragmentContainer=findViewById(R.id.debts_fragment_container);
//para el navigation drawer y la hamburquesa
mDrawerLayout = findViewById(R.id.drawer_layout_id);
mToggle = new ActionBarDrawerToggle(this,mDrawerLayout,R.string.open,R.string.close);
mDrawerLayout.addDrawerListener(mToggle);
mToggle.syncState();
//Get no shadow under appBar
getSupportActionBar().setElevation(0);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setNavigationItemSelectedListener(this);
//Declare FragmentTransactions and set their views
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mDelayedFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.add(R.id.home_fragment_container,home,"Home Fragment");
mFragmentTransaction.commit();
//TODO: make this other shit after first shit
mDelayedFragmentTransaction.add(R.id.conteo_fragment_container,conteo,"Conteo Fragment");
mDelayedFragmentTransaction.add(R.id.exchange_fragment_container,cambio,"Exchange Fragment");
mDelayedFragmentTransaction.add(R.id.debts_fragment_container,deudas,"Debts Fragment");
mDelayedFragmentTransaction.commit();
//Select First item on the list
mNavigationView.setCheckedItem(R.id.home_fragment_selector);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(mToggle.onOptionsItemSelected(item)){
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(final MenuItem item) {
final int id = item.getItemId();
Runnable closeDrawerLayoutRunnable = new Runnable() {
@Override
public void run() {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
};
Handler mHandler = new Handler();
switch (id){
case R.id.home_fragment_selector:
if(homeFragmentContainer.getVisibility()!=View.VISIBLE){
homeFragmentContainer.startAnimation(fullSlideIn);
homeFragmentContainer.setVisibility(View.VISIBLE);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
exchangeFragmentContainer.setVisibility(View.INVISIBLE);
debtsFragmentContainer.setVisibility(View.INVISIBLE);
}
break;
case R.id.conteo_fragment_selector:
if(conteoFragmentContainer.getVisibility()!=View.VISIBLE){
conteoFragmentContainer.startAnimation(fullSlideIn);
conteoFragmentContainer.setVisibility(View.VISIBLE);
homeFragmentContainer.setVisibility(View.INVISIBLE);
exchangeFragmentContainer.setVisibility(View.INVISIBLE);
debtsFragmentContainer.setVisibility(View.INVISIBLE);
conteo.isOptionsOpen=false;
}
break;
case R.id.exchange_fragment_selector:
if(exchangeFragmentContainer.getVisibility()!=View.VISIBLE) {
exchangeFragmentContainer.startAnimation(fullSlideIn);
exchangeFragmentContainer.setVisibility(View.VISIBLE);
homeFragmentContainer.setVisibility(View.INVISIBLE);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
debtsFragmentContainer.setVisibility(View.INVISIBLE);
cambio.isOptionsOpen = false;
}
break;
case R.id.debts_fragment_selector:
if(debtsFragmentContainer.getVisibility()!=View.VISIBLE){
debtsFragmentContainer.startAnimation(fullSlideIn);
debtsFragmentContainer.setVisibility(View.VISIBLE);
homeFragmentContainer.setVisibility(View.INVISIBLE);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
exchangeFragmentContainer.setVisibility(View.INVISIBLE);
}
break;
case R.id.navigation_settings:
Intent settings = new Intent(getApplicationContext(), ActivitySettings.class);
startActivity(settings);
break;
case R.id.about_cuanto:
Intent about = new Intent(getApplicationContext(), ActivityAbout.class);
startActivity(about);
break;
default:
break;
}
mHandler.post(closeDrawerLayoutRunnable);
return true;
}
@Override
public void onBackPressed() {
// check if there are some FAB menu opened
if(cambio.isOptionsOpen){
cambio.animateFab();
cambio.isOptionsOpen=false;
}
else if(conteo.isOptionsOpen){
conteo.animateFab();
conteo.isOptionsOpen=false;
}
// this sequence works fine just because first is checked if there are FABs open, then the selected fragment
else if(homeFragmentContainer.getVisibility()!=View.VISIBLE){
homeFragmentContainer.setVisibility(View.VISIBLE);
mNavigationView.setCheckedItem(R.id.home_fragment_selector);
if(conteoFragmentContainer.getVisibility()==View.VISIBLE){
conteoFragmentContainer.startAnimation(slideOut);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
}
else if(exchangeFragmentContainer.getVisibility()==View.VISIBLE){
exchangeFragmentContainer.startAnimation(slideOut);
exchangeFragmentContainer.setVisibility(View.INVISIBLE);
}
else if(debtsFragmentContainer.getVisibility()==View.VISIBLE){
debtsFragmentContainer.startAnimation(slideOut);
debtsFragmentContainer.setVisibility(View.INVISIBLE);
}
}
else{
super.onBackPressed();
}
}
//Custom interfaces implementation
@Override
public void onButtonListener(View view) {
if(view.getId()==R.id.conteo_card){
mNavigationView.setCheckedItem(R.id.conteo_fragment_selector);
conteoFragmentContainer.startAnimation(fullSlideIn);
conteoFragmentContainer.setVisibility(View.VISIBLE);
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
homeFragmentContainer.setVisibility(View.INVISIBLE);
exchangeFragmentContainer.setVisibility(View.INVISIBLE);
}
},300);
conteo.isOptionsOpen=false;
}
else if(view.getId()==R.id.cambio_card){
mNavigationView.setCheckedItem(R.id.exchange_fragment_selector);
exchangeFragmentContainer.startAnimation(fullSlideIn);
exchangeFragmentContainer.setVisibility(View.VISIBLE);
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
homeFragmentContainer.setVisibility(View.INVISIBLE);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
}
},300);
cambio.isOptionsOpen=false;
}
else if(view.getId()==R.id.debts_card){
mNavigationView.setCheckedItem(R.id.debts_fragment_selector);
debtsFragmentContainer.startAnimation(fullSlideIn);
debtsFragmentContainer.setVisibility(View.VISIBLE);
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
homeFragmentContainer.setVisibility(View.INVISIBLE);
conteoFragmentContainer.setVisibility(View.INVISIBLE);
}
},300);
}
}
//My own Functions
private void grantPhoneRelatedPermissions(){
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.READ_PHONE_STATE)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ActivityMain.this,new String[]{Manifest.permission.CALL_PHONE,Manifest.permission.READ_PHONE_STATE},1);
return;
}
}
private boolean allPermissionsGranted(){
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.READ_PHONE_STATE)== PackageManager.PERMISSION_GRANTED){
return true;
}
else
return false;
}
}
推荐答案
FragmentManager
在重新创建活动"(即savedInstanceState != null
时)时会自动还原以前添加的所有片段.因此,您需要确保仅添加一次初始Fragment-当savedInstanceState
为null时.
FragmentManager
automatically restores any previously added Fragments when your Activity is recreated (i.e., when savedInstanceState != null
). Therefore you'll want to ensure that you only add your initial Fragment once - when the savedInstanceState
is null.
if (savedInstanceState == null) {
// Create new instances if the savedInstanceState == null
home = new FragmentHome();
conteo = new FragmentConteo();
cambio = new FragmentCambio();
deudas = new FragmentRecargas();
//Declare FragmentTransactions and set their views
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
mDelayedFragmentTransaction = getSupportFragmentManager().beginTransaction();
mFragmentTransaction.add(R.id.home_fragment_container,home,"Home Fragment");
mFragmentTransaction.commit();
//TODO: make this other shit after first shit
mDelayedFragmentTransaction.add(R.id.conteo_fragment_container,conteo,"Conteo Fragment");
mDelayedFragmentTransaction.add(R.id.exchange_fragment_container,cambio,"Exchange Fragment");
mDelayedFragmentTransaction.add(R.id.debts_fragment_container,deudas,"Debts Fragment");
mDelayedFragmentTransaction.commit();
} else {
// Get the already existing Fragments out of FragmentManager
home = (FragmentHome) getSupportFragmentManager().findFragmentById(R.id.home_fragment_container);
conteo = (FragmentConteo) getSupportFragmentManager().findFragmentById(R.id.conteo_fragment_container);
cambio = (FragmentCambio) getSupportFragmentManager().findFragmentById(R.id.exchange_fragment_container);
deudas = (FragmentRecargas) getSupportFragmentManager().findFragmentById(R.id.debts_fragment_container);
}
您会注意到,当保存的实例状态为 not null时,我们将从FragmentManager获取已经存在的片段实例,而不是创建一个新实例.
You'll note that when the saved instance state is not null, we get the already existing fragment instances from FragmentManager rather than creating a new instance.
这篇关于重新启动活动会创建重复的片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!