浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
来源:互联网 发布:网络教育介绍 编辑:程序博客网 时间:2024/06/07 06:51
转自:http://www.tuicool.com/articles/2eM32a
自从Android3.0引入了Fragment之后,使用Activity去嵌套一些Fragment的做法也变得更加流行,这确实是Fragment带来的一些优点,比如说:Fragment可以使你能够将activity分离成多个可重用的组件,每个都有它自己的生命周期和UI,更重要的是Fragment解决了Activity间的切换不流畅,实现了一种轻量及的切换,但是在官方提供的android.support.v4包中,Fragment还是或多或少的存在一些BUG,今天就与大家分享一下这些BUG和解决方法。
Case 1:当使用Fragment去嵌套另外一些子Fragment的时候,我们需要去管理子Fragment,这时候需要调用ChildFragmentManager去管理这些子Fragment,由此可能产生的Exception主要是:
java.lang.IllegalStateException: No activity
首先我们来分析一下Exception出现的原因:
通过DEBUG发现,当第一次从一个Activity启动Fragment,然后再去启动子Fragment的时候,存在指向Activity的变量,但当退出这些Fragment之后回到Activity,然后再进入Fragment的时候,这个变量变成null,这就很容易明了为什么抛出的异常是No activity
这个Exception是由什么原因造成的呢?如果想知道造成异常的原因,那就必须去看Fragment的相关代码,发现Fragment在detached之后都会被reset掉,但是它并没有对ChildFragmentManager做reset,所以会造成ChildFragmentManager的状态错误。
找到异常出现的原因后就可以很容易的去解决问题了,我们需要在Fragment被detached的时候去重置ChildFragmentManager,即:
<span class="nd">@Override</span><span class="indent"> </span><span class="kd"><span class="keyword" style="font-weight: bold;">public</span></span> <span class="kt"><span class="keyword" style="font-weight: bold;">void</span></span> <span class="nf">onDetach</span><span class="o">()</span> <span class="o">{</span><span class="indent"> </span><span class="indent"> </span><span class="kd"><span class="keyword" style="font-weight: bold;">super</span></span><span class="o">.</span><span class="na">onDetach</span><span class="o">();</span><span class="indent"> </span><span class="indent"> </span><span class="k"><span class="keyword" style="font-weight: bold;">try</span></span> <span class="o">{</span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="n">Field</span> <span class="n">childFragmentManager</span> <span class="o">=</span> <span class="n">Fragment</span><span class="o">.</span><span class="na"><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"><span class="keyword" style="color: rgb(51, 51, 51);">class</span></span></span><span class="class" style="color: rgb(68, 85, 136); font-weight: bold;"><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="o">.</span><span class="na"><span class="title">getDeclaredField</span></span><span class="o">(</span><span class="s">"<span class="title">mChildFragmentManager</span>"</span><span class="o">);</span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="n"><span class="title">childFragmentManager</span></span><span class="o">.</span><span class="na"><span class="title">setAccessible</span></span><span class="o">(</span><span class="kc"><span class="title">true</span></span><span class="o">);</span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="n"><span class="title">childFragmentManager</span></span><span class="o">.</span><span class="na"><span class="title">set</span></span><span class="o">(</span><span class="k"><span class="title">this</span></span><span class="o">,</span> <span class="kc"><span class="title">null</span></span><span class="o">);</span><span class="indent"> </span><span class="indent"> </span><span class="o">}</span> <span class="k"><span class="title">catch</span></span> <span class="o">(</span><span class="n"><span class="title">NoSuchFieldException</span></span> <span class="n"><span class="title">e</span></span><span class="o">)</span> <span class="o">{</span></span><span class="o"></span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="k"><span class="keyword" style="font-weight: bold;">throw</span></span> <span class="k"><span class="keyword" style="font-weight: bold;">new</span></span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span><span class="indent"> </span><span class="indent"> </span><span class="o">}</span> <span class="k"><span class="keyword" style="font-weight: bold;">catch</span></span> <span class="o">(</span><span class="n">IllegalAccessException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span><span class="indent"> </span><span class="indent"> </span><span class="indent"> </span><span class="k"><span class="keyword" style="font-weight: bold;">throw</span></span> <span class="k"><span class="keyword" style="font-weight: bold;">new</span></span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span><span class="indent"> </span><span class="indent"> </span><span class="o">}</span><span class="indent"> </span><span class="o">}</span>
Case 2:当我们从一个Activity启动了一个Fragment,然后在这个Fragment中又去实例化了一些子Fragment,在子Fragment中去有返回的启动了另外一个Activity,即通过startActivityForResult方式去启动,这时候造成的现象会是,子Fragment接收不到OnActivityResult,如果在子Fragment中是以getActivity.startActivityForResult方式启动,那么只有Activity会接收到OnActivityResult,如果是以getParentFragment.startActivityForResult方式启动,那么只有父Fragment能接收(此时Activity也能接收),但无论如何子Fragment接收不到OnActivityResult。
这是一个非常奇怪的现象,按理说,应该是让子Fragment接收到OnActivityResult才对,究竟是什么造成的呢?这是由于某位写代码的员工抱怨没发奖金,稍稍偷懒了,少写了一部分代码,没有考虑到Fragment再去嵌套Fragment的情况。
我们来看看FragmentActivity中的代码:
<span class="kd"><span class="keyword" style="font-weight: bold;">protected</span></span> <span class="kt"><span class="keyword" style="font-weight: bold;">void</span></span> <span class="nf">onActivityResult</span><span class="o">(</span><span class="kt"><span class="keyword" style="font-weight: bold;">int</span></span> <span class="n">requestCode</span><span class="o">,</span> <span class="kt"><span class="keyword" style="font-weight: bold;">int</span></span> <span class="n">resultCode</span><span class="o">,</span> <span class="n">Intent</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span> <span class="k"><span class="keyword" style="font-weight: bold;">this</span></span><span class="o">.</span><span class="na">mFragments</span><span class="o">.</span><span class="na">noteStateNotSaved</span><span class="o">();</span> <span class="kt"><span class="keyword" style="font-weight: bold;">int</span></span> <span class="n">index</span> <span class="o">=</span> <span class="n">requestCode</span> <span class="o">>></span> <span class="mi"><span class="number" style="color: rgb(0, 153, 153);">16</span></span><span class="o">;</span> <span class="k"><span class="keyword" style="font-weight: bold;">if</span></span> <span class="o">(</span><span class="n">index</span> <span class="o">!=</span> <span class="mi"><span class="number" style="color: rgb(0, 153, 153);">0</span></span><span class="o">)</span> <span class="o">{</span> <span class="n">index</span><span class="o">--;</span> <span class="k"><span class="keyword" style="font-weight: bold;">if</span></span> <span class="o">((</span><span class="k"><span class="keyword" style="font-weight: bold;">this</span></span><span class="o">.</span><span class="na">mFragments</span><span class="o">.</span><span class="na">mActive</span> <span class="o">==</span> <span class="kc"><span class="keyword" style="font-weight: bold;">null</span></span><span class="o">)</span> <span class="o">||</span> <span class="o">(</span><span class="n">index</span> <span class="o"><</span> <span class="mi"><span class="number" style="color: rgb(0, 153, 153);">0</span></span><span class="o">)</span> <span class="o">||</span> <span class="o">(</span><span class="n">index</span> <span class="o">>=</span> <span class="k"><span class="keyword" style="font-weight: bold;">this</span></span><span class="o">.</span><span class="na">mFragments</span><span class="o">.</span><span class="na">mActive</span><span class="o">.</span><span class="na">size</span><span class="o">()))</span> <span class="o">{</span> <span class="n">Log</span><span class="o">.</span><span class="na">w</span><span class="o">(</span><span class="s"><span class="string" style="color: rgb(221, 17, 68);">"FragmentActivity"</span></span><span class="o">,</span> <span class="s"><span class="string" style="color: rgb(221, 17, 68);">"Activity result fragment index out of range: 0x"</span></span> <span class="o">+</span> <span class="n">Integer</span><span class="o">.</span><span class="na">toHexString</span><span class="o">(</span><span class="n">requestCode</span><span class="o">));</span> <span class="k"><span class="keyword" style="font-weight: bold;">return</span></span><span class="o">;</span> <span class="o">}</span> <span class="n">Fragment</span> <span class="n">frag</span> <span class="o">=</span> <span class="o">(</span><span class="n">Fragment</span><span class="o">)</span><span class="k"><span class="keyword" style="font-weight: bold;">this</span></span><span class="o">.</span><span class="na">mFragments</span><span class="o">.</span><span class="na">mActive</span><span class="o">.</span><span class="na"><span class="keyword" style="font-weight: bold;">get</span></span><span class="o">(</span><span class="n">index</span><span class="o">);</span> <span class="k"><span class="keyword" style="font-weight: bold;">if</span></span> <span class="o">(</span><span class="n">frag</span> <span class="o">==</span> <span class="kc"><span class="keyword" style="font-weight: bold;">null</span></span><span class="o">)</span> <span class="o">{</span> <span class="n">Log</span><span class="o">.</span><span class="na">w</span><span class="o">(</span><span class="s"><span class="string" style="color: rgb(221, 17, 68);">"FragmentActivity"</span></span><span class="o">,</span> <span class="s"><span class="string" style="color: rgb(221, 17, 68);">"Activity result no fragment exists for index: 0x"</span></span> <span class="o">+</span> <span class="n">Integer</span><span class="o">.</span><span class="na">toHexString</span><span class="o">(</span><span class="n">requestCode</span><span class="o">));</span> <span class="o">}</span> <span class="k"><span class="keyword" style="font-weight: bold;">else</span></span> <span class="o">{</span> <span class="n">frag</span><span class="o">.</span><span class="na">onActivityResult</span><span class="o">(</span><span class="n">requestCode</span> <span class="o">&</span> <span class="mi"><span class="number" style="color: rgb(0, 153, 153);">0</span></span><span class="number" style="color: rgb(0, 153, 153);">xFFFF</span><span class="n"></span><span class="o">,</span> <span class="n">resultCode</span><span class="o">,</span> <span class="n">data</span><span class="o">);</span> <span class="o">}</span> <span class="k"><span class="keyword" style="font-weight: bold;">return</span></span><span class="o">;</span> <span class="o">}</span> <span class="kd">super</span><span class="o">.</span><span class="na">onActivityResult</span><span class="o">(</span><span class="n">requestCode</span><span class="o">,</span> <span class="n">resultCode</span><span class="o">,</span> <span class="n">data</span><span class="o">);</span> <span class="o">}</span>
很显然,设计者把Fragment的下标+1左移16位来标记这个request是不是Fragment的,拿到result再解码出下标,直接取对应的Fragment,这样并没有去考虑对Fragment嵌套Fragment做一个Map映射,所以出现了这种BUG。
但是如果我们需要在OnActivityResult的时候处理一些事情的话,我们可以通过在子Fragment中以getParentFragment.startActivityForResult的方式来启动,然后在父Fragment中去接收数据,我们需要在子Fragment中提供一个方法,如:getResultData(Object obj),通过父Fragment中的子Fragment实例去调用这个方法,把相应的数据传过去,然后去更新子Fragment。
以上是在使用Fragment去嵌套Fragment的时候可能会遇到的BUG,了解了BUG存在的原因之后,就可以完美的解决问题。
- Android Fragment嵌套使用存在的一些BUG以及解决方法
- Android Fragment嵌套使用存在的一些BUG以及解决方法
- Android Fragment嵌套使用存在的一些BUG以及解决方法
- Android Fragment嵌套使用存在的一些BUG以及解决方法
- Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- c#基础总结
- LeetCode刷题笔录 Merge Two Sorted Lists
- web开发知识点
- OpenCV2.3.1在Win7+VS2010下的配置过程
- C++知识点总结
- 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法
- mini2440裸机试炼之--myled
- LeetCode刷题笔录Balanced Binary Tree
- grunt命令
- mini2440裸机试炼之--按键控制蜂鸣器和LED
- NSTimer实现动画
- iOS动画浅析
- Reading files in JavaScript using the File APIs
- Tomcat应用绑定域名以及Apache端口转发