2013-01-20 3 views
5

Leute, ich bin ziemlich fest auf einer neuen Android-Anwendung, die ich gerade entwickle. Für die Anwendung (Kartenspiel) muss ich einige Daten speichern. Ich benutze Serialisierung, um das zu erledigen.Java löst NotSerializableException nach dem Hinzufügen eigener Schnittstelle

Nun das Problem: Wenn ich versuche, eine Schnittstelle ich den Überblick über die Zahler drehen zu halten gemacht zu implementieren, die Anwendung eine NoSerializableException aus der Klasse Spiel gibt (Haupttätigkeit). Alles funktioniert, wenn ich die Schnittstelle entferne.

Die Turn-Klasse enthält den folgenden Code:

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

} 
} 

Wenn ich den folgenden Code in der Haupttätigkeit hinzufügen (Spiel) Ich erhalte eine Ausnahme jedes Mal, wenn ich die Aktivität schließen.

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

Sie können den vollständigen Code der Spiel- und GameData-Klasse sowie das Fehlerprotokoll unten finden.

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

(ich eine Menge Code aus dem obigen Beispiel entfernt, da dieser Code nicht benötigt wird, um dieses Problem zu lösen)

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 

Antwort

1

erweitern die Anwendung eine NoSerializableException aus der Klasse Spiel gibt (Haupttätigkeit).

Nein, es wirft ein NotSerializableException die Klasse Spiel 6 $ zu erwähnen, die eine anonyme Instanz OnTurnEndedListener, ist, dass Sie in der Zeile erstellt

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

beginnen, die nicht Serializable erstreckt. Also entweder haben Sie das in Ordnung bringen oder die

private ArrayList<OnTurnEndedListener<T>> turnEndListenerList; 

in eine transient variabel zu machen, was auch immer es ist, dass Sie wollen.

+0

Die 'private ArrayList > turnEndListenerList;' transient hat das Problem gelöst, aber einen neuen Fehler erzeugt (der für dieses Problem nicht relevant ist). Ich werde versuchen, es serialisierbar zu machen und zu sehen, was das macht. –

2

Jemand korrigieren Sie mich, wenn ich falsch liege, aber ich würde die Verwendung der Serialisierung zum Speichern von Daten nicht empfehlen. Da jede Änderung an der Klasse die zuvor gespeicherten Versionen der Daten unbrauchbar macht. Sie sollten ein unabhängiges Format zum Strukturieren der Daten verwenden, z. B. JSON oder XML oder ein benutzerdefiniertes Format.

Die Verwendung von JSON ist sehr einfach und lässt sich sehr einfach auf (und von) Java-Objekten abbilden und kann einfach als String Preference in der App gespeichert werden. Und Sie können auch alle Änderungen an dem Data-Pojo bearbeiten, das den gespeicherten Status enthält, falls Sie in Zukunft Dinge hinzufügen oder entfernen möchten.

+0

Können Sie mir empfehlen eine Möglichkeit, ein Objekt als JSON zu retten? Ich habe ein paar Dinge über Gson gelesen und bin bereits (ohne Erfolg) damit experimentiert. –

+0

Beantwortet die Frage nicht. – EJP

+0

Es beantwortet die Frage nicht, aber es bietet eine möglicherweise bessere Lösung für den betreffenden Anwendungsfall. Verwendung von zum Beispiel Jackson ist eine einfache Möglichkeit, Java-Objekt JSON <-> zu mappen. –

1

Let OnTurnEndedListener Serializable

+0

Sorry, aber das hat den Fehler nicht behoben. –

+0

@DirkGroenen Es sollte haben. War die Ausnahme danach genau gleich? Haben Sie die Neukompilierung/erneute Bereitstellung durchgeführt? – EJP

-1

Ihre Turn-Schnittstelle verfügt über eine ArrayList und eine ArrayList. Wenn beide nicht serialisierbar sind, erhalten Sie diesen Fehler. Die Tatsache, dass T zur Laufzeit entschieden wird, erzeugt eine weitere debugging Abfrage.Obwohl es ein gutes Design ist, empfehle ich, dass Sie es javadoc, so dass Entwickler Ihre Turn-Schnittstelle wissen, dass das T auch serialisierbar sein muss, sonst kann es während der Laufzeit brechen.

In Ihrem Fall Klasse Hand ist in den meisten Wahrscheinlichkeit nicht Serializable.

+0

Korrekte Terminologie bitte. * Serialisierbar, * nicht 'serialisiert'. – EJP

+0

Yup, korrigiert. Danke, dass du es aufgezeigt hast. – Siddharth

+0

Nicht durchgehend korrigiert. Versuch es noch einmal. – EJP

Verwandte Themen