Android fragment(一)

一、概述

          


Android 在 3.0 的时候推出了 fragment 的概念,起初在谷歌文档上面看到 fragment 的作用是为了大屏手机和平板电脑设计的,但在某篇文章中我看到了这样一句话 「 尽量用 Activity 去处理逻辑,用 fragment 去绘制界面 」,这样让 我对 fragment 有了新的认识,不过自从 MVP 的出现,这种做法也就不会被流传了。现如今 大量的 app 都使用 one Activity + more fragment 的方式去编写,那么为什么回事这样的形式呢,首先 fragment 的「 复用性 」非常的强,这个界面的 Activity 可以加载 这个 fragment ,另一个 Activity 也可以加载这个 fragment ,其次的是 fragment 的适配性也非常的好。例如,我们在平板上面可以在 Activity 的左边放一个 fragment ,右边放一个 fragment ,然后这个效果移动到手机,就可以在刚进入的时候显示列表 fragment ,然后在点击之后去显示另一个 fragment ,这样就完成了平板到手机的迁移,如果这个效果换做 Activity 去实现,就会很麻烦。说了这么多,我们下面进入正题,看看 fragment 的使用和生命周期。



二、fragment 的简单用法和生命周期





要想看到 fragment ,就一定要有 Activity 这个载体,那么如何在 Activity 中去添加 fragment,有两种方法,第一种就是静态添加,也就是写在 xml 文件中,第二种就是在代码中动态去添加,也就是通过「事务」去添加,这种方法是我们下节要说的,这里就不在说了,我们先说一下第一种方法,下面看代码:



<fragment  
        android:id="@+id/fm_listfragment"  
        android:name="com.andya.fragment.listfragment"  
        android:layout_width="match_parent"  
        android:layout_height="45dp" />  




只要把这个写进 Activity 的布局中,就可以添加了,这里面有一个属性,是 name 这个属性,这个属性你需要指定一个 fragment 的包名,通过这个属性, Activity 去找到 fragment 的视图。
这样添加 fragment 的操作我们就完成了,下面说说 Activity 和 fragment 之间是如何联系的。
在 fragment 中如果我们想去获取 Activity 的实例的话,我们可以通过 getActivity()去获取,我们在 Activity 中可以通过 findFragmentById(这个里面是 fragment 的 id 属性) 和 findFragmentByTag(这个里面是 fragment 的 tag) 方法去获取 fragment 的实例,通过这个实例去操作 fragment ,这两个方法属于 FragmentManager 。
好了说了这么多下面看一下我们实现的一个简单的 fragment 的例子:



public class DetaliFragment extends Fragment{

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_list_book_layout,null);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }
}




这就是一个最基本的 fragment 的实现,其实 fragment 我认为最重要的声明周期就是 onCreateView, 从上面的代码中我们可以看出 fragment 比 Activity 多出很多生命周期, 下面说一下几个相比 Actiivty 额外每个生命周期的作用。

     onAttach()

      此方法的作用是与 Activity 进行绑定。
     
     onCreateView()
 
     此方法的作用是创建 fragment 的视图。

        onActivityCreate()

当 Activity 的 onCreate() 方法返回时调用。

  onDestoryView()

     与 onCreateView 相对应,销毁 fragment 的视图。

onDetach()

与 onAttach 相对应,销毁与 Activity 的关系。

下面借用一张图片来表示 Activity 和 fragment 的生命周期的关联





三、fragment 的事务

这节我们将说一下 fragment 事务相关的内容,如果对数据库有了解的同学可能对事务很眼熟,其实 fragment 的事务和数据库中的事务相类似,数据库中的事务就是对一个逻辑单元进行一定的操作,那么 fragment 的事务就是对某个 Activity 的 fragment 进行操作。也就是我们上节所说的动态添加 fragment(其实不仅仅是添加)


如果要完成一个 fragment 的事务,你需要通过以下步骤:

①、我们首先要通过 getFragmentManager 方法去获取 FragmentManager ,如果你用的是 V4 包下面的 fragment 那么你需要用 getSupportFragmentManager 去获取FragmentManager 。

②、通过获去的 FragmentManager 去开启一个事务也就是 FragmentTransaction transaction = fm.benginTransatcion() 。

③、通过 FragmentTransaction 的API 去进行一系列的操作

④、调用 FragmentTransaction.commit() 去提交一个事务。

其实这里面主要的就是第三步,那么我们先说一下相关 API:


transaction.add()
加入一个 fragment 到 Activity 中。

transaction.remove()
将一个 fragment 从 Activity 中移除,如果这个 fragment 没有被添加到回退栈,那么这个 Activity 将被永久销毁。

transaction.replace()
使用一个新的 fragment 替换当前的 fragment,相当于先 remove() 然后又 add()。
transaction.show()
展示一个被隐藏的 fragment 这个 fragment 必须先被添加到 Activity 中才能调用这个方法。

transaction.hide()
隐藏当前 fragment,这个和 show()是一个双胞胎方法。

detach()
这个方法会将 onCreateView 中的 view 在 fragment移除,这个方法和 remove() 类似,不过不同的是,这个 fragment
没有被完全销毁,他还会有生命周期,只不过没有 UI。

Attach()
重新创建一个 View 并添加到 fragment 中去。

API 基本上介绍的差不多了,光说不练是弱者,下面看一下代码:
FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        Fragment fragmentLeft = fm.findFragmentByTag("left");
        Fragment fragmentRigth = fm.findFragmentByTag("rigth");
        switch (v.getId()){
            case R.id.btn_two_add:
                LeftFragment leftFragment = new LeftFragment();
                ft.add(R.id.lv_rongqi,leftFragment,"left");
                ft.commit();
                break;
            case R.id.btn_two_remove:

                if(null != fragmentLeft){
                    ft.remove(fragmentLeft);
                } else if(null != fragmentRigth){
                    ft.remove(fragmentRigth);
                }
                ft.commit();
                break;
            case R.id.btn_two_replace:
                if(null != fragmentLeft){
                    RigthFragment rigthFragment = new RigthFragment();
                    ft.replace(R.id.lv_rongqi,rigthFragment,"rigth");
                }
                if(null != fragmentRigth){
                    ft.replace(R.id.lv_rongqi,fragmentRigth);
                }
                ft.commit();
                break;
            case R.id.btn_two_hide:
                if(null != fragmentLeft){
                    ft.hide(fragmentLeft);
                }
                if(null != fragmentRigth){
                    ft.hide(fragmentRigth);
                }
                ft.commit();
                break;
            case R.id.btn_two_show:
                if(null != fragmentLeft){
                    ft.show(fragmentLeft);
                }
                if(null != fragmentRigth){
                    ft.show(fragmentRigth);
                }
                ft.commit();
                break;


注意:如果你一直点击 add 按钮,那么就会无限的 add leftFragment,也就是说你需要点很多次 remove 才能把它 remove
干净,其实 replace 也是一样的,每次只能移除一个 fragment。




四、fragment 与 Activity 的交互



本节主要说一下 fragment 和 Activity 之间的交互,还有 fragment 和 fragment 之间的交互。我们先说一下 Activity 和 fragment 之间的交互:
1、Activity 可以通过自己管理的 fragment 的引用去操作 fragment 的所有 public 方法。
2、如果没有 fragment 的引用,那么可以通过 findFragmentByTag 和 findFragmentById 方法获取 fragment。
3、fragment 可以通过 getActivity() 方法获取 Activity 的实例去操作 Activity 中的数据和方法。

不过通过这样的直接去操作数据,显然是不合理的,而且 fragment 的设计就是要能复用,如果像上述那样做,fragment 的复用性将会很弱,而且 Activity 和 fragment 的耦合度也会很高。

那么我们怎么去解决呢,解决的办法有两种:
1、我们在 Activity 中可以通过 setArgument() 方法去加入数据,然后在 fragment 中通过 getArgument() 去获取数据,这样就完成了和 Intent 类似的操作。下面看代码:

 RigthFragment rigthFragment = new RigthFragment();
        rigthFragment.setArguments(bundle);
if(getArguments() != null){
            position = getArguments().getInt(MainActivity.STRINGPOSITION);
        }

这样就轻松完成了 Activity 和 Fragment 之间数据的交换。不过这样会造成 Fragment 和 Activity 之间的耦合度有点高,那么下面的方法就会很好的解决这个问题。



2、我们在 fragment 中去定义一个接口,然后在 Activity 中去

实现这个接口,这样就可以完美的实现了解耦,这样做的话,我们需要在 onAttach 中去设置 Activity 的引用,然后在 onDetach 去把这个引用置空,在 fragment 中我们只需要用这个引用去调用 Activity 的方法就可以实现和 Activity 的交互了,下面看代码:


/**
 * Created by andy on 2017/3/13.
 */
public class LeftFragment extends Fragment implements View.OnClickListener {

    Button first,second,thried;
    public Callbacks callbacks;
    @Override
    public void onAttach(Activity activity){
        super.onAttach(activity);
        if(!(activity instanceof Callbacks)){
            throw new IllegalStateException("Activity必须实现onItemSelectState方法");
        }
        callbacks = (Callbacks)activity;
    }
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.layout_left_fragment,container,false);
        first = (Button)view.findViewById(R.id.first_button);
        second = (Button)view.findViewById(R.id.second_button);
        thried = (Button)view.findViewById(R.id.third_button);
        first.setOnClickListener(this);
        second.setOnClickListener(this);
        thried.setOnClickListener(this);
        return view;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.first_button:
                callbacks.onItemSelectState(1);
                break;
            case R.id.second_button:
                callbacks.onItemSelectState(2);
                break;
            case R.id.third_button:
                callbacks.onItemSelectState(3);
                break;
        }
    }

    public interface Callbacks{
        public void onItemSelectState(int position);
    }
}



然后我们在Activity 中只要实现这个 Callbacks 这个回调接口就可以了

 @Override
    public void onItemSelectState(int position) {
        Bundle bundle = new Bundle();
        bundle.putInt(STRINGPOSITION,position);
        RigthFragment rigthFragment = new RigthFragment();
        rigthFragment.setArguments(bundle);
        //这个地方是让layout_rigth_fragment这个布局的代码动态刷新
        getFragmentManager().beginTransaction().replace(R.id.right_layout,rigthFragment).commit();
    }

这个 position 就是 fragment 传递给我们的数据。



五、fragment 最佳实践


1、我们可以在每个 fragment 中去定义一个静态方法去创建 fragment 。
2、我们在创建 fragment 的过程中我们尽量去判断一下这个 fragment 是否存在,如果存在的话我们可以通过事务去 hide和 show 而不需要新创建一个对象。
3、fragment 的 onSaveInstanceState 方法也是有的,所以我们可以根据它去恢复 fragment 的数据。
4、屏幕旋转的 Activity会重新创建,那么我们的 fragment 也会重新创建,这样如果无限的旋转屏幕,就会生成无限多的 fragment ,不过我们可以通过判断Activity中 onCreate 中 saveInsanceState 中是否有值去判断是否需要重新创建 fragment。






总结:


本篇主要讲了 fragment 的一些基本的功能,下一篇会给大家讲一下使用 fragment 中的一些问题,和解决这些问题的办法。代码中如果有什么问题欢迎指出,谢谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值