首页 > 代码库 > ViewPager+Fragment取消预加载(延迟加载)

ViewPager+Fragment取消预加载(延迟加载)

在项目中,都或多或少地使用的Tab布局,所以大都会用到ViewPager+Fragment,但是Fragment有个不好或者太好的地方。例如你在ViewPager中添加了三个Fragment,当加载ViewPager中第一个Fragment时,它会默认帮你预先加载了第二个Fragment,当你加载第二个Fragment时,它会帮你加载第三个Fragment。这样虽然有时很好,但是用户只需看一个Fragment时,我们就做了一些多余工作加载了第二个Fragment。在这只需要取消Fragment的预加载即可,只有当用户切换到某个Fragment才加载..

技术分享

首先,介绍两个方法void setUserVisibleHint(boolean isVisibleToUser)、boolean getUserVisibleHint(),它们分别用作设置/获得Fragment可见状态,我们可以重写Fragment在其中做判断,代码如下:

import android.support.v4.app.Fragment;

public abstract class BaseFragment extends Fragment {
	
	/** Fragment当前状态是否可见 */
	protected boolean isVisible;
	
	
	@Override
	public void setUserVisibleHint(boolean isVisibleToUser) {
		super.setUserVisibleHint(isVisibleToUser);
		
		if(getUserVisibleHint()) {
			isVisible = true;
			onVisible();
		} else {
			isVisible = false;
			onInvisible();
		}
	}
	
	
	/**
	 * 可见
	 */
	protected void onVisible() {
		lazyLoad();		
	}
	
	
	/**
	 * 不可见
	 */
	protected void onInvisible() {
		
		
	}
	
	
	/** 
	 * 延迟加载
	 * 子类必须重写此方法
	 */
	protected abstract void lazyLoad();
}

在我们的Fragment中,只需要继承这个类,然后重写其中的lazyLoad()方法,当Fragment对用户可见(即用户切换到此Fragment时)我们在lazyLoad()中加载所需数据,详细代码看下面,我写了个假的获取数据线程:

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class CustomListFragment extends BaseFragment {

	private static final String FRAGMENT_INDEX = "fragment_index";
	private final int FIRST_FRAGMENT = 0;
	private final int SECOND_FRAGMENT = 1;
	private final int THIRD_FRAGMENT = 2;

	private TextView mFragmentView;

	private int mCurIndex = -1;
	/** 标志位,标志已经初始化完成 */
	private boolean isPrepared;
	/** 是否已被加载过一次,第二次就不再去请求数据了 */
	private boolean mHasLoadedOnce;

	/**
	 * 创建新实例
	 * 
	 * @param index
	 * @return
	 */
	public static CustomListFragment newInstance(int index) {
		Bundle bundle = new Bundle();
		bundle.putInt(FRAGMENT_INDEX, index);
		CustomListFragment fragment = new CustomListFragment();
		fragment.setArguments(bundle);
		return fragment;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		if(mFragmentView == null) {
			mFragmentView = (TextView) inflater.inflate(R.layout.fragment, container, false);
			//获得索引值
			Bundle bundle = getArguments();
			if (bundle != null) {
				mCurIndex = bundle.getInt(FRAGMENT_INDEX);
			}
			isPrepared = true;
			lazyLoad();
		}
		
		//因为共用一个Fragment视图,所以当前这个视图已被加载到Activity中,必须先清除后再加入Activity
		ViewGroup parent = (ViewGroup)mFragmentView.getParent();
		if(parent != null) {
			parent.removeView(mFragmentView);
		}
		return mFragmentView;
	}

	@Override
	protected void lazyLoad() {
		if (!isPrepared || !isVisible || mHasLoadedOnce) {
			return;
		}

		new AsyncTask<Void, Void, Boolean>() {

			@Override
			protected void onPreExecute() {
				super.onPreExecute();
				//显示加载进度对话框
				UIHelper.showDialogForLoading(getActivity(), "正在加载...", true);
			}

			@Override
			protected Boolean doInBackground(Void... params) {
				try {
					Thread.sleep(2000);
					//在这里添加调用接口获取数据的代码
					//doSomething()
				} catch (Exception e) {
					e.printStackTrace();
				}
				return true;
			}

			@Override
			protected void onPostExecute(Boolean isSuccess) {
				if (isSuccess) {
					// 加载成功
					setView();
					mHasLoadedOnce = true;
				} else {
					// 加载失败
				}
				//关闭对话框
				UIHelper.hideDialogForLoading();
			}
		}.execute();
	}

	private void setView() {
		// 根据索引加载不同视图
		switch (mCurIndex) {
		case FIRST_FRAGMENT:
			mFragmentView.setText("第一个");
			break;

		case SECOND_FRAGMENT:
			mFragmentView.setText("第二个");
			break;

		case THIRD_FRAGMENT:
			mFragmentView.setText("第三个");
			break;
		}
	}
}

到这里我们只是写好了Fragment,在FragmentActivity中还需要对ViewPager设置一下,让它每次只加载一个Fragment,ViewPager.setOffscreenPageLimit(int limit),其中参数可以设为0或者1,参数小于1时,会默认用1来作为参数,未设置之前,ViewPager会默认加载两个Fragment。所以,我们只需要调用下它,设置下加载Fragment个数即可。

import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RadioButton;
import android.os.Bundle;

public class MainActivity extends FragmentActivity implements OnClickListener{

	private RadioButton mFstBtn;
	private RadioButton mSndBtn;
	private RadioButton mThdBtn;
	
	private ViewPager mViewPager;
	private ListFragmentPagerAdapter mPagerAdapter;
	private List<Fragment> mFragments = new ArrayList<Fragment>();
	
	private final int FIRST_FRAGMENT = 0;
	private final int SECOND_FRAGMENT = 1;
	private final int THIRD_FRAGMENT = 2;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initButton();
		initViewPager();
	}
	
	
	/**
	 * 初始化按钮
	 */
	private void initButton() {
		mFstBtn = (RadioButton)findViewById(R.id.id_rb_fst);
		mFstBtn.setOnClickListener(this);
		mSndBtn = (RadioButton)findViewById(R.id.id_rb_snd);
		mSndBtn.setOnClickListener(this);
		mThdBtn = (RadioButton)findViewById(R.id.id_rb_thd);
		mThdBtn.setOnClickListener(this);
	}
	
	
	/**
	 * 初始化ViewPager控件
	 */
	private void initViewPager() {
		mViewPager = (ViewPager)findViewById(R.id.id_vp_viewpager);
		//关闭预加载,默认一次只加载一个Fragment
		mViewPager.setOffscreenPageLimit(1);
		//添加Fragment
		mFragments.add(CustomListFragment.newInstance(FIRST_FRAGMENT));
		mFragments.add(CustomListFragment.newInstance(SECOND_FRAGMENT));
		mFragments.add(CustomListFragment.newInstance(THIRD_FRAGMENT));
		//适配器
		mPagerAdapter = new ListFragmentPagerAdapter(getSupportFragmentManager(), mFragments);
		mViewPager.setAdapter(mPagerAdapter);
		mViewPager.setOnPageChangeListener(onPageChangeListener);
	}

	
	private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
		
		@Override
		public void onPageSelected(int position) {
			//根据用户选中的按钮修改按钮样式
			switch (position) {
			case FIRST_FRAGMENT:
				mFstBtn.setChecked(true);
				mSndBtn.setChecked(false);
				mThdBtn.setChecked(false);
				break;

			case SECOND_FRAGMENT:
				mFstBtn.setChecked(false);
				mSndBtn.setChecked(true);
				mThdBtn.setChecked(false);
				break;
				
			case THIRD_FRAGMENT:
				mFstBtn.setChecked(false);
				mSndBtn.setChecked(false);
				mThdBtn.setChecked(true);
			break;
			}
		}
		
		@Override
		public void onPageScrolled(int arg0, float arg1, int arg2) {}
		
		@Override
		public void onPageScrollStateChanged(int arg0) {}
	};
	
	
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.id_rb_fst:
			mViewPager.setCurrentItem(FIRST_FRAGMENT);
			break;

		case R.id.id_rb_snd:
			mViewPager.setCurrentItem(SECOND_FRAGMENT);
			break;
			
		case R.id.id_rb_thd:
			mViewPager.setCurrentItem(THIRD_FRAGMENT);
			break;
		}
	}
}

源码下载


ViewPager+Fragment取消预加载(延迟加载)