重新启动活动会创建重复的片段 [英] Restarting Activity creates duplicate fragments

查看:118
本文介绍了重新启动活动会创建重复的片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我的活动重新开始时,我会得到彼此重叠的片段,新片段会覆盖旧片段,并且只有最新片段是可编辑的

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆