这是我的代码:
@Nullable
private static String streamBlaModelsIntoJsonString(List<BlaModel> blaModels) {
try {
Gson gson = new Gson();
ByteArrayOutputStream out = new ByteArrayOutputStream();
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
writer.setIndent(" ");
writer.beginArray();
for (BlaModel blaModel : blaModels) {
gson.toJson(blaModel, BlaModel.class, writer);
}
writer.endArray();
writer.close();
return out.toString("UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
这是Fabric的崩溃报告:
Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 1219838 byte allocation with 265632 free bytes and 255KB until OOM
at java.lang.StringFactory.newStringFromBytes(StringFactory.java:176)
at java.lang.StringFactory.newStringFromBytes(StringFactory.java:59)
at java.io.ByteArrayOutputStream.toString(ByteArrayOutputStream.java:232)
at com.example.magnificentapp.util.SharedPrefsUtils.streamBlaModelsIntoJsonString(SharedPrefsUtils.java:230)
at com.example.magnificentapp.util.SharedPrefsUtils.saveBlaList(SharedPrefsUtils.java:207)
at com.example.magnificentapp.BlaListActivity.goToDetail(BlaListActivity.java:462)
at com.example.magnificentapp.presentation.view.activity.BlaListActivity.onItemClick(BlaListActivity.java:605)
at com.example.magnificentapp.adapter.viewholder.BlaViewHolder$2.onClick(BlaViewHolder.kt:34)
at android.view.View.performClick(View.java:6261)
at android.view.View$PerformClick.run(View.java:23748)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
崩溃发生在行return out.toString("UTF-8");
上。编写此代码是为了解决应用程序中的OutOfMemory
崩溃问题,但与以前相比,我得到的错误仍然更多。
我试图一个又一个地流式传输BlaModels并附加一个StringBuilder,但这似乎消耗了更多的内存。
我无法重现崩溃,但是此崩溃报告是我的Fabric中所有崩溃中的旗舰。
我的代码需要进一步提高,但是我正在尽力而为。有人要加油。
致谢。
答案 0 :(得分:0)
您需要关闭 ByteArrayOutputStream ,并在完成 out 实例
后尝试此操作if (out != null) {
try {
out.close();
} catch (Exception ex) {
}
}
答案 1 :(得分:0)
我绝对不是Android专家,但是明显的例外是告诉您它不能处理大字符串。 即使对于台式机/企业Java,处理大字符串也是有问题的,如果在没有充分理由的情况下使用,通常会认为它是反模式。 我猜测,您至少有两种处理方式:
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
}
这需要付出更多的努力才能对共享的首选项结构进行一些重大更改,但这将节省内存,并且不会遇到由中间字符串引起的内存不足问题。
希望这会有所帮助。