在项目中需要进行Fragment的切换,一直都是用replace()方法来替换Fragment
但是,这样会有一个问题 ,应该很多朋友都遇到过:
每次切换的时候,Fragment都会重新实例化,也就是运行OnCreatVIew()方法
那么如何让多个Fragment彼此切换时不重新实例化?
正确的切换方式是add(),切换时hide(),add()另一个Fragment,再次切换时,只需hide()当前,show()另一个。
//之前显示的fragment
private Fragment mContent;
/** 修改显示的内容 不会重新加载 **/
public void switchContent(Fragment to) {
if (mContent != to) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
if (!to.isAdded()) { // 先判断是否被add过
transaction.hide(mContent).add(R.id.content, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
} else {
transaction.hide(mContent).show(to).commit(); // 隐藏当前的fragment,显示下一个
}
mContent = to;
}
showContent();
}
-
Android之Fragment的切换不对Fragment进行重新加载
2016-09-01 16:25:36开发的时候,有时候Fragment的切换,是不需要对原先的Fragment进行重新加载的...如果,不对fragment的数据进行重新加载的话,那么就用add来添加fragment,显示的时候用show,切换的时候用hide掉当前的,show切换的目标开发的时候,有时候Fragment的切换,是不需要对原先的Fragment进行重新加载的。而Fragment的界面是既可以进行重新加载,也可以不进行重新加载。
每次重新加载的话,我们是使用的replace来进行fragment的替换的。
如果,不对fragment的数据进行重新加载的话,那么就用add来添加fragment,显示的时候用show,切换的时候用hide掉当前的,show切换的目标。
具体的实现代码如下:
private FragmentManager fm; private FragmentTransaction ft;
//之前显示的fragment public Fragment mContent, fragment_in, fragment_qm, fragment_se;
//三个fragment fragment_in = new MakePlanFragment(); fragment_qm = new CourseFragment(); fragment_se = new MakePlanFragment(); setDefaultFragment(fragment_in);
设置默认的fragment的显示。没有切换的时候显示的fragment。public void setDefaultFragment(Fragment fragment) { fm = getFragmentManager(); ft = fm.beginTransaction(); ft.add(R.id.fragment_content, fragment).commit(); mContent = fragment; }
//切换fragment的显示隐藏 public void switchContent(Fragment to) { if (mContent != to) { fm = getFragmentManager(); ft = fm.beginTransaction(); if (!to.isAdded()) { // 先判断是否被add过 ft.hide(mContent).add(R.id.fragment_content, to).commit(); // 隐藏当前的fragment,add下一个到Activity中 } else { ft.hide(mContent).show(to).commit(); // 隐藏当前的fragment,显示下一个 } mContent = to; } }
上面的这个switchContent的方法就是切换fragment的方法封装。在使用的地方,直接传入我们需要的目标fragment即可。如下:switchContent(fragment_in);
传参为我们要切换的目标fragment。这样就实现了我们的切换fragment,但是不重新进行加载。如果要进行重新加载,关键代码如下:
fm = getFragmentManager(); ft = fm.beginTransaction(); ft.replace(R.id.fragment_content, fragment_in); ft.commit();
这就是重载与不重新加载的区别。理解了本质就简单多了。 -
Android 关于fragment切换重新加载的解决方法
2015-12-31 16:04:40在项目中需要进行Fragment的切换,一直都是用replace()...那么如何让多个Fragment彼此切换时不重新实例化? 正确的切换方式是add(),切换时hide(),add()另一个Fragment,再次切换时,只需hide()当前,show()另一个。 -
Android _关于fragment切换重新加载的解决分享给大家
2014-11-20 11:22:00一直都是用replace()方法来替换Fragment但是,这样会有一个问题 ,应该很多朋友都遇到过:每次切换的时候,Fragment都会重新实例化,也就是运行OnCreatVIew()方法那么如何让多个Fragment彼此切换时不重新实例化?...转载于:https://www.cnblogs.com/changkai244/p/4110164.html
-
怎样重新加载当前的Fragment页面
2015-11-08 15:52:12Viewpager+Fragment中的子页面,,我想重新刷新当前页面的数据,,,有什么方法可以刷新,,,页面里有个刷新方法,需要执行getActivity(),,但是如果Fragment不重新执行的滑,,getActivity()就报空指针~~!! 是不是要重新执行... -
android viewpager使用Fragment懒加载,滑到当前fragment才进行数据加载
2017-06-26 14:23:35前言:如果不做fragment的懒加载则每次进入activity就会初始化没必要的数据,消耗内存和网络流量,再每次自动销毁后也需要重新初始化fragment的数据,为此优化,我们要做fragment的懒加载,网络上关于懒加载的文章...前言:如果不做fragment的懒加载则每次进入activity就会初始化没必要的数据,消耗内存和网络流量,再每次自动销毁后也需要重新初始化fragment的数据,为此优化,我们要做fragment的懒加载,网络上关于懒加载的文章数不胜数,可是详细、全面,又有实际源码和例子的很少,下面是我摘抄的技术代码,原文地址见文章下面.
PagerFragment里面适配的fragment只需要继承自LazyFragment处理懒加载关系,而LazyFragment继承自BaseFragment,BaseFragment处理fragment初始化控件和fragment销毁时和activity分离的事情
下面献上LazyFragment的源码:public class LazyFragment extends BaseFragment { private boolean isInit=false;//真正要显示的view是否已经被初始化(正常加载) private Bundle savedInstancseState; public static final String INTENT_BOOLEAN_LAZYLOAD="intent_boolean_lazyLoad"; private boolean isLazyLoad=true;//默认状态需要懒加载 private FrameLayout layout; private boolean isStart=false;// 是否处于可见状态,in the screen @override protected final void onCreateView(Bundle savedInstancseState) { super.onCreateView(savedInstancseState); Bundle bundle=getArguments(); if(bundle!=null) { isLazyLoad=bundle.getBoolean(INTENT_BOOLEAN_LAZYLOAD,isLazyLoad); } //判断是否懒加载 if(isLazyLoad) { //一旦isVisibleToUser==true即可对真正需要的显示内容进行加载 if(getUserVisibleHint()&&!isInint) { this.savedInstancseState=savedInstancseState; onCreateViewLazy(savedInstancseState); isInint=true; }else{ //进行懒加载 layout=new FrameLayout(getApplicationContext); layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); View view=LayoutInflater.from(getApplicationContext()).inflate(R.layout.fragment_lazy_loading,null); layout.addView(view); super.setContentView(layout); } }else { //不需要懒加载,开门见山,调用onCreateViewLazy正常加载显示内容即可 onCreateViewLazy(savedInstancseState); isInint=true; } } @override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); Log.d("TAG", "setUserVisibleHint() called with: " + "isVisibleToUser = [" + isVisibleToUser + "]"); //一旦isVisibleToUser==true即可进行对真正需要的显示内容的加载 //可见,但还没被初始化 if(isVisibleToUser&&!isInint&&getContentView()!=null) { onCreateViewLazy(savedInstancseState); isInint=true; onResumeLazy();//TODO } //已经被初始化(正常加载)过了 if(isInint&&getContentView!=null) { if(isVisibleToUser) { isStart=true; onFragmentStartLazy();//TODO }else{ isStart=false; onFragmentStopLazy(); } } @override public void setContentView(int layoutResID) { //判断若isLazyLoad=true,移除所有lazy view,加载真正要显示的view if(isLazyLoad&&getContentView()!=null&&getContentView().getParent()!=null) { layout.removeAllViews(); View view=inflater.inflate(layoutResID,layout,false); layout.addView(view); }else { super.setContentView(layoutResID); } } @override public void setContentView(View view) { //判断若isLazyLoad=true,移除所有lazy view,加载真正要显示的view if(isLazyLoad&&getContentView()!=null&&getContentView().getParent!=null) { layout.removeAllViews(); layout.addView(view); }else { //否则开门见山,直接加载 super.setContentView(view); } } @override public final void onStart() { Log.d("TAG", "onStart() : " + "getUserVisibleHint():" + getUserVisibleHint()); super.onStart(); if(isInit&&!isStart&&getUserVisibleHint()) { isStart=true; onFragmentStartLazy(); } } //当Fragment被滑到可见的位置时,调用 protected void onFragmentStartLazy() { Log.d("TAG", "onFragmentStartLazy() called with: " + ""); } @override public final void onStop() { super.onStop(); if(isInit&&isStart&&getUserVisibleHint()) { isStart=false; onFragmentStopLazy(); } } @Override @Deprecated public final void onResume() { Log.d("TAG", "onResume() : " + "getUserVisibleHint():" + getUserVisibleHint()); super.onResume(); if (isInit) { onResumeLazy(); } } @Override @Deprecated public final void onResume() { Log.d("TAG", "onResume() : " + "getUserVisibleHint():" + getUserVisibleHint()); super.onResume(); if (isInit) { onResumeLazy(); } } @Override @Deprecated public final void onPause() { Log.d("TAG", "onPause() : " + "getUserVisibleHint():" + getUserVisibleHint()); super.onPause(); if (isInit) { onPauseLazy(); } } @Override @Deprecated public final void onDestroyView() { Log.d("TAG", "onDestroyView() : " + "getUserVisibleHint():" + getUserVisibleHint()); super.onDestroyView(); if (isInit) { onDestroyViewLazy(); } isInit = false; } //当Fragment被滑到不可见的位置,offScreen时,调用 protected void onFragmentStopLazy() { Log.d("TAG", "onFragmentStopLazy() called with: " + ""); } protected void onCreateViewLazy(Bundle savedInstanceState) { Log.d("TAG", "onCreateViewLazy() called with: " + "savedInstanceState = [" + savedInstanceState + "]"); } protected void onResumeLazy() { Log.d("TAG", "onResumeLazy() called with: " + ""); } protected void onPauseLazy() { Log.d("TAG", "onPauseLazy() called with: " + ""); } protected void onDestroyViewLazy() { } }
Basefragment的源码如下:
public class BaseFragment extends Fragment { protected LayoutInflater inflater; private View contentView; private Context context; private ViewGroup container; @override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); context=getActivity().getApplicationContext(); } //子类通过重写onCreateView,调用setContentView进行布局设置,否者contentView==null,返回Null @override public final View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) { this.inflater=inflater; this.container=container; onCreateView(savedInstanceState); if(contentView==null) return super.onCreateView(inflater,container,savedInstanceState); return contentView; } protected void onCreateView(Bundle savedInstanceState) { } @override public void onDestroyView() { super.onDestroyView(); contentView=null; container=null; inflater=null; } public Context getApplicationContex() { return context; } public void setContentView(int layoutResID) { setContetnView((ViewGroup)inflater.inflate(layoutResID,container,false)); } public void setContentView(View view) { contentView=view; } public void getContentView() { return contentView; } public View findViewById(int id) { if(contentView!=null) { return contentView.findViewById(id); } return null; } // http://stackoverflow.com/questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed @Override public void onDetach() { Log.d("TAG", "onDetach() : "); super.onDetach(); try { Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); childFragmentManager.setAccessible(true); childFragmentManager.set(this, null); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } @Override public void onDestroy() { Log.d("TAG", "onDestroy() : "); super.onDestroy(); } }
亲测有效
备注:转载地址 (http://www.jianshu.com/p/8a772b9df6d5) -
关于ViewPager清除已加载Fragment,重新创建新的Fragment的方法
2019-08-16 09:14:58但是遇到一个问题:在不退出当前Activity的情况下,重新加载Fragment,却得到了空白界面,并没有生成新的Fragment添加进去。 这个问题可能是由于旧的Fragment没有被清除导致的。 查看了 FragmentPagerAdapter 类的...最近在项目中使用ViewPager+Fragment实现左右两个滑动切换界面。但是遇到一个问题:在不退出当前Activity的情况下,重新加载Fragment,却得到了空白界面,并没有生成新的Fragment添加进去。
这个问题可能是由于旧的Fragment没有被清除导致的。
查看了 FragmentPagerAdapter 类的创建实例的函数 instantiateItem :
@NonNull public Object instantiateItem(@NonNull ViewGroup container, int position) { if (this.mCurTransaction == null) { this.mCurTransaction = this.mFragmentManager.beginTransaction(); } long itemId = this.getItemId(position); String name = makeFragmentName(container.getId(), itemId); Fragment fragment = this.mFragmentManager.findFragmentByTag(name); if (fragment != null) { this.mCurTransaction.attach(fragment); } else { fragment = this.getItem(position); this.mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); } if (fragment != this.mCurrentPrimaryItem) { fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); } return fragment; }
我们看到这个函数会先检查是否已经存在了这样一个Fragment,如果不存在才会去调用 getItem 方法产生一个新的Fragment。所以我们可以利用类似的方法先去FragmentManager中清除对应的Fragment,然后再让适配器重新加载新Fragment。如下我们重写 FragmentPagerAdapter 类:
public class ViewMaterialFragmentPagerAdapter extends FragmentPagerAdapter { private FragmentManager mFragmentManager; private FragmentTransaction mCurTransaction; private Context mContext; private List<Fragment> mFragmentArrayList; private int[] pagerTitles = new int[]{R.string.text_material_qr_code, R.string.text_material_list}; public ViewMaterialFragmentPagerAdapter(FragmentManager fm, Context ctx, List<Fragment> fragments) { super(fm); mFragmentManager = fm; mContext = ctx; mFragmentArrayList = fragments; } @Override public Fragment getItem(int i) { return mFragmentArrayList.get(i); } @Override public int getCount() { return mFragmentArrayList.size(); } @Override public CharSequence getPageTitle(int position) { return mContext.getString(pagerTitles[position]); } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { return super.instantiateItem(container, position); } /** * 清除缓存fragment * @param container ViewPager */ public void clear(ViewGroup container){ if (this.mCurTransaction == null) { this.mCurTransaction = this.mFragmentManager.beginTransaction(); } for(int i=0;i<mFragmentArrayList.size();i++){ long itemId = this.getItemId(i); String name = makeFragmentName(container.getId(), itemId); Fragment fragment = this.mFragmentManager.findFragmentByTag(name); if(fragment != null){//根据对应的ID,找到fragment,删除 mCurTransaction.remove(fragment); } } mCurTransaction.commitNowAllowingStateLoss(); } /** * 等同于FragmentPagerAdapter的makeFragmentName方法, * 由于父类的该方法是私有的,所以在此重新定义 * @param viewId * @param id * @return */ private static String makeFragmentName(int viewId, long id) { return "android:switcher:" + viewId + ":" + id; } }
代码重点是 clear 方法,只要在需要销毁已经加载过得Fragment的地方,调用这个clear方法,再让ViewPager重新设置适配器即可。
pagerAdapter.clear(mViewPager); mViewPager.setAdapter(pagerAdapter);
clear 方法中的 makeFragmentName 方法,可以在 FragmentPagerAdapter 类源码中找到,此处的makeFragmentName与源码中一模一样,只是由于这个方法在源码中私有的,我就暂且复制过来使用吧,当然也可以使用反射调用。
############ 好了,调大音量,听首歌吧 ~ ###############
-
viewPager 页面切换时 fragment重新加载问题
2014-01-09 16:38:07当viewpager切换页面时,当页面比较多时,当前显示页面不相邻的fragment会被viewpager destory掉,重新显示时会再次调用oncreateview, 解决方法是调用viewpager.setOffscreenPageLimit(int a)设置当前显示页面相邻... -
使用viewpager+fragment,在activity启动模式为singleTask,跳转到当前页面重新加载数据fragment数据不更新
2016-12-30 13:42:03A启动模式为singleTask,目前显示当前页面,我在fragment里面获取数据: dataMap = Converter.string2Map(getArguments().getString("dataMap")); courseMap = Converter.string2Map(getArguments().... -
ViewPager中有超过两个Fragment后,切换时Fragment会重走onCreateView导致页面重新加载
2019-05-24 11:09:22当ViewPager中添加三个以上的Fragment相互切换时,不是相邻的Fragment会重走onCreateView,这样页面会重新加载。 ViewPager默认是会保留当前页的前一页和后一页,也就是到了第三页的时候,第一页已经被销毁了,回到... -
在ViewPager中切换Fragment 不重新创建 - Android
2016-04-25 13:40:00在使用Viewpager滑动Fragment时,ViewPager只会保存当前页两边的Fragment状态.这样就会出现这样的情况: 一打开会初始化page1和page2,当手动切换到page3时page4就会初始化,但是page1就会销毁,当再切换到page1时page1就... -
viewpager中多fragment及时加载
2016-02-25 15:50:29Viewpager是我们经常使用的一个控件,它的...是在此频道为当前页的时候才进行加载,而不是一开始就加载的(这里说明一点,就是viewpager有预加载的功能),同时,当我们切换回来的时候,此页面并没有重新加载,数据还是 -
怎么让Fragment 切换时不重新执行生命周期的方法
2016-02-18 09:24:46> fragment是我们经常使用到的一个控件,但是,相信大家会出现这样的一个问题,每次切换fragment的时候,fragment就会重新调用一次生命周期的方法,从而会重新加载一次数据,这样既消耗用户的数据流量和机器性能;... -
关于Activity和Fragment的一些问题
2016-08-23 09:47:15概述Activity和Fragment是Android开发中经常需要用到的,但是在使用的过程中有些细节性的...重新加载一遍数据,非常消耗性能和用户的数据流量,如果不是项目需求的话,不建议采用这种方式。 public void switchFragmen -
Fragment与Activity区别,及生命周期
2020-08-14 19:09:36onRestart():表示Activity正在重新启动,一般情况下,当前Acitivty从不可见重新变为可见时,OnRestart就会被调用; onStart():表示Activity正在被启动,此时Activity可见但不在前台,还处于后台,无法与用户交互... -
FragmentStatePagerAdapter的使用
2015-03-18 22:48:00会根据数据源的变动更新,不过是全部重新加载,和ListView不一样 为了从外界(Activity)操作当前的fragment界面,使用了SparseArray<WeakReference<Fragment>>将当前的fragment实例存起来。 public ... -
刚开始学android看第一行代码照敲酷欧天气报错打不开活动有大佬拉一把不?
2020-12-16 23:56:14//记住你划到的位置,重新加载数据的时候不会改变位置,只是改变了数据; listView.setSelection(0); //将第一个数据项设置在最上面 currentLevel =LEVEL_PROVINCE; //将当前级别设置为省级 } //如果数据库没有... -
工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究
2017-02-28 21:22:19尽我所知,除了文中特别加以标注和致谢的地方外,论文中不包含其他人已经发表或撰写过的研究成果,也不包含为获得东南大学或其它教育机构的学位或证书而使用过的材料。与我一同工作的同志对本研究所做的任何贡献均已... -
多fragment单activity拦截器不管用,难道只能用于拦截activity的跳转?那如果是要实现登录拦截的话,那不是只能在PathReplaceService中进行了? 网络解决办法 第一个疑问:由于我使用阿里路由,所以我看到zhi1ong...
-
35、Fragment相关 36、Gson转换相关 37、16进制转换相关 38、图片加载器 39、意图相关工具类 40、JSON操作相关 41、软键盘相关 42、打印日志 43、循环定时器 44、阴历阳历相关 45、m3u8文件解析类 46、偶对象相关 47...
-
普通界面只需要编写Fragment,然后使用ContainerActivity盛装(代理),这样就不需要每个界面都在AndroidManifest中注册一遍。 全局操作 全局的Activity堆栈式管理,在程序任何地方可以打开、结束指定的Activity,...
-
banner本身不提供图片加载功能,首先确认banner本身使用是否正确,具体参考demo, 然后请检查你的图片加载框架或者网络请求框架,服务端也可能加了https安全认证,是看下是否报有证书相关错误 怎么实现视频轮播? ...
-
Android项目源码开源的 Material Design 豆瓣客户端.zip
2019-07-10 18:16:58Android 默认在冷启动应用进程至能够调用 Activity.onCreate() 前会加载应用主题中的背景作为预览,而默认背景是白色,与应用在上部拥有绿色 AppBar 的效果不相匹配。 为了生成适应于不同屏幕大小、系统版本的图片... -
精通Android 3--详细书签版
2013-02-08 11:19:588.2.2 将非托管对话框重新转换为托管对话框 201 8.2.3 简化托管对话框协议 202 8.3 使用Toast 209 8.4 资源 210 8.5 小结 210 第9章 管理和组织首选项 211 9.1 探索首选项框架 211 9.1.1 ...
-
JOKER.ONE的代码审计怎么样?joker.one说多签是什么?joker.one去中心化程度怎么样?
-
监听器接口
-
Windows系统管理
-
阿罗拉罗希特-源码
-
浅析JavaScript的事件代理和委托
-
Wave breaking in tapered holey fibers
-
MHA 高可用 MySQL 架构与 Altas 读写分离
-
【Python-随到随学】FLask第二周
-
Buffer count exceeding default GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS. Shader might not work on all h
-
一种基于MOOC的中文映射知识域的构建方法
-
基于抖动调制的自适应隐写技术,可抵抗jpeg压缩和统计检测
-
Django后端处理post请求的request.body中数据
-
Samba 服务配置与管理
-
Nondestructive identification of ancient Chinese glasses by Raman and proton-induced X-ray emission spectroscopy
-
弄皱的球-源码
-
【数据结构】链表:LeetCode题(四)234.回文链表
-
进阶JavaScript之玩转递归与数列
-
Mycat 实现 MySQL的分库分表、读写分离、主从切换
-
强化学习的学习之路(三十一)_2021-01-31: REINFORCE
-
D2D网络中基于社交意识的团购:一种博弈论方法