Android——Fragment

2017-11-23  本文已影响0人  pkqgo

描述

Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接接受其宿主activity的生命周期的影响。你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入的事件,并且可以在activity运行时添加或者删除。

应该将每一个fragment设计为模块化和可复用化的activity组件。也就是说,你可以在多个activity中引用同一个fragment,因为fragment定义了它自己的布局,并且使用它本身生命周期回调的行为。

生命周期

图片.png

Fragment比Activity多了几个额外的生命周期回调方法:

onAttach(Activity):当Fragment和Activity发生关联时使用。

onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图

onActivityCreate(Bundle):当Activity的onCreate()方法返回时调用

onDestoryView():与onCreateView相对应,当该Fragment的视图被移除时调用

onDetach():与onAttach()相对应,当Fragment与Activity关联被取消时调用

注意:除了onCreateView()方法,其他的所有的方法如果你重写了,必须调用父类对于该方法的实现

管理fragment生命周期与管理activity生命周期很相像,像activity一样,fragment也有三种状态:
1、Resumed:
fragment在运行中的activity中可见。

2、Paused:
另一个activity处于前台且得到焦点,但是这个fragment所在的activtiy仍然可见(前台activity部分透明,或者没有覆盖全屏)。

3、Stopped:
fragment不可见。要么宿主activity已经停止,要么fragment已经从activity上移除,但已被添加到后台栈中。一个停止的fragment仍然活着(所有的状态和成员信息仍然由系统保留着)。但是,它对于用户来讲已经不再可见,并且如果activity被杀掉,它也将被杀掉。

Fragment持久化

如果activity的进程被杀掉了,在activity被重新创建时,你恢复fragment状态。可以执行fragment的onSaveIntanceState()来保存状态(注意:fragment是在onCreate(),onCreateView()或者onActivityCreate()中进行恢复)。

在生命周期方面,activity和fragment之间一个很重要的不同就是在各自的后台栈中是如何存储的。当activity停止时,默认情况下activity被安置在由系统管理的activity后台栈中;fragment仅当在一个事务被移除时,通过显式调用addToBackStack()请求保存的实例,该fragment才被置于由宿主activity管理的后台栈。

使用方法

静态使用:直接在xml文件中使用 fragment标签
<RelativeLayout 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" >
             <fragment
                  android:id="@+id/id_fragment_title"
                  android:name="com.zhy.zhy_fragments.TitleFragment"//直接对应Fragment类
                  android:layout_width="fill_parent"
                  android:layout_height="45dp" />
             <fragment
                  android:layout_below="@id/id_fragment_title"
                  android:id="@+id/id_fragment_content"
                  android:name="com.zhy.zhy_fragments.ContentFragment"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent" />
</RelativeLayout>
动态使用
       add()、replace()、remove()、hide()、show()
       getSupportFragmentManager().beginTransaction().add(R.id.content, new FirstFragment())
                        .commit();

API介绍

    //根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID
    1、fragmentManager.findFragmentById();

    //根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例
    2、fragmentManager.findFragmentByTag();

    //获取所有被ADD进Activity中的Fragment
    3、fragmentManager.getFragments();

    //替换containerViewId中的fragment实例,注意,它首先把containerViewId中所有fragment删除,然后再add进去当前的fragment
    4、replace(int containerViewId, Fragment fragment);

    //将一个fragment实例添加到Activity容器的最上层
    5、add(int containerViewId, Fragment fragment, String tag);

    //从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
    6、remove(Fragment fragment);

    //隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
    7、hide(Fragment fragment)

    //显示之前隐藏的Fragment
    8、show(Fragment fragment)

Fragment回退栈

类似与Android系统为Activity维护一个任务栈,我们也可以通过Activity维护一个回退栈来保存每次Fragment事务发生的变化。

如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。

      //添加方法
       fragmentTransaction.addToBackStack(String)

       ex:
        FragmentTwo fTwo = new FragmentTwo();
        FragmentManager fm = getFragmentManager();
        FragmentTransaction tx = fm.beginTransaction();
        tx.replace(R.id.id_content, fTwo, "TWO");
        tx.addToBackStack(null);
        tx.commit();

把FragmentTwo加入回退栈,再使用replace方法替换,
由于FragmentTwo加入回退栈,之前加入的FragmentOne实例不会被销毁。

在创建Fragment时要传入参数

通过Arguments创建Fragment,不建议通过为Fragment添加带参数的构造函数

    public class ContentFragment extends Fragment  {
        private String mArgument;
        public static final String ARGUMENT = "argument";

        @Override
        public void onCreate(Bundle savedInstanceState)          {
            super.onCreate(savedInstanceState);
            // mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
            Bundle bundle = getArguments();
            if (bundle != null)
                mArgument = bundle.getString(ARGUMENT);
        }

        /**
         * 传入需要的参数,设置给arguments
         * @param argument
         * @return
         */
        public static ContentFragment newInstance(String argument)          {
            Bundle bundle = new Bundle();
            bundle.putString(ARGUMENT, argument);
            ContentFragment contentFragment = new ContentFragment();
            contentFragment.setArguments(bundle);
            return contentFragment;
        }
    }

Fragment、Viewpager、懒加载

1、FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。

2、FragmentStatePagerAdapter:会销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragment从当前Activity的FragmentManager中移除。

3、懒加载,核心方法是 setUserVisibleHint()

public class BaseLazyLoadFragment extends Fragment {

    private boolean mIsInit = false;//数据是否加载完成
    private boolean mIsPrepared = false;//UI是否准备完成

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View mRootView = inflater.inflate(R.layout.fragment_first, container, false);
        mIsPrepared = true;
        lazyLoad();
        return mRootView;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            lazyLoad();
        }
    }

    public void lazyLoad() {
        if (getUserVisibleHint() && mIsPrepared && !mIsInit) {
            // 异步初始化,在初始化后显示正常UI
            loadData();
        }
    }

    private void loadData() {
        new Thread() {
            public void run() {
                // 1. 加载数据
                // 2. 更新UI
                // 3. mIsInit = true
                mIsInit = true;
            }
        }.start();
    }
    
}

多个Fragment重叠

原因1:横竖屏切换,造成Fragment重新实例化。
原因2:按下Home键,Activity处于后台,由于内存不足被销毁,重新唤醒时Fragment重新实例化。

注:出现的原因是在 API24 之前的 v4包 的源码问题,
解决方案:通过检查onCreate的参数Bundle savedInstanceState就可以判断,当前是否发生Activity的重新创建:

默认的savedInstanceState会存储一些数据,只有在savedInstanceState==null时,才进行创建Fragment实例:

public class MainActivity extends Activity {
    private static final String TAG = "FragmentOne";
    private FragmentOne mFOne;

    @Override
    protected void onCreate(Bundle savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState == null)   {
            mFOne = new FragmentOne();
            FragmentManager fm = getFragmentManager();
            FragmentTransaction tx = fm.beginTransaction();
            tx.add(R.id.id_content, mFOne, "ONE");
            tx.commit();
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读