Android Endless列表内存管理

时间:2014-03-10 09:15:46

标签: android android-listview listadapter

我正在通过在onScrollStateChanged(...)方法中向arraylist加载更多项来实现无穷无尽的列表视图。如果我实现这个方案来获取超过一百万个条目,我将有一百万个对象添加到arraylist,这是内存密集型的。我可以使用哪些方案进行有效的内存管理?

PS:问题是关于可以放入适配器的项目数量。 编辑:

更多详情:

数据来源是互联网。我必须从Internet获取数据并将其放入listview适配器。

9 个答案:

答案 0 :(得分:11)

我认为您应该保留当前条目以及它们之前或之后的条目(可能是100),将此数据放入缓存中。

滚动列表视图时,获取更多条目并像以前一样更新缓存(一次不要达到100万)。

答案 1 :(得分:3)

  

在Android中,ListView被虚拟化。实际上,这意味着   其中的元素数量没有实际限制。你可以放   列表中有数百万行,它只会为内存分配内存   目前可见的(或更多的顶部)。

Source

另请查看此文章Performance Tips for Android’s 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)

您应该使用pagingLoad More按钮作为ListView的页脚。例如:

url = http://your_full_url.php?page=1

假设您在每个页面中有100条记录,然后第一次获得page 1的所有这100条记录,并在ListViewcache上显示这些记录。现在向下滚动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亿)。适配器使用ListsMaps在内部存储数据,have the same limit

因此,您不应该担心适配器的限制而不是使用太多内存。我建议你将10-100个元素加载到适配器中,只要用户到达列表视图的底部,就可以添加更多项目。

答案 7 :(得分:0)

天威的方法是可行的。

如果ListView是延迟加载的,并且由于ListView本身是回收视图,因此最好只保留内存中的可见列表条目。您基本上在ListView为视图执行的适配器中执行相同操作。

如果您将所有数据保存在内存中,那么延迟加载ListView的重点是什么?只需加载所有数据并跳过延迟加载部分...... 当然,对于只加载可见数据(可能还有更多)的延迟加载方法,您必须在列表的底部和顶部实现延迟加载才能使其工作。

既然由于没有关于数据(文本,图像)或来源(Internet,SQLite Db,文本文件......)的信息,我无法给你代码(样本)如何实现这一点。如果你详细说明数据,我可以更准确地回答这个问题。

答案 8 :(得分:-1)

如果你需要在内存中保留1M对象,并假设对象数据很小,那么它只是几MB的内存,应该可以保留在内存中。根据我的理解,当用户向前滚动时,您将阅读更多项目,因此在实践中您将不会有1M行 - 用户需要滚动很长时间才能达到1M。 只要正确使用ListView,就可以使适配器数据在内存中增长到1M +行而不会出现任何问题