Android——了解Fragment懒加载、Material Design、picasso的应用。

有些天没有写博客了,这两天写了一个demo,今天分享给大家,关于Fragment的懒加载,现在很多应用都应用到了懒加载,如网易、今日头条、微信等等,非常普遍,design扩展的伸缩效果,市场上应用的比较少,但是这一类都会被成为流行派,我们还是掌握一些较好;Picasso强大的图片缓存框架,也比较常见了。

那我们马上动手吧!我们一点点的分析,不急着看整体效果,先带大家看下项目结构:
这里写图片描述

从Fragment包中可以看到7个类,BaseFragment是父类,其他6个FirstFragment~SexFragment都是继承其父类(单词写错了,不要太在意细节!!!),在MainActivity中用到了ViewPager,把6个Fragment放入其中,在adapter包中可以看到有ViewPagerAdapter,view包里面是自定义的FloatingActionButton效果,既然有了FloatingActionButton,也会嵌入CoordinatorLayout,这点无疑。项目的大致就是这样,说这些我只是想大家不要一头雾水就看代码,先了解项目整体的结构,要实现的东西,你脑子里至少有这些思路了,脑海里构思出整体效果的画面,大概会是什么效果,先想想,后面自然事半功倍了。

我们先看下注意布局:main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <include layout="@layout/activity_main" />

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:layout_gravity="start"
        app:menu="@menu/menu" />
</android.support.v4.widget.DrawerLayout>

activity_main.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"

    >
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="scrollable"
            app:tabGravity="center"/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/btn_float"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        android:src="@android:drawable/ic_dialog_email"
        app:layout_behavior="com.lai.mylazyfragment.view.ScrollingFabBehavior" />

</android.support.design.widget.CoordinatorLayout>

在FloatingActionButton控件中的app:layout_behavior="com.lai.mylazyfragment.view.ScrollingFabBehavior"就是我们view中的那个类,这样就一目了然了,现在的整体布局相信仔细看了的博友脑子里已经非常清晰了,我们看下效果图:
这里写图片描述

是不是跟你想的差不多。。。。

我们看下MainActivity的实现:

package com.lai.mylazyfragment;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import android.support.design.internal.NavigationMenuView;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.bigkoo.alertview.AlertView;
import com.bigkoo.alertview.OnItemClickListener;
import com.lai.mylazyfragment.activity.PersonalActivity;
import com.lai.mylazyfragment.adapter.ViewPagerAdapter;
import com.lai.mylazyfragment.fragment.FirstFragment;
import com.lai.mylazyfragment.fragment.FiveFragment;
import com.lai.mylazyfragment.fragment.FourFragment;
import com.lai.mylazyfragment.fragment.SecondFragment;
import com.lai.mylazyfragment.fragment.SexFragment;
import com.lai.mylazyfragment.fragment.ThirdFragment;
import com.lai.mylazyfragment.utils.ToastUtils;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private AlertView alertView;//对话框的view
    private List<Fragment> fragmentList;
    private DrawerLayout drawerLayout;
    private ActionBarDrawerToggle actionBarDrawerToggle;
    private Toolbar toolbar;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private NavigationView navigationView;
    private FloatingActionButton btn_float;
    private ImageView iv_image;//头像
    private TextView tv_jieshao;//介绍字体
    private String title[] = {"下拉上拉", "GridView", "Volley请求", "文明教育", "初学者", "老油条"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initView();//初始化控件
        initClick();//初始化控件
        removeNavigationViewScrollbar(navigationView);//隐藏侧滑菜单栏的滚动条
        addViewInToViewPager();//把Fragment添加到ViewPager中
        setTabLayoutView();//为tablayout设置菜单
    }

    /**
     * navigation隐藏滚动条
     *
     * @param navigationView
     */
    private void removeNavigationViewScrollbar(NavigationView navigationView) {
        if (navigationView != null) {
            NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView.getChildAt(0);
            if (navigationMenuView != null) {
                navigationMenuView.setVerticalScrollBarEnabled(false);
            }
        }
    }


    /**
     * 设置显示tablayout菜单
     */
    private void setTabLayoutView() {
        tabLayout.setupWithViewPager(viewPager);
        tabLayout.getTabAt(0).setText(title[0]);
        tabLayout.getTabAt(1).setText(title[1]);
        tabLayout.getTabAt(2).setText(title[2]);
        tabLayout.getTabAt(3).setText(title[3]);
        tabLayout.getTabAt(4).setText(title[4]);
        tabLayout.getTabAt(5).setText(title[5]);
    }

    /**
     * 把Fragment添加到ViewPager中
     */
    private void addViewInToViewPager() {
        fragmentList = new ArrayList<>();
        fragmentList.add(new FirstFragment());
        fragmentList.add(new SecondFragment());
        fragmentList.add(new ThirdFragment());
        fragmentList.add(new FourFragment());
        fragmentList.add(new FiveFragment());
        fragmentList.add(new SexFragment());
        viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), fragmentList));
    }

    /**
     * 初始化控件点击
     */
    private void initClick() {
        //浮动按钮的点击
        btn_float.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                alertView = new AlertView("对话框提示", "恭喜你进入装逼模式", "取消", new String[]{"确定"}, null, MainActivity.this, AlertView.Style.Alert, new OnItemClickListener() {
                    @Override
                    public void onItemClick(Object o, int position) {
                        //对话框取消和确定
                        if (position == 0) {
                            ToastUtils.showShort(MainActivity.this, "确定之后就去做其他事吧!");
                            alertView.dismiss();
                        } else {
                            alertView.dismiss();
                        }
                    }
                });
                alertView.show();
            }
        });
        //头像的点击
        iv_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this, PersonalActivity.class));
            }
        });
        //介绍字体的点击
        tv_jieshao.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri.parse("http://blog.csdn.net/u013836857");
                startActivity(new Intent(Intent.ACTION_VIEW, uri));
            }
        });

        //侧滑菜单按钮的点击
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {
                //直接写相应的操作
                switch (menuItem.getItemId()) {
                    case R.id.nav_camera://拍照
                        ToastUtils.showShort(MainActivity.this, "拍照");
                        break;
                    case R.id.nav_gallery://画廊
                        ToastUtils.showShort(MainActivity.this, "画廊");
                        break;
                    case R.id.nav_slideshow://幻灯片
                        ToastUtils.showShort(MainActivity.this, "幻灯片");
                        break;
                    case R.id.nav_manage://设置
                        ToastUtils.showShort(MainActivity.this, "设置");
                        break;
                    case R.id.nav_share://分享
                        ToastUtils.showShort(MainActivity.this, "分享");
                        break;
                    case R.id.nav_send://发送
                        ToastUtils.showShort(MainActivity.this, "发送");
                        break;
                }
                drawerLayout.closeDrawer(GravityCompat.START);//开始处于关闭状态
                return true;
            }
        });

    }

    /**
     * 初始化控件
     */
    private void initView() {
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        btn_float = (FloatingActionButton) findViewById(R.id.btn_float);
        navigationView = (NavigationView) findViewById(R.id.navigation);
        setSupportActionBar(toolbar);
        View view = navigationView.inflateHeaderView(R.layout.activity_navigation);//加入navigation的头部
        iv_image = (ImageView) view.findViewById(R.id.iv_image);
        tv_jieshao = (TextView) view.findViewById(R.id.tv_jieshao);
        actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open, R.string.close);
        drawerLayout.addDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();//状态
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            alertView = new AlertView("退出", "你确定要退出程序?", "取消", new String[]{"确定"}, null, MainActivity.this, AlertView.Style.Alert, new OnItemClickListener() {
                @Override
                public void onItemClick(Object o, int position) {
                    //对话框取消和确定
                    if (0 == position) {
                        Process.killProcess(Process.myPid());
                        System.exit(0);
                    } else {
                        alertView.dismiss();
                    }
                }
            });
            alertView.show();
        }
        return false;
    }
}

我们再一点一点的细分,先看下侧滑页的菜单图:
这里写图片描述

从上述的两个布局效果图,我们知道主页的TabLayout有6个选项,MainActivity中的private String title[] = {"下拉上拉", "GridView", "Volley请求", "文明教育", "初学者", "老油条"};已经声明,第一个默认选中的 自然就是FirstFragment了,那么这6个选项放在ViewPager中是通过setTabLayoutView()方法里面的代码,6个Fragment自然就是addViewInToViewPager()方法了,这些大家都看得懂;然后removeNavigationViewScrollbar(NavigationView navigationView)是侧滑菜单隐藏滚动条的方法,上面也写了注释了,要传入navigationView对象。再者就是些点击事件了,需要多注意的是initView()初始化方法顺序,其他都很简单。

下面看看上述提到的整体效果:
这里写图片描述

我们会看到TabLayout选项没有显示全,隐藏了其他几项,原因是我在TabLayout设置了属性

<android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="scrollable"
            app:tabGravity="center"/>

app:tabMode=”scrollable”就是将tab左右滚动,不会挤在屏幕所在的宽度,app:tabGravity=”center”是指,如果你后面还有很多选项,那么你选中的那个选项将会放在中间。
效果:
这里写图片描述

也许细心的人会注意到,不管在MainActivity中还是在项目结构看出,都没有看出Dialog的痕迹,而在MainActivity中只有一个AlertView对象,也并没有实现接口之类的东西,为什么点击FloatingActionButton出来的对话框这么漂亮,是的,我导入了对话框的Model,后面会贴链接出来。

上面一个效果图中点击“Volley请求”选项的时候屏幕暗了一下,没错,这也是一个Model,我们都知道,网络请求网络不好的时候,首先是不是要弹出一个对话框提示下用户?如果没有对话框,进去以后没有数据,让别人等了一段时间后,突然数据冒出来了,这种体验,每个用户用了都会觉得恶心,或许都会吐槽“尼玛,这个什么鬼,什么垃圾软件,cao”,

Volley请求的工具类:

package com.lai.mylazyfragment.utils;

import android.content.Context;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * Volley请求工具类
 */
public class VolleyUtil {
    public static void postJsonData(final Context context, String url, JSONObject params,
                                    final PostJsonListener postJsonListener) {
        try {
            // 1.创建请求队列
            RequestQueue volleyRequestQueue = Volley.newRequestQueue(context);
            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, params,
                    new Response.Listener<JSONObject>() {
                        public void onResponse(JSONObject jsonResult) {
                            postJsonListener.onSuccee(jsonResult);
                        }
                    }, new Response.ErrorListener() {
                public void onErrorResponse(VolleyError volleyError) {
                    postJsonListener.onFail(volleyError);
                }
            });

            // 4.请求对象放入请求队列
            volleyRequestQueue.add(jsonObjectRequest);
        } catch (Exception e) {
        }
    }

    /**
     * 返回的成功码
     *
     * @param jsonResult
     * @return
     */
    public static int getResponedCode(JSONObject jsonResult) {
        try {
            String dateText = jsonResult.getString("ret");
            int code = Integer.parseInt(dateText);
            return code;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return -1;
    }

    public interface PostJsonListener {
        void onSuccee(JSONObject jsonResult);//请求成功接口

        void onFail(VolleyError volleyError);//请求失败
    }

}

调用postJsonData方法的时候传入相应的参数,同时实现两个接口:

        void onSuccee(JSONObject jsonResult);//请求成功接口
        void onFail(VolleyError volleyError);//请求失败

成功或者失败后的操作,这些操作我写在ThirdFragment中,代码如下:

package com.lai.mylazyfragment.fragment;

import android.content.Intent;
import android.os.Handler;
import android.support.v7.widget.LinearLayoutManager;
import android.widget.LinearLayout;

import com.android.volley.VolleyError;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jcodecraeer.xrecyclerview.ProgressStyle;
import com.jcodecraeer.xrecyclerview.XRecyclerView;
import com.lai.mylazyfragment.R;
import com.lai.mylazyfragment.activity.LoadingActivity;
import com.lai.mylazyfragment.adapter.ThirdAdapter;
import com.lai.mylazyfragment.bean.Image;
import com.lai.mylazyfragment.utils.ToastUtils;
import com.lai.mylazyfragment.utils.VolleyUtil;

import org.json.JSONObject;

import java.lang.reflect.Type;
import java.util.List;

/**
 * Created by laiyingtang on 2016/8/10.
 */
public class ThirdFragment extends BaseFragment {
    private XRecyclerView xRecyclerView;
    private Handler handler = new Handler();
    private int rows = 10;//每次请求10条
    private int classify = 1;//请求最新的数据10条
    private ThirdAdapter thirdAdapter;

    @Override
    protected int getLayoutId() {
        return R.layout.fragment_third;
    }

    @Override
    protected void initView() {
        xRecyclerView = findView(R.id.xrecyclerview);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());//创建manager对象
        linearLayoutManager.setOrientation(LinearLayout.VERTICAL);//设置布局垂直显示
        xRecyclerView.setLayoutManager(linearLayoutManager);
        xRecyclerView.setRefreshProgressStyle(ProgressStyle.BallScaleMultiple);//下拉刷新的样式
        xRecyclerView.setLaodingMoreProgressStyle(ProgressStyle.LineScaleParty);//上拉的样式
        xRecyclerView.setArrowImageView(R.drawable.iconfont_downgrey);//指定下拉的头图片

        xRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                //下拉
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        xRecyclerView.refreshComplete();//停止刷新
                        rows += 5;
                        getData(rows, classify);
                    }
                }, 2000);
            }

            @Override
            public void onLoadMore() {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        xRecyclerView.loadMoreComplete();//上拉停止
                        rows += 5;
                        classify += 1;
                        getData(rows, classify);
                    }
                }, 2000);
            }
        });
        getData(rows, classify); //初始化数据
    }

    //初始化data
    @Override
    protected void initData() {

    }

    /**
     * 调用api获取数据
     *
     * @param rows     条数
     * @param classify 类别
     */
    private void getData(int rows, int classify) {
        String url = "http://www.tngou.net/tnfs/api/news";
        try {
            JSONObject param = new JSONObject();
            param.put("rows", rows);
            param.put("classify", classify);

            Intent intent = new Intent(getActivity(), LoadingActivity.class);
            startActivity(intent);

            VolleyUtil.postJsonData(getActivity(), url, null, new VolleyUtil.PostJsonListener() {
                @Override
                public void onSuccee(JSONObject jsonResult) {
                    try {
                        LoadingActivity.instance.finish();//请求数据成功,关闭掉loading
                        System.out.println("请求成功,参数:" + jsonResult.toString());
                        String resultJson = jsonResult.getString("tngou");
                        Gson gson = new Gson();
                        Type tokenType = new TypeToken<List<Image>>() {
                        }.getType();
                        List<Image> imageArrayList = gson.fromJson(resultJson, tokenType);
                        thirdAdapter = new ThirdAdapter(imageArrayList, getActivity());
                        xRecyclerView.setAdapter(thirdAdapter);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFail(VolleyError volleyError) {
                    ToastUtils.showShort(getActivity(), "请求失败!");
                    LoadingActivity.instance.finish();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

http://www.tngou.net/tnfs/api/news:是我百度随便找的一个图片api接口,搜索“图片api接口”就出来了,链接天狗美阅,后来用Picasso解析图片出来后,根本无法直视,尼玛,都是性感图片。。。我的天!!!

好了,回到正题,继承的BaseFragment最后才说,该接口并没有返回码(如需了解查看上述链接详情),参数也不是必传的,在请求之前,intent了LoadingActivity类,该类就是正在加载数据的dialog,请求成功后调用finish(),继续执行相应的操作,请求失败提示用户,并finish,完美。用了Gson解析参数,Image是实体,名字让人有点混淆,大家明白就行了,解析出来的img肯定是一个地址链接,所以我要用到Picasso来读取显示,用法非常简单,在根项目的gradle文件中加入Picasso包:compile 'com.squareup.picasso:picasso:2.5.2'就可以使用了,设置在ImageView控件中,例如:Picasso.with(context).load(imageUri).error(R.drawable.icon).into(holder.iv_image1);//设置img到控件中,imageUri就是请求回来的图片url地址(这里请求回来的图片地址不是完整的,需要加前缀,api里面有详细说明),R.drawable.icon显示的错误图片,成功以后设置在holder.iv_image1(ImageView控件)中。

接下来才是今天的重点,Fragment懒加载,BaseFragment类:

package com.lai.mylazyfragment.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by laiyingtang on 2016/8/10.
 */
public abstract class BaseFragment extends Fragment {

    private boolean isVisible = false;//当前Fragment是否可见
    private boolean isInitView = false;//是否与View建立起映射关系
    private boolean isFirstLoad = true;//是否是第一次加载数据

    private View convertView;
    private SparseArray<View> mViews;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        convertView = inflater.inflate(getLayoutId(), container, false);
        mViews = new SparseArray<>();
        initView();
        isInitView = true;
        lazyLoadData();
        return convertView;
    }


    /**
     * 懒加载  隐藏
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        if (isVisibleToUser) {
            isVisible = true;
            lazyLoadData();
        } else {
            isVisible = false;
        }
        super.setUserVisibleHint(isVisibleToUser);
    }

    private void lazyLoadData() {
        if (isFirstLoad) {
            System.out.println("第一次加载--> " + " isInitView:" + isInitView + "  isVisible:" + isVisible + "   fragment:" + this.getClass().getSimpleName());
        } else {
            System.out.println("不是第一次加载--> " + " isInitView:" + isInitView + "  isVisible:" + isVisible + "   fragment:" + this.getClass().getSimpleName());
        }
        if (!isFirstLoad || !isVisible || !isInitView) {
            System.out.println("不加载-->" + "   fragment:" + this.getClass().getSimpleName());
            return;
        }

        System.out.println("完成数据第一次加载-->" + "   fragment:" + this.getClass().getSimpleName());
        initData();
        isFirstLoad = false;
    }

    /**
     * 加载页面布局文件
     *
     * @return
     */
    protected abstract int getLayoutId();

    /**
     * 让布局中的view与fragment中的变量建立起映射
     */
    protected abstract void initView();

    /**
     * 加载要显示的数据
     */
    protected abstract void initData();

    /**
     * fragment中可以通过这个方法直接找到需要的view,而不需要进行类型强转
     *
     * @param viewId
     * @param <E>
     * @return
     */
    protected <E extends View> E findView(int viewId) {
        if (convertView != null) {
            E view = (E) mViews.get(viewId);
            if (view == null) {
                view = (E) convertView.findViewById(viewId);
                mViews.put(viewId, view);
            }
            return view;
        }
        return null;
    }

}

作一个工具类,可以复用,这边我打印了需要加载的Fragment,记录了是不是第一次加载和第一次加载后的打印,我们看下切换下选项看日志
切换至FirstFragment这里写图片描述
再看日志打印:

08-11 23:08:10.492 3545-3545/com.lai.mylazyfragment I/System.out: 不是第一次加载-->  isInitView:true  isVisible:true   fragment:FirstFragment
08-11 23:08:10.492 3545-3545/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment
08-11 23:08:10.496 3545-3545/com.lai.mylazyfragment I/System.out: 不是第一次加载-->  isInitView:true  isVisible:true   fragment:FirstFragment
08-11 23:08:10.496 3545-3545/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment
08-11 23:08:10.500 3545-3545/com.lai.mylazyfragment I/System.out: 不是第一次加载-->  isInitView:true  isVisible:false   fragment:SecondFragment
08-11 23:08:10.500 3545-3545/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:SecondFragment

我们可以看到已经加载过的Fragment不会重新加载,我重新打开应用,再看看日志:

08-11 23:11:06.550 4500-4500/com.lai.mylazyfragment I/System.out: 第一次加载-->  isInitView:false  isVisible:true   fragment:FirstFragment
08-11 23:11:06.550 4500-4500/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment
08-11 23:11:06.586 4500-4500/com.lai.mylazyfragment I/System.out: 第一次加载-->  isInitView:true  isVisible:true   fragment:FirstFragment
08-11 23:11:06.586 4500-4500/com.lai.mylazyfragment I/System.out: 完成数据第一次加载-->   fragment:FirstFragment
08-11 23:11:06.618 4500-4500/com.lai.mylazyfragment I/System.out: 第一次加载-->  isInitView:true  isVisible:false   fragment:SecondFragment
08-11 23:11:06.618 4500-4500/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:SecondFragment

可以看到重新打开应用已经重新加载了Fragment,注意:初始化第一个Fragment(FirstFragment)的时候,第二个Fragment(SecondFragment)也初始化了,这个ViewPager的原因:
**分析:**ViewPager的默认加载方式是缓存当前界面前后相邻的两个界面,即最多共缓存包括当前界面在内的三个界面信息。当滑动切换界面的时候,非相邻界面信息将被释放。界面2是当前界面,界面1和3是缓存界面,当切换到1时,界面2仍缓存,界面3被销毁释放,于是便有了onDestroyView的调用。由1切换到2或3时,界面3又被重新创建,于是走了onCreateView流程。

解决方法,我写入BaseFragment中了,整理后代码如下:

package com.lai.mylazyfragment.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by laiyingtang on 2016/8/10.
 */
public abstract class BaseFragment extends Fragment {

    private boolean isVisible = false;//当前Fragment是否可见
    private boolean isInitView = false;//是否与View建立起映射关系
    private boolean isFirstLoad = true;//是否是第一次加载数据

    private View convertView;
    private SparseArray<View> mViews;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (convertView == null) {
            convertView = inflater.inflate(getLayoutId(), container, false);
            mViews = new SparseArray<>();
            initView();
            isInitView = true;
            lazyLoadData();
        }
        return convertView;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (convertView != null) {
            ((ViewGroup) convertView.getParent()).removeView(convertView);
        }
    }

    /**
     * 懒加载  隐藏
     *
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        if (isVisibleToUser) {
            isVisible = true;
            lazyLoadData();
        } else {
            isVisible = false;
        }
        super.setUserVisibleHint(isVisibleToUser);
    }

    private void lazyLoadData() {
        if (isFirstLoad) {
            System.out.println("第一次加载--> " + " isInitView:" + isInitView + "  isVisible:" + isVisible + "   fragment:" + this.getClass().getSimpleName());
        } else {
            System.out.println("不是第一次加载--> " + " isInitView:" + isInitView + "  isVisible:" + isVisible + "   fragment:" + this.getClass().getSimpleName());
        }
        if (!isFirstLoad || !isVisible || !isInitView) {
            System.out.println("不加载-->" + "   fragment:" + this.getClass().getSimpleName());
            return;
        }

        System.out.println("完成数据第一次加载-->" + "   fragment:" + this.getClass().getSimpleName());
        initData();
        isFirstLoad = false;
    }

    /**
     * 加载页面布局文件
     *
     * @return
     */
    protected abstract int getLayoutId();

    /**
     * 让布局中的view与fragment中的变量建立起映射
     */
    protected abstract void initView();

    /**
     * 加载要显示的数据
     */
    protected abstract void initData();

    /**
     * fragment中可以通过这个方法直接找到需要的view,而不需要进行类型强转
     *
     * @param viewId
     * @param <E>
     * @return
     */
    protected <E extends View> E findView(int viewId) {
        if (convertView != null) {
            E view = (E) mViews.get(viewId);
            if (view == null) {
                view = (E) convertView.findViewById(viewId);
                mViews.put(viewId, view);
            }
            return view;
        }
        return null;
    }

}

解决办法中还提到可以调用viewPager.setOffscreenPageLimit(2);,如果应用Fragment页面过多的话,十分耗内存,会导致异常,所以页面多时,不建议使用。

现在的效果:
这里写图片描述

完美解决。

好了,今天介绍到这里,看完这篇你敢说你没收获?

最后附上下载链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值