Android之Fragment

Android 之 Fragment

为什么 Fragment ?

为了让界面在平板上更好地展示;代码复用;Activity 可用来管理 Fragment;可控性更好,可以像普通对象那样自由地创建和控制,传递参数更加容易方便,也不用处理系统相关的事情,显示方式、替换、不管整体还是部分,都可以做到相应的更改;可作为 View Controllers

添加 Fragment

1
2
3
4
5
6
<fragment
android:id="@+id/fragment1"
android:name="com.example.fragmentdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
1
2
Fragment1 fragment1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();

Fragment 生命周期

Fragment 生命周期

几个新方法:

  • onAttach():Fragment 和 Activity 建立关联的时候调用
  • onCreateView():为 Fragment 加载布局时调用
  • onActivityCreated():当 Activity 中的onCreate()执行完调用
  • onDestroyView():Fragment 中的布局被移除时调用
  • onDetach():Fragment 和 Activity 解除关联时调用

注意一点:除了onCreateView(),其他方法必须调用父类对于该方法的实现。

通信方式:

  1. 直接在一个 Fragment 中调用另外一个 Fragment 中的方法。适用于布局文件已定义了的 Fragment。

    1
    2
    Fragment1 f1 = (Fragment1) getActivity().getFragmentManager().findFragmentById(R.id.fragment1);
    fi.func();
  2. 使用接口

    1
    2
    3
    public interface IFunc{
    void func();
    }
1
2
3
4
5
6
7
8
public class Activity1 implements IFunc{
...
@Override
public void func(){
// do something
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Fragment1 extends Fragment{
private IFunc mCallback;
...
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
if(activity != null){
mCallback = (IFunc) activity; // then you can use mCallback to do something
}
}
...
}
  1. 广播
  2. getActivity()Fragment 中直接调用 Activity 中的公开方法;
  3. onAttach()之前可以调用fragment.setArguments(bundle);Activity 中可有 Fragment 的引用;
  4. Eventbus、数据存储等其他方式;

getActivity()为 null:异步网络请求的回调中调用此方法会出现空指针的问题。如果 APP 长时间在后台运行,再次进入可能会出现 crash,而且 fragment 会有重叠现象。如果系统内存不足、切换横竖屏、APP 长时间后台运行,Activity 都可能被系统回收然后重建,但 Fragment 并不会随着 Activity 的回收而被回收,创建的所有 Fragment 会被保存到 Bundle 里面,从而导致 Fragment 丢失对应承载它的 Activity。

解决方法:可在onAttach()获取 Activity 上下文;重叠问题的解决:1.想办法不让 Activity 意外退出重建时保存信息//super.onSaveInstanceState(outState);(不推荐);2.旋转屏幕时等场景不让 Activity 走生命周期方法android:configChanges="keyboardHidden|orientation|screenSize";3.当 Activity 恢复时,取出保存的 Fragment 重新加入即可,即保留了 Activity 的视图状态,也完美地解决了重叠问题。

其他知识点

回退栈管理

1
2
3
4
5
6
Fragment f = new Fragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ftx = fm.beginTransactoin();
ftx.replace(R.id.fragment_container, f, "ONE"); // Fragment 实例不会被销毁,但是视图层次会被销毁,即会调用 onDestroyView 和 onCreateView
ftx.addToBackStack(null); //将当前事务添加到回退栈
ftx.commit();

Fragment 与 ActionBar 和 MenuItem

a. 在 Fragment 的onCreate()调用setHasOptionsMenu(true)
b. 然后再 Fragment 类中实现 onCrateOptionsMenu()
c. 如果希望在 Fragment 中处理 MenuItem 的点击,也可以实现onOptionsItemSelected(),Activity 也可以直接处理该 MenuItem 的点击事件。

没有布局的 Fragment —— 保存大数据

主要用于处理异步请求带来的数据保存问题,尤其是异步请求未完成时屏幕旋转这种现象

  1. 继承 Fragment,声明引用指向你的有状态的对象
  2. 当 Fragment 创建时onCreate()调用setRetainInstance(boolean)
  3. 把 Fragment 实例添加到 Activity 中
  4. 当 Activity 重新启动后,使用 FragmentManager 对 Fragment 进行恢复

DialogFragment 的使用

  1. 新建对话框布局文件
  2. 继承 DialogFragment 重写onCreateDialog()
  3. dialog.show(getFragmentManager(), "testDialog");

Fragment 的startActivityForResult

  1. 只嵌套了一层 Fragment:Fragment 中使用时,不要使用getActivity().startActivityForResult(),而是应该直接使用;如果 Activity 中重写了onActivityResult(),其中一定要加上super.onActivityResult()。若违反,则只能传递到 Activity 中而不能到达 Fragment 中的onActivityResult()
  2. 嵌套多层 Fragment:此时是不能传递到第二层的 Fragment 中的。可以通过 FragmentManager 递归调用fragment.onActivityResult()。同样需要注意1.中的限制
  3. 在所有的 Fragment 中若是直接使用startActivityForResult(),那么传到 Activity 的onActivityResult()中的 requestCode 就会不对,resultCode 是对的,当然,传到 Fragment 中也会如此。若是用getActivity().startActivityForResult()则都会是正确的。当然若是直接返回键返回,那么会自动给一个 resultCode,在重写的时候需要判定 resultCode。

Fragment add & replace

两种方法不同之处:是否要清空容器再添加 Fragment 的区别,用法上add配合hide或者remove

1
2
3
4
5
FragmentTransaction ft = getFragmentManager().beginTransaction();

ft.add(R.id.fragment_container, fragment1).hide(fragment2).commit();

ft.replace(R.id.fragment_container, fragment1).commit();


参考引用

对于Fragment的一些理解
Android Fragment完全解析,关于碎片你所需知道的一切
Android Fragment学习与使用—高级篇
对于Fragment的一些理解
关于Fragment与Fragment、Activity通信的四种方式
Fragment中调用getActivity为null的问题
fragment重叠的完美解决方案
谈谈Fragment中的onActivityResult
Fragment add replace 区别