zoukankan      html  css  js  c++  java
  • Android开发之多Fragment切换优化

    问题分析


    一直在简书里看别人的技术贴,今天我也来写点自己的心得!最近在写一个项目用到大量的Fragment后的总结!

    我想刚刚接触安卓的同学或许会这么写:

    FragmentManager     fragmentManager=getSupportFragmentManager();
    FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
    fragmentTransaction.add(ViewId,fragment);// 或者fragmentTransaction.replace(ViewId,fragment);
    fragmentTransaction.commit();

    基础更好一点的同学会用show和hide方法

      FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.hide(new FirstFragment())
            .show(new SecondFragment())
            .commit();

    诚然这两种都可以切换Fragment,但是面对用户大量点击来回切换,或者你的Fragment本来就很多,每次都这样操作,那么很快你的应用就会OOM,就算不崩那也会异常的卡顿!so why?

    当我们replace时发生了以下的生命周期:

     
     

    想想看每次都replace一下!!这世界会有多美好!!!那么问题出在哪?回过头看看代码就会发现每次在add/replace或者show/hide都会new 一个新的实例,这就是致命原因!!!!!

    废话少说,开始优化


    方案一:

    预加载模式:

    //首先需要先实例好三个全局Fragment

    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.add(R.id.fragment, FirstFragment.getInstance());
    ft.add(R.id.fragment, SecondFragment.getInstance());
    ft.add(R.id.fragment, ThirdFragment.getInstance());
    ft.hide(SecondFragment.getInstance());
    ft.hide(ThirdFragment.getInstance());
    ft.commit();

    在加载第一个Fragment时就把全部Fragment加载好,下次使用直接调用如:

    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.hide(FirstFragment.getInstance())
           .show(SecondFragment.getInstance())
           .commit();

    是不是总觉怪怪的,虽然比之前的代码好,但是这种做法很Java,当然需要预加载的朋友依然是不二之选!!!

    那有没有更好的方法呢?答案是肯定的

    方案二:

    动态加载模式:

    //首先需要先实例好n个全局Fragment
    
    //private  Fragment  currentFragment=new Fragment();(全局)
    
    private  FragmentTransaction switchFragment(Fragment targetFragment) {
    
       FragmentTransaction transaction = getSupportFragmentManager()
               .beginTransaction();
       if (!targetFragment.isAdded()) {
           //第一次使用switchFragment()时currentFragment为null,所以要判断一下
           if (currentFragment != null) {
               transaction.hide(currentFragment);
               }
           transaction.add(R.id.fragment, targetFragment,targetFragment.getClass().getName());
    
           } else {
               transaction
                       .hide(currentFragment)
                       .show(targetFragment);
    
    
           }
           currentFragment = targetFragment;
          return   transaction;
       }
    
    在点击切换Fragment时:
    
    @Override
    public void onTabSelected(@IdRes int tabId) {
    
            if (tabId == R.id.tab_one){
    
                switchFragment(first).commit();
    
            }
            if (tabId == R.id.tab_two){
                switchFragment(second).commit();
            }
            if (tabId == R.id.tab_three){
                switchFragment(third).commit();
            }
        }

    现在你的Fragment无论怎么切都不会出现卡顿了,因为你的所有Fragment只会被实例化一次!实例一次的Fragment会被存入内存中,下次切换会判断内存中是否含有要切换的Fragment,如果有就直接复用,没有就add一个新的!优化大法完成!

    外番


    WHAT?等等!只实例一次,那我的Fragment里的数据要更新怎么办?我的回答是——软件关了再次重启!

     
     

    要是这样,这样的软件真的要逆天了!好在官方提供了onHiddenChanged方法,每次切换hide或者show时该方法会被执行,可以在这里面更新数据!

    //此方法在Fragment中

    @Override
    public void onHiddenChanged(boolean hidden) {
       super.onHiddenChanged(hidden);
       if (hidden){
          //Fragment隐藏时调用
       }else {
           //Fragment显示时调用
       }

    }

    此方法是不是比每次add或replace更新数据执行一大坨的生命周期要优雅的多的多!

    GitHub地址:FragmentDemo (欢迎 fork 和 star)

    注:提醒小白(老手请忽略)

    此demo只供fragment理解,此样例app的业务逻辑建议ViewPager+Fragment或者其他。。。



    作者:8金木研8
    链接:https://www.jianshu.com/p/4c5f015b3b6c
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 相关阅读:
    STM32 F4 DAC DMA Waveform Generator
    STM32 F4 General-purpose Timers for Periodic Interrupts
    Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
    Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块
    查看SQL Server服务运行帐户和SQL Server的所有注册表项
    Pycharm使用技巧(转载)
    SQL Server 2014内存优化表的使用场景
    Python第十天 print >> f,和fd.write()的区别 stdout的buffer 标准输入 标准输出 从控制台重定向到文件 标准错误 重定向 输出流和输入流 捕获sys.exit()调用 optparse argparse
    Python第七天 函数 函数参数 函数里的变量 函数返回值 多类型传值 函数递归调用 匿名函数 内置函数
    Python第六天 类型转换
  • 原文地址:https://www.cnblogs.com/Im-Victor/p/9556257.html
Copyright © 2011-2022 走看看