android中的第五大组件->Fragment

简介

fragment在android中是以碎片的形式依附在activity中,常被成为android控件中的第五大组件,现在更多的形式都是以单activity+多fragment的app结构。在相同界面中,用fragment比activity所占用内存要小的多,如果我们考虑到性能优化这方面,我们也可以优先考虑使用fragment。我们可以从以下几个方面进行解析。

  1. fragment为何成为第五大组件?
  2. fragment的加载方式。
  3. fragment的生命周期。
  4. fragment的常用方式。
  5. fragment与activity进行的通信。
fragment为何成为android第五大组件?

我们都知道android有主要的四大组件:activity,service,broadcastReceiver,Contentprovider.所以引发我们的思考fragment为什么称为android第五大组件呢?
1.随着android越来越成熟,各方面的性能优化,如内存优化,界面性能优化方面,使用fragment所占用的内存少,界面比较顺滑。
2.在使用频率上,fragment是不输与其他四大组件的,它具有自己的生命周期,同时可以灵活的动态,静态的加载activity的内容,所以成为第五大组件。

fragment的加载方式

fragment分为动态加载和静态加载。
动态加载:

主布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.trip.fragmenttest.MainActivity">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="切换fragment"/>

    <FrameLayout
        android:id="@+id/fragment_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>
</LinearLayout>

fragment1的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/lblFragment1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="fragment1"
        android:textColor="#000000"
        android:textSize="25sp" />
</LinearLayout>

MainActivity代码:

public class MainActivity extends AppCompatActivity {

    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = findViewById(R.id.btn);
        //获取fragmentManager管理者 如果继承为FragmentActivity则:
    FragmentManager fragmentManager = getSupportFragmentManager();
    final FragmentManager fragmentManager = getFragmentManager();
        //开启FragmentTransaction事务
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //通过事务向Activity的布局中添加MyFragment
        fragmentTransaction.add(R.id.fragment_content, new Fragment1());
        fragmentTransaction.commit();

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //开启事务
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                fragmentTransaction.replace(R.id.fragment_content,new Fragment2());
                fragmentTransaction.commit();
            }
        });
    }
}

注:
1.如果mainActivity继承Activity则Fragment为 android.app.Fragment,如果继承FragmentActivity则是android.support.v4.app.Fragment;
2.fragment01和fragment02需动态的继承import android.app.Fragment或import android.support.v4.app.Fragment;
3.fragmentTransaction需要再次进行add,replace,remove操作的时候,需重新beginTransaction(),然后进行commit提交操作。如果直接进行commit会报commit already called异常.

静态加载:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.trip.fragmenttest.MainActivity">

    <fragment
        android:id="@+id/lblFragment1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.trip.fragmenttest.Fragment1"/>
</LinearLayout>

关于静态加载可直接在主布局加入fragment,android:name的属性是该fragment的布局。

fragment的生命周期

这里写图片描述

当fragment启动的时候:

12-18 13:14:29.395 32566-32566/com.trip.fragmenttest E/fragment1: onAttach
12-18 13:14:29.395 32566-32566/com.trip.fragmenttest E/fragment1: onCreate
12-18 13:14:29.398 32566-32566/com.trip.fragmenttest E/fragment1: onCreateView
12-18 13:14:29.399 32566-32566/com.trip.fragmenttest E/MainActivity: onCreate
12-18 13:14:29.401 32566-32566/com.trip.fragmenttest E/fragment1onActivityCreated
12-18 13:14:29.402 32566-32566/com.trip.fragmenttest E/fragment1: onStart
12-18 13:14:29.402 32566-32566/com.trip.fragmenttest E/MainActivity: onStart
12-18 13:14:29.406 32566-32566/com.trip.fragmenttest E/MainActivity: onResume
12-18 13:14:29.407 32566-32566/com.trip.fragmenttest E/fragment1: onResume

按home键回到桌面的时候:

12-18 13:16:28.855 32566-32566/com.trip.fragmenttest E/fragment1: onPause
12-18 13:16:28.855 32566-32566/com.trip.fragmenttest E/MainActivity: onPause
12-18 13:16:29.211 32566-32566/com.trip.fragmenttest E/fragment1: onStop
12-18 13:16:29.211 32566-32566/com.trip.fragmenttest E/MainActivity: onStop

回到应用的时候:

12-18 13:17:11.243 32566-32566/com.trip.fragmenttest E/MainActivity: onRestart
12-18 13:17:11.243 32566-32566/com.trip.fragmenttest E/fragment1: onStart
12-18 13:17:11.243 32566-32566/com.trip.fragmenttest E/MainActivity: onStart
12-18 13:17:11.244 32566-32566/com.trip.fragmenttest E/MainActivity: onResume
12-18 13:17:11.244 32566-32566/com.trip.fragmenttest E/fragment1: onResume

跳转页面的时候:

12-18 13:21:16.707 3659-3659/com.trip.fragmenttest E/fragment1: onPause
12-18 13:21:16.707 3659-3659/com.trip.fragmenttest E/MainActivity: onPause
12-18 13:21:17.069 3659-3659/com.trip.fragmenttest E/fragment1: onStop
12-18 13:21:17.069 3659-3659/com.trip.fragmenttest E/MainActivity: onStop

退出应用:

12-18 13:22:29.086 3659-3659/com.trip.fragmenttest E/fragment1: onPause
12-18 13:22:29.086 3659-3659/com.trip.fragmenttest E/MainActivity: onPause
12-18 13:22:29.462 3659-3659/com.trip.fragmenttest E/fragment1: onStop
12-18 13:22:29.462 3659-3659/com.trip.fragmenttest E/MainActivity: onStop
12-18 13:22:29.463 3659-3659/com.trip.fragmenttest E/fragment1: onDestroyView
12-18 13:22:29.463 3659-3659/com.trip.fragmenttest E/fragment1: onDestroy
12-18 13:22:29.463 3659-3659/com.trip.fragmenttest E/fragment1: onDetach
12-18 13:22:29.463 3659-3659/com.trip.fragmenttest E/MainActivity: onDestroy

注意:
以上为fragment的生命周期各个执行过程,fragment只能依附在activity中存在,并不能单独的界面存在。

4.fragment的常用方式

fragment常常与viewpager进行搭配使用.可参考:
http://blog.csdn.net/zhang31jian/article/details/29867951

可涉及到FragmentPagerAdapter和FragmentStatePagerAdapter的区别:

当ViewPager使用的是FragmentPagerAdapter的时候:

This version of the pager is best for use when there are a handful of
 * typically more static fragments to be paged through, such as a set of tabs.
 * The fragment of each page the user visits will be kept in memory, though its
 * view hierarchy may be destroyed when not visible.  This can result in using
 * a significant amount of memory since fragment instances can hold on to an
 * arbitrary amount of state.  For larger sets of pages, consider

上面描述解释的意思是: 这个pager最好的使用是用于一些静态界面,像一些tabs栏,这些fragment会一直保存在内存当中,即使fragment中的view被destroyed。

fragment被移除所执行的方法为:onPouse()->onStop()->onDestroyView()(不会执行onDestroy()方法和onDetach())。

当ViewPager使用FragmentStatePagerAdapter的时候:

This version of the pager is more useful when there are a large number
 * of pages, working more like a list view.  When pages are not visible to
 * the user, their entire fragment may be destroyed, only keeping the saved
 * state of that fragment.  This allows the pager to hold on to much less
 * memory associated with each visited page as compared to
 * {@link FragmentPagerAdapter} at the cost of potentially more overhead when
 * switching between pages.

由官方解释的意思是:这个pager比较适合一些比较多的fragment的界面,当界面不可见的时候,所用到的fragment也会被destroyed,因为它只缓存保存状态的Fragment。

fragment被移除所执行的方法为:onPouse()->onStop()->onDestroyView()-_onDestroy()->onDetach()。

总结:当page数量少,用FragmentPagerAdapter;反之则用FragmentStatePagerAdapter;它们两的Fragment生命周期在ViewPage的切换过程中都会重复执行多次,所以它都不适用于App主页Tab。

5. fragment与activity进行的通信。

activity传值给fragment方式:

1.使用Bundle传值:

        Fragment1  fragment = new Fragment1();
        Bundle bundle = new Bundle();
        bundle.putString("id", "123");
        fragment.setArguments(bundle);

  在fragment接收值:      String type = (String) getArguments().get("id");

2.使用方法获取值:

public String getTitles(){
    return "hello";
}
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    titles = ((MainActivity) activity).getTitles();//通过强转成宿主activity,就可以获取到传递过来的数据
}

3.创建Fragment和传递数值

Fragment1 fragment1 = MyFragment.newInstance("这是第一个fragment");
在fragment中接收:
static MyFragment newInstance(String s){
        MyFragment myFragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString("DATA",s);
        myFragment.setArguments(bundle);
        return myFragment;
    }

fragment传值给activity:
使用回调函数传值:

public class MenuFragment extends Fragment implements View.OnClickListener {
    // 2.1 定义用来与外部activity交互,获取到宿主activity
    private FragmentInteraction listterner;
    // 1 定义了所有activity必须实现的接口方法
    public interface FragmentInteraction {
        void process(String str);
    }
    // 当FRagmen被加载到activity的时候会被回调
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if(activity instanceof FragmentInteraction) {
            listterner = (FragmentInteraction)activity; // 2.2 获取到宿主activity并赋值
        } else{
            throw new IllegalArgumentException("activity must implements FragmentInteraction");
        }
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_menu, container, false);
        View btn = view.findViewById(R.id.tv_button);
        View btn_m = view.findViewById(R.id.movie_button);
        if (btn != null||btn_m!=null) {
            btn.setOnClickListener(this);
            btn_m.setOnClickListener(this);
        }
        return view;
    }
    @Override
    public void onClick(View v) {
        int id  = v.getId();
        switch (id) {
            case R.id.tv_button:
                listterner.process("我是电视剧"); // 3.1 执行回调
                break;
            case R.id.movie_button:
                listterner.process("我是电影");
                break;
        }
    }
    //把传递进来的activity对象释放掉
    @Override
    public void onDetach() {
        super.onDetach();
        listterner = null;
    }
}

然后在mainActivity中实现该回调函数:

public class MainActivity extends Activity implements MenuFragment.FragmentInteraction{

    private TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textView = (TextView) findViewById(R.id.content_text);
    }

    // 3.2 +实现接口,实现回调
    @Override
    public void process(String str) {
        if (str != null) {
            textView.setText(str);
        }
    }
}

注:可使用第三方开源框架(EventBus)来实现fragment与activity进行通信。可自行百度搜索。

总结

fragment在android中使用的范围越来越广泛,当前fragment中也有很多坑,官方Fragment库的那些自身的BUG,并给出解决方案。但是真真切切也给程序带来了优化,已经让android界面更加的流畅。
扩展内容:
http://www.jianshu.com/p/d9143a92ad94

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值