首页 > 解决方案 > 当 FragmentActivity 在 Android 中进入后台时出现 NotSerializableException

问题描述

我的活动中有 5 个片段,其中一个片段一次保持活动状态。单击一个 recyclerview 项目会打开另一个片段并将当前片段放入后台堆栈。
几天前相同的代码运行良好,但现在每当我单击主页按钮将应用程序置于后台时,应用程序都会抛出NotSerializableException 。我尝试将初始化变量放在 onStart 中,然后在 onStop 中给出空值,但这不起作用。
片段代码:

public class PaperListFragment extends Fragment implements Serializable {

private static final String TAG = "PaperListFragment";
private static final String QUESTIONS_FRAGMENT_TAG = "questions_fragment";
private static final String ADD_PAPER_FRAGMENT_TAG = "add_paper_fragment";

private OnFragmentActiveListener mOnFragmentActiveListener;
private TextView mHeadingText;
private Bundle mOutState;
private FirebaseAuth mAuth;
private DatabaseReference mDatabaseReference;
private ProgressBar mProgressBar;
private OnItemClickListener mOnItemClickListener;
private FloatingActionButton mFab;
private RecyclerView mRecyclerViewPaper;
private ArrayList<Paper> mPaperList = new ArrayList<>();
private Subject mSubject = new Subject();
private Exam mExam = new Exam();

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_recycler_list, container, false);


    mProgressBar = (ProgressBar) rootView.findViewById(R.id.progressbar_news);
    mFab = (FloatingActionButton) rootView.findViewById(R.id.floatingActionButton);
    mProgressBar.setVisibility(View.VISIBLE);
    Log.d(TAG, "onCreateView: Fragment created");
    mAuth = FirebaseAuth.getInstance();
    mDatabaseReference = FirebaseDatabase.getInstance().getReference();
    if (mAuth.getCurrentUser() == null) {
        startActivity(new Intent(getActivity(), LoginActivity.class));
        getActivity().finish();
        return null;
    }

    if (getArguments() != null) {
        mOnFragmentActiveListener = (OnFragmentActiveListener) getArguments().getSerializable(Keys.FRAGMENT_ACTIVE_LISTENER);
        mSubject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
        mExam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
    }

    mRecyclerViewPaper = (RecyclerView) rootView.findViewById(R.id.recycler_list);
    LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()) {
        @Override
        public boolean canScrollVertically() {
            return false;
        }
    };
    mRecyclerViewPaper.setLayoutManager(layoutManager);
    Log.d(TAG, "onCreateView: Layout Manager Set.");

    mFab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            startAddPaperFragment();
        }
    });

    mOnItemClickListener = new OnItemClickListener() {
        @Override
        public void onItemClicked(RecyclerView.ViewHolder holder, int position) {
            Log.d(TAG, "onItemClicked: Clicked item position is: "+ position);
            QuestionListFragment questionFragment = new QuestionListFragment();
            questionFragment.setRetainInstance(true);

            startFragment(position, questionFragment, QUESTIONS_FRAGMENT_TAG);

        }

        @Override
        public void OnItemLongClicked(RecyclerView.ViewHolder holder, int position) {

        }
    };

    mHeadingText = (TextView) rootView.findViewById(R.id.heading_textview);
    mHeadingText.setText(mExam.getExam_name()+" > "+ mSubject.getSubject_name());

    if (mOutState != null) {
        mPaperList = (ArrayList<Paper>) mOutState.getSerializable(Keys.PAPER_LIST_KEY);
        updateUI();
    } else {
        updateUIFromDatabase();
    }


    return rootView;
}

private void startFragment(int position, Fragment fragment, String fragmentTag) {
    Paper paper = new Paper();
    if (mPaperList.size() > 0) {
        paper = mPaperList.get(position);
    }
    Bundle args = new Bundle();
    args.putSerializable(Keys.EXAMS_KEY, mExam);
    args.putSerializable(Keys.SUBJECT_KEY, mSubject);
    args.putSerializable(Keys.PAPER, paper);
    args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);
    fragment.setArguments(args);
    FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
    fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);

    fragmentTransaction.replace(R.id.questions_fragment_container, fragment, fragmentTag);
    fragmentTransaction.addToBackStack(fragmentTag);
    fragmentTransaction.commit();
}

private void startAddPaperFragment() {
    AddPaperFragment addPaperFragment = new AddPaperFragment();
    addPaperFragment.setRetainInstance(true);
    startFragment(0, addPaperFragment, ADD_PAPER_FRAGMENT_TAG);
}

private void updateUIFromDatabase() {
    if (getArguments() != null){
        Exam exam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
        Subject subject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
        DatabaseReference paperReference =
                mDatabaseReference
                .child(Keys.APP_DATA_KEY)
                .child(Keys.EXAM_PAPERS)
                .child(exam.getExam_name())
                .child(subject.getSubject_name());
        Query query = paperReference.orderByChild(Keys.TIME_ADDED);
        query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                mPaperList.clear();
                for (DataSnapshot paperChild : dataSnapshot.getChildren()) {
                    mPaperList.add(paperChild.getValue(Paper.class));
                }

                updateUI();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }
}

private void updateUI() {
    PaperRecyclerAdapter adapter = new PaperRecyclerAdapter(
            getActivity(),
            mRecyclerViewPaper,
            mPaperList,
            mOnItemClickListener
    );
    mRecyclerViewPaper.setAdapter(adapter);
    mProgressBar.setVisibility(View.GONE);
}

@Override
public void onResume() {
    super.onResume();
    if (getArguments()!=null){
        mOnFragmentActiveListener.onFragmentActive(
                this,
                "Topics"
        );
    }
}

@Override
public void onPause() {
    super.onPause();
    mOutState = new Bundle();
    mOutState.putSerializable(Keys.PAPER_LIST_KEY, mPaperList);
}

}

例外:

2018-12-26 17:49:38.344 14834-14834/in.crazybytes.bankmaniaadmin E/AndroidRuntime: FATAL EXCEPTION: main
Process: in.crazybytes.bankmaniaadmin, PID: 14834
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = in.crazybytes.bankmaniaadmin.activities.QuestionsActivity)
    at android.os.Parcel.writeSerializable(Parcel.java:1526)
    at android.os.Parcel.writeValue(Parcel.java:1474)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
    at android.os.Bundle.writeToParcel(Bundle.java:1133)
    at android.os.Parcel.writeBundle(Parcel.java:763)
    at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124)
    at android.os.Parcel.writeTypedArray(Parcel.java:1306)
    at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639)
    at android.os.Parcel.writeParcelable(Parcel.java:1495)
    at android.os.Parcel.writeValue(Parcel.java:1401)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
    at android.os.Bundle.writeToParcel(Bundle.java:1133)
    at android.os.Parcel.writeBundle(Parcel.java:763)
    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697)
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6123)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
 Caused by: java.io.NotSerializableException: com.google.firebase.auth.internal.zzj
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1224)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at android.os.Parcel.writeSerializable(Parcel.java:1521)
    at android.os.Parcel.writeValue(Parcel.java:1474) 
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:723) 
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408) 
    at android.os.Bundle.writeToParcel(Bundle.java:1133) 
    at android.os.Parcel.writeBundle(Parcel.java:763) 
    at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124) 
    at android.os.Parcel.writeTypedArray(Parcel.java:1306) 
    at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639) 
    at android.os.Parcel.writeParcelable(Parcel.java:1495) 
    at android.os.Parcel.writeValue(Parcel.java:1401) 
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:723) 
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408) 
    at android.os.Bundle.writeToParcel(Bundle.java:1133) 
    at android.os.Parcel.writeBundle(Parcel.java:763) 
    at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697) 
    at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768) 
    at android.os.Handler.handleCallback(Handler.java:751) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6123) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

注意:奇怪的是片段之一具有完全相同的代码并且托管在相同的活动中,但是当该片段处于活动状态并且应用程序进入后台时,有趣的是应用程序并没有崩溃。 

**考试模型类:package in.crazybytes.bankmaniaadmin.models;

import java.io.Serializable;

public class Exam implements Serializable {
private String mExam_name;
private String mExam_key;
private Long mTime_added;
private int mNum_subjects;
private int mNum_questions;

public Exam(String exam_name, String exam_key, Long time_added, int num_subjects, int num_questions) {
    mExam_name = exam_name;
    mExam_key = exam_key;
    mTime_added = time_added;
    mNum_subjects = num_subjects;
    mNum_questions = num_questions;
}

public Exam() {
}

public String getExam_name() {
    return mExam_name;
}

public void setExam_name(String exam_name) {
    mExam_name = exam_name;
}

public String getExam_key() {
    return mExam_key;
}

public void setExam_key(String exam_key) {
    mExam_key = exam_key;
}

public Long getTime_added() {
    return mTime_added;
}

public void setTime_added(Long time_added) {
    mTime_added = time_added;
}

public int getNum_subjects() {
    return mNum_subjects;
}

public void setNum_subjects(int num_subjects) {
    mNum_subjects = num_subjects;
}

public int getNum_questions() {
    return mNum_questions;
}

public void setNum_questions(int num_questions) {
    mNum_questions = num_questions;
}

}

纸模型类

package in.crazybytes.bankmaniaadmin.models;

import java.io.Serializable;

public class Paper implements Serializable {
private String mPaper_name;
private String mPaper_key;
private Long mTime_added;
private int mNum_questions;

public Paper(String paper_name, String paper_key, Long time_added, int num_questions) {
    mPaper_name = paper_name;
    mPaper_key = paper_key;
    mTime_added = time_added;
    mNum_questions = num_questions;
}

public Paper() {
}

public String getPaper_key() {
    return mPaper_key;
}

public void setPaper_key(String paper_key) {
    mPaper_key = paper_key;
}

public Long getTime_added() {
    return mTime_added;
}

public void setTime_added(Long time_added) {
    mTime_added = time_added;
}

public int getNum_questions() {
    return mNum_questions;
}

public void setNum_questions(int num_questions) {
    mNum_questions = num_questions;
}

public String getPaper_name() {
    return mPaper_name;
}

public void setPaper_name(String paper_name) {
    mPaper_name = paper_name;
}

}

学科模型类:

package in.crazybytes.bankmaniaadmin.models;

import java.io.Serializable;

public class Subject implements Serializable {
private String mSubject_name;
private String mSubject_key;
private Long mTime_added;
private int mNum_papers;
private int mNum_questions;

public Subject(String subject_name, String subject_key, Long time_added, int num_papers, int num_questions) {
    mSubject_name = subject_name;
    mSubject_key = subject_key;
    mTime_added = time_added;
    mNum_papers = num_papers;
    mNum_questions = num_questions;
}

public Subject() {
}

public String getSubject_name() {
    return mSubject_name;
}

public void setSubject_name(String subject_name) {
    mSubject_name = subject_name;
}

public String getSubject_key() {
    return mSubject_key;
}

public void setSubject_key(String subject_key) {
    mSubject_key = subject_key;
}

public Long getTime_added() {
    return mTime_added;
}

public void setTime_added(Long time_added) {
    mTime_added = time_added;
}

public int getNum_papers() {
    return mNum_papers;
}

public void setNum_papers(int num_papers) {
    mNum_papers = num_papers;
}

public int getNum_questions() {
    return mNum_questions;
}

public void setNum_questions(int num_questions) {
    mNum_questions = num_questions;
}

}

标签: javaandroidandroid-studioandroid-fragmentsnotserializableexception

解决方案


不知何故,QuestionsActivity 正在进入片段保存状态,即使您不打算发生这种情况。在对 QuestionsActivity 进行序列化时,遇到了另一个不可序列化的对象。这就是为什么您会看到 TextViews 和其他试图序列化的东西,因为 QuestionsActivity 的所有实例变量默认情况下都会被序列化。

我对为什么会发生这种情况的最佳猜测是由于这条线:

args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);

但是如果不查看 OnFragmentActiveListener 的定义位置,就很难确定。我假设 QuestionsActivity 实现 OnFragmentActiveListener,或者 QuestionsActivity 将 OnFragmentActiveListener 定义为内部类。无论哪种方式,如果您将 OnFragmentActiveListener 放入片段参数中,您将遇到异常,因为您也间接地将整个 QuestionsActivity 存储为片段 arg。当一个片段停止时,所有片段参数都成为片段保存状态的一部分。这就是错误的原因。

我建议不要将 OnFragmentActiveListener 作为片段 arg 传递。如果 OnFragmentActiveListener 来自 Activity,只需使用 getActivity() 获取对 Activity 的引用,然后获取对侦听器的引用。

我还注意到 PaperListFragment 实现了 Serializable,我假设您对 QuestionsActivity 做了同样的事情。您可能这样做是为了避免编译错误。但这导致了运行时错误,因为这两个类上的实例变量都不是可序列化的。所以为了避免更多的运行时问题,我建议永远不要让活动或片段实现可序列化,因为这些类由于它们的成员而本质上是不可序列化的。


推荐阅读