首页 > 代码库 > FragmentViewpager与Fragment实现懒加载
FragmentViewpager与Fragment实现懒加载
做项目的时候会我也会遇到许许多多的问题,也会失望,想放弃,那就是心态的问题了,如果遇到问题你以积极的心态去解决,我相信任何问题都不是问题,记住万事,自有方法,关键是不怕问题,去解决它,把挫折转化为经验,那才是最好的。
好了,废话不多说了,我也改讲一讲怎么实现懒加载,
先看看界面是怎样的:
暂时没有数据,不影响我们的效果,界面是一个订单的Activity,布局是上面一个自定义的TitileBar,下面是一个TabLayout,一个最下面是一个Viewpager,待会会在viewpager里面通过ViewpagerFragmentAdapter实现数据的填充
订单的Activity布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="net.xiemo.app.ui.OrderInfoActivity">
<net.anchong.app.view.TitleBarView
android:id="@+id/orders_titileBarView"
android:background="@color/cube_holo_blue_light"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</net.anchong.app.view.TitleBarView>
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout_orders"
android:layout_below="@id/orders_titileBarView"
android:layout_width="match_parent"
android:layout_height="25dp"/>
<android.support.v4.view.ViewPager
android:layout_below="@+id/tab_layout_orders"
android:id="@+id/viewpager_orders"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
首先我们要实现的效果是,这里我是复用的同一个fragment:
我是直接点击进入我的订单页面的全部,然后一直滑动到退货,然后又滑动到全部,仅会加载当前viewpager的fragment的页面,而且仅仅加载一次,之后左右滑动都不会在加载,除非返回后重新进入。
第二个效果是:
每次滑动也仅加载当前的fragment页面,但是每次滑动都会请求,只需要在上面效果基础上修改一个代码即可,虽然频繁请求,有利于数据的实时更新
先上代码:
订单的Activity页面:
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import net.anchong.app.R;
import net.anchong.app.adapter.MyOrdersFragmentViewPagerAdapter;
import net.anchong.app.view.TitleBarView;
public class OrderInfoActivity extends FragmentActivity implements TitleBarView.TitleBarClickListener{
private TitleBarView ordersTitileBarView;
private TabLayout tabLayoutOrders;
private ViewPager viewpagerOrders;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_info2);
Intent intent = getIntent();
initView();
//设置是点击根据position进入订单选择的viewpager
int position = intent.getIntExtra("position", 0);
viewpagerOrders.setCurrentItem(position);
}
private void initView() {
//自定义的titileBar(可忽略)
ordersTitileBarView = (TitleBarView)findViewById( R.id.orders_titileBarView );
ordersTitileBarView.setTitle("我的订单");
ordersTitileBarView.setTitleBarClickListener(this);
tabLayoutOrders = (TabLayout)findViewById( R.id.tab_layout_orders );
viewpagerOrders = (ViewPager)findViewById( R.id.viewpager_orders);
//这句话是设置默认缓存viewpager,不设置默认是1,就会先缓存左右两边的viewpager,0代表不缓存,1代表缓存左右两边的Viewpager
viewpagerOrders.setOffscreenPageLimit(2);
//设置填充freagment
MyOrdersFragmentViewPagerAdapter myOrdersFragmentViewPagerAdapter = new MyOrdersFragmentViewPagerAdapter(getSupportFragmentManager(), new String[]{"全部",
"待付款", "待发货", "待收获", "退货"},this);
//设置到viewpager
viewpagerOrders.setAdapter(myOrdersFragmentViewPagerAdapter);
//关联Tablayout
tabLayoutOrders.setupWithViewPager(viewpagerOrders);
}
//这两个方法是titileBar定义接口的方法(可忽略)
@Override
public void leftClick() {
finish();
}
@Override
public void rightClick() {
}
}
上面主要的方法是:
避免viewpager的重复创建可以设置:
viewpager.setOffscreenPageLimit(2);
设置当前page左右两侧应该被保持的page数量,超过这个限制,page会被销毁重建(只是销毁视图),onDestroy-onCreateView,但不会执行onDestroy。尽量维持这个值小,特别是有复杂布局的时候,因为如果这个值很大,就会占用很多内存,如果只有3-4page的话,可以全部保持active,可以保持page切换的顺滑
这下很好理解了,默认情况下是1,所以当前fragment左右两侧,就会被保持1页pager,所以上述切换到fragment2并不会销毁任何视图,但是到fragment1,3会。这里注意这个值,是左右两侧能够维持的page,所以如果setOffscreenPageLimit(2),维持保持左右两边2个,Viewpager那么就不会频繁的销毁了.
另外,在ViewpagerFragmentAdapter中的destroyItem()方法
//super.destroyItem(container, position, object); 注释掉调用父类方法即可
取消预加载:
可以fragment的setUserVisibleHint实现,具体实现参考代码示例
setUserVisibleHint 意思就是:
fragment对用户可见,isVisibleToUser为true,不可见isVisibleToUser为false。对应于viewpager,当前pager,非当前pager
import android.support.v4.app.Fragment;
import android.widget.Toast;
/**
* Created by xiemo on 16/3/15.
*/
public abstract class BaseFragment extends Fragment {
/** Fragment当前状态是否可见 */
protected boolean isVisible;
//setUserVisibleHint adapter中的每个fragment切换的时候都会被调用,如果是切换到当前页,那么isVisibleToUser==true,否则为false
@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:
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import net.anchong.app.R;
import net.anchong.app.adapter.MyOrderListFragmentAdapter;
import net.anchong.app.app.MyApplication;
import net.anchong.app.entity.request.model.OrderInfoRequestParam;
import net.anchong.app.entity.response.model.OrderInfoResponse;
import net.anchong.app.net.RequestUtils;
/**
* 订单的每个fragment(实现了懒加载)
* A simple {@link Fragment} subclass.
*/
public class MyOrdersFragment extends BaseFragment implements RequestUtils.OnMyOrdersListener{
private static final String TAG = "MyOrdersFragment";
private int stateId;
private ListView order_Listview;
private LinearLayout fl_empty_view;
private Context mContext;
MyOrderListFragmentAdapter myOrderListFragmentAdapter;
OrderInfoResponse.ResultDataEntity mResultDataEntity;
/** 标志位,标志已经初始化完成 */
private boolean isPrepared;
/** 是否已被加载过一次,第二次就不再去请求数据了 */
private boolean mHasLoadedOnce;
View view;
public MyOrdersFragment() {
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
public static MyOrdersFragment newInstance(int stateId) {
Bundle args = new Bundle();
args.putInt("stateId",stateId);
MyOrdersFragment fragment = new MyOrdersFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_all_order, container, false);
stateId = getArguments().getInt("stateId");
initView(view);
//设置加载完成
isPrepared = true;
//开始加载
lazyLoad();
return view;
}
private void initView(View view) {
fl_empty_view = (LinearLayout)view.findViewById(R.id.fl_empty_view);//默认没有订单为显示
order_Listview = (ListView) view.findViewById(R.id.order_Listview);
myOrderListFragmentAdapter = new MyOrderListFragmentAdapter(mResultDataEntity, mContext);
order_Listview.setAdapter(myOrderListFragmentAdapter);
RequestUtils.setOnMyOrdersListener(this);
}
//获取订单的回调,返回的数据填充,可以忽略
@Override
public void getOrderInfos(OrderInfoResponse orderInfoResponse) {
mResultDataEntity = orderInfoResponse.getResultData();
if(mResultDataEntity.getTotal()!=0){
fl_empty_view.setVisibility(View.GONE);
order_Listview.setVisibility(View.VISIBLE);
myOrderListFragmentAdapter.setResultDataEntities(mResultDataEntity);
myOrderListFragmentAdapter.notifyDataSetChanged();
}
}
@Override
protected void lazyLoad() {
//这里可以实现完全懒加载,仅仅加载一次
//isPrepared是CreateView方法执行后设置为ture已经准备,isVisible(父类的)是否显示当前页面,mHasLoadedOnce是否已经加载过
//如果只设置!isPrepared || !isVisible,的话每次每个页面都会重新加载,每次只加载一个页面
//!isPrepared || !isVisible|| mHasLoadedOnce这样就完全的懒加载,每次进入只加载一次,之后不会再次加载了
if (!isPrepared || !isVisible|| mHasLoadedOnce) {
return;
}
//设置已经加载过
mHasLoadedOnce = true;
//开始请求加载
OrderInfoRequestParam orderInfoRequestParam = new OrderInfoRequestParam(stateId+"","1");
Log.e(TAG, "stateId=: "+stateId );
RequestUtils.MyOrdersListener(MyApplication.ORDERORDERINFO,orderInfoRequestParam,mContext);
}
}
ViewpagerFragmentadapter:
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.util.Log;
import android.view.ViewGroup;
import net.anchong.app.fragment.MyOrdersFragment;
/**
* 我的订单
* Created by Administrator on 2016/9/1.
*/
public class MyOrdersFragmentViewPagerAdapter extends FragmentPagerAdapter /*FragmentStatePagerAdapter*/ {
private static final String TAG = "PagerAdapter";
private String[] titles;
private Context mContext;
public MyOrdersFragmentViewPagerAdapter(FragmentManager fm, String[] titles,Context context) {
super(fm);
this.titles = titles;
mContext = context;
}
public MyOrdersFragmentViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return MyOrdersFragment.newInstance(position);
}
@Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
@Override
public int getCount() {
return titles.length;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.e(TAG, "destroyItem2" );
//如果注释这行,那么不管怎么切换,page都不会被销毁
super.destroyItem(container, position, object);
}
}
这样就实现了第一个效果
第二个效果只需要把mHasLoadedOnce去掉即可
FragmentViewpager与Fragment实现懒加载