Я определенно не эксперт по Android, но исключение ясно говорит вам, что он не может обрабатывать большие строки.
Работа с большими строками проблематична даже для настольной / корпоративной Java и обычно считается анти-паттерном, если используется без уважительной причины.
Я догадываюсь , у вас есть как минимум два способа справиться с этим:
- делать реальную потоковую передачу и записывать настоящий JSON в другое место, не буферизуя в промежуточную строку;
- выполняет своего рода ленивое отображение и сохраняет каждый элемент списка отдельно (я заглянул в трассировку стека и обнаружил
SharedPrefsUtils
, что, скорее всего, указывает на использование хранилища значения ключа).
Если вы согласны с первым подходом и хотите записать в хранилище, тогда все очень просто:
// Gson instances can be reused and you can save time and memory just having it as a static field
private static final Gson gson = new Gson();
// Let speed it up by caching the reference to the type adapter
private static final TypeAdapter<BlaModel> blaModelTypeAdapter = gson.getAdapter(BlaModel.class);
private static void stream(final Iterable<? extends BlaModel> blaModels, final Writer writer) {
@SuppressWarnings("resource")
final JsonWriter jsonWriter = new JsonWriter(writer);
jsonWriter.beginArray();
for ( final BlaModel blaModel : blaModels ) {
blaModelTypeAdapter.write(jsonWriter, blaModel);
}
jsonWriter.endArray();
}
Если вам все еще нужно использовать строки (насколько я вижу, редактор общих настроек не может работать с потоками), вы можете лениво преобразовывать элементы списка один за другим и позволять коду вызывающей стороны решать, когда и что делать.
Я не уверен, что он может содержать большой объем данных в одной транзакции, но если это не так, вы, возможно, захотите (опять же, я не эксперт по Android) чаще фиксировать настройки или писать JSON документы в хранилище и просто поместите пути в качестве значений (своего рода символические ссылки).
private static Iterable<String> mapBlaModels(final Iterable<BlaModel> blaModels) {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private final Iterator<? extends BlaModel> iterator = blaModels.iterator();
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public String next() {
final BlaModel blaModel = iterator.next();
return blaModelTypeAdapter.toJson(blaModel);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
Или, если вы используете Google Guava:
private static Iterable<String> mapBlaModels(final Iterable<? extends BlaModel> blaModels) {
// Or even Iterables.transform(blaModels, blaModelTypeAdapter::toJson); when using RetroLambda
return Iterables.transform(blaModels, new Function<BlaModel, String>() {
@Override
public String apply(@Nullable final BlaModel blaModel) {
return blaModelTypeAdapter.toJson(blaModel);
}
});
}
А потом
final Iterable<BlaModel> blaModels = ImmutableList.of(new BlaModel(), new BlaModel(), new BlaModel());
final Iterable<String> jsonDocuments = mapBlaModels(blaModels);
final Iterator<String> jsonDocumentIterator = jsonDocuments.iterator();
for ( int i = 0; jsonDocumentIterator.hasNext(); i++ ) {
final String jsonDocument = jsonDocumentIterator.next();
// TODO manage the document index and the JSON document
// Say, something like putString("blaModel:" + i, jsonDocument), etc
}
Это потребует немного больше усилий для внесения некоторых серьезных изменений в структуру общих настроек, но это сэкономит память и не приведет к проблемам с нехваткой памяти, вызванным промежуточными строками.
Надеюсь, это поможет.