respuestas - Gestión de la lista de listas de Android sin fin
trivia 360 (9)
Estoy implementando una vista de lista sin fin al cargar más elementos en el arraylist en el método onScrollStateChanged (...). Si estoy implementando este esquema para obtener más de 1 millón de entradas, se agregará un millón de objetos al arraylist, que requiere mucha memoria. ¿Qué esquemas puedo usar para una gestión eficiente de la memoria?
PD: la pregunta es sobre la cantidad de elementos que se pueden colocar en el adaptador. Editar:
Más detalles:
La fuente de los datos es internet. Tengo que buscar los datos de Internet y colocarlos en el adaptador de vista de lista.
En Android, el ListView está virtualizado. Prácticamente eso significa que no hay un límite real para el número de elementos dentro de él. Puedes poner millones de filas dentro de la lista, solo asignará memoria a las que están visibles en ese momento (o algunos tops más).
También puedes ver este artículo Consejos de rendimiento para ListView de Android
Creo que deberías mantener las entradas actuales y la anterior o posterior a ellas (quizás 100), poner estos datos en un caché.
Cuando desplace la vista de lista, obtenga más entradas y actualice la memoria caché como antes (no obtenga 1 millón a la vez).
Debe usar la función de paging
y el botón Load More
como pie de página de ListView
. Por ejemplo:
url = http://your_full_url.php?page=1
Digamos que tiene 100 registros en cada página y, por primera vez, obtenga todos estos 100 registros de la page 1
, ListView
en ListView
y cache
. Ahora desplácese hacia abajo en su ListView
y haga clic en el botón Cargar más (el botón Cargar más debe configurarse como pie de página del ListView
).
Al hacer clic en Cargar más, obtendrá los siguientes 100 registros llamando
url = http://your_full_url.php?page=2
y así sucesivamente para
url = http://your_full_url.php?page=3
,
url = http://your_full_url.php?page=4
etc ...
Cada vez que almacene en caché esos registros para que en caso de pérdida de conexión pueda mostrar los registros disponibles en caché.
El enfoque de Tianwei es el camino a seguir.
Si el ListView está cargado perezosamente y como el mismo ListView está reciclando vistas, es mejor mantener solo las entradas de la lista visible en la memoria. Básicamente haces lo mismo en el adaptador que hace ListView para las Vistas.
Si mantuviera todos los datos en la memoria, ¿cuál sería el motivo para cargar de forma perezosa el ListView de todos modos? Simplemente cargue todos los datos y omita la parte de carga perezosa ... Por supuesto, con el método de carga perezosa que carga solo los datos visibles (y quizás algunos más) tendría que implementar la carga perezosa en la parte inferior y superior de la lista para hacer este trabajo
Ahora, ya que no hay información sobre la naturaleza de los datos (texto, imágenes) o la fuente (Internet, SQLite Db, archivo de texto ...) No puedo darle un código (ejemplos) sobre cómo implementar esto. Si desarrolla los datos, puedo responder la pregunta con mayor precisión.
Esta pregunta no tiene nada que ver con la "capacidad" del Adapter
. En su lugar, está relacionado con la cantidad de memoria asignada por su aplicación.
Tiene un heap reservado para asignar objetos, si supera este límite obtendrá una excepción de memoria insuficiente
Aquí, una pequeña prueba, podría darle una idea sobre la cantidad de datos que podría asignar. Pero tenga en cuenta que en este ejemplo, el objeto contiene solo una String
, si se tratara de un Bitmap
magnífico, la cantidad de objetos a asignar sería mucho, mucho menor.
// 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";
}
No pude encontrar un número exacto mencionado en los documentos. Sin embargo, los tipos de retorno de todos los Adapter#getCount()
(mire las subclases) son ints .
Por lo tanto, podemos sospechar que puede agregar elementos Integer.MAX_VALUE
en un adaptador, que es 2 31 -1 (más de 2 billones). Los adaptadores utilizan Lists
y Maps
para almacenar los datos internamente, que tienen el mismo límite .
Por lo tanto, no debe preocuparse por las limitaciones del adaptador en lugar de utilizar demasiada memoria. Le sugiero que cargue 10-100 elementos en el adaptador y simplemente agregue más elementos tan pronto como el usuario llegue al final de la vista de lista.
Si necesita mantener en la memoria los objetos 1M, y suponiendo que los datos del objeto son pequeños, se trata de unos pocos MB de memoria, y debería estar bien solo para mantenerlos en la memoria. De la pregunta, entiendo que leerá más elementos cuando los usuarios se desplacen hacia adelante, por lo que en la práctica no tendrá filas de 1M; los usuarios deberán desplazarse durante mucho tiempo para llegar a 1M. Siempre que use ListView correctamente, puede hacer que los datos del adaptador se conviertan en 1M + filas en la memoria sin ningún problema
Si su ListView solo contiene elementos de texto, no hay mucho que deba hacer. Sin embargo, si está cargando cosas con más memoria, como los elementos dibujables (por ejemplo, tiene una imagen en el lado derecho de su vista), entonces debería hacer un poco de reciclaje para obtener un mejor resultado. Es posible que reciba una OutOfMemoryException
muy rápidamente en un dispositivo más débil. Podría ir a OOM incluso en un Nexus 4. Solo intente desplazarse muy rápido, arriba y abajo, arriba y abajo, y repita hasta que la fuerza se cierre.
Echa un vistazo a RecyclerListener , es muy fácil de implementar.
Supongo que la base de datos sqlite y el analizador de streaming (GSON).