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

来源:互联网 发布:淘宝账号是什么 从哪看 编辑:程序博客网 时间:2024/05/29 04:56

有些天没有写博客了,这两天写了一个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:FirstFragment08-11 23:08:10.492 3545-3545/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment08-11 23:08:10.496 3545-3545/com.lai.mylazyfragment I/System.out: 不是第一次加载-->  isInitView:true  isVisible:true   fragment:FirstFragment08-11 23:08:10.496 3545-3545/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment08-11 23:08:10.500 3545-3545/com.lai.mylazyfragment I/System.out: 不是第一次加载-->  isInitView:true  isVisible:false   fragment:SecondFragment08-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:FirstFragment08-11 23:11:06.550 4500-4500/com.lai.mylazyfragment I/System.out: 不加载-->   fragment:FirstFragment08-11 23:11:06.586 4500-4500/com.lai.mylazyfragment I/System.out: 第一次加载-->  isInitView:true  isVisible:true   fragment:FirstFragment08-11 23:11:06.586 4500-4500/com.lai.mylazyfragment I/System.out: 完成数据第一次加载-->   fragment:FirstFragment08-11 23:11:06.618 4500-4500/com.lai.mylazyfragment I/System.out: 第一次加载-->  isInitView:true  isVisible:false   fragment:SecondFragment08-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页面过多的话,十分耗内存,会导致异常,所以页面多时,不建议使用。

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

完美解决。

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

最后附上下载链接

0 0