實現(xiàn)ViewPager+Fragment懶加載的另一個套路
前言
我們實現(xiàn)ViewPager
+Fragment
懶加載罐农,通常是處理Fragment
來控制盅藻。先給一個預(yù)加載View
,通常是類似ProgressBar
的View
組合珠洗,當(dāng)ViewPager
滑動到當(dāng)前Fragment
時移除預(yù)加載View
,加載業(yè)務(wù)View
這樣通常會修改Fragment
的結(jié)構(gòu),這里我想到了另一個方法碧绞,不修改Fragment
,而是去修改FragmentPagerAdapter
項目地址:LazyPagerAdapter
引用 implementation 'com.github.MycroftWong:LazyPagerAdapter:v1.0'
實現(xiàn)
首先構(gòu)造一個占位ViewGroup
, 其中包含一個預(yù)加載View
, 當(dāng)滑動到當(dāng)前ViewPager
時吱窝,移除預(yù)加載的View
讥邻,再添加Fragment
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.PagerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* 想完成的功能,F(xiàn)ragment 不用特意去實現(xiàn)懶加載院峡,完全在 PagerAdapter 中處理懶加載
*
* @author wangqiang
*/
public abstract class LazyPagerAdapter extends PagerAdapter {
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
private View mCurrentPrimaryItem = null;
/**
* 存儲每個位置的View兴使,以免每次都創(chuàng)建
*/
private final List<View> mViews = new ArrayList<>();
public LazyPagerAdapter(@NonNull FragmentManager fm) {
mFragmentManager = fm;
}
/**
* Return the Fragment associated with a specified position.
*
* @param position position
* @return 當(dāng)前position的Fragment
*/
@NonNull
public abstract Fragment getItem(int position);
@Override
public void startUpdate(@NonNull ViewGroup container) {
if (container.getId() == View.NO_ID) {
throw new IllegalStateException("ViewPager with adapter " + this
+ " requires a view id");
}
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
while (mViews.size() <= position) {
mViews.add(null);
}
View view = mViews.get(position);
if (view == null) {
view = LayoutInflater.from(container.getContext()).inflate(getPlaceholderView(position), container, false);
mViews.set(position, view);
container.addView(view);
view.setId(View.generateViewId());
}
return view;
}
/**
* 獲取占位View
*
* @param position position
* @return
*/
@LayoutRes
public abstract int getPlaceholderView(int position);
/**
* 移除預(yù)加載的View
*
* @param view 預(yù)加載的view
* @param position position
*/
public abstract void removePreloadView(ViewGroup view, int position);
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final int itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(((View) object).getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
mCurTransaction.hide(fragment);
}
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
ViewGroup actualView = (ViewGroup) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (actualView != mCurrentPrimaryItem) {
try {
removePreloadView(actualView, position);
} catch (Exception e) {
// 避免多次 remove views
}
// 隱藏 actualView 中的 fragment
final int itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(actualView.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
mCurTransaction.show(fragment);
} else {
fragment = getItem(position);
mCurTransaction.add(actualView.getId(), fragment, makeFragmentName(actualView.getId(), itemId));
}
mCurrentPrimaryItem = actualView;
}
}
@Override
public void finishUpdate(@NonNull ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitNowAllowingStateLoss();
mCurTransaction = null;
}
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
/**
* Return a unique identifier for the item at the given position.
*
* @return Unique identifier for the item at position
*/
private int getItemId(int position) {
return position;
}
private static String makeFragmentName(int viewId, int id) {
return "android:switcher:" + viewId + ":" + id;
}
}
使用
class ContentPagerAdapter extends LazyPagerAdapter {
private final List<String> mData;
public ContentPagerAdapter(FragmentManager fm, List<String> data) {
super(fm);
mData = data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Fragment getItem(int position) {
return ContentFragment.newInstance(mData.get(position));
}
@Override
public CharSequence getPageTitle(int position) {
return mData.get(position);
}
@Override
public int getPlaceholderView(int position) {
return R.layout.fragment_placeholder;
}
@Override
public void removePreloadView(ViewGroup view, int position) {
View progressBar = view.findViewById(R.id.progressBar);
if (progressBar != null) {
view.removeView(progressBar);
}
}
}
demo.gif
后語
這樣是一種實現(xiàn)懶加載的方法,有優(yōu)點也有缺點照激,個人覺得可以用于日常開發(fā)发魄,使用簡單,不影響Fragment
的代碼邏輯
優(yōu)點
使用簡單俩垃、Fragment
的結(jié)構(gòu)不變励幼,適合主頁使用ViewPager
的情況
缺點
中間加了一層View
,層次深一點口柳,用Fragment
的話幾乎沒什么影響苹粟。不適合在Fragment
里控制加載邏輯的。