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页面过多的话,十分耗内存,会导致异常,所以页面多时,不建议使用。
现在的效果:
完美解决。
好了,今天介绍到这里,看完这篇你敢说你没收获?
最后附上下载链接
- Android——了解Fragment懒加载、Material Design、picasso的应用。
- 了解Material Design的使用
- ANDROID L——Material Design综合应用(Demo)
- ANDROID L——Material Design综合应用(Demo)
- ANDROID L——Material Design综合应用(Demo) .
- Android L——Material Design综合应用(Demo)
- 指尖资讯——基于MVP架构、遵循Material Design的Android应用
- Android 构建 Material Design 应用
- 创建Material Design风格的Android应用--应用主题
- 创建Material Design风格的Android应用--应用主题
- 创建Material Design风格的Android应用--应用主题
- 创建Material Design风格的Android应用--应用主题
- 创建Material Design风格的Android应用--应用主题
- Material Design 系列(4)—TabLayout&ViewPager&Fragment
- Android Material Design控件——TabLayout的用法
- Material Design你真的了解吗?
- Android 5.0——Material Design详解
- Android Material Design —— RecyclerView
- 移动联通基站定位
- CSS3自定义Checkbox复选框
- [Codevs5339][hzwerNOIP模拟赛]小奇挖矿
- Kotlin开发Android笔记10:Kotlin中Kotlin Android Extensions
- Checking operating system version: must be 4.0, 5.0, 5.1 or 5.2. Actual 6.1
- Android——了解Fragment懒加载、Material Design、picasso的应用。
- oracle创建主键自增长
- Android反编译与回编译
- poj 2503 Babelfish
- 湖南省第六届省赛 Biggest Number (搜索)
- LeetCode—382. Linked List Random Node
- mysql导出数据库结构并清空数据库
- 1. Two Sum
- 在Asp.net上获取svn版本号 的实践