我正在开发一个产品的详细视图,该产品提供类似产品的建议(与另一个也有建议的产品同样的活动),或多或少像Google Play应用详情活动。当访问导致OutOfMemoryException 的多个相关产品时,问题就出现了(因为我们在BackStack上保留了该ProductDetailActivity的所有先前实例)。
有没有办法提供适当的产品回溯历史而不必保留所有以前的活动消耗内存?
我已经检查过谷歌播放应用程序,我无法看到如何,但似乎它保留了以前的所有活动,并且在相关应用程序上导航相关应用程序时没有导致任何OutOfMemory。
答案 0 :(得分:0)
我有类似的问题。在我的情况下,我使用片段,但我会分享技术,以便您可以将其用于您的活动。
您可以将多个活动视为堆栈。当用户选择产品建议时,当前活动被推送到堆栈并开始新活动。相反,当按下后退按钮时,活动结束,之前的活动从堆栈中弹出并变为当前活动。
这会占用大量内存,具体取决于您的应用程序。
我的洞察力是我可以通过自己管理该堆栈来节省大量内存,并且只保存重新创建该UI所需的最少数据量。
所以让我们从创建堆栈开始:
private ArrayList<Bundle> mProductStack;
您需要在onSaveInstanceState()
中保留此堆栈并在onCreate()
中恢复它。让我们把它们排除在外:
@Override
public void onSaveInstanceState(Bundle outState) {
// ... all your other state saving code
outState.putParcelableArrayList("productStack", mProductStack);
super.onSaveInstanceState(outState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ... all your other activity create logic
if (savedInstanceState != null) {
mProductStack = savedInstanceState.getParcelableArrayList("productStack");
} else {
mProductStack = new ArrayList<>();
}
}
使用列表而不是堆栈的原因。我在使用Stack<Bundle>
施放等等时遇到了很多问题,因此我决定使用ArrayList<Bundle>
直接支持的简单Bundle
({{1}等等)。
现在,当用户导航到新产品时,您需要将当前状态保存在堆栈中,并将新产品加载到当前活动中。您的州甚至可能像产品ID一样简单:
putParcelableArrayList()
您可能需要保留一些实际的UI状态,例如我有这个:
Bundle entry = new Bundle();
entry.putInt("productId", mProductId);
mProductStack.add(entry); // push
// ... load the data for the next product
现在您只需要按下后退按钮:
int scrollPos = mNestedScrollView.getScrollY(); // remember where we were in the list
entry.putInt("scrollPos", scrollPos);
我不知道您的状态有多复杂,但请记住,您要保存的所有数据类型都需要实现@Override
public void onBackPressed() {
if (mProductStack.isEmpty()) {
super.onBackPressed();
return;
}
Bundle entry = mProductStack.remove(mProductStack.size() - 1); // pop
mProductId= entry.getInt("productId");
// ... load the data for the previous product
}
。在这个主题上有很多在线内容(包括SO)。
似乎对记忆影响最大的是图像。位图的内存管理本身就是一个令人讨厌的话题。您可能希望为图像实现某种类型的LRU缓存,这样您就不必重新获取以前产品的图像 - 除非内存限制迫使您这样做。