Android关于Fragment的学习与使用及问题的处理

Fragment 切换方法一

public class MainActivity extends AppCompatActivity {
    Fragment_one one=new Fragment_one();
    Fragment_two two=new Fragment_two();
    FragmentManager manager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        manager=getSupportFragmentManager();//获得Frgment的管理类
    }
    public void one(View view) {
        Toast.makeText(this, "点击了1"+one.isHidden(), Toast.LENGTH_SHORT).show();
        //显示指定的Fragment
        showNewFragment(R.id.mfragment,one);
    }
    public void two(View view) {
        Toast.makeText(this, "点击了2"+two.isHidden(), Toast.LENGTH_SHORT).show();
        //显示制定的Fragment
        showNewFragment(R.id.mfragment,two);
    }

    //这里one.isHidden()和two.isHidden()打印的都为true
    /**
     *
     * @param layoutId 制定的占位视图ID
     * @param fragment 替换的Fragment
     *                 1. !fragment.isAdded() 这里是判断如果我们添加了 之后就不会再添加
     *                 否则会出现异常:Fragment already added 
     *                 2.每次事务只能提交一次
     *                 否则也会出现异常:Fragment already commit
     *
     */
    public void showNewFragment(int layoutId,Fragment fragment){
        FragmentTransaction t1= manager.beginTransaction();
        if(fragment!=null&& !fragment.isAdded()){
            t1.add(layoutId,fragment);
        }
        hideAllFragment();
        t1.show(fragment);
        t1.commit();
    }
    /**
     * 隐藏所以Fragment
     */
    public void hideAllFragment(){
        FragmentTransaction t2= manager.beginTransaction();
            if(one != null){
                t2.hide(one);
            }
            if(two != null){
                t2.hide(two);
            }
            t2.commit();
    }
}

Fragment切换方法二

public class MainActivity extends AppCompatActivity {
    Fragment_one one=new Fragment_one();
    Fragment_two two=new Fragment_two();
    FragmentManager manager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        manager=getSupportFragmentManager();//获得Frgment的管理类
        manager.beginTransaction()//添加需要的Fragment,显示默认显示的Fragment
                .add(R.id.mfragment,one)
                .add(R.id.mfragment,two)
                .show(one)
                .commit();
    }
    //这里one.isHidden()和two.isHidden()打印的都为true
    public void one(View view) {
        Toast.makeText(this, "点击了1"+one.isHidden(), Toast.LENGTH_SHORT).show();
        //替换指定的Fragment
        showNewFragment(R.id.mfragment,one);
        manager.beginTransaction()
                .replace(R.id.mfragment,one)
                .commit();
    }
    public void two(View view) {
        Toast.makeText(this, "点击了2"+two.isHidden(), Toast.LENGTH_SHORT).show();
        //替换制定的Fragment
        manager.beginTransaction()
                .replace(R.id.mfragment,two)
                .commit();
    }

Fragment切换的第三种方式就是结合ViewPager

主要呢就是写一个ViewPager的适配器(FragmentPagerAdapter),将实例化好的Fragment放到适配器里,这样就可以左右滑动了,也可以监听到下标来控制,导航栏显示那一页,代码就懒得写了,

ViewPager对Fragment生命周期的影响

ViewPager+Fragment已经是比较常见的组合,一般搭配ViewPager的FragmentPagerAdapter或FragmentStatePagerAdapter使用。不过ViewPager为了防止滑动出现卡顿,有一个缓存机制,默认情况下ViewPager会创建并缓存当前页面左右两边的页面(如Fragment)。此时左右两个Fragment都会执行从onAttach->….->onResume的生命周期,明明Fragment没有显示却已经到onResume了,在某些情况下会出现问题。比如数据的加载时机、判断Fragment是否可见等。

懒加载

如果不对数据加载时机做处理,使用ViewPager默认会将左右两个Fragment的数据也加载,当数据加载比较消耗资源会影响性能。我们可以对加载时机做调整使用懒加载,具体就是在Fragment真正可见时才加载数据。

在Fragment切换时候会调用setUserVisibleHint(boolean isVisibleToUser),isVisibleToUser表示是否对用户可见。setUserVisibleHint不单单在Fragment切换时调用,在onAttach之前都会调用一次此时isVisibleToUser为false,在onCreateView之前会调用一次此时isVisibleToUser的值为当前Fragment是否可见,之后就是在Fragment切换的时候会调用。

因为setUserVisibleHint会在onCreateView之前调用,如果数据加载涉及到view相关的操作别忘了设置一个变量来判断一下视图是否已经创建好。

--------------------------------------------------------------------------------------------------------

在分析一下replaceHide  Show的区别。

Fragment和replaceHide  Show的区别。

1、replace,加回退栈,Fragment不销毁,但是切换回销毁视图和重新创建视图。

2、replace,不加回退栈,Fragment销毁掉。

3、hide、show,Fragment不销毁,也不销毁视图。隐藏和显示不走生命周期。

这是从视图一跳转到视图二的生命周期 使用的是 replace

这是使用Hide  Show的方法生命周期

可以看出来我们的视图没有销毁,我们从视图一的创建跳转到视图二在返回视图一的时候没有执行任何生命周期

在总结下每个方法对Fragment的生命周期影响

add:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume

remove:onPause->onStop->onDestroyView->onDestroy->onDetach

show:onHiddenChanged(boolean hidden) hidden为false

hide:onHiddenChanged(boolean hidden) hidden为true

replace:旧Fragment的remove生命周期->新Fragment的add生命周期

replace+addToBackStack:onPause->onStop->onDestroyView->新Fragment的add生命周期
之后点击back:新Fragment的remove->onCreateView->onViewCreated->onActivityCreated->onStart->onResume 就是第一张图的线

detach:onPause->onStop->onDestroyView 可以看到只是视图被移除,Fragment关联状态还是不变,还是处于FragmentManger的管理下

FragmentTransaction.attach(Fragment var1):onStart->onResume->onCreateView

正常Fragment的生命周期

onAttach(Context context):在Fragment和Activity关联上的时候调用,且仅调用一次。在该回调中我们可以将context转化为Activity保存下来,从而避免后期频繁调用getAtivity()获取Activity的局面,避免了在某些情况下getAtivity()为空的异常(Activity和Fragment分离的情况下)。同时也可以在该回调中将传入的Arguments提取并解析,在这里强烈推荐通过setArguments给Fragment传参数,因为在应用被系统回收时Fragment不会保存相关属性。

onCreate():在最初创建Fragment的时候会调用,和Activity的onCreate类似。View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState):在准备绘制Fragment界面时调用,返回值为Fragment要绘制布局的根视图,当然也可以返回null。注意使用inflater构建View时一定要将attachToRoot指明false,因为Fragment会自动将视图添加到container中,attachToRoot为true会重复添加报错。onCreateView并不是一定会被调用,当添加的是没有界面的Fragment就不会调用,比如调用FragmentTransaction的 add(Fragment fragment, String tag)方法。

onCreateView() : 加载Fragment布局,绑定布局文件
onActivityCreated() : 表名与Fragment绑定的Activity已经执行完成了onCreate,可以与Activity进行交互操作。
onStart() : Fragment变为可见状态
onResume() : Fragment变为可交互状态
onPause(): Fragment变为不可交互状态(不代表不可见)
onSaveInstanceState():保存当前Fragment的状态。记录一些数据,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。
onStop(): Fragment变为不可见状态
onDestroyView() : 销毁Fragment的有关视图,但并未和Activity解绑,可以通过onCreateView()重新创建视图。Fragment销毁时或者ViewPager+Fragment情况下会调用
onDestroy() : 销毁Fragment时调用。
onDetach() : 解除和Activity的绑定。Fragmen销毁最后一步

应用被系统回收对生命周期的影响

为了防止在系统回收应用情况下,再次进不出错,强烈建议大家
1. 使用setArguments(Bundle bundle)方法传递参数。对于常规变量想必大家都已经十分熟练了,就不细说了。这里主要强调View变量和接口变量,View变量可以通过传入View的id,之后再通过id获取view的方法来实现。接口可以通过Activity实现,Fragment强转Activity实现。
2. addFragment之前先通过findFragmentById判断是否添加过避免重复添加,如使用FragmentAdapter可以在onSaveInstanceState存储相应Fragment.getTag

推荐使用的框架 Fragmentation

来看看YoKey大神对Fragmentation解释吧。

https://www.jianshu.com/p/d9143a92ad94

猜你喜欢

转载自blog.csdn.net/yuhui77268769/article/details/103200840
今日推荐