添加自己的接口后,Java会抛出NotSerializableException

时间:2013-01-20 20:28:09

标签: java android serialization

人们,我正在坚持我正在开发的新Android应用程序。对于应用程序(纸牌游戏),我需要保存一些数据。我使用序列化来完成它。

现在出现问题: 当我尝试实现一个用于跟踪付款人转向的界面时,应用程序从类Game(主要活动)返回NoSerializableException。当我删除界面时,每件事都有效。

转弯类包含以下代码:

public class Turn<T> implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

public interface OnTurnEndedListener<T>{
    void onTurnEnded(T currentPlayer);
}

private ArrayList<T> players;
private int turnIndex;
private int rounds;
private ArrayList<OnTurnEndedListener<T>> turnEndListenerList;

public Turn() {
    throw new UnsupportedOperationException("cannot init without players");
}

public Turn(ArrayList<T> players, int startingPlayerIndex) {
    this.players = players;
    this.turnIndex = startingPlayerIndex;
    this.rounds = 0;
    turnEndListenerList = new ArrayList<OnTurnEndedListener<T>>();
}

public int getRounds() {
    return rounds;
}

public T next() {
    turnIndex = (turnIndex + 1) % players.size();
    if (turnIndex == 0) {
        rounds++;
    }
    T retVal = players.get(turnIndex);
    for (OnTurnEndedListener<T> l : turnEndListenerList) {
        l.onTurnEnded(retVal);
    }
    return retVal;
}

public T peek() {
    return players.get(turnIndex);
}

public void addOnTurnEndedListener(OnTurnEndedListener<T> l) {
    this.turnEndListenerList.add(l);

}
}

当我在主要活动(游戏)中添加以下代码时,每次关闭活动时都会收到异常。

gameData.getTurn().addOnTurnEndedListener(new Turn.OnTurnEndedListener<Hand>() {
            @Override
            public void onTurnEnded(Hand hand) {
                turnEndedHandler(hand);
            }
        });

您可以找到Game和GameData类的完整代码,以及下面的错误日志。

import java.util.ArrayList;
import java.util.Collections;

import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class Game extends Activity implements OnTouchListener{

    private Deck deck;
    private GameData gameData;
    Hand playerHand, oppHand;
    private ImageView ivDeckClosed, ivDeckOpen, ivPlayerCard1, ivPlayerCard2,ivPlayerCard3, ivPlayerCard4, ivPlayerCard5, ivPlayerCard6,ivPlayerCard7, ivPlayerCard8, ivPlayerCard9, ivPlayerCard10,ivPlayerCard11, ivPlayerCard12, ivPlayerCard13, ivPlayerCard14;
    private ImageView[] playerCards;
    private TextView tvOpp1;
    private ArrayList<Hand> playersInOrder;
    private LinearLayout llPlayGround,llPlayGroundRow1,llPlayGroundRow2,llCardDeck;
    private ArrayList<PlayedSet> playedSets;
    public static final String SAVE_FILENAME = "jokerensave.ser";
    private SaveHandler savehandler;
    private Hand currentHand;
    private int defaultStartingPlayer = 0;

    public static enum STATES {
        start, resume, end
    };

    public static final int START_CODE = 0;
    public static final int RESUME_CODE = 1;
    public static final String GAME_STATE = "STATE";
    public static final String GAME_DATA = "GameData";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("PUKI","onCreate");

        // Get save game
        savehandler = SaveHandler.getInstance(this);
        gameData = savehandler.readLastState();

        setContentView(R.layout.gamescreen);

        // Load which state was given by the mainscreen
        switch ((STATES) getIntent().getExtras().get(GAME_STATE)) {
        case start:
            gameData.setFirstRun(true);
            Log.i("ONCREATE", "Received state: start");
            break;
        case resume:
            gameData.setFirstRun(false);
            Log.i("ONCREATE", "Received state: resume");
            break;
        default:
            gameData.setFirstRun(true);
            Log.i("ONCREATE", "Received state: none");
            break;
        }

        // Transferring game data to MainScreen
        Bundle b = new Bundle();
        b.putInt("int", 5);
        b.putSerializable(GAME_DATA, gameData);
        Intent i = new Intent();
        i.putExtras(b);
        setResult(0, i);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("PUKI","onStart");
        Log.i("FIRSTRUN", "Firstrun = "+gameData.getFirstRun());

        init(gameData.getFirstRun());


        gameData.getTurn().addOnTurnEndedListener(new Turn.OnTurnEndedListener<Hand>() {
            @Override
            public void onTurnEnded(Hand hand) {
                turnEndedHandler(hand);
            }
        });
    }

    private void init(boolean first) {
        initGraphics(first);
        Log.i("INIT", "Game init graphics");
        if (first) {
            Log.i("INIT", "Game init core");
            initGameCore();
        }
    }

    private void initGameCore() {
        deck = new Deck();
        playedSets = new ArrayList<PlayedSet>();

        // Create array with players and their hand
        playersInOrder = new ArrayList<Hand>();
        playerHand = new PlayerHand(playerCards, "Player name");
        playersInOrder.add(playerHand);
        oppHand = new OppHand(new GameStrategy(), null, "Opponent");
        playersInOrder.add(oppHand);

        // Push all data to gamedata class
        gameData.init(playerHand, oppHand, playersInOrder, deck, playedSets, new Turn<Hand>(playersInOrder,defaultStartingPlayer));
        gameData.setGameInProgress(true);

        // Deal cards to players
        dealCards();
    }


    //TODO
    protected void turnEndedHandler(final Hand hand) {
        if(hand.isAwaitingInput()){
            // This means the turn is for a human player, so do nothing.
            Log.i("TURN", "The turn is for the human player: "+hand.getPlayerName());
        }
        else{
            // This means the turn is for a AI. Decide!
            Log.i("TURN", "The turn is for the AI player: "+hand.getPlayerName());
            gameData.getTurn().next();

            // Update players hand size for human player
            this.updateOppScore();
        }
    }

(我从上面的例子中删除了很多代码,因为解决这个问题不需要代码)

import java.io.Serializable;
import java.util.ArrayList;

public class GameData implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -3796450525724090900L;

    private Hand playerHand, oppHand;
    private ArrayList<Hand> playersInOrder;
    private Deck deck;
    private boolean gameInProgress,grabbedCard,playerMustThrow,firstRun;
    private ArrayList<PlayedSet> playedSets; 
    private Turn<Hand> turn;

    private static GameData instance = new GameData();

    public GameData(){
        // Do nothing
    }

    public static GameData getInstance(){
        return instance;
    }

    public void init(Hand playerHand, Hand oppHand, ArrayList<Hand> playersInOrder, Deck deck, ArrayList<PlayedSet> playedSets, Turn<Hand> turn) {
        this.playerHand = playerHand;
        this.playersInOrder = playersInOrder;
        this.oppHand = oppHand;
        this.deck = deck;
        this.grabbedCard = false;
        this.playerMustThrow = false;
        this.playedSets = playedSets;
        this.firstRun = false;
        this.turn = turn;
    }

    public Hand getPlayerHand(){
        return playerHand;
    }
    public Hand getOppHand(){
        return oppHand;
    }
    public Deck getDeck(){
        return deck;
    }
    public ArrayList<Hand> getPlayersInOrder(){
        return playersInOrder;
    }
    public void setGrabbedCard(boolean set){
        this.grabbedCard = set;
    }
    public boolean getGrabbedCard(){
        return grabbedCard;
    }

    public void setGameInProgress(boolean progress) {
        this.gameInProgress = progress;
    }

    public boolean isGameInProgress(){
        return gameInProgress;
    }

    public void createNewPlaySet(PlayedSet newSet){
        playedSets.add(newSet);
    }

    public ArrayList<PlayedSet> getAllPlayedSets(){
        return playedSets;
    }

    public void setPlayerCanThrow(boolean set){
        this.playerMustThrow = set;
    }

    public boolean canPlayerThrow(){
        return playerMustThrow;
    }

    public boolean getFirstRun(){
        return firstRun;
    }

    public void setFirstRun(boolean set){
        this.firstRun = set;
    }

    public Turn<Hand> getTurn(){
        return turn;
    }

}

日志:

01-20 21:05:16.678: W/dalvikvm(27035): threadid=1: thread exiting with uncaught exception (group=0x40c5c1f8)
01-20 21:05:16.693: E/AndroidRuntime(27035): FATAL EXCEPTION: main
01-20 21:05:16.693: E/AndroidRuntime(27035): java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = nl.dirkgroenen.jokeren.GameData)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Parcel.writeSerializable(Parcel.java:1181)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Parcel.writeValue(Parcel.java:1135)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Parcel.writeMapInternal(Parcel.java:493)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Bundle.writeToParcel(Bundle.java:1612)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Parcel.writeBundle(Parcel.java:507)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.content.Intent.writeToParcel(Intent.java:6224)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.ActivityManagerProxy.finishActivity(ActivityManagerNative.java:1831)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.Activity.finish(Activity.java:3709)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.Activity.onBackPressed(Activity.java:2124)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.Activity.onKeyUp(Activity.java:2099)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.view.KeyEvent.dispatch(KeyEvent.java:2633)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.Activity.dispatchKeyEvent(Activity.java:2334)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1958)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3565)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.view.ViewRootImpl.handleFinishedEvent(ViewRootImpl.java:3538)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2646)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Looper.loop(Looper.java:137)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.app.ActivityThread.main(ActivityThread.java:4511)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.lang.reflect.Method.invokeNative(Native Method)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.lang.reflect.Method.invoke(Method.java:511)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at dalvik.system.NativeStart.main(Native Method)
01-20 21:05:16.693: E/AndroidRuntime(27035): Caused by: java.io.NotSerializableException: nl.dirkgroenen.jokeren.Game$6
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1364)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.util.ArrayList.writeObject(ArrayList.java:644)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.lang.reflect.Method.invokeNative(Native Method)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.lang.reflect.Method.invoke(Method.java:511)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1053)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:979)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:368)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1074)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:979)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:368)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1074)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1404)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
01-20 21:05:16.693: E/AndroidRuntime(27035):    at android.os.Parcel.writeSerializable(Parcel.java:1176)
01-20 21:05:16.693: E/AndroidRuntime(27035):    ... 23 more

4 个答案:

答案 0 :(得分:2)

如果我错了,有人会纠正我,但我不建议使用序列化来保存数据。由于对类的任何更改都将使以前保存的任何数据版本无法使用。 您应该考虑使用独立格式来构造数据,例如JSON或XML,或者自定义格式。

使用JSON非常简单,并且可以非常容易地映射到(和来自)Java对象,并且可以轻松地在应用程序中保存为字符串首选项。您还可以处理保存已保存状态的Data pojo的任何更改,以防您以后想要添加或删除内容。

答案 1 :(得分:1)

让OnTurnEndedListener扩展Serializable

答案 2 :(得分:1)

  

应用程序从类Game(主要活动)返回NoSerializableException。

没有。它抛出一个NotSerializableException提到类游戏$ 6,这是你在行开始时创建的OnTurnEndedListener,的匿名实例

gameData.getTurn().addOnTurnEndedListener(...)

不会延伸Serializable。所以要么你必须解决这个问题或者做出

private ArrayList<OnTurnEndedListener<T>> turnEndListenerList;

transient变量中,无论你想要什么。

答案 3 :(得分:-1)

您的Turn界面有一个ArrayList和一个ArrayList。如果其中任何一个不可序列化,您将收到此错误。在运行时确定T的事实会产生另一个debugging挑战。虽然它是一个很好的设计,但我建议你javadoc它,以便开发人员使用你的Turn接口知道T必须也是Serializable,否则它可能在运行时中断。

  
    
      

在您的情况下,类Hand最不可能是Serializable。