zoukankan      html  css  js  c++  java
  • Fragment的实际开发中总结(二)

    在实际项目的开发过程Fragment的情况越来越多。大家肯定须要遇到过Fragment被销毁重建的情况。

    结合自己在项目开发的一点总结和学习开源项目的代码。继续分享自己对Fragment的一点总结。


    1.Fragment保存销毁前状态究竟保存什么?

    我们知道Fragment的实例会在多种情况下被系统销毁回收掉。当我们的Fragment又一次回到屏幕前,我们想要的还是销毁前的状态。因此。我们在Fragment被销毁掉的时候,我们须要保存Fragment的状态。

    以下回到我们的问题,Fragment保存销毁前状态究竟保存什么?TextView的文字,还是WebView的载入内容?好像问题有点复杂。 Android的系统设计者已经为我们设计了一套保存机制,我们根本不用去考虑这些问题。 我们看看TextView的源代码的一段代码:

    @Override
        public Parcelable onSaveInstanceState() {
            Parcelable superState = super.onSaveInstanceState();
    
        }
    
        @Override
        public void onRestoreInstanceState(Parcelable state) {
            if (!(state instanceof SavedState)) {
                super.onRestoreInstanceState(state);
                return;
            }
    
            SavedState ss = (SavedState) state;
            super.onRestoreInstanceState(ss.getSuperState());
        }

    看上面的代码相信从字面意思大家也能明确。上面的代码保存TextView的状态和控件恢复时候状态恢复。我们去查看ListView的源代码。我们基类AbsListView的源代码会也看到类似onSaveInstanceState、onRestoreInstanceState方法。对ListView控件,这里有一点须要我们注意,当ListView销毁恢复的时候。我们不能恢复ListView到绑定数据的状态。由于ListView的实现是基于适配器模式的设计实现,ListView 仅仅不关心数据负责展示数据。不关心数据源。

    如今我们知道Fragment状态的恢复。由于谷歌的攻城狮的强大机制的设计,我们不用去考虑控件本身状态的恢复(ListView等控件数据的恢复以下会说道)。那哪些是我们要考虑的呢?能够总结下例如以下:

    • 我们要考虑第三方控件的实现。在恢复控件状态的时候是否考虑全面;
    • 对 Fragment的成员变量的状态保存(ScrollView当前滑动到的位置、用户操作标记的图片等)。

    第一种情况不是我们这次讨论的重点,我们主要来讨论另外一种情况的状态保存。结合自己的项目里的经验,我们有两种保存方式:

    第一种实现方式:

    我们来结合对ListView的数据状态恢复来说明对Fragment的状态恢复的标准实现。

    public class XXXFragment extends Fragment {
    
        private static final String VIEW_POSITION = "view_postion";
        private ListView listView;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = (ViewGroup) inflater.inflate(
                    R.layout.order_list_fragment, container, false);
            initView(rootView, inflater);
            if (savedInstanceState != null) { // biaoshi
                mCurrentPage = savedInstanceState.getInt(VIEW_POSITION);
                // 再次又一次请求数据(从缓存)。listView绑定数据,又一次设置上次浏览的位置mCurrentPage
            } else {
                // 首次请求数据,listView绑定数据
            }
            return rootView;
        }
    
        /*
         * 保存当前Frament状态
         */
        @Override
        public void onSaveInstanceState(Bundle outState) {
            outState.putInt(VIEW_POSITION, mCurrentPage);
            super.onSaveInstanceState(outState);
        }
    }

    第一种实现方式:

    通过学习chrisbanes大神的photup项目,我们把Fragment的状态用Controller 类对象记录。该Controller在 Application的onCreate完毕初始化,我们能够理解Fragment的状态我们用全局变量在记录。由于photup项目对Fragment的状态信息的管理,我们能够不用操心Fragment被销毁时候状态保存,我们在每次调用Fragment的时候,我们又一次实例化一个新的Fragment再恢复销毁前的状态。详细项目实现我这里就不给出来了。參看chrisbanes的photup项目实现。

    针对chrisbanes的实现,我个人认为有些看法:

    1.我认为这样的实现方式(Fragment + Controller)的长处在于,方便同一个Activity下多个Fragment的沟通实现,作为一个小项目的实现还是非常灵活方便。

    假设开发一个业务繁杂的项目,这样的方式实现会造成过多全局Congtroller对象。

    2.我认为。这样Fragment + Controller的方式实现Service的时候能够借鉴,一般项目的Service都不会太多。并且(Service + Controller)的方式也方面Service和其它组件沟通。

    对Fragment销毁和重建的管理方式

    在学习wordpress-androi的源代码实现的时候,学习到wordpress通过ViewPager来实现对Activity下的Fragment的管理方式最大简化我们对Fragment销毁和重建的管理。

    (ps:Wordpress-Android源代码值得学习的地方远不止这一点,假设大家感兴趣,去看看wordpress-android的实现。一定会有不少收获)。

    对Fragment的管理一些注意的地方,在我前一篇博客 Fragment的实际开发的一些总结 里说道一些关于Fragment被系统销毁重建管理的一些问题。我们通过前面模仿模仿QQ首页的样例通过wordpress-android的方式来实现一次。

    我们先重写ViewPager一些方法:

    public class HViewPager extends ViewPager {
        private boolean mPagingEnabled = true;
    
        public HViewPager(Context context) {
            super(context);
        }
    
        public HViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (mPagingEnabled) {
                try {
                    return super.onInterceptTouchEvent(ev);
                } catch (IllegalArgumentException e) {
    
                }
            }
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (mPagingEnabled) {
                try {
                    return super.onTouchEvent(ev);
                } catch (IllegalArgumentException e) {
    
                }
            }
            return false;
        }
    
        /*
         * 设置是否关闭ViewPager的滑动效果(我们能够实现ViewPager的Fragment间切换如Activity切换的感觉)
         */
        public void setPagingEnabled(boolean pagingEnabled) {
            mPagingEnabled = pagingEnabled;
        }
    }

    然后我们用HViewPager相应的FragmentPagerAdapter子类SwitchPagerAdapter负责管理Fragment,简单实现例如以下:

    public class SwitchPagerAdapter extends FragmentPagerAdapter {
    
        private static final int NUM_TABS = 2;
        private static final int TAB_MESSAGE = 0;
        private static final int TAB_CALL = 1;
    
        public SwitchPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public int getCount() {
            return NUM_TABS;
        }
    
        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case TAB_MESSAGE:
                return new MessageFragment();
            case TAB_CALL:
                return new CallFragment();
            default:
                return null;
            }
        }
    }

    我们再来看首页的切换效果如今例如以下所看到的:

    public class SwitchActivity extends FragmentActivity {
    
        private Button btn_message, btn_call;
        private HViewPager viewpager;
    
        public static final int MESSAGE_FRAGMENT_TYPE = 1;
        public static final int CALL_FRAGMENT_TYPE = 2;
        public int currentFragmentType = -1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_switch);
    
            btn_message = (Button) findViewById(R.id.btn_message);
            btn_call = (Button) findViewById(R.id.btn_call);
            viewpager = (HViewPager) findViewById(R.id.viewpager);
            SwitchPagerAdapter adapter = new SwitchPagerAdapter(
                    getSupportFragmentManager());
            viewpager.setPagingEnabled(false);
            viewpager.setAdapter(adapter);
            btn_message.setOnClickListener(onClicker);
            btn_call.setOnClickListener(onClicker);
    
            if (savedInstanceState != null) {
                int index = savedInstanceState.getInt("currentFragmentType");
                if (index > 0)
                    switchPager(1);
                else
                    switchPager(0);
            } else {
                switchPager(0);
            }
    
        }
    
        private void switchPager(int index) {
            viewpager.setCurrentItem(index);
            currentFragmentType = index;
        }
    
        /*
         * 保存当前展示那个页面
         */
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt("lastFragmentTag", currentFragmentType);
        }
    
        private OnClickListener onClicker = new OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                case R.id.btn_message:
                    btn_message.setTextColor(Color.parseColor("#df3031"));
                    btn_call.setTextColor(Color.WHITE);
                    btn_message
                            .setBackgroundResource(R.drawable.baike_btn_pink_left_f_96);
                    btn_call.setBackgroundResource(R.drawable.baike_btn_trans_right_f_96);
                    switchPager(0);
    
                    break;
                case R.id.btn_call:
    
                    btn_message.setTextColor(Color.WHITE);
                    btn_call.setTextColor(Color.parseColor("#df3031"));
                    btn_message
                            .setBackgroundResource(R.drawable.baike_btn_trans_left_f_96);
                    btn_call.setBackgroundResource(R.drawable.baike_btn_pink_right_f_96);
                    switchPager(1);
    
                    break;
    
                }
            }
        };
    }
    

    以上是通过ViewPager来达到管理Fragment 销毁和重建的实现。在WordPress-android源代码实现里关于Fragment的管理原理上差点儿相同这样,当然WordPress-android的实如今代码编写上能够学习的地方远不止如此。除了代码编写上。WordPress-android界面效果利用Fragment达到了非常多非常不错的使用效果。以下贴出WordPress-Android的博客编辑器编辑界面仅仅用一个Activity+多个Fragment的实现效果。实现还是相当给力的。

    这里写图片描写叙述
    这里写图片描写叙述
    这里写图片描写叙述

    ps:第一次用 markdown编辑器。真心还有点不习惯,格式学习中。

    转载请注明出处:http://blog.csdn.net/johnnyz1234/

  • 相关阅读:
    Zk学习笔记——权限控制
    guava学习笔记
    Elasticsearch学习笔记——别名
    Kafka学习笔记——存储结构
    分布式协议——Paxos、Raft和ZAB
    图解 Java 中的数据结构及原理!
    牛逼哄哄的 Lambda 表达式,简洁优雅就是生产力!
    你必须了解Spring的生态
    盘点 35 个 Apache 顶级项目,我拜服了…
    前后端分离如何做权限控制设计?
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7040132.html
Copyright © 2011-2022 走看看