美文网首页
Android学习整理 -1- Fragment 学习

Android学习整理 -1- Fragment 学习

作者: minminaya | 来源:发表于2017-03-03 21:26 被阅读280次

    Android学习整理 - 系列


    经过一年多的Android的学习,最近越来越感觉到了瓶颈,所以打算整理一下学习Android Fragment找到的各种资料,博客,还有大牛们的笔记等等

    从图解分析Fragment的生命周期

    Fragment生命周期.png

    图解说明

    • 从图解可以看到,Fragment的一些生命周期方法与Activity比较相似,毕竟Fragment表示“碎片、块”的含义,本身实现出来一个主要目的就是帮Activity分担UI代码部分的实现逻辑的。

    • 蓝色背景的生命周期方法:从onCreateView() 到onDestroyView(),在整个Fragment创建到被销毁的过程中可以不只被执行一次,这里就涉及到管理着Fragment事务(FragmentTransaction)的FragmentManager底层的后台记录栈的东西了

    • 绿色背景的生命周期方法:在整个Fragment的生命周期中,仅仅执行一次。

    一张关于Activity Fragment的周期图

    Fragment生命周期.jpg
    • 从上往下 Activity与Fragmen的生命周期顺序

    Fragment是否很完美

    因为Fragment是由FragmentManager来管理,每一个Activity有一个FragmentManager,管理着一个Fragment的栈,Activity是系统级别的,由系统来管理ActivityManager,栈也是系统范围的。而Fragment则是每个Activity范围内的,所以在使用Fragment的时候也有几点要注意。

    • 同一个Activity中,只能有一个ID或TAG标识的Fragment实例。

      这很容易理解,同一个范围内,有标识的实例肯定是要唯一才行(否则还要标识干嘛)这个在布局中经常犯错,在布局中写Fragment最好不要加ID或者TAG,否则很容易出现不允许创建的错误。我的原则是如果放在布局中,就不要加ID和TAG,如果需要ID和TAG就全用代码控制。创建新实例前先到FragmentManager中查找一番,这也正是有标识的意义所在。

    • 一个Activity中有一个Fragment池,实例不一定会被销毁,可能会保存在池中。

    这个跟第一点差不多。就好比系统会缓存Activity的实例一样,FragmentManager也会缓存Fragment实例,以方便和加速再次显示。

    • FragmentManager的作用范围是整个Activity,所以,某一个布局ID,不能重复被Fragment替换。

      通常显示Fragment有二种方式,一种是层叠到某个布局上,或者把某个布局上面的Fragment替换掉,但是这个布局不能出现二次,比如布局A中有ID为id的区域,要显示为Fragment,此布局A,只能在一个Activity中显示一个,否则第二个id区域不能被Fragment成功替换。因为虽有二个ID布局的实例,但ID是相同的,对FragmentManager来说是一样的,它会认为只有一个,因为它看的是布局的ID,而不是布局的实例。

    • Fragment的生命周期反应Activity的生命周期。

    Fragment在显示和退出时会走一遍完整的生命周期。此外,正在显示时,就跟Activity的一样,Activity被onPause,里面的Fragment就onPause,以此类推,由此带来的问题就是,比如你在onStart()里面做了一些事情,那么,当宿主Activity被挡住,又出现时(比如接了个电话),Fragment的onStart也会被高到,所以你要想到,这些生命周期不单单在显示和退出时会走到。

    • Fragment的对用户可见性。

    这个问题出现在有Fragment栈的时候,也就是说每个Fragment不知道自己是否真的对用户可见。比如现在是Fragment A,又在其上面显示了Fragment B,当B显示后,A并不知道自己上面还有一个,也不知道自己对用户不可见了,同样再有一个C,B也不知。C退出后,B依然不知自己已在栈顶,对用户可见,B退后,A也不知。也就是说Fragment显示或者退出,栈里的其他Fragment无法感知。这点就不如Activity,a被b盖住后,a会走到onStop(),同样c显示后,b也能通过onStop()感知。Fragment可以从FragmentManager监听BackStackState的变化,但它只告诉你Stack变了,不告诉你是多了,还是少,还有你处的位置。有一个解决方案就是,记录页面的Path深度,再跟Fragment所在的Stack深度来比较,如果一致,那么这个Fragment就在栈顶。因为每个页面的Path深度是固定的,而Stack深度是不变化的,所以这个能准确的判断Fragment是否对用户可见,当然,这个仅针对整个页面有效,对于布局中的一个区域是无效的。

    • Fragment的事件传递。

      对于层叠的Fragment,其实就相当于在一个FrameLayout里面加上一堆的View,所以,如果处于顶层的Fragment没处理点击事件,那么事件就会向下层传递,直到事件被处理。比如有二个Fragment A和B,B在A上面,B只有一个简单的TextView且没处理事件,那么点击B时,会发现A里的View处理了事件。这个对于Activity也不会发生,因为事件不能跨窗体传播,上面的Activity没处理事件,也不会传给下面的Activity,即使它可见。解决之法,就是让上面的Fragment的根布局吃掉事件,为每个根ViewGroup添加onClick=“true”。

    • 与第三方Activity交互。与第三方交互,仍要采用Android的标准startActivityForResult()和onActivityResult()这二个方法来进行。但对于Fragment有些事情需要注意,Fragment也有这二个方法,但是为了能正确的让Fragment收到onActivityResult(),需要:

      1.宿主Activity要实现一个空的onActivityResult(),里面调用super.onActivityResult()

      2.调用Fragment#startActivityForResult()而不是用Activity的 当然,也可以直接使用Activity的startActivityForResult(),那样的话,就只能在宿主Activity里处理返回的结果了。

    Fragment以及它的宿主Activity的复用

    鸿洋博客中的一个Fragment例子,例子突出在 复用

      public class ContentFragment extends Fragment  
        {  
            private String mArgument;///Activity传递的数据(值)
            public static final String ARGUMENT = "argument";///Activity传递的数据名(键)  
            public static final String RESPONSE = "response";///Activity
    
            @Override  
            public void onCreate(Bundle savedInstanceState)  
            {  
                super.onCreate(savedInstanceState);  
                Bundle bundle = getArguments();  
                if (bundle != null)  
                {  
                    mArgument = bundle.getString(ARGUMENT);  
                    Intent intent = new Intent();  
                    intent.putExtra(RESPONSE, "good");  
                    getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);  
                }  
    
            }  
            ////在实例化时获取Activity传入的值(这里示例为String类型)
            public static ContentFragment newInstance(String argument)  
            {  
                Bundle bundle = new Bundle();  
                bundle.putString(ARGUMENT, argument);  
                ContentFragment contentFragment = new ContentFragment();  
                contentFragment.setArguments(bundle);  
                return contentFragment;  
            }  
    
            @Override  
            public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                    Bundle savedInstanceState)  
            {  
                Random random = new Random();  
                TextView tv = new TextView(getActivity());  
                ///.........
                return tv;  
            }  
        }
    
    • 一个抽象Activity 用于简单状态Fragment 的Activity自身代码的复用
    public abstract class SingleFragmentActivity extends FragmentActivity  {  
        protected abstract Fragment createFragment();  
        @Override  
        protected void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_single_fragment);  
            FragmentManager fm = getSupportFragmentManager();  
            Fragment fragment =fm.findFragmentById(R.id.id_fragment_container);  
            if(fragment == null )  
            {  
                fragment = createFragment() ;  
                fm.beginTransaction().add(R.id.id_fragment_container,fragment).commit();  
            }  
        }  
    }
    

    感谢阅读

    相关文章

      网友评论

          本文标题:Android学习整理 -1- Fragment 学习

          本文链接:https://www.haomeiwen.com/subject/wpnrgttx.html