2013-01-20 25 views
5

Mọi người, tôi đang gặp khó khăn trên một ứng dụng Android mới mà tôi đang phát triển. Đối với ứng dụng (trò chơi bài) tôi cần lưu một số dữ liệu. Tôi sử dụng Serialization để thực hiện điều đó.Java ném NotSerializableException sau khi thêm giao diện riêng

Bây giờ vấn đề: Khi tôi cố gắng thực hiện một giao diện tôi thực hiện để theo dõi các đối tượng nộp biến, ứng dụng trả về một NoSerializableException từ lớp game (hoạt động chính). Mọi thứ đều hoạt động khi tôi xóa giao diện.

lớp Những biến chứa đoạn mã sau:

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

} 
} 

Khi tôi thêm đoạn mã sau vào các hoạt động chính (game) tôi nhận được một ngoại lệ mỗi khi tôi đóng hoạt động.

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

Bạn có thể tìm mã đầy đủ của lớp Game và GameData cũng như nhật ký lỗi bên dưới.

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

(Tôi đã gỡ bỏ rất nhiều mã từ ví dụ trên, bởi vì mã mà là không cần thiết để giải quyết vấn đề này)

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 

Trả lời

1

ứng dụng trả về một NoSerializableException từ lớp game (hoạt động chính).

số Nó ném một NotSerializableException nhắc đến lớp game $ 6, đó là một trường hợp vô danh của OnTurnEndedListener, mà bạn đã tạo trong dòng bắt đầu

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

mà không mở rộng Serializable. Vì vậy, bạn phải sửa chữa hoặc làm cho số điện thoại

private ArrayList<OnTurnEndedListener<T>> turnEndListenerList; 

thành biến số transient, tùy theo điều bạn muốn.

+0

Làm cho 'Private ArrayList > turnEndListenerList;' tạm thời giải quyết vấn đề, nhưng tạo ra một lỗi mới (không liên quan đến vấn đề này). Tôi sẽ cố gắng làm cho nó serializable và xem những gì mà không. –

2

người sửa tôi nếu tôi sai, nhưng tôi sẽ không khuyên bạn sử dụng Serialization để lưu dữ liệu. Vì bất kỳ thay đổi nào đối với lớp sẽ làm cho bất kỳ phiên bản nào của dữ liệu đã lưu trước đó không sử dụng được. Bạn nên cân nhắc sử dụng định dạng độc lập để cấu trúc dữ liệu, ví dụ JSON hoặc XML hoặc tùy chỉnh.

Sử dụng JSON rất dễ dàng và ánh xạ rất dễ dàng (và từ) đối tượng Java chẳng hạn và có thể dễ dàng được lưu dưới dạng Tùy chọn chuỗi trong ứng dụng. Và bạn cũng có thể xử lý bất kỳ thay đổi nào cho Kho dữ liệu chứa trạng thái đã lưu trong trường hợp bạn muốn thêm hoặc xóa nội dung trong tương lai.

+0

Bạn có thể giới thiệu cho tôi cách nào để lưu một đối tượng như JSON? Tôi đọc một vài điều về Gson, và đã hết hạn (không thành công) với nó. –

+0

Không trả lời câu hỏi. – EJP

+0

Nó không trả lời câu hỏi nhưng nó cung cấp một giải pháp tốt hơn cho trường hợp sử dụng được đề cập. Sử dụng ví dụ Jackson là cách dễ dàng để ánh xạ đối tượng Java <-> Java. –

1

Hãy OnTurnEndedListener mở rộng Serializable

+0

Xin lỗi, nhưng điều đó không khắc phục được lỗi. –

+0

@DirkGroenen Nên có. Là ngoại lệ chính xác như vậy sau đó? Bạn đã biên dịch lại/triển khai lại? – EJP

-1

Giao diện Turn của bạn có ArrayList và ArrayList. Nếu một trong số chúng không được tuần tự hóa, bạn sẽ gặp phải lỗi này. Thực tế là T được quyết định trong thời gian chạy tạo ra một thách thức debugging.Mặc dù nó là một thiết kế tốt, tôi khuyên bạn nên javadoc nó để các nhà phát triển sử dụng giao diện Turn của bạn biết rằng T phải được Serializable quá, nếu không nó có thể phá vỡ trong thời gian chạy.

Trong trường hợp của bạn lớp Hand không phải là Serializable trong hầu hết các xác suất.

+0

Thuật ngữ chính xác, vui lòng. * Serializable, * không 'serialized'. – EJP

+0

Yup, đã sửa. Cảm ơn đã chỉ ra điều đó. – Siddharth

+0

Không sửa chữa trong suốt. Thử lại. – EJP

Các vấn đề liên quan