Android Бесконечное управление памятью списков
Я реализую бесконечный список, загружая больше элементов в arraylist в методе onScrollStateChanged (...). Если я реализую эту схему для получения более 1 миллиона записей, у меня будет миллион объектов, добавленных в arraylist, который будет интенсивным в памяти. Какие схемы можно использовать для эффективного управления памятью?
PS: Вопрос о количестве элементов, которые можно поместить в адаптер.
Edit:
Подробнее:
Источником данных является Интернет. Мне нужно получить данные из Интернета и поместить их в адаптер списка.
Ответы
Ответ 1
Я думаю, что вы должны просто сохранить текущие записи и только до или после них (может быть, 100), поместить эти данные в кеш.
Когда вы прокручиваете список, выбираете больше записей и обновляете кеш по-прежнему (не получаете 1 миллион за один раз).
Ответ 2
В Android виртуализируется ListView. Практически это означает, что нет фактического предела для количества элементов внутри него. Вы можете положить миллионы строк внутри списка, он будет выделять только память для в настоящее время видимые (или несколько других вершин).
Источник
Также проверьте эту статью Рекомендации по производительности для списка андроидов ListView
Ответ 3
Этот вопрос не имеет ничего общего с емкостью Adapter
. Вместо этого это связано с объемом памяти, выделенной вашим приложением.
Он имеет зарезервированную кучу, чтобы выделить объекты, если вы пройдете этот предел, вы получите Исключение из памяти
Здесь небольшой тест, он может дать вам представление о количестве данных, которые вы могли бы выделить. Но имейте в виду, что в этом примере объект содержит только 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";
}
Ответ 4
Если ваш ListView содержит только текстовые элементы, вам нечего делать. Однако, если вы загружаете больше насыщенных памяти, например drawables (например, у вас есть изображение с правой стороны вашего вида), то вам следует сделать некоторую переработку, чтобы получить лучший результат. Вы можете получить OutOfMemoryException
очень быстро на более слабом устройстве. Я мог бы пойти OOM даже на Nexus 4. Просто попробуйте прокрутить очень быстро, вверх и вниз, вверх и вниз, и повторите, пока сила не закроется.
Взгляните на RecyclerListener, его очень легко реализовать.
Ответ 5
Вы должны использовать кнопки paging
и Load More
в качестве нижнего колонтитула ListView
. Например:
url = http://your_full_url.php?page=1
скажем, у вас есть 100 записей на каждой странице, а затем в первый раз получите все эти 100 записей page 1
, покажите их на ListView
и cache
им. Теперь прокрутите вниз свой ListView
и нажмите кнопку "Загрузить еще" (кнопка "Загрузить больше" должна быть установлена как нижний колонтитул ListView
).
Когда вы нажмете на Load More, вы получите следующие 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
и т.д.
каждый раз, когда вы будете кэшировать эти записи, чтобы в случае потери соединения вы могли показывать записи, доступные в кеше.
Ответ 6
Я предполагаю, что sqlite Database и потоковый анализатор (GSON).
Ответ 7
Я не смог найти точное число, упомянутое в документах. Однако возвращаемые типы всех Adapter#getCount()
(посмотрите подклассы): ints.
Поэтому мы можем сильно подозревать, что вы можете добавить до Integer.MAX_VALUE
элементы в адаптер, который составляет 2 31 -1 (более 2 миллиардов). Адаптеры используют Lists
и Maps
для хранения данных внутри, которые имеют одинаковый предел.
Поэтому вы не должны беспокоиться об ограничениях адаптера, а не использовать слишком много памяти. Я предлагаю вам загрузить 10-100 элементов в адаптер и просто добавить больше элементов, как только пользователь достигнет нижней части списка.
Ответ 8
Подход Tianwei - это путь.
Если ListView загружен с леними, и поскольку сам ListView перерабатывает представления, лучше всего сохранить только заметные записи в памяти. Вы в основном делаете то же самое в адаптере ListView для представлений.
Если бы вы сохранили все данные в памяти, что бы было проблемой ленивой загрузки ListView? Просто загрузите все данные и пропустите ленивую загрузочную часть...
Конечно, при ленивом подходе загрузки, который загружает только видимые данные (и, возможно, еще несколько), вам нужно будет выполнить ленивую загрузку внизу и в верхней части списка, чтобы сделать эту работу.
Теперь, когда нет информации о характере данных (текст, изображения) или источника (Интернет, SQLite Db, текстовый файл...), я не могу дать вам код (образцы), как это реализовать. Если вы уточняете данные, я могу более точно ответить на вопрос.
Ответ 9
Если вам нужно сохранить в памяти 1M объекты и предполагать, что данные объекта малы, то это всего лишь несколько МБ памяти, и должно быть хорошо, чтобы просто хранить в памяти. Из вопроса я понимаю, что вы будете читать больше элементов, когда пользователи прокручиваются вперед, поэтому на практике у вас не будет 1M строк - пользователям потребуется прокрутить в течение длительного времени, чтобы добраться до 1M.
До тех пор, пока вы правильно используете ListView, вы можете заставить данные адаптера стать 1M + строк в памяти без каких-либо проблем.