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

Fragment Lazy Loading in Android Development

Preface

Lazy loading refers to loading data only when the fragment is fully visible. When developing applications, an Activity may use a viewpager (or other container) to combine multiple fragments. If each fragment needs to load data, either from local storage or from the network, then when the activity is created, it becomes necessary to initialize a large amount of resources. Of course, this result is not satisfactory. So, can we initialize it only when switching to this fragment?

The answer is in the setUserVisibleHint method in Fragment.

Please refer to the API documentation about this method in Fragment:

Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore. 
An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior. 
Parameters 
isVisibleToUser is true if this fragment's UI is currently visible to the user (default), false if it is not. 

This method is used to inform the system whether the UI of this Fragment is visible or not. Therefore, we only need to inherit Fragment and override this method to implement data loading operations only when the fragment is visible, which is known as Fragment's lazy loading.

The code is as follows:

/* 
 * Date: 14-7-17 
 * Project: Access-Control-V2 
 */ 
package cn.irains.access_control_v2.common; 
import android.support.v4.app.Fragment; 
/** 
 * Author: msdx ([email protected]) 
 * Time: 14-7-17 Afternoon5:46 
 */ 
public abstract class LazyFragment extends Fragment { 
 protected boolean isVisible; 
 /** 
  * Here, implement the caching of Fragment data. 
  * @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(){} 
} 

In LazyFragment, I added three methods, one is onVisiable, which is called when the fragment is set to be visible, and another is onInvisible, which is called when the fragment is set to be invisible. In addition, I wrote an abstract method lazyLoad, which is called in onVisible. You may wonder, why not call it directly in getUserVisibleHint?

I write it for code reusability. Because in fragment, we still need to create the view (in the onCreateView() method), and may also need to perform other small initialization operations when it is not visible (such as initializing the remote service that needs to be called through AIDL) and so on. Since setUserVisibleHint is called before onCreateView, if it is used in lazyLoad when the view is not initialized, it will result in a null pointer exception. By extracting lazyLoad into a method, its subclass can do it like this:

public class OpenResultFragment extends LazyFragment{ 
 // Flag indicating that the initialization has been completed. 
 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 initialize the controls of the view 
 isPrepared = true; 
  lazyLoad(); 
  return view; 
 } 
 @Override 
 protected void lazyLoad() { 
  if(!isPrepared || !isVisible) { 
   return; 
  } 
  //Fill in the data of each control 
 } 
} 

In the above class, we added a flag isPrepared to indicate whether the initialization is complete. Then call it after the necessary initialization operations are completed, as in the above example, after initializing the view, set isPrepared to true, and call the lazyLoad() method. In lazyLoad(), it is judged that isPrepared and isVisible must both be true before proceeding. That is, only continue to load when initialization is complete and visible, which avoids the problem of using it before initialization is complete.

Summary

That's all for the introduction of the lazy loading implementation of fragment. If you are interested, you can further explore based on this, such as writing a Fragment with features like缓初始化 and refresh when visible. I hope the content of this article can be helpful to everyone's learning or work, and if you have any questions, you can leave comments for communication.

You May Also Like