简体   繁体   中英

Why does my fragment crash when switching to landscape?

Well to be more specific I have made a create account fragment and a login fragment. When switching to landscape in the create account fragment it actually goes back to the login fragment. And then if you try to switch back into portrait then the app crashes. I've looked at similar questions but I couldnt make anything out from them. I really appreciate the help guys!

CreateAccountFragment

package com.keyconsultant.parse.logintutorial;
/**
 * Create an Account. Username is the primary method of login. Email is used for forgotten password recovery. 
 * 
 * @author Trey Robinson
 *
 */
public class CreateAccountFragment extends BaseFragment implements OnClickListener {

    protected static final String EXTRA_EMAIL = "com.keyconsultant.parse.logintutorial.fragment.extra.EMAIL";
    protected static final String EXTRA_USERNAME = "com.keyconsultant.parse.logintutorial.fragment.extra.USERNAME";
    protected static final String EXTRA_PASSWORD = "com.keyconsultant.parse.logintutorial.fragment.extra.PASSWORD";
    protected static final String EXTRA_CONFIRM = "com.keyconsultant.parse.logintutorial.fragment.extra.CONFIRMPASSWORD";

    private EditText mUserNameEditText;
    private EditText mEmailEditText; 
    private EditText mPasswordEditText;
    private EditText mConfirmPasswordEditText;
    private Button mCreateAccountButton;

    private String mEmail;
    private String mUsername;
    private String mPassword;
    private String mConfirmPassword;

    /**
     * Factory method for creating fragment instances.
     * @return
     */
    public static CreateAccountFragment newInstance(){
        return new CreateAccountFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_create_account, container, false);

        mUserNameEditText = (EditText)view.findViewById(R.id.etUsername);
        mEmailEditText = (EditText)view.findViewById(R.id.etEmail);
        mPasswordEditText = (EditText)view.findViewById(R.id.etPassword);
        mConfirmPasswordEditText = (EditText)view.findViewById(R.id.etPasswordConfirm);

        mCreateAccountButton = (Button)view.findViewById(R.id.btnCreateAccount);
        mCreateAccountButton.setOnClickListener(this);
        return view;
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        if(savedInstanceState != null){
            mEmailEditText.setText(savedInstanceState.getString(EXTRA_EMAIL));
            mUserNameEditText.setText(savedInstanceState.getString(EXTRA_USERNAME));
            mPasswordEditText.setText(savedInstanceState.getString(EXTRA_PASSWORD));
            mConfirmPasswordEditText.setText(savedInstanceState.getString(EXTRA_CONFIRM));
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(EXTRA_EMAIL, mEmailEditText.getText().toString());
        outState.putString(EXTRA_USERNAME, mUserNameEditText.getText().toString());
        outState.putString(EXTRA_PASSWORD, mPasswordEditText.getText().toString());
        outState.putString(EXTRA_CONFIRM, mConfirmPasswordEditText.getText().toString());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btnCreateAccount:
            createAccount();
            break;

        default:
            break;
        }
    }

    /**
     * Some front end validation is done that is not monitored by the service. 
     * If the form is complete then the information is passed to the service. 
     */
    private void createAccount(){
        clearErrors();

        boolean cancel = false;
        View focusView = null;

     // Store values at the time of the login attempt.
        mEmail = mEmailEditText.getText().toString();
        mUsername = mUserNameEditText.getText().toString();
        mPassword = mPasswordEditText.getText().toString();
        mConfirmPassword = mConfirmPasswordEditText.getText().toString();

        // Check for a valid confirm password.
        if (TextUtils.isEmpty(mConfirmPassword)) {
            mConfirmPasswordEditText.setError(getString(R.string.error_field_required));
            focusView = mConfirmPasswordEditText;
            cancel = true;
        } else if (mPassword != null && !mConfirmPassword.equals(mPassword)) {
            mPasswordEditText.setError(getString(R.string.error_invalid_confirm_password));
            focusView = mPasswordEditText;
            cancel = true;
        }
        // Check for a valid password.
        if (TextUtils.isEmpty(mPassword)) {
            mPasswordEditText.setError(getString(R.string.error_field_required));
            focusView = mPasswordEditText;
            cancel = true;
        } else if (mPassword.length() < 4) {
            mPasswordEditText.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordEditText;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(mEmail)) {
            mEmailEditText.setError(getString(R.string.error_field_required));
            focusView = mEmailEditText;
            cancel = true;
        } else if (!mEmail.contains("@")) {
            mEmailEditText.setError(getString(R.string.error_invalid_email));
            focusView = mEmailEditText;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            UserManager.getInstance().signUp(mUsername.toLowerCase(Locale.getDefault()), mEmail, mPassword);

        }

    }

    /**
     * Remove error messages from all fields. 
     */
    private void clearErrors(){ mEmailEditText.setError(null);
        mUserNameEditText.setError(null);
        mPasswordEditText.setError(null);
        mConfirmPasswordEditText.setError(null);
    }

    @Subscribe
    public void onSignInError(AuthenticateUserErrorEvent event){
        clearErrors();
        switch (event.getErrorCode()) {
            case ParseException.INVALID_EMAIL_ADDRESS:
                mEmailEditText.setError(getString(R.string.error_invalid_email));
                mEmailEditText.requestFocus();
                break;
            case ParseException.EMAIL_TAKEN:
                mEmailEditText.setError(getString(R.string.error_duplicate_email));
                mEmailEditText.requestFocus();
                break;
            case ParseException.USERNAME_TAKEN:
                mUserNameEditText.setError(getString(R.string.error_duplicate_username));
                mUserNameEditText.requestFocus();
                break;
            default:
                UnknownErrorDialogFactory.createUnknownErrorDialog(this.getActivity()).show();
                break;
        }
    }

}

LoginFragment

package com.keyconsultant.parse.logintutorial;
/**
 * Fragment for logging in. Includes button for loading the Create account view.
 * 
 * @author Trey Robinson
 * 
 */
public class LoginFragment extends BaseFragment {

    public static final String EXTRA_USERNAME = "com.keyconsultant.parse.logintutorial.activity.extra.USERNAME";
    public static final String EXTRA_PASSWORD = "com.keyconsultant.parse.logintutorial.activity.extra.PASSWORD";

    // UI references.
    private EditText mUserNameEditText;
    private EditText mPasswordEditText;

    /**
     * Factory method for creating new fragments
     * 
     * @return
     */
    public static LoginFragment newInstance() {
        return new LoginFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_login, container, false);

        mUserNameEditText = (EditText) view.findViewById(R.id.username);

        mPasswordEditText = (EditText) view.findViewById(R.id.password);
        mPasswordEditText
                .setOnEditorActionListener(new TextView.OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView textView, int id,
                            KeyEvent keyEvent) {
                        if (id == EditorInfo.IME_NULL) {
                            attemptLogin();
                            return true;
                        }
                        return false;
                    }
                });

        view.findViewById(R.id.sign_in_button).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        attemptLogin();
                    }
                });

        view.findViewById(R.id.register_button).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        createAccount();
                    }
                });

        view.findViewById(R.id.forgot_button).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        forgotPassword();
                    }
                });
        return view;
    }

    /**
     * Open the forgotPassword dialog
     */
    private void forgotPassword() {
        FragmentManager fm = getActivity().getSupportFragmentManager();
        ForgotPasswordDialogFragment forgotPasswordDialog = new ForgotPasswordDialogFragment();
        forgotPasswordDialog.show(fm, null);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) {
            mUserNameEditText.setText(savedInstanceState
                    .getString(EXTRA_USERNAME));
            mPasswordEditText.setText(savedInstanceState
                    .getString(EXTRA_PASSWORD));
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(EXTRA_USERNAME, mUserNameEditText.getText()
                .toString());
        outState.putString(EXTRA_PASSWORD, mPasswordEditText.getText()
                .toString());
    }

    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (invalid email, missing fields, etc.), the
     * errors are presented and no actual login attempt is made.
     */
    public void attemptLogin() {

        clearErrors();

        // Store values at the time of the login attempt.
        String username = mUserNameEditText.getText().toString();
        String password = mPasswordEditText.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid password.
        if (TextUtils.isEmpty(password)) {
            mPasswordEditText
                    .setError(getString(R.string.error_field_required));
            focusView = mPasswordEditText;
            cancel = true;
        } else if (password.length() < 4) {
            mPasswordEditText
                    .setError(getString(R.string.error_invalid_password));
            focusView = mPasswordEditText;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(username)) {
            mUserNameEditText
                    .setError(getString(R.string.error_field_required));
            focusView = mUserNameEditText;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // perform the user login attempt.
            UserManager.getInstance().authenticate(
                    username.toLowerCase(Locale.getDefault()), password);
        }
    }

    /**
     * Load the create account view.
     */
    private void createAccount() {
        FragmentManager fragmentManager = getActivity()
                .getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager
                .beginTransaction();
        fragmentTransaction
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        fragmentTransaction.replace(
                ((ViewGroup) getView().getParent()).getId(),
                CreateAccountFragment.newInstance());
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }

    /**
     * Remove all edit text errors
     */
    private void clearErrors() {
        mUserNameEditText.setError(null);
        mPasswordEditText.setError(null);
    }

    @Subscribe
    public void onSignInError(AuthenticateUserErrorEvent event) {
        clearErrors();
        switch (event.getErrorCode()) {
        case ParseException.OBJECT_NOT_FOUND:
            mPasswordEditText
                    .setError(getString(R.string.error_incorrect_password));
            mPasswordEditText.requestFocus();
            break;
        default:
            UnknownErrorDialogFactory.createUnknownErrorDialog(
                    this.getActivity()).show();
            break;
        }
    }
}

Just in case you need it here is my LoginActivity

package com.keyconsultant.parse.logintutorial;

/**
 * Activity which displays a login screen to the user, offering registration as
 * well. Based loosley on the default Login template.
 * 
 * @author Trey Robinson
 */
public class LoginActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

        Parse.initialize(this, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");


        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager
                .beginTransaction();
        fragmentTransaction
                .replace(R.id.main_view, LoginFragment.newInstance());
        fragmentTransaction.commit();
        parseCache();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.activity_login, menu);
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.menu_forgot_password:
            forgotPassword();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Open the forgotPassword dialog
     */
    private void forgotPassword() {
        FragmentManager fm = getSupportFragmentManager();
        ForgotPasswordDialogFragment forgotPasswordDialog = new ForgotPasswordDialogFragment();
        forgotPasswordDialog.show(fm, null);
    }

    @Subscribe
    public void onSignInStart(AuthenticateUserStartEvent event) {
        showProgress(true, getString(R.string.login_progress_signing_in));
    }

    @Subscribe
    public void onSignInSuccess(AuthenticateUserSuccessEvent event) {
        showProgress(false, getString(R.string.login_progress_signing_in));
        Intent loginSuccess = new Intent(this, MainActivity.class);
        startActivity(loginSuccess);
        finish();
    }

    @Subscribe
    public void onSignInError(AuthenticateUserErrorEvent event) {
        showProgress(false, getString(R.string.login_progress_signing_in));
    }

    @Subscribe
    public void onForgotPasswordStart(UserForgotPasswordStartEvent event) {
        showProgress(true, getString(R.string.login_progress_signing_in));
    }

    @Subscribe
    public void onForgotPasswordSuccess(UserForgotPasswordSuccessEvent event) {
        showProgress(false, getString(R.string.login_progress_signing_in));
        Toast toast = Toast.makeText(this,
                "A password reset email has been sent.", Toast.LENGTH_LONG);
        toast.show();
    }

    @Subscribe
    public void onForgotPasswordError(UserForgotPasswordErrorEvent event) {
        showProgress(false, getString(R.string.login_progress_signing_in));
        Toast toast = Toast.makeText(this,
                "An error has occured. Please try again.", Toast.LENGTH_LONG);
        toast.show();
    }

    private void parseCache() {
        Intent intent;

        if (ParseUser.getCurrentUser() != null) {
            intent = new Intent(this, MainActivity.class);
            startActivity(intent);
            this.finish();
        }
    }
}

Here is the logcat

01-10 16:09:05.796: I/Process(1923): Sending signal. PID: 1923 SIG: 9
01-10 17:00:57.513: I/Choreographer(1975): Skipped 111 frames!  The application may be doing too much work on its main thread.
01-10 17:00:57.513: D/gralloc_goldfish(1975): Emulator without GPU emulation detected.
01-10 17:00:58.363: I/Choreographer(1975): Skipped 36 frames!  The application may be doing too much work on its main thread.
01-10 17:00:58.833: I/Choreographer(1975): Skipped 37 frames!  The application may be doing too much work on its main thread.
01-10 17:00:59.163: I/Choreographer(1975): Skipped 32 frames!  The application may be doing too much work on its main thread.
01-10 17:01:11.253: D/dalvikvm(1975): GC_FOR_ALLOC freed 74K, 5% free 5533K/5820K, paused 2ms, total 3ms
01-10 17:01:11.253: I/dalvikvm-heap(1975): Grow heap (frag case) to 7.992MB for 2500620-byte allocation
01-10 17:01:11.263: D/dalvikvm(1975): GC_FOR_ALLOC freed 2K, 4% free 7972K/8264K, paused 2ms, total 3ms
01-10 17:01:11.273: D/dalvikvm(1975): GC_FOR_ALLOC freed <1K, 4% free 7972K/8264K, paused 3ms, total 4ms
01-10 17:01:11.273: I/dalvikvm-heap(1975): Grow heap (frag case) to 10.696MB for 2838540-byte allocation
01-10 17:01:11.283: D/dalvikvm(1975): GC_FOR_ALLOC freed 0K, 3% free 10744K/11040K, paused 4ms, total 4ms
01-10 17:01:15.953: D/dalvikvm(1975): GC_FOR_ALLOC freed 5268K, 45% free 6880K/12360K, paused 0ms, total 3ms
01-10 17:01:15.953: I/dalvikvm-heap(1975): Grow heap (frag case) to 8.489MB for 1642512-byte allocation
01-10 17:01:15.973: D/dalvikvm(1975): GC_FOR_ALLOC freed <1K, 32% free 8483K/12360K, paused 13ms, total 13ms
01-10 17:01:16.053: I/Choreographer(1975): Skipped 42 frames!  The application may be doing too much work on its main thread.
01-10 17:01:17.473: I/Choreographer(1975): Skipped 58 frames!  The application may be doing too much work on its main thread.
01-10 17:01:18.043: I/Choreographer(1975): Skipped 57 frames!  The application may be doing too much work on its main thread.
01-10 17:01:23.363: D/AndroidRuntime(1975): Shutting down VM
01-10 17:01:23.363: W/dalvikvm(1975): threadid=1: thread exiting with uncaught exception (group=0xb0f2e648)
01-10 17:01:23.363: E/AndroidRuntime(1975): FATAL EXCEPTION: main
01-10 17:01:23.363: E/AndroidRuntime(1975): java.lang.NullPointerException
01-10 17:01:23.363: E/AndroidRuntime(1975):     at com.keyconsultant.parse.logintutorial.LoginFragment.onSaveInstanceState(LoginFragment.java:119)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.support.v4.app.Fragment.performSaveInstanceState(Fragment.java:1607)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.java:1587)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1655)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:527)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.Activity.performSaveInstanceState(Activity.java:1147)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1223)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3714)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.ActivityThread.access$700(ActivityThread.java:141)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.os.Looper.loop(Looper.java:137)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at android.app.ActivityThread.main(ActivityThread.java:5103)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at java.lang.reflect.Method.invokeNative(Native Method)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at java.lang.reflect.Method.invoke(Method.java:525)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
01-10 17:01:23.363: E/AndroidRuntime(1975):     at dalvik.system.NativeStart.main(Native Method)

Your logcat shows you have problems in LoginFragment.onSaveInstanceState()

First, make super.onSaveInstanceState() the last line instead of the first line as it is now.

Then make sure you don't have mUserName and mPassword and their texts as nulls

Initialize mUserName and password texts to "" somewhere and the error should be gone, I think.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM