Optimización del rendimiento de Android: ViewPagers + optimización de caché de fragmentos

Al mirar el título, es posible que esté un poco confundido acerca de qué son los ViewPagers, porque hace mucho tiempo usábamos ViewPager, pero ahora se usa cada vez más ViewPager2, por lo que se usan ViewPagers (ViewPager, ViewPager2) para reemplazar los dos. Lo principal es introducir la diferencia entre los dos.

La arquitectura de fragmentos anidados de ViewPager se puede ver en todas partes en nuestras aplicaciones de uso común, como la página de inicio de Douyin, la página de inicio de las principales aplicaciones de comercio electrónico (Taobao, JD.com, Pinduoduo), etc. Puede cambiar de pestaña deslizándose hacia la izquierda o hacia la derecha. ; pero debido al mecanismo de precarga de ViewPager, veamos primero el código fuente de ViewPager:

public void setOffscreenPageLimit(int limit) {
   
    
    
    if (limit < DEFAULT_OFFSCREEN_PAGES) {
   
    
    
        Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                + DEFAULT_OFFSCREEN_PAGES);
        limit = DEFAULT_OFFSCREEN_PAGES;
    }
    if (limit != mOffscreenPageLimit) {
   
    
    
        mOffscreenPageLimit = limit;
        populate();
    }
}

Cuando configuramos el valor de offscreenPageLimit (carga fuera de la pantalla), podemos ver que el valor del límite es limitado y no puede ser menor que DEFAULT_OFFSCREEN_PAGES

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

Esto significa que ViewPager admite la precarga de forma predeterminada. Veamos la imagen a continuación.

Insertar descripción de la imagen aquí

Si desea la versión completa del archivo de optimización del rendimiento de Android, haga clic para obtenerlo gratis

Si el área roja es la página de inicio de forma predeterminada, de acuerdo con el umbral de precarga predeterminado de ViewPager, también se cargarán las páginas de la izquierda y la derecha. Si hay una solicitud de red, es decir, no hemos abierto la página de la izquierda, ya ha realizado una solicitud de red de forma predeterminada, esta experiencia es muy pobre porque consume tráfico en secreto.

Idealmente, lo que necesitamos es cargar una página cuando se abre, por lo que debemos optimizarla mediante carga diferida.

1 Optimización de carga diferida de ViewPager

1.1 Mecanismo de almacenamiento en caché de ViewPager

Muchas veces, cuando usamos Fragment, encontramos que la página abierta regresa y la página no se reconstruye ni se actualiza. Mucha gente piensa que Fragment está almacenado en caché. De hecho, no es que Fragment tenga caché, sino que ViewPager tiene capacidad de almacenamiento en caché. ;

Si algún amigo ha usado la arquitectura Actividad única + Fragmento múltiple, encontrará que cuando la página abierta se devuelva nuevamente, el Fragmento se reconstruirá, por lo que ambas arquitecturas tienen ventajas y desventajas. La clave depende de cómo elijamos. Tomemos un Mire a continuación el mecanismo de almacenamiento en caché de ViewPager.

public void setAdapter(@Nullable PagerAdapter adapter) {
   
    
    
    if (mAdapter != null) {
   
    
    
        ①
        mAdapter.setViewPagerObserver(null);
        mAdapter.startUpdate(this);
        for (int i = 0; i < mItems.size(); i++) {
   
    
    
            final ItemInfo ii = mItems.get(i);
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        mAdapter.finishUpdate(this);
        mItems.clear();
        removeNonDecorViews();
        mCurItem = 0;
        scrollTo(0, 0);
    }final PagerAdapter oldAdapter = mAdapter;
    mAdapter = adapter;
    mExpectedAdapterCount = 0;if (mAdapter != null) {
   
    
    
        if (mObserver == null) {
   
    
    
            mObserver = new PagerObserver();
        }
        mAdapter.setViewPagerObserver(mObserver);
        mPopulatePending = false;
        final boolean wasFirstLayout = mFirstLayout;
        mFirstLayout = true;
        mExpectedAdapterCount = mAdapter.getCount();
        if (mRestoredCurItem >= 0) {
   
    
    
            mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
            setCurrentItemInternal(mRestoredCurItem, false, true);
            mRestoredCurItem = -1;
            mRestoredAdapterState = null;
            mRestoredClassLoader = null;
        } else if (!wasFirstLayout) {
   
    
    populate();
        } else {
   
    
    requestLayout();
        }
    }

    // Dispatch the change to any listeners
    if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) {
   
    
    
        for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) {
   
    
    
            mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter);
        }
    }
}

El método principal es setAdapter. Al igual que RecyclerView, debido a que hay un caché, cuando la página se desliza, si la página existe en el caché, se recuperará del caché. Si no, debe crear una nueva página, así que hagámoslo. Primero , preste atención a PagerAdapter.

public abstract class PagerAdapter {
   
    
    
    private final DataSetObservable mObservable = new DataSetObservable();
    private DataSetObserver mViewPagerObserver;

    public static final int POSITION_UNCHANGED = -1;
    public static final int POSITION_NONE = -2;

    public abstract int getCount();
    //开始更新
    public void startUpdate(@NonNull ViewGroup container) {
   
    
    
        startUpdate((View) container);
    }
    //初始化页面
    @NonNull
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
   
    
    
        return instantiateItem((View) container, position);
    }
    //销毁页面
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
   
    
    
        destroyItem((View) container, position, object);
    }
    //结束刷新
    public void finishUpdate(@NonNull ViewGroup container) {
   
    
    
        finishUpdate((View) container);
    }
}

PagerAdapter es una clase abstracta, por lo que estos métodos deben ser implementados por clases de implementación específicas. Si usamos ViewPager para anidar fragmentos, usamos FragmentPageAdapter

Luego regrese al método setAdapter

①: Hay una variable global mAdapter. Si se carga primero, entonces mAdapter está vacío. Vaya a ②

②: Aquí asignamos el adaptador que pasamos a mAdapter

③: En este momento, mAdapter no está vacío, hay varios parámetros a los que se debe prestar atención aquí:

wasFirstLayout = true
mRestoredCurItem = -1

Entonces vaya directamente a ⑤ y llame al método requestLayout, que se ejecutará enMeasure. En este método, se ejecutará el método populate (puede subir las escaleras usted mismo)

¿Qué hizo el pueblo? Hay demasiado código, así que no lo publicaré aquí, solo ve a la imagen.

Insertar descripción de la imagen aquí

Si es el caché predeterminado (mOffscreenPageLimit = 1), se almacenarán en caché 3 fragmentos en mItems.

private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();

Cuando la página se desliza, la página 2 se convierte en la página actual, entonces, ¿qué hace el relleno de ViewPager?

(

Supongo que te gusta

Origin blog.csdn.net/m0_70748458/article/details/130384728
Recomendado
Clasificación