Otimização de desempenho do Android – ViewPagers + Otimização de cache de fragmentos

Olhando para o título, você pode ficar um pouco confuso sobre o que é ViewPager, porque há muito tempo atrás usávamos ViewPager, mas agora cada vez mais ViewPager2 é usado, então ViewPager (ViewPager, ViewPager2) é usado para substituir os dois. o principal é apresentar a diferença entre os dois.

A arquitetura de fragmentos aninhados do ViewPagers pode ser vista em todos os lugares em nossos aplicativos comumente usados, como a página inicial de Douyin, a página inicial dos principais aplicativos de comércio eletrônico (Taobao, JD.com, Pinduoduo), etc. ; mas por causa do mecanismo de pré-carregamento do ViewPager , vamos primeiro dar uma olhada no código-fonte do 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();
    }
}

Quando definimos o valor de offscreenPageLimit (carregamento fora da tela), podemos ver que o valor do limite é limitado e não pode ser menor que DEFAULT_OFFSCREEN_PAGES

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

Isso significa que o ViewPager suporta pré-carregamento por padrão. Vejamos a imagem abaixo.

Insira a descrição da imagem aqui

Se você deseja a versão completa do arquivo de otimização de desempenho do Android, clique para obtê-lo gratuitamente

Se a área vermelha for padronizada para a página inicial, de acordo com o limite de pré-carregamento padrão do ViewPager, as páginas à esquerda e à direita também serão carregadas.Se houver uma solicitação de rede, ou seja, não abrimos a página à esquerda, ele já fez uma solicitação de rede por padrão. Essa experiência é muito ruim porque consome tráfego secretamente.

Idealmente, o que precisamos é carregar uma página quando ela é aberta, então precisamos otimizá-la através do carregamento lento.

1 Otimização de carregamento lento do ViewPager

1.1 Mecanismo de cache do ViewPager

Muitas vezes, quando usamos o Fragment, descobrimos que a página aberta volta e a página não é reconstruída e atualizada. Muitas pessoas pensam que o Fragment está armazenado em cache. Na verdade, não é que o Fragment tenha cache, mas que o ViewPager tenha capacidade de cache ;

Se algum amigo tiver usado a arquitetura de atividade única + vários fragmentos, eles descobrirão que quando a página aberta for retornada novamente, o fragmento será reconstruído, portanto, ambas as arquiteturas têm prós e contras. A chave depende de como escolhemos. Vamos dar uma olhada veja abaixo o mecanismo de cache do 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);
        }
    }
}

O método principal é setAdapter. Assim como o RecyclerView, porque há um cache, quando a página desliza, se a página existir no cache, ela será buscada no cache. Caso contrário, você precisa criar uma nova página, então vamos fazer primeiro . Preste atenção ao 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 é uma classe abstrata, portanto esses métodos devem ser implementados por classes de implementação específicas. Se usarmos ViewPager para aninhar fragmentos, usaremos FragmentPageAdapter

Em seguida, retorne ao método setAdapter

①: Existe uma variável global mAdapter. Se for carregada primeiro, então mAdapter estará vazio. Vá para ②

②: Aqui atribuímos o adaptador que passamos para mAdapter

③: Neste momento, o mAdapter não está vazio. Existem vários parâmetros que precisam ser observados aqui:

wasFirstLayout = true
mRestoredCurItem = -1

Então vá diretamente para ⑤ e chame o método requestLayout, que será executado onMeasure. Neste método, o método populate será executado (você mesmo pode subir as escadas)

O que o povoado fez? Há muito código, então não vou publicá-lo aqui, basta ir em frente e carregá-lo na imagem.

Insira a descrição da imagem aqui

Se for o cache padrão (mOffscreenPageLimit = 1), então 3 fragmentos serão armazenados em cache em mItems

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

Quando a página desliza, a página2 se torna a página atual, então o que o preenchimento do ViewPager faz?

(

Acho que você gosta

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