2013-01-20 13 views
5

Ludzie, utknąłem na nowej aplikacji na Androida, którą rozwijam. W przypadku aplikacji (gry karcianej) muszę zapisać niektóre dane. Używam serializacji, aby to zrobić.Java rzuca NotSerializable wyjątek po dodaniu własnego interfejsu

Teraz problem: Kiedy próbuję zaimplementować interfejs zrobiłem śledzić płatników kolei aplikacja zwraca NoSerializableException od Grze klasy (główna działalność). Każda rzecz działa po usunięciu interfejsu.

Przełom klasa zawiera następujący kod:

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

} 
} 

Kiedy dodać następujący kod w głównej działalności (game) uzyskać wyjątek każdym razem zamknąć działalność.

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

Możesz znaleźć pełny kod klasy Game i GameData, a także poniższy dziennik błędów.

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

(Usunąłem dużo kodu z powyższego przykładu, ponieważ kod nie jest potrzebne, aby rozwiązać ten problem)

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

} 

Log:

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 

Odpowiedz

1

aplikacja zwraca NoSerializableException od Grze klasy (główna działalność).

No. To rzucaNotSerializableException wspomnieć klasę Grę $ 6, która jest anonimowa instancja OnTurnEndedListener,, który został utworzony w linii startu

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

który nie rozciąga Serializable. Więc albo trzeba naprawić lub dokonać

private ArrayList<OnTurnEndedListener<T>> turnEndListenerList; 

w transient zmienna, w zależności od tego jest to, że chcesz.

+0

Tworzenie 'private ArrayList > turnEndListenerList;' transient rozwiązało problem, ale utworzył nowy błąd (który nie jest związany z tym problemem). Spróbuję zrobić to serializowalnym i zobaczyć, co to robi. –

2

Ktoś popraw mnie, jeśli się mylę, ale nie zalecałbym używania serializacji do zapisywania danych. Ponieważ wszelkie zmiany w klasie spowodują, że wszelkie zapisane wcześniej wersje danych staną się bezużyteczne. Należy rozważyć użycie niezależnego formatu do strukturyzacji danych, na przykład JSON lub XML, lub niestandardowego.

Używanie JSON jest bardzo łatwe i bardzo łatwo odwzorowuje (na przykład) z obiektów Java i może być z łatwością zapisane jako Preferencja ciągu w aplikacji. Możesz także obsługiwać wszelkie zmiany w Data pojo, które przechowuje zapisany stan na wypadek, gdybyś chciał dodać lub usunąć coś w przyszłości.

+0

Czy możesz mi jakiś sposób, aby zapisać obiekt jako JSON polecić? Przeczytałem kilka rzeczy o Gsonie i już się z nim skończyłem (bez powodzenia). –

+0

Nie odpowiada na pytanie. – EJP

+0

Nie odpowiada na pytanie, ale zapewnia możliwie lepsze rozwiązanie danego przypadku użycia. Używanie np. Jacksona jest łatwym sposobem odwzorowania obiektu JSON <-> Java. –

1

Let OnTurnEndedListener przedłużyć Serializable

+0

Przepraszamy, ale to nie naprawiło błędu. –

+0

@DirkGroenen To powinno mieć. Czy wyjątek był taki sam później? Czy dokonałeś rekompilacji/ponownego wdrożenia? – EJP

-1

Twój interfejs Turn ma ArrayList i ArrayList. Jeśli żadnego z nich nie można szeregować, otrzymasz ten błąd. Decyzja o podjęciu czynnika T w środowisku wykonawczym powoduje kolejne wyzwanie: debugging.Mimo, że jest to dobry projekt, polecam go javadoc, aby programiści korzystali z interfejsu Turn wiedząc, że T również musi być Serializable, bo inaczej może się zepsuć podczas pracy.

W swojej klasie przypadku Hand nie jest Serializable w większości prawdopodobieństwa.

+0

Poprawna terminologia, proszę. * Serializable, * nie "serialized". – EJP

+0

Yup, poprawione. Dziękuję za wskazanie. – Siddharth

+0

Nieskorygowane przez cały czas. Spróbuj ponownie. – EJP

Powiązane problemy