【问题标题】:Android RunTimeException: Parcel: unable to marshal valueAndroid RunTimeException:包裹:无法编组值
【发布时间】:2016-10-15 01:44:27
【问题描述】:

注意:

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

每当我按下 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(接口):

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

为什么要在这个类中实现可序列化?

【问题讨论】:

  • StackOverflow 不像经典论坛那样工作,它是一个问答网站。请编辑问题并从标题和解决方案中删除 (solved)。使用下面的回答您的问题 按钮添加解决方案。并且对于未来,请记住只发布触发问题所需的最少量代码。
  • @perissf 谢谢你这么说。我编辑了我的帖子。不幸的是,我不知道问题出在哪里,所以我认为提供整个代码是个好主意。

标签: java android serializable parcel


【解决方案1】:

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

【讨论】:

  • “Action”是否可序列化?
  • 在“Action”中添加了“implements Serializable”。错误已更改:请参阅帖子进行编辑。
  • 好的,我了解您的代码。你不能那样做。序列化对象时,只有字段被序列化并保存。但是在这里您尝试序列化 doAction() 方法...您需要更改 Action 对象。也许您可以将项目位置保存在 HashMap 上,或者创建一个对象并将您的信息存储在字段中。
  • 是的,您可以序列化一个没有任何字段的对象,但这不是一个好习惯,您可能会遇到错误...根据您的需要,您必须保存在包值而不是方法中。在您的示例中,您只需要项目 id 或项目位置,因此您可以使用 new HashMap&lt;String, int&gt; 更改您的 HashMap 并获取 int 以执行您的操作。
  • 您可以在您的活动或片段中创建一个方法,例如void makeAction(int action) { if(action == 1) { //action for 1.. } else if(action == 2) { //.... }
【解决方案2】:

解决方案:

遵循 Johann67 的想法:

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

所以我修改了我的代码。

首先,我将 menuEntries 对象更改为字符串列表。

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

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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多