首页 > 代码库 > 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去掉即可

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    FragmentViewpager与Fragment实现懒加载