Android RunTimeException:Parcel:无法编组值

时间:2016-06-14 10:59:47

标签: java android serializable parcel

注意:

  

下面显示的代码可能有点难以阅读,但我希望它可以提供帮助。对不起。

每当我按下HOME按钮并且我的应用程序变为背景时,我都会收到此错误。

  

java.lang.RuntimeException:Parcel:无法编组值   elektro_fr.newapplication.FragmentsActivity$3@a6c25e4

我是Android编程的新手,我想创建一个可以为我提供所有功能的类,而不是每次都实现它们。

我做了一个My_Activity课程:

package elektro_fr.my_android;

import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.WindowManager;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

public abstract class My_Activity extends AppCompatActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{

    private int myLayout;

    protected Bundle mySettings;

    private boolean gesturesEnabled=false;
    private GestureDetectorCompat myGestureDetector;

    private boolean canStart=false;

    private boolean menuEnabled=false;
    private HashMap<String,Action> menuEntries;

    protected List<My_Fragment> fragmentsList=new LinkedList<>();

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        myGestureDetector = new GestureDetectorCompat(this,this);

        if (savedInstanceState==null){

            canStart=true;
        }

        init();
        setContentView(myLayout);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

        super.onSaveInstanceState(outState);

        outState.putSerializable("LIST",menuEntries);

        for (int counter=0;counter<fragmentsList.size();counter++){

            getSupportFragmentManager().putFragment(outState,"FRAGMENT_SETTINGS_"+counter,fragmentsList.get(counter));
        }
    }

    @Override
    protected void onStart() {

        super.onStart();
        if (canStart) setGraphics();
        canStart=false;
    }

    protected abstract void init();
    protected abstract void setGraphics();

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {

        super.onRestoreInstanceState(savedInstanceState);

        if (savedInstanceState!=null){

            menuEntries=(HashMap<String, Action>) savedInstanceState.getSerializable("LIST");
            int size=getSupportFragmentManager().getFragments().size();

            for (int counter=0;counter<size;counter++){

                fragmentsList.add(counter,(My_Fragment)getSupportFragmentManager().getFragment(savedInstanceState,"FRAGMENT_SETTINGS_"+counter));
            }
        }

        refreshState();
    }

    abstract protected void refreshState();

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        return menuEnabled;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        super.onOptionsItemSelected(item);

        if (menuEntries.get(item.getTitle())!=null){

            menuEntries.get(item.getTitle()).doAction();
        }

        return menuEnabled;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {

        super.onPrepareOptionsMenu(menu);

        if (menuEnabled){

            if (menuEntries.size()!=0){

                menu.clear();
                int counter=0;

                for (String s: menuEntries.keySet()){

                    menu.add(Menu.NONE,counter,Menu.NONE,s);
                    counter++;
                }
            }
        }

        return menuEnabled;
    }

    protected void setGestures(boolean enabled){

        gesturesEnabled=enabled;
    }

    protected void setMenu(boolean enabled){

        menuEnabled=enabled;
        menuEntries=new HashMap<>();
    }

    protected HashMap<String, Action> getMenuEntries(){

        return menuEntries;
    }

    public My_Fragment addFragment(Class<? extends My_Fragment> fragmentClass, int fragmentContainer, int fragmentID, Bundle fragmentArgs){

        My_Fragment fragment = null;

        try {

            fragment = fragmentClass.newInstance();

        }
        catch (InstantiationException e){

        }
        catch (IllegalAccessException e){

            e.printStackTrace();
        }

        fragment.setArguments(fragmentArgs);
        getSupportFragmentManager().beginTransaction().add(fragmentContainer, fragment).commit();

        fragmentsList.add(fragment);

        return fragment;
    }

    protected My_Fragment getFragment(Class<? extends My_Fragment> fragmentClass){

        for (My_Fragment f: fragmentsList){

            if (fragmentClass.isInstance(f)){

                return f;
            }
        }
        return null;
    }

    public void removeFragment(My_Fragment fragment,boolean addToBackStack){

        if (fragment.isAdded()){

            FragmentTransaction transaction=getSupportFragmentManager().beginTransaction();
            if (addToBackStack)transaction.addToBackStack(null);
            transaction.remove(fragment);
            transaction.commit();
            getSupportFragmentManager().executePendingTransactions();
            if (!addToBackStack)fragmentsList.remove(fragment);
        }
    }

    protected void setFullScreen(boolean fullScreen){

        WindowManager.LayoutParams attrs = getWindow().getAttributes();

        if (fullScreen) {

            attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
        }
        else {

            attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
        }

        getWindow().setAttributes(attrs);
    }

    protected void hideActionBar(boolean hidden){

        if (hidden){

            getSupportActionBar().hide();
        }
        else getSupportActionBar().show();
    }

    protected void setLayout(int layoutID){

        myLayout=layoutID;
    }

    public boolean onTouchEvent(MotionEvent event) {

        if (gesturesEnabled){

            this.myGestureDetector.onTouchEvent(event);
        }

        return true;
    }

    public boolean onSingleTapConfirmed(MotionEvent e) {

        My_AndroidTools.KeyboardTools.closeInputKeyboard(getCurrentFocus());
        return true;
    }

    public boolean onDoubleTap(MotionEvent e) {

        return true;
    }

    public boolean onDoubleTapEvent(MotionEvent e) {

        return true;
    }

    public boolean onDown(MotionEvent e) {

        return true;
    }

    public void onShowPress(MotionEvent e) {

    }

    public boolean onSingleTapUp(MotionEvent e) {

        return true;
    }

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

        return true;
    }

    public void onLongPress(MotionEvent e) {

    }

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        return false;
    }
}

这是FragmentsActivity,它扩展并实现了My_Activity:

package elektro_fr.newapplication;

import android.os.Bundle;
import android.util.Log;
import android.widget.RelativeLayout;

import elektro_fr.my_android.Action;
import elektro_fr.my_android.My_Activity;
import elektro_fr.my_android.My_Fragment;
import elektro_fr.newapplication.R;

public class FragmentsActivity extends My_Activity implements My_Fragment.fragmentOperations {

    private MyTopFragment topFragment;
    private MyBottomFragment bottomFragment;

    @Override
    protected void init() {

        setLayout(R.layout.fragments);
        setGestures(true);
        setMenu(true);
    }

    @Override
    protected void setGraphics() {

        Bundle args=new Bundle();
        args.putInt(MyTopFragment.LAYOUT_ID,R.layout.ts_fragment);
        args.putInt(My_Fragment.CENTER_HORIZONTAL,RelativeLayout.CENTER_HORIZONTAL);

        topFragment = (MyTopFragment) addFragment(MyTopFragment.class,R.id.MainLayout,R.layout.ts_fragment,args);

        Bundle args2=new Bundle();

        args2.putInt(My_Fragment.LAYOUT_ID,R.layout.bs_fragment);

        args2.putInt(My_Fragment.LAYOUT_WIDTH,RelativeLayout.LayoutParams.MATCH_PARENT);
        args2.putInt(My_Fragment.LAYOUT_HEIGHT,RelativeLayout.LayoutParams.WRAP_CONTENT);

        args2.putInt(My_Fragment.BELOW, R.id.ts);
        args2.putInt(My_Fragment.CENTER_HORIZONTAL,RelativeLayout.CENTER_HORIZONTAL);

        bottomFragment = (MyBottomFragment) addFragment(MyBottomFragment.class,R.id.MainLayout,R.layout.bs_fragment,args2);

        getMenuEntries().put("Menu Item #1", new Action() {

            @Override
            public void doAction() {

                Log.i("Ciccio","you pressed 1");
            }
        });

        getMenuEntries().put("Menu Item #2", new Action() {

            @Override
            public void doAction() {

                Log.i("Ciccio","you pressed 2");
            }
        });

        getMenuEntries().put("Menu Item #3", new Action() {
            @Override
            public void doAction() {

                Log.i("Ciccio","you pressed 3");
            }
        });
    }

    protected void refreshState(){

        topFragment = (MyTopFragment) getFragment(MyTopFragment.class);
        bottomFragment = (MyBottomFragment) getFragment(MyBottomFragment.class);
    }

    @Override
    public void ClickButtonOperation(Object[] arguments) {

        switch((Integer)arguments[0]){

            case 0:

                bottomFragment.setText((String)arguments[1],(String)arguments[2]);
            break;
        }
    }
}

这是My_Fragment类:

package elektro_fr.my_android;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.Layout;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;

public abstract class My_Fragment extends Fragment {

    public final static String LAYOUT_ID="layout_id";
    public final static String LAYOUT_WIDTH="layout_width";
    public final static String LAYOUT_HEIGHT="layout_height";

    public final static String BELOW="layout_below";
    public final static String ABOVE="layout_above";

    public final static String ALIGN_PARENT_BOTTOM="align_parent_bottom";
    public final static String CENTER_HORIZONTAL="center_horizontal";

    private String[] params={

            LAYOUT_ID,LAYOUT_WIDTH, LAYOUT_HEIGHT, ALIGN_PARENT_BOTTOM, CENTER_HORIZONTAL, BELOW, ABOVE
    };

    protected int fragmentLayout;

    protected fragmentOperations myActivity;
    protected Bundle mySettings;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        if (savedInstanceState!=null){

            mySettings=new Bundle();
            mySettings.putAll(savedInstanceState);
        }
        else mySettings=getArguments();
        fragmentLayout=mySettings.getInt(LAYOUT_ID);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

        if (savedInstanceState != null) {

            mySettings.putAll(savedInstanceState);
            refreshState();
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

        super.onSaveInstanceState(outState);

        setState();
        outState.putAll(mySettings);
    }

    public interface fragmentOperations{

        void ClickButtonOperation(Object[] arguments);
    }

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

        View view=inflater.inflate(fragmentLayout,container,false);

        int widthSettings=mySettings.getInt(params[1]);
        int heightSettings=mySettings.getInt(params[2]);

        view.setLayoutParams(new RelativeLayout.LayoutParams((widthSettings==0?RelativeLayout.LayoutParams.WRAP_CONTENT:widthSettings),(heightSettings==0?RelativeLayout.LayoutParams.WRAP_CONTENT:heightSettings)));

        RelativeLayout.LayoutParams layoutConfig= (RelativeLayout.LayoutParams) view.getLayoutParams();

        for (int counter=3;counter<params.length;counter++){

            int settings=mySettings.getInt(params[counter]);

            if (settings!=0){

                if (counter==5){

                    layoutConfig.addRule(RelativeLayout.BELOW,settings);
                }
                else if (counter==6){

                    layoutConfig.addRule(RelativeLayout.ABOVE,settings);
                }
                else{

                    layoutConfig.addRule(settings);
                }
            }
        }

        init(view);

        return view;
    }

    protected abstract void init(View v);
    protected abstract void setState();
    protected abstract void refreshState();

    @Override
    public void onAttach(Context context) {

        super.onAttach(context);
        myActivity=(fragmentOperations)getActivity();
    }
}

修改

最后,我编辑的Action(界面),以实现Serializable:

package elektro_fr.my_android;

import java.io.Serializable;

public interface Action extends Serializable{

    public void doAction();
}

这是错误:

  

流程:elektro_fr.newapplication,PID:24970                                                                              java.lang.RuntimeException:Parcelable遇到IOException编写可序列化对象(name = elektro_fr.newapplication.FragmentsActivity $ 3)

引起:

  

引起:java.io.NotSerializableException:elektro_fr.newapplication.FragmentsActivity

为什么我要在这个类中实现serializable?

2 个答案:

答案 0 :(得分:0)

您尝试在OnSaveInstanceState中保存menuEntries,但类型为HashMap,并且此类型不可序列化。当你自己实现序列化时,只有原始可以保存或自定义对象。

答案 1 :(得分:0)

<强> SOLUTION:

遵循Johann67的想法:

  

好的我理解你的代码。你不能这样做。当你序列化一个   对象,只有字段被序列化并保存。但在这里你试着   序列化doAction()方法......您需要更改Action   宾语。也许你可以在HashMap上保存项目位置或   创建一个对象并将您的信息存储在字段中。

所以我修改了我的代码。

首先,我将menuEntries对象更改为String of List。

其次,我创建了一个新方法:

protected void dispatchItemAction(int itemID);

可以根据itemID覆盖以便在要执行的操作之间切换。

我修改了这个方法:

   @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        super.onOptionsItemSelected(item);

        dispatchItemAction(item.getItemId());

        return menuEnabled;
    }

    protected void dispatchItemAction(int itemID){


    }

现在,要添加菜单项:

protected void addMenuItems(){

    getMenuEntries().add("Menu Item #1");
    getMenuEntries().add("Menu Item #2");
    getMenuEntries().add("Menu Item #3");
}

@Override
protected void dispatchItemAction(int itemID) {

    switch(itemID){

        case 0:

            Log.i("Log","Pressed #1.");
        break;

        case 1:

            Log.i("Log","Pressed #2.");
        break;

        case 2:

            Log.i("Log","Pressed #3.");
        break;
    }
}