Oleg Riabtsev
Oleg Riabtsev

Reputation: 477

Android can not perform this action after saveInstanceState when run app via another app

I have a Fragment with BroadcastReceiver inside, which is contained in Activity. Activity has intent-filter to determine application links. After some actions in fragment I get an e-mail from server with application link. So when I tap on home button on device application doesn't destroy and when I click on link in e-mail, a new fragment must open but I have an IllegalStateException with text Can not perform this action after saveInstanceState instead. How to fix it? Below I've attached my activity and two fragments code:

public class PerfectoActivity extends AppCompatActivity implements ProgressUpdater, AuthFragment.ProgressActivator {

    @Bind(R.id.sign_up_progress) ProgressBar mSignUpProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_perfecto);
        ButterKnife.bind(this);
        if (cameFromMail()) {
            if (isSignUpProcess()) {
                mSignUpProgressBar.setVisibility(View.VISIBLE);
                String login = Utils.getLogin(this);
                String password = Utils.getPassword(this);
                String username = Utils.getUsername(this);
                String phone = Utils.getPhone(this);
                Utils.removePasswordAndPhone(this);
                ApiService.startActionAuth(this, login, password);
                getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, SignUpThirdStepFragment.newInstance(username, phone)).commit();
            } else {
                String login = Utils.getLogin(this);
                String resetCode = Utils.getResetCode(this);
                ApiService.startActionCheckConfirmReset(this, login, resetCode);
                getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, ResetPasswordFourthStepFragment.newInstance(login, resetCode)).commit();
            }
        } else {
            Utils.removePasswordAndPhone(this);
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new AuthFragment()).commit();
        }
    }

    private boolean isSignUpProcess() {
        Intent intent = getIntent();
        if (intent.getData() != null) {
            if (intent.getData().getLastPathSegment().equals("confirmreset")) {
                return false;
            }
            return true;
        }
        return false;
    }

    private boolean cameFromMail() {
        Intent intent = getIntent();
        if (intent.getData() != null)
        if (Intent.ACTION_VIEW.equals(intent.getAction())) return true;
        return false;
    }

    @Override
    public void updateProgress(int progress) {
        mSignUpProgressBar.setProgress(progress);
    }

    @Override
    public void activateProgress() {
        if (mSignUpProgressBar.getVisibility() == View.VISIBLE) {
            mSignUpProgressBar.setVisibility(View.GONE);
        }
        else {
            mSignUpProgressBar.setVisibility(View.VISIBLE);
        }
    }
}

Here is the first fragment

public class ResetPasswordSecondStepFragment extends Fragment {


    private static final String BUNDLE_LOGIN = "com.rcd.perfecto.fragments.ResetPasswordSecondStep.bundle.LOGIN";
    public static final String RESET_PASSWORD_FILTER = "com.rcd.perfecto.fragments.filter.RESET_PASSWORD";

    private String mLogin;
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
            if (!intent.getBooleanExtra(ApiService.EXTRA_SUCCESS, false)) {
                mPhoneErrorTextView.setVisibility(View.VISIBLE);
                mPhoneErrorTextView.setText(intent.getStringExtra(ApiService.EXTRA_MESSAGE));
            } else {
                String phone = mLastDigitsEditText.getText().toString();
                String resetCode = intent.getStringExtra(ApiService.EXTRA_DATA);
                FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragment_container, ResetPasswordThirdStepFragment.newInstance(mLogin, phone, resetCode)).commit();
            }
        }
    };

    @Bind(R.id.et_last_digits) EditText mLastDigitsEditText;
    @Bind(R.id.tv_phone_error) TextView mPhoneErrorTextView;

    @OnTextChanged(R.id.et_last_digits)
    void resetPassword(CharSequence digits) {
        if (digits.length() == 4) ApiService.startActionResetPassword(getActivity(), mLogin, mLastDigitsEditText.getText().toString());
    }

    public ResetPasswordSecondStepFragment() {
        // Required empty public constructor
    }

    public static ResetPasswordSecondStepFragment newInstance(String login) {
        ResetPasswordSecondStepFragment fragment = new ResetPasswordSecondStepFragment();
        Bundle args = new Bundle();
        args.putString(BUNDLE_LOGIN, login);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            mLogin =  args.getString(BUNDLE_LOGIN);
        }
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver, new IntentFilter(RESET_PASSWORD_FILTER));
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_reset_password_second_step, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onDestroy() {
       super.onDestroy();
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
    }
}

And the last one

public class ResetPasswordThirdStepFragment extends Fragment {

    private static final String BUNDLE_LOGIN = "com.rcd.perfecto.fragments.bundle.LOGIN";
    private static final String BUNDLE_RESET_CODE = "com.rcd.perfecto.fragments.bundle.RESET_CODE";
    private static final String BUNDLE_PHONE = "com.rcd.perfecto.fragments.bundle.PHONE";

    public static final String CHECK_CONFIRM_RESET_FILTER = "com.rcd.perfecto.fragments.filters.CHECK_CONFIRM_RESET";

    private String mResetCode;
    private String mLogin;
    private String mPhone;

    private BroadcastReceiver mConfirmReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!intent.getBooleanExtra(ApiService.EXTRA_SUCCESS, false)) {
                Utils.showAlert(R.string.reset_password_error, intent.getStringExtra(ApiService.EXTRA_MESSAGE), getActivity());
            } else {
                if (intent.getBooleanExtra(ApiService.EXTRA_DATA, false)) {
                     FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
                    transaction.replace(R.id.fragment_container, ResetPasswordFourthStepFragment.newInstance(mLogin, mResetCode)).commit();
                } else {
                    Utils.showAlert(R.string.reset_password_error, getResources().getString(R.string.reset_password_error_desc), getActivity());
               }
            }
        }
    };

    private BroadcastReceiver mSendConfirmationReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!intent.getBooleanExtra(ApiService.EXTRA_SUCCESS, false)) {
                Utils.showAlert(R.string.reset_password_error, intent.getStringExtra(ApiService.EXTRA_MESSAGE), getActivity());
            } else {
                mResetCode = intent.getStringExtra(ApiService.EXTRA_DATA);
                Utils.showAlert(R.string.sign_up_confirmation_link_title, getResources().getString(R.string.sign_up_confirmation_link), getActivity());
            }
        }
    };

    @Bind(R.id.btn_continue) Button mContinueButton;
    @Bind(R.id.tv_not_got_email) TextView mNotGotMailTextView;

    @OnClick(R.id.btn_continue)
    void confirmResetting() {
        ApiService.startActionCheckConfirmReset(getActivity(), mLogin, mResetCode);
    }

    @OnClick(R.id.tv_not_got_email)
    void sendConfirmationAgaing() {
        ApiService.startActionResetPassword(getActivity(), mLogin, mPhone);
    }

    public ResetPasswordThirdStepFragment() {
        // Required empty public constructor
    }

    public static ResetPasswordThirdStepFragment newInstance(String login, String phone, String resetCode) {
        ResetPasswordThirdStepFragment fragment = new ResetPasswordThirdStepFragment();
        Bundle args = new Bundle();
        args.putString(BUNDLE_LOGIN, login);
        args.putString(BUNDLE_PHONE, phone);
        args.putString(BUNDLE_RESET_CODE, resetCode);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
           mLogin = args.getString(BUNDLE_LOGIN);
           mPhone = args.getString(BUNDLE_PHONE);
           mResetCode = args.getString(BUNDLE_RESET_CODE);
           Utils.saveLogin(getActivity(), mLogin);
           Utils.savePhone(getActivity(), mPhone);
           Utils.saveResetCode(getActivity(), mResetCode);
        }
          LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mConfirmReceiver, new IntentFilter(CHECK_CONFIRM_RESET_FILTER));
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mSendConfirmationReceiver, new IntentFilter(ResetPasswordSecondStepFragment.RESET_PASSWORD_FILTER));
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_reset_password_third_step, container, false);
        ButterKnife.bind(this, view);
        return view;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mConfirmReceiver);
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mSendConfirmationReceiver);
    }
}

Upvotes: 0

Views: 92

Answers (1)

Alex Orlov
Alex Orlov

Reputation: 18107

I see you are doing some fragment transactions in your BroadcastReceivers, so these operations can be performed when activity is paused and onSaveInstanceState was already called. Try using FragmentTransaction.commitAllowingStateLoss() instead of simple FragmentTransaction.commit();

Upvotes: 1

Related Questions