【问题标题】:Store and manage (de)serialized objects properly and how to work with them after deserialisation存储和管理(正确反序列化的对象以及反序列化后如何使用它们
【发布时间】:2019-04-30 19:29:32
【问题描述】:

我想使用(反)序列化的具有保存/加载功能的类中的数据将多个对象加载和渲染到游戏世界,但我不知道如何正确地将它们重新引入程序,因为它们包含瞬态对象必须渲染/显示它们。

我第一次运行我的程序时,它会尝试从一个名为“Data.txt”的 txt 文件中加载数据,但该文件并不存在。该程序创建一个新的 Data.txt 文件,向其中添加一个名为“campfire”的 Campfire 对象并保存它。只要程序运行,它就会被渲染到屏幕上(这部分工作正常)。关闭程序并重新启动它应该检查文件后,找到它并使用先前保存/序列化的篝火对象加载 ArrayList“数据”。然后它向它添加另一个相同类型的 Object 并渲染它们。这部分在我的 Campfire 类的 render 方法中抛出 NullPointerException。

这是主类:

public class MainClass extends ApplicationAdapter{
public static SpriteBatch batch;    

private Data data;
private Campfire campfire;

@Override
public void create () {
    batch = new SpriteBatch();

    data = new Data();
    data.load();

    campfire = new Campfire();
    data.addCampfire(campfire);

    System.out.println(data.getSize());
    data.save();
}

@Override
public void render () {
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.begin();
        data.render(batch);
    batch.end();
}

加载所有文件的类:

public class Data {
private String filename;
private ArrayList<Campfire> data;

 public Data() {
    data = new ArrayList<Campfire>(); 
    filename = "Data.txt"; 
 }

 public void save(){
     try {  
         FileOutputStream file = new FileOutputStream (filename); 
         ObjectOutputStream out = new ObjectOutputStream (file);       

         out.writeObject(data); 
         out.close(); 
         file.close();      
     }catch (IOException e) {e.printStackTrace();} 
 }

public void load() {
     try {                                  
         FileInputStream file = new FileInputStream (filename); 
         ObjectInputStream in = new ObjectInputStream(file); 

         data = (ArrayList<Campfire>)in.readObject();  
         in.close(); 
         file.close();  
     } 
     catch (IOException io) {System.out.println("File not found.");} 
     catch (ClassNotFoundException ex) {System.out.println("Cant load from file.");}
 } 

 public void addCampfire(Campfire object) {
     data.add(object);
 }
 public void render(SpriteBatch batch) {
     for(int i = 0;i < data.size(); i++) {
         Campfire camp = data.get(i);
         camp.render(batch);
        //data.get(i).render(batch);
     }
 }

 public Campfire get(int index) {
    return data.get(index);
 }

 public void set(int index, Campfire object) {
     data.set(index, object);
 }

 public int getSize() {
     return data.size();
 }

这是在 render() 中抛出 NullPointerException 的类:

public class Campfire implements Serializable{
private transient Texture img;
private int id;

public Campfire() {             
    img = new Texture("campfire.png");
}

public void render(SpriteBatch batch) {
    batch.draw(img, 200,200, 2000,2000);
}

原因是纹理“img”不存在,因为我需要对它使用瞬态关键字,因此它不会被保存/加载到数据文件中。

我需要一种不同的方法来根据我从中加载的数组列表创建对象。我无法使用 arrayList 中的对象,因为它们无法被渲染(transient 关键字必须分配给 Texture() 对象 - 它不可序列化)。我已经看过很多教程并阅读了大量关于这个主题的文章,但是我找不到一篇提到我如何重新引入该对象以便我可以利用它的函数,这些函数依赖于它的不可(反)序列化部分。

所以这是我的问题: 有没有比我的尝试更好的方法(再次创建对象然后为其分配反序列化值?我不知道如何在反序列化过程之后正确加载和使用“数据”ArrayList,我很感谢关于如何将它们重新引入程序。

提前致谢, M

【问题讨论】:

    标签: java libgdx transient


    【解决方案1】:

    我建议不要为此使用 java 序列化。它在序列化格式的大小方面可能具有优势,但根据我的经验,使用它有点痛苦。您遇到了这种痛苦,因为您无法序列化该Texture 对象,因为它不是Serializable。您通过将其标记为瞬态来避免该问题,这是一个错误。可能有一些解决方法可以处理您不拥有的对象 - 注册一些处理程序,但是我不知道细节,因为我避免了它。

    相反,请选择像 json 这样友好的格式。这意味着您的序列化数据文件会更大一些,但是,您可以打开它并阅读它并查看您保存的内容。

    而且... libgdx 附带了一些工具。参见他们的 wiki 页面here

    还有其他选择——比如谷歌的 gson 库,但为什么不坚持使用 libgdx 的工具——我发现它们非常可靠。

    只是一个额外的警告 - 如果您在 Android 中使用某种代码混淆/最小化工具,您需要将其配置为不重命名您序列化的任何对象,因为它确实依赖包和对象名称进行反序列化.如果您保存游戏状态,也需要注意 - 然后更改对象的名称/包,然后尝试加载该游戏状态。

    【讨论】:

    • 感谢您为我指明了正确的方向。您的回答和链接对我帮助很大!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 2011-04-06
    • 1970-01-01
    相关资源
    最近更新 更多