Android应用中使用Fragment组件的一些问题及解决方案总结

2019-12-10 18:03:22丽君
  • 依然利用requestCode,将其低16位拆分,其中的高8位用来存储childFragmentManager中的index,低8位留给ChildFragment使用.(如果嵌套层级不深,那么此方案还是不错的,如果层级较深,那么留给Fragment的requestCode的可用值区间将非常局限)
  • Android 4.2(Api 17)以后,可以使用内置的Fragment,以及ChildFragmentManager,内置Fragment不再需要借助requestCode的高16比特来记录它的index.而是由Framework收到Fragment.startActivityForResult()时,记录该Fragment的标识(android:fragment:${parentIndex}:${myIndex}),派发result时,就根据这个标识找到那个Fragment.因此就不会出现ChildFragment收不到onActivityResult()回调的问题了.可以参考Activity.dispatchActivityResult()

    Tips

    开发的时候,可以打开Fragment相关的调试信息

    FragmentManager.enableDebugLogging(BuildConfig.DEBUG);
    Activity的onResume被调用时,Fragment的onResume还未被调用.
    protected void onPostResume() {
      super.onPostResume();
      mHandler.removeMessages(MSG_RESUME_PENDING);
      onResumeFragments();
      mFragments.execPendingActions();
    }
    protected void onResumeFragments() {
      mFragments.dispatchResume();
    }
    

    如果需要在Fragment的onResume都执行完后再执行某个操作,可以重写onPostResume()方法,一定要调用 super.onPostResume()

    1.IllegalStateException(Fragment not attached to Activity)的问题
    这个异常通常的发生情况是:在Fragment中启动一个异步任务,然后在回调中执行和resource相关的操作(getString(...)),或者startActivity(...)之类的操作.但是这个时候Fragment可能已经被detach了,所以它的mHost==null,因此在执行这些操作之前,需要先判断一下isAdded().
    注意: 这里不要使用isDetached()来判断,因为Fragment被detach之后,它的isDetached()方法依然可能返回false

    2.如果Fragment A是因为被replace而detach的,那么它的isDetached()将返回false
    3.如果Fragment A对应的FragmentTransaction被加入到返回栈中,因为出栈而detach,那么它的isDetached()将返回true

    final public Resources getResources() {
      if (mHost == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to Activity");
      }
      return mHost.getContext().getResources();
    }
    public void startActivity(Intent intent, @Nullable Bundle options) {
      if (mHost == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to Activity");
      }
      mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1, options);
    }