我正在通过在onScrollStateChanged(...)方法中向arraylist加载更多项来实现无穷无尽的列表视图。如果我实现这个方案来获取超过一百万个条目,我将有一百万个对象添加到arraylist,这是内存密集型的。我可以使用哪些方案进行有效的内存管理?
PS:问题是关于可以放入适配器的项目数量。 编辑:
更多详情:
数据来源是互联网。我必须从Internet获取数据并将其放入listview适配器。
答案 0 :(得分:11)
我认为您应该保留当前条目以及它们之前或之后的条目(可能是100),将此数据放入缓存中。
滚动列表视图时,获取更多条目并像以前一样更新缓存(一次不要达到100万)。
答案 1 :(得分:3)
在Android中,ListView被虚拟化。实际上,这意味着 其中的元素数量没有实际限制。你可以放 列表中有数百万行,它只会为内存分配内存 目前可见的(或更多的顶部)。
答案 2 :(得分:2)
这个问题与Adapter
“容量”无关。相反,它与您的应用分配的内存量有关。
为了分配对象,它有一个保留的heap,如果超过此限制,您将获得Out of Memory Exception
这里有一点测试,它可以让您了解可以分配的数据量。但请注意,在此示例中,对象仅包含String
,如果它是一个华丽的Bitmap
,则要分配的对象数量将少得多。
// MemoryActivity
public class MemoryActivity extends Activity {
private List<TestObject> _testObjects = new ArrayList<TestObject>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_memory);
coolGuysDoNotLookBackAtExplosion();
starCountdown();
}
private void starCountdown() {
new CountDownTimer(300000, 500) {
public void onTick(long millisUntilFinished) {
TextView tv_watcher = (TextView) findViewById(R.id.tv_watcher);
tv_watcher.setText(getMemoryUsage());
}
public void onFinish() {
starCountdown();
}
}.start();
}
private String getMemoryUsage() {
String heapSize = String.format("%.3f", (float) (Runtime.getRuntime().totalMemory() / 1024.00 / 1024.00));
String freeMemory = String.format("%.3f", (float) (Runtime.getRuntime().freeMemory() / 1024.00 / 1024.00));
String allocatedMemory = String
.format("%.3f", (float) ((Runtime.getRuntime()
.totalMemory() - Runtime.getRuntime()
.freeMemory()) / 1024.00 / 1024.00));
String heapSizeLimit = String.format("%.3f", (float) (Runtime.getRuntime().maxMemory() / 1024.00 / 1024.00));
String nObjects = "Objects Allocated: " + _testObjects.size();
return "Current Heap Size: " + heapSize
+ "\n Free memory: "
+ freeMemory
+ "\n Allocated Memory: "
+ allocatedMemory
+ "\n Heap Size Limit: "
+ heapSizeLimit
+ "\n" + nObjects;
}
private void coolGuysDoNotLookBackAtExplosion(){
new Thread(new Runnable() {
@Override
public void run() {
_testObjects = new ArrayList<TestObject>();
while (true) {
_testObjects.add(new TestObject());
}
}
}).start();
}
}
//的TestObject
public class TestObject {
private String sampleText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry";
}
答案 3 :(得分:1)
如果ListView仅包含文本项,则无需执行任何操作。但是,如果你要加载更多内存密集的东西,比如drawables(例如,你在视图的右侧有一张图片),那么你应该进行一些回收,以获得最佳效果。您可能会在较弱的设备上很快收到OutOfMemoryException
。我甚至可以在Nexus 4上使用OOM。只需尝试上下快速滚动,上下滚动,然后重复直到强制关闭。
看看RecyclerListener,它很容易实现。
答案 4 :(得分:1)
您应该使用paging
和Load More
按钮作为ListView
的页脚。例如:
url = http://your_full_url.php?page=1
假设您在每个页面中有100条记录,然后第一次获得page 1
的所有这100条记录,并在ListView
和cache
上显示这些记录。现在向下滚动ListView
并单击“加载更多”按钮(“加载更多”按钮应设置为ListView
的页脚)。
当您点击加载更多时,您将通过调用
获得接下来的100条记录 url = http://your_full_url.php?page=2
依此类推
url = http://your_full_url.php?page=3
,
url = http://your_full_url.php?page=4
等......
每次您将缓存这些记录,以便在连接丢失的情况下,您可以显示缓存中可用的记录。
答案 5 :(得分:0)
我猜sqlite数据库和流解析器(GSON)。
答案 6 :(得分:0)
我无法找到文档中提到的确切数字。但是,所有Adapter#getCount()
的返回类型(查看子类)都是整数。
因此,我们强烈怀疑您可以将Integer.MAX_VALUE
项添加到适配器中,该适配器 2 31 -1 (超过20亿)。适配器使用Lists
和Maps
在内部存储数据,have the same limit。
因此,您不应该担心适配器的限制而不是使用太多内存。我建议你将10-100个元素加载到适配器中,只要用户到达列表视图的底部,就可以添加更多项目。
答案 7 :(得分:0)
天威的方法是可行的。
如果ListView是延迟加载的,并且由于ListView本身是回收视图,因此最好只保留内存中的可见列表条目。您基本上在ListView为视图执行的适配器中执行相同操作。
如果您将所有数据保存在内存中,那么延迟加载ListView的重点是什么?只需加载所有数据并跳过延迟加载部分...... 当然,对于只加载可见数据(可能还有更多)的延迟加载方法,您必须在列表的底部和顶部实现延迟加载才能使其工作。
既然由于没有关于数据(文本,图像)或来源(Internet,SQLite Db,文本文件......)的信息,我无法给你代码(样本)如何实现这一点。如果你详细说明数据,我可以更准确地回答这个问题。
答案 8 :(得分:-1)
如果你需要在内存中保留1M对象,并假设对象数据很小,那么它只是几MB的内存,应该可以保留在内存中。根据我的理解,当用户向前滚动时,您将阅读更多项目,因此在实践中您将不会有1M行 - 用户需要滚动很长时间才能达到1M。 只要正确使用ListView,就可以使适配器数据在内存中增长到1M +行而不会出现任何问题