码迷,mamicode.com
首页 > 其他好文 > 详细

Fragment的实际开发中总结(二)

时间:2015-07-26 19:17:34      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:fragment   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/

版权声明:本文为博主原创文章,未经博主允许不得转载。

Fragment的实际开发中总结(二)

标签:fragment   fragment管理   

原文地址:http://blog.csdn.net/johnnyz1234/article/details/47069913

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!