当活动在旋转时被销毁时,Fragment的自定义侦听器为null

时间:2018-03-10 05:05:48

标签: android android-fragments fragmentmanager

我有3个片段和一个活动。这些片段定义了一个用于将结果传递给活动的接口。

此接口在onAttach()中初始化,并在onDetach()中设置为null。但是,当活动被销毁并在轮换时重新创建时,接口将设置为null,并且在调用它们时,会导致NullPointerException。

这是片段和活动的代码。

MainActivity.java

package com.gianfranco.rsa.view;

import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.gianfranco.rsa.R;
import com.gianfranco.rsa.view.fragment.InputKeySizeFragment;
import com.gianfranco.rsa.view.fragment.InputPlainTextFragment;
import com.gianfranco.rsa.view.fragment.RSADetailsFragment;

public class MainActivity extends AppCompatActivity implements InputKeySizeFragment.OnKeySizeListener,
        InputPlainTextFragment.OnMessageListener, RSADetailsFragment.OnClickHomeListener {

    private InputKeySizeFragment inputKeySizeFragment;
    private InputPlainTextFragment inputPlainTextFragment;
    private RSADetailsFragment rsaDetailsFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            inputKeySizeFragment = new InputKeySizeFragment();
            inputPlainTextFragment = new InputPlainTextFragment();
            rsaDetailsFragment = new RSADetailsFragment();

            getSupportFragmentManager().beginTransaction()
                    .add(R.id.main_container, inputKeySizeFragment)
                    .addToBackStack(null)
                    .commit();
        }
    }

    @Override
    public void onKeySizeSelected(int keySize) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.main_container, inputPlainTextFragment)
                .addToBackStack(null)
                .commit();
    }

    @Override
    public void onMessageEntered(String message) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.main_container, rsaDetailsFragment)
                .addToBackStack(null)
                .commit();
    }

    @Override
    public void onClickHome() {
        getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

        getSupportFragmentManager().beginTransaction()
                .add(R.id.main_container, inputKeySizeFragment)
                .addToBackStack(null)
                .commit();
    }
}

InputKeySizeFragment.java

package com.gianfranco.rsa.view.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;

import com.gianfranco.rsa.R;

public class InputKeySizeFragment extends Fragment {

    private Spinner keySizeSpinner;
    private Button buttonNext;
    private ArrayAdapter<Integer> adapter;

    private OnKeySizeListener listener;

    @FunctionalInterface
    public interface OnKeySizeListener {
        void onKeySizeSelected(int keySize);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        if (context instanceof OnKeySizeListener) {
            listener = (OnKeySizeListener) context;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_input_key_size, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        keySizeSpinner = view.findViewById(R.id.spinner_key_size);
        buttonNext = view.findViewById(R.id.btn_next);

        Integer[] bits = new Integer[]{64, 128, 256, 512, 1024, 2048};
        adapter = new ArrayAdapter<>(getActivity(), R.layout.support_simple_spinner_dropdown_item, bits);
        adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
        keySizeSpinner.setAdapter(adapter);

        buttonNext.setOnClickListener(v -> {
            int keySize = (Integer) keySizeSpinner.getSelectedItem();
            listener.onKeySizeSelected(keySize);
        });
    }

    @Override
    public void onDestroyView() {
        keySizeSpinner = null;
        buttonNext = null;
        adapter = null;
        super.onDestroyView();
    }

    @Override
    public void onDetach() {
        listener = null;
        super.onDetach();
    }
}

InputPlainTextFragment.java

package com.gianfranco.rsa.view.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

import com.gianfranco.rsa.R;

public class InputPlainTextFragment extends Fragment {

    private EditText editTextMessage;
    private Snackbar snackbar;
    private Button buttonNext;

    private OnMessageListener listener;

    @FunctionalInterface
    public interface OnMessageListener {
        void onMessageEntered(String message);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        if (context instanceof OnMessageListener) {
            listener = (OnMessageListener) context;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_input_plain_text, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        editTextMessage = view.findViewById(R.id.et_message);
        buttonNext = view.findViewById(R.id.btn_details);
        buttonNext.setOnClickListener(v -> listener.onMessageEntered(editTextMessage.getText().toString()));
    }

    @Override
    public void onDestroyView() {
        editTextMessage = null;
        buttonNext = null;
        super.onDestroyView();
    }

    @Override
    public void onDetach() {
        listener = null;
        super.onDetach();
    }
}

RSADetailsFragment.java

package com.gianfranco.rsa.view.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import com.gianfranco.rsa.R;

public class RSADetailsFragment extends Fragment {

    private TextView pValue;
    private TextView qValue;
    private TextView nValue;
    private TextView zValue;
    private TextView dValue;
    private TextView eValue;
    private TextView encryptedValue;
    private TextView decryptedValue;
    private Button buttonHome;

    private OnClickHomeListener listener;

    @FunctionalInterface
    public interface OnClickHomeListener {
        void onClickHome();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        if (context instanceof OnClickHomeListener) {
            listener = (OnClickHomeListener) context;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_rsa_details, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        pValue = view.findViewById(R.id.tv_pValue);
        qValue = view.findViewById(R.id.tv_qValue);
        nValue = view.findViewById(R.id.tv_nValue);
        zValue = view.findViewById(R.id.tv_zValue);
        dValue = view.findViewById(R.id.tv_dValue);
        eValue = view.findViewById(R.id.tv_eValue);
        encryptedValue = view.findViewById(R.id.tv_encrypted_value);
        decryptedValue = view.findViewById(R.id.tv_decrypted_value);
        buttonHome = view.findViewById(R.id.btn_home);

        buttonHome.setOnClickListener(v -> listener.onClickHome());
    }

    @Override
    public void onDestroyView() {
        pValue = null;
        qValue = null;
        nValue = null;
        zValue = null;
        dValue = null;
        eValue = null;
        encryptedValue = null;
        decryptedValue = null;
        buttonHome = null;
        super.onDestroyView();
    }

    @Override
    public void onDetach() {
        listener = null;
        super.onDetach();
    }
}

这是错误消息

03-10 00:03:16.243 31676-31676/com.gianfranco.rsa E/AndroidRuntime: FATAL EXCEPTION: main
                                                                    Process: com.gianfranco.rsa, PID: 31676
                                                                    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
                                                                        at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:392)
                                                                        at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:381)
                                                                        at com.gianfranco.rsa.view.MainActivity.onKeySizeSelected(MainActivity.java:39)
                                                                        at com.gianfranco.rsa.view.fragment.InputKeySizeFragment.lambda$onViewCreated$0$InputKeySizeFragment(InputKeySizeFragment.java:58)
                                                                        at com.gianfranco.rsa.view.fragment.InputKeySizeFragment$$Lambda$0.onClick(Unknown Source)
                                                                        at android.view.View.performClick(View.java:4819)
                                                                        at android.view.View$PerformClick.run(View.java:20152)
                                                                        at android.os.Handler.handleCallback(Handler.java:815)
                                                                        at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                        at android.os.Looper.loop(Looper.java:194)
                                                                        at android.app.ActivityThread.main(ActivityThread.java:5562)
                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                        at java.lang.reflect.Method.invoke(Method.java:372)
                                                                        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:968)
                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:763)

我有什么遗漏或做错了吗?请让我知道。

1 个答案:

答案 0 :(得分:0)

Add this line in your activity manifest
  

机器人:configChanges = “keyboardHidden |取向|屏幕尺寸”

 <activity android:name=".MainActivity"
           android:configChanges="keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>