Правильно хранить и управлять (де) сериализованными объектами и как с ними работать после десериализации - PullRequest
0 голосов
/ 30 апреля 2019

Я хочу загрузить и визуализировать несколько объектов в игровом мире, используя данные из класса с функциональностью сохранения / загрузки, используя (де) сериализацию, но я не могу понять, как правильно заново ввести их в программу, поскольку они содержат временные объекты, которыенеобходимо их отобразить / отобразить.

При первом запуске моей программы она пытается загрузить данные из txt-файла с именем «Data.txt», который не существует.Программа создает новый файл Data.txt, добавляет к нему объект Campfire с именем 'campfire' и сохраняет его.Пока программа работает, она будет отображаться на экране (эта часть работает нормально).После закрытия программы и ее перезапуска она должна проверить файл, найти его и загрузить из него «данные» ArrayList с ранее сохраненным / сериализованным объектом костра.Затем он добавляет еще один объект того же типа и отображает их обоих.Эта часть генерирует исключение NullPointerException в методе рендеринга моего класса Campfire.

Это основной класс:

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

И это класс, который генерирует исключение NullPointerException в render ():

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 не существует, так как мне нужно использовать ключевое слово transient с ней и, следовательно,он не будет сохранен / загружен в / из файла данных.

Мне нужен другой способ создания объектов на основе списка массивов, из которого я загружаю.Я не могу работать с объектами в arrayList, потому что они не могут быть отображены (временное ключевое слово должно быть назначено объекту Texture () - его нельзя сериализовать).Я просмотрел множество учебных пособий и прочитал большое количество статей по этой теме, но не могу найти один, в котором упоминается, как я могу заново представить объект, чтобы я мог использовать его функции, которые полагаются на не деизериализируемые части.

Итак, вот мой вопрос: есть ли лучший способ, чем моя попытка (создать объект заново, а затем присвоить ему десериализованные значения? Я понятия не имею, как правильно загружать и работать с ArrayList 'data' послепроцесс десериализации, и я благодарен за каждый совет о том, как повторно ввести их в программу.

Заранее спасибо, M

1 Ответ

1 голос
/ 02 мая 2019

Я бы порекомендовал не использовать сериализацию Java для этого. Он может иметь преимущества с точки зрения размера его сериализованного формата, но по моему опыту работать с ним немного затруднительно. Вы столкнулись с этой болью, потому что вы не можете сериализовать этот Texture объект, потому что это не Serializable. Вы избежали этой проблемы, пометив ее как временную, что является ошибкой. Вероятно, есть обходные пути для работы с объектами, которые вам не принадлежат - регистрация какого-либо обработчика, но я не знаю деталей, потому что я этого избегаю.

Вместо этого перейдите на хороший дружественный формат, такой как json. Это будет означать, что ваш файл сериализованных данных будет немного больше, но вы можете открыть его, прочитать и посмотреть, что вы сохранили.

И ... libgdx поставляется с некоторыми инструментами для этого. Смотрите их вики-страницу об использовании здесь

Существуют альтернативы - например, библиотека googles gson, но почему бы просто не использовать инструменты libgdx - я считаю, что они довольно надежные.

Просто дополнительное предупреждение - если вы используете какой-то инструмент обфускации / минимизации кода в Android, вам нужно будет настроить его так, чтобы он не переименовывал какой-либо объект, который вы сериализуете, потому что он использует имена пакетов и объектов для десериализации. , Это также то, о чем следует знать, если вы сохраняете игровое состояние - затем изменяйте имена / пакеты ваших объектов и затем пытайтесь загрузить это игровое состояние.

...