有些天没有写博客了,这两天写了一个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页面过多的话,十分耗内存,会导致异常,所以页面多时,不建议使用。
现在的效果:
完美解决。
好了,今天介绍到这里,看完这篇你敢说你没收获?