English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Técnica de desarrollo de Android: carga perezosa de Fragment

Prólogo

Lo que se conoce como carga perezosa es cargar los datos cuando el fragmento está completamente visible. Durante el desarrollo de aplicaciones, es posible que dentro de un Activity se utilice un ViewPager (u otro contenedor) junto con varios Fragmentos. Si cada fragmento necesita cargar datos, ya sea desde el almacenamiento local o desde la red, en el momento de la creación del activity se necesitará inicializar una gran cantidad de recursos. Este resultado, naturalmente, no nos satisfará. ¿Podemos lograr que se inicialice solo cuando se cambie a este fragmento?

La respuesta se encuentra en el método setUserVisibleHint de Fragment.

Consulte la documentación de API sobre este método en Fragment:

Establezca una sugerencia para el sistema sobre si la UI de este fragmento es actualmente visible para el usuario. Esta sugerencia por defecto es verdadera y es persistente a través del guardado y restauración del estado de la instancia del fragmento. 
Una aplicación puede establecer esto en falso para indicar que la UI del fragmento está desplazada fuera de la visibilidad o de otra manera no es directamente visible para el usuario. Esto puede ser utilizado por el sistema para priorizar operaciones como actualizaciones del ciclo de vida del fragmento o comportamientos de ordenamiento de loaders. 
Parámetros 
isVisibleToUser verdadero si la UI de este fragmento es actualmente visible para el usuario (por defecto), falso si no lo es. 

Este método se utiliza para informar al sistema si la UI de este Fragment es visible o no. Por lo tanto, solo necesitamos heredar Fragment y sobrescribir este método para lograr que se realicen las operaciones de carga de datos solo cuando el fragmento es visible, es decir, el carga perezosa del Fragment.

El código es el siguiente:

/* 
 * Fecha: 14-7-17 
 * Proyecto: Acceso-Control-V2 
 */ 
paquete cn.irains.access_control_v2.common; 
import android.support.v4.app.Fragment; 
/** 
 * Autor: msdx ([email protected]) 
 * Hora: 14-7-17 Tarde5:46 
 */ 
public abstract class LazyFragment extends Fragment { 
 protected boolean isVisible; 
 /** 
  * Aquí se implementa la carga de datos del fragmento en segundo plano. 
  * @param isVisibleToUser 
  */ 
 @Override 
 public void setUserVisibleHint(boolean isVisibleToUser) { 
  super.setUserVisibleHint(isVisibleToUser); 
  if(getUserVisibleHint()) { 
   isVisible = true; 
   onVisible(); 
  } else { 
   isVisible = false; 
   onInvisible(); 
  } 
 } 
 protected void onVisible(){ 
  lazyLoad(); 
 } 
 protected abstract void lazyLoad(); 
 protected void onInvisible(){} 
} 

En LazyFragment, he agregado tres métodos: uno es onVisiable, que se llama cuando el fragmento se establece como visible; otro es onInvisible, que se llama cuando el fragmento se establece como invisible. Además, he escrito un método abstracto lazyLoad, que se llama dentro de onVisible. Te preguntarás, ¿por qué no llamarlo directamente en getUserVisibleHint?

Escribo así para facilitar la reutilización del código. Porque en el fragmento, también necesitamos crear la vista (método onCreateView()), y es posible que necesitemos realizar otras pequeñas operaciones de inicialización cuando el fragmento no sea visible (por ejemplo, inicializar servicios remotos que necesitan ser llamados a través de AIDL) y otros. Ya que setUserVisibleHint es llamado antes de onCreateView, si se utiliza en lazyLoad cuando la vista no está inicializada, se producirá una excepción de puntero nulo. Al separar lazyLoad en un método, sus subclases pueden hacerlo de la siguiente manera:

public class OpenResultFragment extends LazyFragment{ 
 // Bandera, indica que la inicialización se ha completado. 
 private boolean isPrepared; 
 @Override 
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
  Log.d(LOG_TAG, "onCreateView"); 
  View view = inflater.inflate(R.layout.fragment_open_result, container, false); 
  //XXX inicializar los controladores de la vista 
 isPrepared = true; 
  lazyLoad(); 
  return view; 
 } 
 @Override 
 protected void lazyLoad() { 
  if(!isPrepared || !isVisible) { 
   return; 
  } 
  //Rellenar los datos de los controladores 
 } 
} 

En la clase anterior, hemos agregado una bandera isPrepared para indicar si la inicialización se ha completado. Luego llamamos a esta función después de completar las operaciones de inicialización necesarias, como en el ejemplo anterior, después de inicializar la vista, establecemos isPrepared en true y llamamos al método lazyLoad(). En lazyLoad(), si isPrepared o isVisible no son true, no se ejecuta el siguiente código. Es decir, solo se carga cuando la inicialización está completa y la vista es visible, evitando así problemas relacionados con el uso de una inicialización no completa.

Resumen

Aquí termina mi introducción sobre la implementación de carga perezosa de fragmentos. Si estás interesado, puedes profundizar en este tema, por ejemplo, escribiendo un Fragmento con características de inicialización diferida y actualización al hacerse visible. Espero que el contenido de este artículo te sea útil para tu aprendizaje o trabajo, y si tienes alguna pregunta, puedes dejar un comentario para discutirlo.

Te gustará