10月 272016
 

  我们知道,当app的屏幕进行旋转或者其他的配置变化的时候,Fragment会执行它的周期变化,重新创建Fragment并加载(除非设置了setRetainInstance(true)),那么在重建的时候Fragment中的变量就会被重新初始化,运行中的状态将无法保留。

  setArgument中的Bundle可以用来存放各种需要保持的数据,即使Fragment由于配置改变而重建,这些保存的数据也不会被清除。

  下面我们将通过一个实例来测试一下,在实例的Fragment中共有3个TextView和一个Button,为了使测试的内容更清晰,下面把三个TextView对应的字符串列表如下:

textview1->banana,   textview2->apple,   textview3->pear

  对应的三个字符串:

  • mParam1: 在Fragment.newInstance中传入,并保存在setArgument中,但是在点击按钮时未更新到Argument中
  • mParam2: Fragment中的私有变量,和Argument无任何交互
  • mParam3: 在Fragment.newInstance中传入,并保存在setArgument中,并且在点击按钮时更新到了Argument中

  测试程序的布局代码和java代码如下:

  Fragment部局文件的代码

  Fragment的Java代码

  主Activity的代码

  主Activity的布局文件代码

  程序启动时显示默认如下内容:

  textview1和textview3的值取自getArgument并显示在了屏幕上,当点击按钮时会重新给三个String变量赋值,并显示到textview中,如下图:

  这时三个字符串变量都有了新的值,那么当我们把屏幕进行一下旋转操作后,看结果如何呢?

  由图可知,字符串1回到了最初的状态(创建Fragment时传入的值),而字符串2被清除了。

  字符串3因为在点击按钮的时候重新被保存在getArgument中,而没有任何的变化的被保留下来了。

  因此大家在给Fragment传入参数的时候最好通过setArgument进行保存,而不是简单的通过一个变量进行保存。

注意:

  1. setArgument只能在Fragment中创建后(MyFragment fragment = new MyFragment())立即调用,如果在Fragment被附加到Activity中后再调用就会报错,可以在按钮的点击事件中添加一下setArgument的调用进行一下试验,应用将被异常终止。
11月 142014
 

  做了一个小的app,其中用到了tab形式的actionBar和多个fragment,后来因为需求需要在某两个fragment中加入context menu,加入后添加onContextItemSelected事件响应菜单按下的效果,一开始运行正常,在两个fragment中打开context menu正常,两个fragment中的菜单响应事件也正常,后来改动了一些代码后突然发现菜单响应的不正确了,只有一个fragment中的菜单有响应,另外一个没响应。经过一番修改后,发现是onContextItemSelected的返回值影响到了菜单点击事件的执行。

  我们先来看一下onContextItemSelected的官方描述:

  我们主要看这个返回值部分,返回为了一布尔型变量,当返回false值时由系统去决定此菜单事件的响应流程,返回true则表示菜单响应到此为止,停止后面的流程。

  本人没做深入研究,猜想大概流程是这样的,因为在fragment中调用context menu中通过如下方式

  是通过父activity来填充这个弹出菜单,所以首先是父activity先接收到onContextItemSelected事件,如果父activity中不做处理,则activity会把这个事件分发到各个fragment中去,本人在此次犯的错误就是在子fragment中的onContextItemSelected事件中返回了true值,所以只在一个fragment中响应了事件,另外一个没有响应。

  既然在所有的fragment中都会响应onContextItemSelected这个事件,那么我们在每个fragment中处理该事件的时候就需要做一些判断,以避免多个fragment同时执行这个事件,这个是非常重要的,因为不做判断很可能出现一些莫名奇妙的而且不好测试的问题。如下例子: