Robospice хранит объект, который расширяет ArrayList в базе данных через Ormlite

Задний план

Я пытаюсь изменить пример кода Robospice Ormlite , который я успешно выполнил . Единственные изменения, которые я сделал, это то, что у меня есть ответ JSON, содержащий массив объектов.

Я создал 2 класса:

public class Foos extends ArrayList<Foo> public class Foo 

У меня были начальные проблемы, так как мой ответ JSON был чистым массивом без внешнего контейнера. Я прочитал через группы google, что способ решить это – создать «поддельный» класс (Foos), который расширяет ArrayList. Это привело к следующему коду:

 public class FooRequest extends SpringAndroidSpiceRequest< Foos > { private String baseUrl; public FooRequest() { super( Foos.class ); this.baseUrl = "http://somewhere.com/jsonurl"; } @Override public Foos loadDataFromNetwork() throws RestClientException { Ln.d( "Call web service " + baseUrl ); return getRestTemplate().getForObject( baseUrl, Foos.class ); } } 

Затем я создал следующий служебный код, адаптированный из примеров.

 public class MySpiceService extends SpringAndroidSpiceService { private static final int WEBSERVICES_TIMEOUT = 10000; @Override public CacheManager createCacheManager( Application application ) { CacheManager cacheManager = new CacheManager(); List< Class< ? >> classCollection = new ArrayList< Class< ? >>(); // add persisted classes to class collection classCollection.add( Foos.class ); // init RoboSpiceDatabaseHelper databaseHelper = new RoboSpiceDatabaseHelper( application, "sample_database.db", 2 ); InDatabaseObjectPersisterFactory inDatabaseObjectPersisterFactory = new InDatabaseObjectPersisterFactory( application, databaseHelper, classCollection ); cacheManager.addPersister( inDatabaseObjectPersisterFactory ); return cacheManager; } @Override public RestTemplate createRestTemplate() { RestTemplate restTemplate = new RestTemplate(); // set timeout for requests HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(); httpRequestFactory.setReadTimeout( WEBSERVICES_TIMEOUT ); httpRequestFactory.setConnectTimeout( WEBSERVICES_TIMEOUT ); restTemplate.setRequestFactory( httpRequestFactory ); // web services support xml responses MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter(); FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); final List< HttpMessageConverter< ? >> listHttpMessageConverters = restTemplate.getMessageConverters(); listHttpMessageConverters.add( jsonConverter ); listHttpMessageConverters.add( formHttpMessageConverter ); listHttpMessageConverters.add( stringHttpMessageConverter ); restTemplate.setMessageConverters( listHttpMessageConverters ); return restTemplate; } } 

Проблема

Код работает без каких-либо ограничений силы, однако я никогда не попадал в внутренний класс RequestListener в пределах своей активности. Ни один из методов сообщения об успехе или неудаче не запускается, и это кажется довольно сложным для отладки, поэтому он чувствует себя как «молчащий сбой».

  public final class MyRequestListener implements RequestListener< Foos > { @Override public void onRequestFailure( SpiceException spiceException ) { Toast.makeText( SampleSpiceActivity.this, "failure", Toast.LENGTH_SHORT ).show(); } @Override public void onRequestSuccess( final Articles result ) { Toast.makeText( SampleSpiceActivity.this, "success", Toast.LENGTH_SHORT ).show(); } } 

Что я пробовал

Я попытался аннотировать класс Foo с аннотациями Ormlite, чтобы узнать, нужна ли библиотеке помощь, но все равно не повезло. Как указано ниже:

 @DatabaseTable public class Foo { @DatabaseField(generatedId = true) private int id; @DatabaseField private String someText; } 

Интересно, является ли это результатом класса Foos, когда я действительно хочу, чтобы таблица базы данных хранила Foo. Любой совет будет полезен!

Этот вопрос на самом деле не является ошибкой в ​​RoboSpice, но является ограничением модели ORM Lite.

Если вы хотите сериализовать коллекцию Foo с использованием ORMLite, вы должны использовать сериализацию класса, который представляет собой коллекцию Foo. Вы подходите правильно. Тем не менее, вы не можете просто избавиться от него, чтобы сохранить элементы Foo индивидуально. Вы не только должны использовать класс Foos для анализа ответа, но и для хранения данных в базе данных.

Foos должен:

  • Определить идентификатор
  • Аннотироваться с использованием базы данных DataBaseTable и DataField и иностранной коллекции

Проблема в том, что вы не можете аннотировать класс и говорить «Я коллектив Foreig». Эта аннотация может использоваться только для полей, а не для классов. Итак, если ваш класс будет «держать» коллекцию, это будет работать, но не для класса, который является «коллекцией».

Итак, я считаю, что короткий ответ: нет, вы не можете сделать это с ORM Lite. Вы должны хранить верхний класс, такой как Foos, но он должен быть сериализуемым для ORM Lite, и для этого он должен иметь поле коллекции и не может быть коллекцией напрямую.

Чтобы добавить к этому замечательному вопросу, я также испытывал эту «тихую неудачу» и не знал, что делать. В конечном итоге я выбрал внутри Android Studios, чтобы увидеть все сообщения в logcat, поэтому не только ошибки android, но и все. Я сделал это, выбрав «Verbose» и «No Filters».

LogCat

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

  Caused by: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: post.ID (code 1555) 

Я исправил это, выполнив это в своем поле внешнего идентификатора класса, которое позволило ему генерировать уникальные идентификаторы самостоятельно:

 @DatabaseField(allowGeneratedIdInsert=true, generatedId=true) private int ID; 

Как сказал @Snicolas, вы должны перейти в коллекцию вместо ArrayList. Я хотел бы сделать более или менее то же самое, но без объекта результата. Мое обходное решение по этому вопросу RoboSpice сохраняет массив JSON с OrmLite, который должен работать на вас.

 @DatabaseTable public class Foos { @DatabaseField(id = true) private int id; @ForeignCollectionField(eager = false) private Collection<Foo> result; // getters and setters ... } @DatabaseTable public class Foo { @DatabaseField(id = true) private int id; @DatabaseField(foreign = true) private Foos foos; // getters and setters ... }