fragmentviewpager与fragment实现懒加载

携墨 携墨     2022-08-02     330

关键词:

做项目的时候会我也会遇到许许多多的问题,也会失望,想放弃,那就是心态的问题了,如果遇到问题你以积极的心态去解决,我相信任何问题都不是问题,记住万事,自有方法,关键是不怕问题,去解决它,把挫折转化为经验,那才是最好的。
好了,废话不多说了,我也改讲一讲怎么实现懒加载,
先看看界面是怎样的:
这里写图片描述

暂时没有数据,不影响我们的效果,界面是一个订单的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(代码片段)

简书《Fragment(一)从源码角度看add和replace过程》《Fragment(二)状态改变与管理》《Fragment(三)ViewPager中使用Fragment》《Fragment(四)常见问题》CSDN《Fragment(一)从源码角度看add和replace过程》《Fragment(二)状态改变与管理》《Fragment(三)ViewPa... 查看详情

fragmentviewpager中使用fragment(代码片段)

简书《Fragment(一)从源码角度看add和replace过程》《Fragment(二)状态改变与管理》《Fragment(三)ViewPager中使用Fragment》《Fragment(四)常见问题》CSDN《Fragment(一)从源码角度看add和replace过程》《Fragment(二)状态改变与管理》《Fragment(三)ViewPa... 查看详情

fragment中tablayout加fragmentviewpager

这是要放TabLayout的Fragment<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="m 查看详情

fragmen直接来回切换deno

思路:第一步。建立一个activity。用来管理fragment。第二步‘获取fragmentManger和fragmentTraction.privateFragmentManagerfm;privateFragmentTransactionft;fm=getFragmentManager();ft=fm.beginTransaction();第三步,调用切换方法ft.replace(andro 查看详情

androidfragment

Fragment:  fragment是application的用户界面或行为的一部分,Activity通过FragmentManager与fragment来交互, 获取FragementManager:  Activity.getFragmentManager() and Fragment.getFragmentManager().Fragmen 查看详情

优化片段着色器

】优化片段着色器【英文标题】:OptimizeFragmentShader【发布时间】:2019-03-0401:24:05【问题描述】:我想的性能。目前我的片段着色器是fragmenthalf4fragmen_shader_texture(VertexOutTexturevIn[[stage_in]],texture2d<half>texture[[texture(0)]])constexprsampl... 查看详情

fragment延迟加载

/***Createdbyxzon2017/4/10.*/publicabstractclassBaseFragmentextendsFragment/**是否第一次显示*/privatebooleanisFirstVisible=true;/**是否第一次不显示*/privatebooleanisFirstInVisible=true;/**是否初始化*/privatebooleanisPrepared=false;@OverridepublicvoidonCreate(@... 查看详情

Android 活动组使用

...1】:如前所述,ActivityGroup已弃用。现在安卓开发者使用Fragments和Fragmen 查看详情

动态获取r.drawable.xx资源

StringimageName="index_fragmen"+getColor();finalintresId=context.getResources().getIdentifier(imageName,"drawable",context.getPackageName());if(resId!=0){Log.e("mytest","可以获取到");holder.btnCoupon.setBa 查看详情

fragment的基本应用

...请注明出处:http://blog.csdn.net/crazy1235/article/details/50933621Fragment还是先来基本介绍。Fragment–>片段。在Android3.0的时候被引入,它的出现主要是给大屏幕设备提供更加灵活的UI支持。通过对Activity布局进行分片。更加方便的对每块... 查看详情

使用androidx获取片段内的actionBar

...androidx获取片段内的actionBar【英文标题】:getactionBarinsidefragmentusingandroidx【发布时间】:2019-07-2010:35:07【问题描述】:我只想在一个带有函数的片段中获取actionBar,我正在使用Kotlin语言和AndroidX。这是我的代码:importandroidx.appcompa... 查看详情

片段选项卡未使用所有空间

】片段选项卡未使用所有空间【英文标题】:FragmentTabsnotusingallspace【发布时间】:2016-02-2712:05:52【问题描述】:我正在尝试按照本教程将我的活动应用程序转换为片段:http://www.exoguru.com/android/material-design/navigation/material-design-tab... 查看详情

fragmenttransaction的commit和commitallowingstateloss的差别

1、什么是FragmentTransaction?使用Fragment时。能够通过用户交互来运行一些动作。比方添加、移除、替换等。全部这些改变构成一个集合,这个集合被叫做一个transaction。能够调用FragmentTransaction中的方法来处理这个transaction,而且能... 查看详情

如何在android的地图中获取当前位置?

...来映射......提前致谢..这是我的地图片段..publicclassContactFragmentextendsFragmen 查看详情

如何包含由 Heat 创建的 Wix Fragments

】如何包含由Heat创建的WixFragments【英文标题】:HowtoincludeWixFragmentscreatedbyHeat【发布时间】:2010-11-1609:53:28【问题描述】:我有以下片段:<?xmlversion="1.0"encoding="utf-8"?><Wixxmlns="http://schemas.microsoft.com/wix/2006/wi"><Fragmen 查看详情

需要从寻呼机适配器识别当前视图片段

...器识别当前视图片段【英文标题】:Needtoidentifycurrentviewfragmentfrompageradapter【发布时间】:2017-05-1805:50:40【问题描述】:我们必须知道当前fragment是pageradapter中的可见模式,但无法处理。for(Fragmentfragment:getChildFragmentManager().getFragmen... 查看详情

使用 getFragmentManager().beginTransaction() 在 Android 中为 FragmentTransaction 键入不匹配

】使用getFragmentManager().beginTransaction()在Android中为FragmentTransaction键入不匹配【英文标题】:TypemismatchinAndroidforFragmentTransactionwithgetFragmentManager().beginTransaction()【发布时间】:2013-11-2119:20:39【问题描述】:当我尝试通过在活动中声... 查看详情

AsyncTask 在 ViewPager 的每个页面上运行

...evelopmenttutorial现在我想做的很简单,我在每个页面上使用Fragments。我想在每个页面上显示来自rss提要的不同内容。问题是当我转到下一个选项卡时,它会运行上一个Fragmen 查看详情