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

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


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

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

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

  1. @Override
  2. public Parcelable onSaveInstanceState() {
  3. Parcelable superState = super.onSaveInstanceState();
  4. }
  5. @Override
  6. public void onRestoreInstanceState(Parcelable state) {
  7. if (!(state instanceof SavedState)) {
  8. super.onRestoreInstanceState(state);
  9. return;
  10. }
  11. SavedState ss = (SavedState) state;
  12. super.onRestoreInstanceState(ss.getSuperState());
  13. }

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

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

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

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

第一种实现方式:

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

  1. public class XXXFragment extends Fragment {
  2. private static final String VIEW_POSITION = "view_postion";
  3. private ListView listView;
  4. @Override
  5. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  6. Bundle savedInstanceState) {
  7. View rootView = (ViewGroup) inflater.inflate(
  8. R.layout.order_list_fragment, container, false);
  9. initView(rootView, inflater);
  10. if (savedInstanceState != null) { // biaoshi
  11. mCurrentPage = savedInstanceState.getInt(VIEW_POSITION);
  12. // 再次又一次请求数据(从缓存)。listView绑定数据,又一次设置上次浏览的位置mCurrentPage
  13. } else {
  14. // 首次请求数据,listView绑定数据
  15. }
  16. return rootView;
  17. }
  18. /*
  19. * 保存当前Frament状态
  20. */
  21. @Override
  22. public void onSaveInstanceState(Bundle outState) {
  23. outState.putInt(VIEW_POSITION, mCurrentPage);
  24. super.onSaveInstanceState(outState);
  25. }
  26. }

第一种实现方式:

通过学习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一些方法:

  1. public class HViewPager extends ViewPager {
  2. private boolean mPagingEnabled = true;
  3. public HViewPager(Context context) {
  4. super(context);
  5. }
  6. public HViewPager(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. @Override
  10. public boolean onInterceptTouchEvent(MotionEvent ev) {
  11. if (mPagingEnabled) {
  12. try {
  13. return super.onInterceptTouchEvent(ev);
  14. } catch (IllegalArgumentException e) {
  15. }
  16. }
  17. return false;
  18. }
  19. @Override
  20. public boolean onTouchEvent(MotionEvent ev) {
  21. if (mPagingEnabled) {
  22. try {
  23. return super.onTouchEvent(ev);
  24. } catch (IllegalArgumentException e) {
  25. }
  26. }
  27. return false;
  28. }
  29. /*
  30. * 设置是否关闭ViewPager的滑动效果(我们能够实现ViewPager的Fragment间切换如Activity切换的感觉)
  31. */
  32. public void setPagingEnabled(boolean pagingEnabled) {
  33. mPagingEnabled = pagingEnabled;
  34. }
  35. }

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

  1. public class SwitchPagerAdapter extends FragmentPagerAdapter {
  2. private static final int NUM_TABS = 2;
  3. private static final int TAB_MESSAGE = 0;
  4. private static final int TAB_CALL = 1;
  5. public SwitchPagerAdapter(FragmentManager fm) {
  6. super(fm);
  7. }
  8. @Override
  9. public int getCount() {
  10. return NUM_TABS;
  11. }
  12. @Override
  13. public Fragment getItem(int position) {
  14. switch (position) {
  15. case TAB_MESSAGE:
  16. return new MessageFragment();
  17. case TAB_CALL:
  18. return new CallFragment();
  19. default:
  20. return null;
  21. }
  22. }
  23. }

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

  1. public class SwitchActivity extends FragmentActivity {
  2. private Button btn_message, btn_call;
  3. private HViewPager viewpager;
  4. public static final int MESSAGE_FRAGMENT_TYPE = 1;
  5. public static final int CALL_FRAGMENT_TYPE = 2;
  6. public int currentFragmentType = -1;
  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  11. setContentView(R.layout.activity_switch);
  12. btn_message = (Button) findViewById(R.id.btn_message);
  13. btn_call = (Button) findViewById(R.id.btn_call);
  14. viewpager = (HViewPager) findViewById(R.id.viewpager);
  15. SwitchPagerAdapter adapter = new SwitchPagerAdapter(
  16. getSupportFragmentManager());
  17. viewpager.setPagingEnabled(false);
  18. viewpager.setAdapter(adapter);
  19. btn_message.setOnClickListener(onClicker);
  20. btn_call.setOnClickListener(onClicker);
  21. if (savedInstanceState != null) {
  22. int index = savedInstanceState.getInt("currentFragmentType");
  23. if (index > 0)
  24. switchPager(1);
  25. else
  26. switchPager(0);
  27. } else {
  28. switchPager(0);
  29. }
  30. }
  31. private void switchPager(int index) {
  32. viewpager.setCurrentItem(index);
  33. currentFragmentType = index;
  34. }
  35. /*
  36. * 保存当前展示那个页面
  37. */
  38. @Override
  39. protected void onSaveInstanceState(Bundle outState) {
  40. super.onSaveInstanceState(outState);
  41. outState.putInt("lastFragmentTag", currentFragmentType);
  42. }
  43. private OnClickListener onClicker = new OnClickListener() {
  44. @Override
  45. public void onClick(View v) {
  46. switch (v.getId()) {
  47. case R.id.btn_message:
  48. btn_message.setTextColor(Color.parseColor("#df3031"));
  49. btn_call.setTextColor(Color.WHITE);
  50. btn_message
  51. .setBackgroundResource(R.drawable.baike_btn_pink_left_f_96);
  52. btn_call.setBackgroundResource(R.drawable.baike_btn_trans_right_f_96);
  53. switchPager(0);
  54. break;
  55. case R.id.btn_call:
  56. btn_message.setTextColor(Color.WHITE);
  57. btn_call.setTextColor(Color.parseColor("#df3031"));
  58. btn_message
  59. .setBackgroundResource(R.drawable.baike_btn_trans_left_f_96);
  60. btn_call.setBackgroundResource(R.drawable.baike_btn_pink_right_f_96);
  61. switchPager(1);
  62. break;
  63. }
  64. }
  65. };
  66. }

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





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

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

Fragment的实际开发中总结(二)的更多相关文章

  1. 微信小程序开发中的二三事之网易云信IMSDK DEMO

    本文由作者邹永胜授权网易云社区发布. 简介 为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程.用产品的话说就是: 云信 IM 小程序 SDK 的能力 ...

  2. Java 数据类型在实际开发中应用二枚举

    在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的.在JDK1.5之前,人们用接口来描述这一种数据类型. 1. ...

  3. java和h5 canvas德州扑克开发中(二)

    德州扑克网页源码在github上分享 https://github.com/lxr1907/pokers 感兴趣的可以上去看下. 1.通讯使用websocket,主要在message.js中. 2.用 ...

  4. iOS开发-定制多样式二维码

    iOS开发-定制多样式二维码   二维码/条形码是按照某种特定的几何图形按一定规律在平台(一维/二维方向上)分布的黑白相间的图形纪录符号信息.使用若干个与二进制对应的几何形体来表示文字数值信息. 最常 ...

  5. android开发中fragment获取context

    在用到fragment时无法使用.this来指定当前context内容,android开发中fragment获取context,可以使用getActivity().getApplicationCont ...

  6. iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

                   在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...

  7. 二、Cocos2dx概念介绍(游戏开发中不同的坐标系,cocos2dx锚点)

    注:ccp是cocos2dx中的一个宏定义,#define ccp(__X__,__Y__)CCPointMake((float)__X__, (float)__Y__),在此文章中表示坐标信息 1. ...

  8. SQL开发中容易忽视的一些小地方(二)

    原文:SQL开发中容易忽视的一些小地方(二) 目的:继上一篇:SQL开发中容易忽视的一些小地方(一) 总结SQL中的null用法后,本文我将说说表联接查询. 为了说明问题,我创建了两个表,分别是学生信 ...

  9. 设计模式笔记之二:Android开发中的MVP架构(转)

    写在前面,本博客来源于公众号文章:http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=402435540&idx=1&sn ...

随机推荐

  1. 《Unix环境高级编程》读书笔记 第11章-线程

    1. 引言 了解如何使用多个控制线程在单进程环境中执行多个任务. 不管在什么情况下,只要单个资源需要在多个用户键共享,就必须处理一致性问题. 2. 线程概念 典型的Unix进程可以看成只有一个控制线程 ...

  2. n行m列矩阵顺时针填写1~n*m

    程序效果图如下: 程序参考代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ...

  3. c++类模板初探

    #include <iostream> #include <string> using namespace std; // 你提交的代码将嵌入到这里 ; template &l ...

  4. luogu P4137 Rmq Problem / mex(可持久化线段树)

    一开始想的是莫队,然后维护几个bitset,然后瞎搞.脑子里想了想实现,发现并不好写. 还是主席树好写.我们维护一个权值的线段树,记录每一个权值的最后一次出现的位置下标.我们查询的时候要在前\(r\) ...

  5. 【Computer Vision】图像单应性变换/投影/仿射/透视

    一.基础概念 1. projective transformation  = homography = collineation. 2. 齐次坐标:使用N+1维坐标来表示N维坐标,例如在2D笛卡尔坐标 ...

  6. [原创]Linux 下 redis 链接一次

    刚接触 Linux ,在 Linux 下安装 redis 链接redis 出现了以下问题  Could not connect to Redis at 127.0.0.1:6379: Connecti ...

  7. JMS消息

    1.消息可分为3部分:消息头.属性和有效负载 消息头:用于标识消息.声明消息属性及提供路由信息的特殊字段组成. 消息的属性区包含了和该消息有关的附加元数据,这个元数据由应用程序开发者进行设置,或者由J ...

  8. Lorenzini:Laplacian与图上的黎曼-罗赫定理

    前两天去听了一下搞代数几何的Dino Lorenzini在交大的两场讲座(“On Laplacian Of Graphs and Generalization”,“Riemann-Roch Theor ...

  9. POJ 1161 Walls(最短路+枚举)

    POJ 1161 Walls(最短路+枚举) 题目背景 题目大意:题意是说有 n个小镇,他们两两之间可能存在一些墙(不是每两个都有),把整个二维平面分成多个区域,当然这些区域都是一些封闭的多边形(除了 ...

  10. 收集整理的openstack java封装 api的第三方实现的选择

    Apache jclouds 地址:http://jclouds.apache.org/guides/openstack/ 一个开源库,java实现,支持cloudstack,openstack以及各 ...