人们,我正在坚持我正在开发的新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
答案 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。