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. Любой совет будет полезен!
3 ответа
Этот вопрос на самом деле не ошибка в RoboSpice, а ограничение модели ORM Lite.
Если вы хотите сериализовать коллекцию Foo с использованием ORMLite, то вы должны использовать сериализовать класс, который является коллекцией Foo. Вы подходите правильно. Тем не менее, вы не можете просто избавиться от этого, чтобы хранить элементы Foo по отдельности. Вам нужно не только использовать класс Foos для разбора ответа, но и для хранения данных в базе данных.
Фоос должен:
- определить идентификатор
- быть аннотированным с использованием DataBaseTable и DataField и чужой коллекции
Проблема в том, что вы не можете аннотировать класс и говорить: "Я - коллекция Foreig ". Эта аннотация может использоваться только для полей, но не для классов. Так что, если ваш класс будет "содержать" коллекцию, это будет работать, но не для класса, который "является" коллекцией.
Итак, я считаю, что короткий ответ: нет, вы не можете сделать это с ORM Lite. Вы должны хранить топ-класс, такой как Foos, но он должен быть сериализуемым для ORM Lite, и для этого ему нужно иметь поле коллекции, и он не может быть коллекцией напрямую.
Чтобы добавить к этому превосходному вопросу, я также испытывал эту "тихую неудачу" и не знал, что делать. В конце концов я выбрал в Android Studios, чтобы увидеть все сообщения в LogCat, так что не только ошибки Android, но и все. Я сделал это, выбрав "Verbose" и "No Filters".
Когда я запустил свое приложение, я обнаружил, что причина, по которой я получаю тихую ошибку, заключается в том, что я не сгенерировал уникальный идентификатор для своего 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
...
}