fragment 订阅
《Fragment》是花想创作的网络小说,发表于晋江文学网。 展开全文
《Fragment》是花想创作的网络小说,发表于晋江文学网。
信息
作    者
花想
中文名称
Fragment
主    角
亞瑟.柯克蘭,伊莉莎白。女王 [1]
连载平台
晋江文学网
连载状态
连载中 [1]
DevExpress控件应用
作品简介玫瑰枯零了,我会为你栽种新的。婚戒失去了,我会为你亲手戴上专属的。悔懊和骄傲埋在四百年前的土壤下,由泪水疯狂哀恨灌溉至死--或是我以为我会因此而死。然而,四百年後的陵墓破裂了,阳光从冬季复醒,而我看见了爱意与思念的花藤蔓生而出--CP为亚瑟与女王,女王的鬼魂(?)穿越来到现代再续前缘,架空历史向的一篇。有Doctor Who神奇串场、阿尔大发醋劲。原为一年前的即兴短文,结果後面越写越认真了到现在还未完结…… [1] 
收起全文
精华内容
下载资源
问答
  • fragment
    千次阅读
    2022-01-07 12:04:14

    原理

    点击fragment后原来的fragment的位置变为了空的是因为你把fragment加入到回退栈BackStack 。你把放在栈中的fragment弹出栈后(也就是remove()删除了该fragment)或者全部fragment隐藏后 ,放frament的位置的显示的内容都没有了 也就是不显示了任何的控件(只剩下一个空壳activity)因为被你删除了要显示的内容)

    隐藏fragment的方法如下

    
        /**
         * 隐藏所有已加入的fragment
         * //yourFragments 是指你要hide()起来的fragment 可以自己把要隐藏的fragment自己传过来
         */
        public static void setFragmentsHidden(AppCompatActivity activity, List<Fragment> yourFragments) {
    
            if (null == yourFragments) { //没有就不需要清理
                return;
            }
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            final FragmentTransaction transaction = fragmentManager.beginTransaction();
            for (int i = 0; i < yourFragments.size(); i++) {
                Fragment fragment = yourFragments.get(i);
                transaction.hide(fragment);
            }
            transaction.commitAllowingStateLoss();
        }
    

    解决办法

    • 第一步. 将该第一个fragment(也就是默认加载的fragment)不加入到回退栈 直接和activity绑定在一起,跟随avtivity消亡, 其他要跳转的fragment加到回退栈
      这时候第一个加入的fragment就和activity在一起了 当剩下绑定在activity的fragment的时候按返回键键直接和avtivity一起消失,就不会留下空壳的activity

      • 第二步 重写onBackPressed() 每回退一次(就是按下返回键)就把回退栈的栈顶fragment出栈,然后把出栈后的栈顶的fragment显示出来就行了
       /**
         * 重写返回按钮方法 退fragment时退到null fragments时直接退出
         */
        @Override
        public void onBackPressed() {
    
            FragmentManager fragmentManager = this.getSupportFragmentManager();
    
            // 测试代码段
            Log.d("fragmentsAddedInStack", "========================================");
            Log.d("fragmentsAddedInStack", "系统栈里fragment一共有  " + fragmentManager.getBackStackEntryCount());
            Log.d("fragmentsAddedInStack", "fragmentsAddedInStack fragment一共有  " + fragmentsAddedInStack.size());
            for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
                Log.d("fragmentsAddedInStack", "BackStackEntryCount" + i + " " + fragmentManager.getBackStackEntryAt(i).getName());
            }
            Log.d("fragmentsAddedInStack", "========================================");
    
            int stackEntryCount = fragmentManager.getBackStackEntryCount();
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            // 如果返回栈里只有一个fragment了 退出栈顶的这个唯一一个的fragment后,显示默认绑定到activity的的fragment(默认绑定到activity的的fragment默认放到自定义的存储栈里)
            if (stackEntryCount >= 1) {// 返回栈里还有添加到栈里的fragment
                fragmentManager.popBackStack();
                // 推出栈顶的fragment
                fragmentsAddedInStack.remove(fragmentsAddedInStack.size() - 1);
                // 将退栈后 栈的栈顶的fragment显示出来
                transaction.show(fragmentsAddedInStack.get(fragmentsAddedInStack.size() - 1));
                transaction.commit();
            } else if (stackEntryCount == 0) { // 如果返回栈里没有Fragment 就直接销毁activity
                finish();
            }
        }
    

    自己做的用这个方法封装activity 需要的可以自己用

    package com.crystallightghot.frscommunityclient.view.activity;
    
    import android.app.Application;
    import android.content.Context;
    import android.os.Bundle;
    import android.util.Log;
    import androidx.fragment.app.Fragment;
    import androidx.fragment.app.FragmentManager;
    import androidx.fragment.app.FragmentTransaction;
    import com.crystallightghot.frscommunityclient.R;
    import com.crystallightghot.frscommunityclient.view.util.ActivityUtile;
    import com.xuexiang.xui.XUI;
    import lombok.Getter;
    import lombok.Setter;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Getter
    public abstract class FragmentNeededActivity extends BaseActivity {
    
        // 加入到返回栈的fragment 默认加载到activity的fragment为栈底 模拟返回栈的内容
        private final List<Fragment> fragmentsAddedInStack = new ArrayList<>();
        // 添加到activity的fragment
        private final List<Fragment> allFragmentAdded = new ArrayList<>();
        // 用来替换fragment的布局的ID
        @Setter
        private int fragmentContainerId;
    
    
        // 默认在activity显示的fragment并且不加入到返回栈的fragment
        Fragment defaultFragment;
    
        public FragmentNeededActivity() {
            setContainerId();
            setDefaultFragment();
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.contract_frscbase_contract);
            Context context = XUI.getContext();
            XUI.init((Application) context);
    
            FragmentManager fragmentManager = this.getSupportFragmentManager();
            List<Fragment> fragments = fragmentManager.getFragments();
            Log.d("测试", "fragments 里的数量========" + fragments.size() + "===========");
            ActivityUtile.removeAllFragments(this, fragments);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
    
            // 添加默认fragment 到页面
            ActivityUtile.showFragment(getDefaultFragment(), this, false);
        }
    
        /**
         * 重写返回按钮方法 退fragment时退到null fragments时直接退出
         */
        @Override
        public void onBackPressed() {
    
            FragmentManager fragmentManager = this.getSupportFragmentManager();
    
            // 测试代码段
            Log.d("fragmentsAddedInStack", "========================================");
            Log.d("fragmentsAddedInStack", "系统栈里fragment一共有  " + fragmentManager.getBackStackEntryCount());
            Log.d("fragmentsAddedInStack", "fragmentsAddedInStack fragment一共有  " + fragmentsAddedInStack.size());
            for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
                Log.d("fragmentsAddedInStack", "BackStackEntryCount" + i + " " + fragmentManager.getBackStackEntryAt(i).getName());
            }
            Log.d("fragmentsAddedInStack", "========================================");
    
            int stackEntryCount = fragmentManager.getBackStackEntryCount();
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            // 如果返回栈里只有一个fragment了 退出栈顶的这个唯一一个的fragment后,显示默认绑定到activity的的fragment(默认绑定到activity的的fragment默认放到自定义的存储栈里)
            if (stackEntryCount >= 1) {// 返回栈里还有添加到栈里的fragment
                fragmentManager.popBackStack();
                // 推出栈顶的fragment
                fragmentsAddedInStack.remove(fragmentsAddedInStack.size() - 1);
                // 将退栈后 栈的栈顶的fragment显示出来
                transaction.show(fragmentsAddedInStack.get(fragmentsAddedInStack.size() - 1));
                transaction.commit();
            } else if (stackEntryCount == 0) { // 如果返回栈里没有Fragment 就直接销毁activity
                finish();
            }
        }
    
        /**
         *
         * @param defaultFragment 默认加载、、绑定在activity并且不加入系统回退栈的fragment
         */
        public void setDefaultFragment(Fragment defaultFragment) {
            // 将默认加载的fragment加入到自定义的回退栈中
            fragmentsAddedInStack.add(defaultFragment);
            this.defaultFragment = defaultFragment;
        }
    
        /**
         * 设置加载fragment的容器的ID
         */
        abstract void setContainerId();
    
        /**
         * 设置默认加载到activity的fragment
         */
        abstract void setDefaultFragment();
    }
    
    

    ActivityUtil类

    package com.crystallightghot.frscommunityclient.view.util;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.fragment.app.Fragment;
    import androidx.fragment.app.FragmentManager;
    import androidx.fragment.app.FragmentTransaction;
    import com.crystallightghot.frscommunityclient.view.activity.FragmentNeededActivity;
    
    import java.util.List;
    
    /**
     * @author crystallightghost
     * @date 2022/1/6
     * @Version: 1.0
     * description:
     */
    /*
     * @Description TODO
     * @Date 2022/1/6 11:20
     * @Created by CrystalLightGhost
     */
    public class ActivityUtile {
    
        /**
         * 清楚原来fragment里现有的fragment
         */
        public static void removeAllFragments(AppCompatActivity activity, List<Fragment> fragmentsNeededHidden) {
    
            if (null == fragmentsNeededHidden) {
                return;
            }
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            for (int i = 0; i < fragmentsNeededHidden.size(); i++) {
                fragmentTransaction.remove(fragmentsNeededHidden.get(i));
            }
            fragmentTransaction.commit();
        }
    
        /**
         * 隐藏所有已加入的fragment
         */
        public static void hideFragment(AppCompatActivity activity, Fragment fragment) {
    
            if (null == fragment) { //没有就不需要清理
                return;
            }
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            final FragmentTransaction transaction = fragmentManager.beginTransaction();
            transaction.hide(fragment);
            transaction.commitAllowingStateLoss();
        }
    
        public static void showFragment(Fragment showedFragment, FragmentNeededActivity activity) {
            showFragment(showedFragment, activity,  true);
        }
    
        /**
         * 添加fragment
         *
         * @param showedFragment        要添加的fragment
         * @param activity              使用此方法的activity
         * @param isAddedToBackStack    是否将显示的fragment添加到返回栈
         *                              一般只把activity默认的加载的fragment(也就是第一个fragment)设为false 不加入退回栈中
         */
        public static void showFragment(Fragment showedFragment, FragmentNeededActivity activity, boolean isAddedToBackStack) {
            //获取隐藏fragment
            List<Fragment> fragmentsNeededHidden = activity.getAllFragmentAdded();
            // 替换fragment的控件的ID
            int viewId = activity.getFragmentContainerId();
            // 隐藏所有fragment
            if (null != fragmentsNeededHidden && fragmentsNeededHidden.size() != 0) {
                setFragmentsHidden(activity, fragmentsNeededHidden);
            }
    
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            final FragmentTransaction transaction = fragmentManager.beginTransaction();
            // 已经添加fragment 直接显示出来
            if (showedFragment.isAdded()) {
                transaction.show(showedFragment);
            } else {
                // 添加fragment
                transaction.add(viewId, showedFragment, showedFragment.getClass().getSimpleName());
                fragmentsNeededHidden.add(showedFragment);
                // 如果新fragment添加到回退栈
                if (isAddedToBackStack) {
                    transaction.addToBackStack(showedFragment.getClass().getSimpleName());
                    // 记录加入到返回栈的fragment
                    activity.getFragmentsAddedInStack().add(showedFragment);
                }
            }
            transaction.commit();
        }
    
        /**
         * 隐藏所有已加入的fragment
         */
        public static void setFragmentsHidden(AppCompatActivity activity, List<Fragment> yourFragments) {
    
            if (null == yourFragments) { //没有就不需要清理
                return;
            }
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            final FragmentTransaction transaction = fragmentManager.beginTransaction();
            for (int i = 0; i < yourFragments.size(); i++) {
                Fragment fragment = yourFragments.get(i);
                transaction.hide(fragment);
            }
            transaction.commitAllowingStateLoss();
        }
    
    }
    
    

    使用例子

    public class LoginAndRegisterActivity extends FragmentNeededActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login_register);
            ButterKnife.bind(this);
            init();
        }
    
        @Override
        void setContainerId() {
            setFragmentContainerId(R.id.fragmentContainer);
        }
    
        @Override
        void setDefaultFragment() {
            setDefaultFragment(LoginFragment.newInstance("LoginFragment"));
        }
    
        private void init() {
    
    
        }
    }
    

    activity_login_register xml的代码

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
            android:id="@+id/fragmentContainer"
            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"
            tools:context=".view.activity.LoginAndRegisterActivity"/>
    
    
    
    更多相关内容
  • 本文力求为大家说明Fragment如何产生,什么是FragmentFragment生命周期,如何静态和动态的使用FragmentFragment回退栈,Fragment事务;以及Fragment的一些特殊用途,例如:没有布局的Fragment有何用处?Fragment...
  • Android 关于fragment切换重新加载的解决方法

    千次下载 热门讨论 2015-12-31 16:04:40
    在项目中需要进行Fragment的切换,一直都是用replace()方法来替换Fragment 但是,这样会有一个问题 ,应该很多朋友都遇到过: 每次切换的时候,Fragment都会重新实例化,也就是运行OnCreatVIew()方法 那么如何让多个...
  • Android解决多个Fragment切换时布局重新实例化问题,并保存当前fragment页面,系统回收后还原之前fragment页面,更新版
  • Android Fragment

    千次阅读 2022-04-26 13:34:41
    1.Fragment fragment译为“碎片”,是Android 3.0(API 11)提出的,最开始是为了适配大屏的平板。 Fragment看起来和Activity一样,是一个用户界面。可以结合多个Fragments到一个activity中,来构建一个有多方面...

    1.Fragment

    fragment译为“碎片”,是Android 3.0(API 11)提出的,最开始是为了适配大屏的平板。

    Fragment看起来和Activity一样,是一个用户界面。可以结合多个Fragments到一个activity中来构建一个有多方面功能的UI,还可以重用同一个Fragment在多个activities中。Fragment可以当成是activity的一个组件,每个Fragment有单独的生命周期,可以在activity运行时进行添加和移除Fragment。因此,相比较于activity,Fragment更加轻量级,更加灵活。

    一个Fragment总是被植入在一个activity中 ,并且其生命周期受其父activity直接影响,比如activity处于暂停,则其中的Fragment都暂停;activity销毁,则所有Fragment都销毁。但是,当一个activity运行时,你可以独立的操作每一个Fragment,比如添加和删除他们。进行类似的操作时,可以将Fragment添加入被activity管理的后退栈中,这样用户可以通过点击返回按钮来返回之前打开的Fragment。

    Fragment可以作为activity的一部分添加到布局文件中,通过声明元素作为ViewGroup的一部分。也可以将Fragment作为一个没有自己UI的不可见的activity的工人。

    总结一下:

    ①Fragment是依赖于Activity的,不能独立存在。

    ②一个Activity里可以有多个Fragment。

    ③一个Fragment可以被多个Activity重用。

    ③Fragment有自己的生命周期,并能接收输入事件。

    ④可以在Activity运行时动态地添加或删除Fragment。

     

    2.Fragment生命周期

    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

     常见的周期流程

    ①Activity加载Fragment的时候,依次调用:onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() ->onResume()

    ②当做出一个悬浮的对话框风格的Activity,或者其他,就是让Fragment所在的Activity可见,但不获得焦点:onPause()

    ③当对话框关闭,Activity又获得了焦点: onResume()

    ④当替换Fragment,并调用addToBackStack()将它添加到Back栈中:onPause() -> onStop() -> onDestoryView() 。注意,此时的Fragment还没有被销毁哦。

    ⑤当按下键盘的回退键,Fragment会再次显示出来:onCreateView() -> onActivityCreated() -> onStart() -> onResume()

    ⑥如果替换后,在事务commit之前没有调用addToBackStack()方法将Fragment添加到back栈中,或者退出了Activity的话,那么Fragment将会被完全结束,Fragment会进入销毁状态: onPause() -> onStop() -> onDestoryView() -> onDestory() -> onDetach()

     

    3.Fragment创建

    ①静态加载--以<fragment>标签的形式添加到Activity的布局当中。

    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

     1)定义Fragment的布局,就是fragment显示内容

    2)自定义一个Fragment类,需要继承Fragment或者它的子类,重写onCreateView()方法,在该方法中调用inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象。

    public class Fragmentone extends Fragment {

        private View view;

        @Override

        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

            if(view == null) {

                View view = inflater.inflate( R.layout.fragment1, container,false);

            }

            return view;

        }

    }

    3)在需要加载Fragment的Activity对应的布局文件中添加fragment的标签,注意name属性是全限定类名,就是要包含Fragment的包名。

    4)Activity在onCreate( )方法中调用setContentView()加载布局文件。

    ②动态加载--通过java代码将fragment添加到已存在的宿主Activity中

    watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a2f6Iqz6Iqz,size_20,color_FFFFFF,t_70,g_se,x_16

    动态添加fragment常用的类:

    FragmentManager:用来管理Activity中的fragment,app包中使用getFragmentManager() v4包中getSupportFragmentManager。可以通过findFragmentById获取指定的Fragment,可以调用popBackStack()方法弹出后台Fragment,还可以调用addToBackStack()方法加入栈,或监听后台栈的变化:addOnBackStackChangeListener。

    FragmentTransaction:事务,用来添加、移除、替换fragment,记得在操作完后用commoi()提交事务。FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务

    transaction.add():往Activity中添加一个Fragment

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

    transaction.replace():使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体。

    transaction.hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁

    transaction.show():显示之前隐藏的Fragment

    transaction.commit():提交一个事务

    detach():会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。

    注意:在用fragment的时候,可能会经常遇到Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。

    这些基本是操作Fragment的所有方式了,在一个事务开启到提交可以进行多个添加、移除、替换等操作。

    注意:使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。

    attach():重建view视图,附加到UI上并显示。

    1)比如:在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望回到A还能看到数据,则使用的就是hide和show;也就是说,希望保留用户操作的面板,可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。

    2)再比如:不希望保留用户操作,可以使用remove(),然后add();或者使用replace()这个和remove、add是相同的效果。

    3)remove和detach有一点细微的区别:在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果当前Activity一直存在,在不希望保留用户操作的时候,可以优先使用detach。

     

    4.Fragment与Activity的交互

    1)组件获取

    Fragment获得Activity中的组件: getActivity().findViewById(R.id.list);

    Activity获得Fragment中的组件(根据id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1);

    2)数据传递

    ①Activity传递数据给Fragment

    采用Bundle方式:在activity中创建Bundle数据包,把要传的值存入bundle,调用Fragment实例的setArguments(bundle)从而将Bundle数据包传给Fragment,,然后Fragment中调用getArguments获得Bundle对象,然后进行解析就可以了。

    举个例子:动态添加fragment的时候,在添加每个fragment之前,使用Bundle传输数据给每个fragment。

    mManager = getSupportFragmentManager();

    mTransaction = mManager.beginTransaction();

    homeFragment = new HomeFragment();

    //创建Bundle对象,并存储数据

    Bundle bundle=new Bundle();

    bundle.putString("home","Home");

    homeFragment.setArguments(bundle);

    fragment中接收数据:

    Bundle bundle = this.getArguments();

    String home = bundle.getString("home");

    ②Fragment传递数据给Activity

    采用接口回调方式:在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,Fragment就可以通过回调接口传数据了。

    首先定义一个接口回调接口:(Fragment中)

    public interface ICallBack{  

        public void getResult(String result);  

    }  

    接着在Fragment中设置接口回调的方法:

    public void getData(ICallBack callBack){  

        String msg = editText.getText().toString();  

        callBack.getResult(msg);  

    }  

    最后在Activity中回调:

    leftFragment.getData(new ICallBack() {  

     @Override  

       public void getResult(String result) { 

            Toast.makeText(this, result, 1).show();  

        }

    }); 

    ③Fragment与Fragment之间的数据互传

    不同的fragment之间的通信要依靠ativity来完成。可以看成Fragment->Activity->Fragment,因为两个或多个fragment是依附于同一个activity,所以完全可以通过把值传递到共同依附的Activity,然后通过Bundle传给另一个fragment。

    方式一:先调用findFragmentById()方法根据id获得fragment的对象,然后调用fragment中的方法进行赋值。

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

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

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

    然后,直接在一个Fragment中调用另外一个Fragment的公开方法,前提是要先拿到另外一个Fragment的实例。

    一般情况下,都是动态添加Fragment的,所以通过在add每个Fragment的时候,给每个Fragment设置个tag。

    manager = this.getSupportFragmentManager();

    transaction = manager.beginTransaction();

    LeftFragment leftFragment = new LeftFragment();

    RightFragment rightFragment = new RightFragment();

    transaction.add(R.id.left, leftFragment, "left");

    transaction.add(R.id.right, rightFragment, "right");

    transaction.commit();

    在Activity创建的时候,添加上所有的fragment,并为每个fragment设置tag,这样才会在每个fragment中通过findFragmentByTag()时,不会出现空指针。

    在LeftFragment中:

    RightFragment rightFragment = (RightFragment) getActivity().getSupportFragmentManager().findFragmentByTag("right");

    if (rightFragment == null) return;

    rightFragment .setTextView("right now");

    这样就实现了在LeftFragment里给RightFragment传值的效果。

    这种方式是两个fragment直接通信的。(不推荐使用)

    方式二:通过接口回调的方法实现两个fragment之间的通信

    比如点击MessageFragment的Button按钮,给CommunityFragment中的TextView传递数据。就需要在MessageFragment中定义接口,并定义回调的方法,该方法的参数中传一个String的字符串。接着让附属Activity实现这个接口,并重写回调方法,也就得到到传过来的数据,然后通过findFragmentByTag()的方法获取要传给的CommunityFragment的实例。

    在CommunityFragment中定义一个方法用来接收这个数据,然后用对象直接调用这个方法将参数传递给这个方法,就可以了。

    方式三:其他方式

    EventBus:使用方便,但其使用的是反射原理,会有稍微的延迟,并且他人维护不方便;

    static静态变量:使用方便,但是,每个static变量都会占用一块内存区,Android系统分配给每个App的内存是有限的(63M),过多很容易造成App内存溢出;

    广播Broadcast Receiver:Android的广播是有限制的,除了系统的广播外,其他的广播尽量少用。另外,广播会有延迟;

    接口:接口是常用的Fragment之间的通讯方式,通过一个主Activity作为通讯桥梁(谷歌官方声明:两个Fragment之间永远不要直接通讯),实现两个Fragment之间的通讯。

    接口的方式是推荐的,但是,传统的接口方式会造成一些问题,如果主Activity实现了多个Fragment的通讯回调接口,那就需要implements很多接口,类中还要实现一大堆接口的方法,显得有点繁琐。

    展开全文
  • Fragment

    千次阅读 2021-03-25 17:51:51
    1.Fragment简介 在Android3.0之前的版本,通常程序是在较小屏幕的设备上(手机等)。尽管手机屏幕尺寸、分辨率、屏幕密度等参数存在较大的差异,但是手机交互界面的操作习惯基本相同。例如,对于一个联系人管理程序...

    1.Fragment简介

    在Android3.0之前的版本,通常程序是在较小屏幕的设备上(手机等)。尽管手机屏幕尺寸、分辨率、屏幕密度等参数存在较大的差异,但是手机交互界面的操作习惯基本相同。例如,对于一个联系人管理程序,通常都会首先用一个窗口显示所有的联系人名称以及少数的联系人的详细信息(如联系人电话号码等)。然后当单击某一个联系人时会另外显示一个窗口列出该联系人的详细信息,当然,更进一步的操作还可能有修改、删除联系人等。不管与手机屏幕相关参数如何变化,在手机上的联系人管理程序除了界面风格略有差异外,操作的流程都和这一过程基本上类似。

    尽管界面的使用布局很容易实现,但是对于同时适应手机的平板电脑的APK程序就比较麻烦。通常是为不同的界面风格提供不同的布局文件,然后利用Android的本地化特性在不同的环境使用不同的布局文件。这种做法虽然可行,也能达到复用,但如果这类界面过多,就会造成布局文件过多,对于后期的维护就显得格外麻烦。为了解决这个问题,就需要一种可以布局、共享以及控制的通用式系统。

    其目的是为了解决不同屏幕分辩率的动态和灵活UI设计。大屏幕如平板小屏幕如手机,平板电脑的设计使得其有更多的空间来放更多的UI组件,而多出来的空间存放UI使其会产生更多的交互,从而诞生了fragments。

    2.Fragment的生命周期

    Fragment必须依赖于Activity而存在,因此Activity的生命周期会直接影响到Fragment的生命周期。如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。但是,当Activity在活动状态时,可以独立控制Fragment的状态,比如加上或者移除Fragment。当进行fragment transaction(转换)的时候,可以把Fragment放入Activity的back stack中,这样用户就可以返回操作。

    由图1可以看到,Fragment比Activity多了几个额外的生命周期回调函数。

    图1.Activity与Fragment生命周期的关系

    • onAttach(Activity):当Fragment与Activity发生关联时调用,从该方法开始,就可以通过Fragment.getActivity方法获取与Fragment关联的窗口对象了,但在该方法中仍然无法操作Fragment中的控件。
    • onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图。
    • onActivityCreate(Bundle):当Activity的onCreate方法返回时调用。
    • onDestroyView():与onCreateView相对应,当该Fragment的视图被移除时调用。
    • onDetach():与onAttach相对应,当Fragment与Activity关联被取消时调用。

    3.Fragment的简单使用

    1.静态地使用Fragment

    在layout文件下分别创建fragment1.xml和fragment2.xml布局文件,然后在创建一个类Fragment1,这个类继承自Fragment,重写onCreateView()方法绑定fragment1.xml。重复此步,创建Fragment2。

    package com.example.demo_test_for_fragment;
    
    import android.app.Fragment;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    
    public class Fragment1 extends Fragment {
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment1, container, false);
        }
    }

    然后在activity_main.xml布局文件中,静态使用fragemnt1和fragment2。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        android:baselineAligned="false">
        <fragment
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:id="@+id/fragment1"
            android:name="com.example.demo_test_for_fragment.Fragment1"/>
        <fragment
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:id="@+id/fragment2"
            android:name="com.example.demo_test_for_fragment.Fragment2"/>
    </LinearLayout>

    2.动态调用

    在activity_main.xml布局文件中,不静态使用fragment1和fragment2。在MainActivity的onCreate()方法根据屏幕的情况(竖屏或者横屏),使用不同的fragment。

    package com.example.demo_test_for_fragment;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.os.Bundle;
    import android.view.Display;
    
    public class MainActivity extends AppCompatActivity {
    
        @SuppressLint("ResourceType")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Display display = getWindowManager().getDefaultDisplay();
            if (display.getWidth() > display.getHeight()){//横屏采用fragment1
                Fragment1 fragment1 = new Fragment1();
                getFragmentManager().beginTransaction().replace(R.id.main_layout,fragment1).commit();
            }else{//竖屏采用fragment2
                Fragment2 fragment2 = new Fragment2();
                getFragmentManager().beginTransaction().replace(R.id.main_layout,fragment2).commit();
            }
        }
    }
    

    3.Fragment之间的通信

    Fragment的存在必须依附于Activity,FragmentActivity是继承自Activity的。Fragment之间通信的桥梁就是FragmentManager类,这个类是用来管理所有的Fragment的,所以可以找到任何一个所需要的Fragment类。另外,Activity一般都会包含多个Fragment,这时多个Fragment之间如何进行通信就是个非常重要的问题了。下面通过一个例子来演示一下,如何在一个Fragment中去访问另一个Fragment的视图。

    在静态代码上做修改。

    首先打开fragment2.xml,在这个布局里面添加一个按钮。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="fragment2"
            android:textSize="25sp"
            android:textColor="#000000"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            android:text="get fragemnt1 text"/>
    </LinearLayout>

    在fragment1.xml,为TextView添加一个id

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="fragment1"
            android:textSize="25sp"
            android:textColor="#000000"
            android:id="@+id/fragment1_text"/>
    
    </LinearLayout>

    打开Fragment2.java,添加onActivityCreated方法,并处理按钮的单击事件。

    package com.example.demo_test_for_fragment;
    
    import android.app.Fragment;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import androidx.annotation.Nullable;
    
    public class Fragment2 extends Fragment {
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment2, container, false);
        }
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            Button button = getActivity().findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TextView textView = getActivity().findViewById(R.id.fragment1_text);
                    Toast.makeText(getActivity(),textView.getText(),Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    运行效果如下图。如何实现的呢?主要通过getActivity方法可以让Fragment获取关联的Activity,然后再调用Activity的findViewById方法,就可以获取和这个Activity关联的其他Fragment的视图了。

     

    展开全文
  • Fragment实现懒加载

    2015-12-07 13:59:21
    Fragment初始化,Fragment切换,Fragment显示与否,以及Fragment隐藏;Demo中Fragment只创建一次,但可以一直刷新数据
  • Fragment与Activity之间的数据交换,大体上包括三种: 一、Fragment从Activity获取数据(本文章只介绍第一种); 二、Activity从Fragment获取数据; 三、Fragment之间获取数据。 实现效果: 从Activity传递数据到两...
  • Fragment启动流程分析

    千次阅读 2021-12-12 16:40:35
    Fragment已经成为Android开发中应用比较广泛的方案了,几乎每一个APP都离不开它的影子。为了更深入的理解其中原理,我们从Fragment中源码开始分析。 Fragment生命周期 如果我们需要在Activity添加一个Fragment,...

    1.概述

    Fragment已经成为Android开发中应用比较广泛的方案了,几乎每一个APP都离不开它的影子。为了更深入的理解其中原理,我们从Fragment中源码开始分析。

    Fragment生命周期
    在这里插入图片描述
    如果我们需要在Activity添加一个Fragment,代码如下:

    //MainActivity
    public class MainActivity extends Activity{
      ContentFragment mContentFragment;
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        mContentFragment = ContentFragment.newInstance(null);
        getFragmentManager()
            .beginTransaction()
            .replace(R.id.container,mContentFragment)
            .commit();
      }
    }
    

    先大致介绍下即将遇到的几个类。

    1. ActivityThread : Android 入口类
    2. Instrumentation : ActivityThread 的工具类
    3. HostCallbacks : Activity 的内部类,继承自 FragmentHostCallback
    4. FragmentHostCallback : 持有 Handler、FragmentManagerImpl 等等对象的引用,别的对象可以通过持有它的引用间接控制 FragmentManagerImpl 等等对象
    5. FragmentController : Activity 通过控制它间接向 FragmentManagerImpl 发出命令
    6. FragmentManagerImpl : 顾名思义,它继承自 FragmentManager,用来对 Fragment 进行管理,在 FragmentHostCallback 中被初始化
    7. BackStackRecord : 继承自 FragmentTransation 并实现了 Runnable,每次调用 FragmentManager 对象的 beginTransaction() 方法都会产生一个 BackStackRecord 对象,可以将其理解为对 Fragment 的一系列操作(即事务)
    8. Op : 每次对 Fragment 的操作都会产生一个 Op 对象,其表示双向链表的一个结点

    UML图:

    在这里插入图片描述

    2.Fragment事务的执行过程

    从getFragmentManager()方法开始:

    Activity.java

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    
    .....
    
    @Deprecated
    public FragmentManager getFragmentManager() {
        return mFragments.getFragmentManager();
    }
    

    这里的mFragments是FragmentController类实例,在Activity类内部申明时已经初始化,所以在ActivityThread中创建Activity实例的时候mFragments对象已被创建。

    再来看下FragmentController类中对应的方法;

    FragmentController.java

    private final FragmentHostCallback<?> mHost;
    
    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
       return new FragmentController(callbacks)
    }
    
    private FragmentController(FragmentHostCallback<?> callbacks) {
        mHost = callbacks;
    }
    
    public FragmentManager getFragmentManager() {
       return mHost.getFragmentManagerImpl();
    }
    

    FragmentController是把一个callback包装了起来,真正完成任务的是FragmentHostCallback。

    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    
    FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManagerImpl;
    }
    

    所以最终得到的是FragmentMangerImpl对象。

    之后继续Fragment的业务我们需要通过FragmentManger的beginTransaction方法得到一个事务,FragmentImpl中的具体实现为:

    final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
    
    public FragmentTransaction beginTransation() {
        return new BackStackRecord(this);
    }
    
    }
    

    FragmentTransation也是一个接口,他的具体实现为BackStackRecord,并且每次beginTrasaction时返回的都是一个新的事务对象,包括之后进行的后退操作都是通过这个事务对象看来管理的,BackStackRecord对象中保存了创建他的FragmentManagerImpl实例。

    BackStackRecord.java

    final class BackStackRecord extends FragmentTransation implements FragmentManager.BackStackEntry, Runnable {
    
    public FragmentTransation add(Fragment fragment, String tag) {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }
    
    public FragmentTransation add(int containerViewId, Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }
    
    public FragmentTransation add(int containerViewId, Fragment fragment, String tag) {
        doAddOp(containerViewId, fragment, tag, OP_ADD);
    }
    
    public FragmentTransation replace(int containerViewId, Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }
    
    public FragmentTransation replace(int containerViewId, Fragment fragment, String tag) {
        if (containerViewId == 0) {
            //replace操作必须要指定containerViewId.
       }
       doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    }
    
    public FragmentTransaction remove(Fragment fragment) {
       Op op = new Op();
       op.cmd = OP_REMOVE;
       op.fragment = fragment;
       addOp(op);
    }
    
    public FragmentTransaction hide(Fragment fragment) {
       Op op = new Op();
       op.cmd = OP_HIDE;
       op.fragment = fragment;
       addOp(op);
    }
    
    public FragmentTransaction show(Fragment fragment) {
       Op op = new Op();
       op.cmd = OP_SHOW;
       op.fragment = fragment;
       addOp(op);
    }
    
    public FragmentTransaction attach(Fragment fragment) {
       Op op = new Op();
       op.cmd = OP_ATTACH;
       op.fragment = fragment;
       addOp(op);
    }
    
    public FragmentTransaction detach(Fragment fragment) {
       Op op = new Op();
       op.cmd = OP_DETACH;
       op.fragment = fragment;
       addOp(op);
    }
    
    //新建一个操作,并给操作赋值。
    private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
        fragment.mFragmentManager = mManager;
       if (tag != null) {
           if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                 //如果这个 fragment 之前已经有了tag,那么是不允许改变它的。
          }
          fragment.mTag = tag;
       }
       if (containerViewId != 0) {
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                //如果这个fragment已经有了mFragmentId,那么不允许改变它。
           }
           fragment.mContainerId = fragment.mFragmentId = containerViewId;
       }
       Op op = new Op();
       op.cmd = opcmd;
       op.fragment = fragment;
       addOp(op);
    }
    //把操作添加到链表之中。
    void addOp() {
        if (mHead == null) {
            mHead = mTail = op;
        } else {
           op.prev = mTail;
           mTail.next = op;
           mTail = op;
        }
        mNumOp++}
    }
    

    可以看到我们调用add、remove、hide、replace等方法的时候,这些操作都会被实例化成Op对象,然后加入到一个集合中。这些操作真正被执行是在commit方法中。

    public int commit() {
        return commitInternal(false);
    }
    
    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) {
            //已经有事务处理,抛出异常。
        }
        mCommited = true;
        if (mAddToBackState) {
             mIndex = mManager.allocBackStackIndex(this);
        } else {
             mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
    }
    

    最终调用了FragmentManger的enqueueAction方法:

    FragmentManager.java

    public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            mPendingActions.add(action);
            scheduleCommit();
        }
    }
    
        private void scheduleCommit() {
            synchronized (this) {
                boolean postponeReady =
                        mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
                boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
                if (postponeReady || pendingReady) {
                    mHost.getHandler().removeCallbacks(mExecCommit);
                    mHost.getHandler().post(mExecCommit);
                }
            }
        }
    
    
        Runnable mExecCommit = new Runnable() {
            @Override
            public void run() {
                execPendingActions();
            }
        };
    
    
    public boolean execPendingActions() {
            ensureExecReady(true);
    
            boolean didSomething = false;
            while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
                mExecutingActions = true;
                try {
                    removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
                } finally {
                    cleanupExec();
                }
                didSomething = true;
            }
    
            doPendingDeferredStart();
            burpActive();
    
            return didSomething;
        }
    
    • 在调用commit之后,把BackStackRecord加入到FragmentManagerImpl的mPendingActions中,而且通过查看FragmentManager的源码也可以发现,所有对mPendingActions的添加操作只有这一个地方调用,
    • 当其大小为1时,会通过主线程的Handler post一个Runnable mExecCommit出去,当这个Runnable执行时调用execPendingActions()方法。
    • execPendingActions它会拿出这个mPendingActions当中的所有Runnable执行(如果它是 BackStackRecord调用过来的,那么就是调用BackStackRecord的run方法),并把这个列表清空。在每个BackStackRecord的run方法执行时,它是通过遍历BackStackRecord链表当中每个节点的cmd来判断我们之前通过FragmentTransation加入期望执行的那些操作的。
    • 可以看出execPendingActions这个方法很关键,因为它决定了我们添加的操作什么时候会被执行,我们看下还有那些地方调用到了它,为什么要分析这个呢,因为我们在项目当中发现很多来自于Fragment的异常都是由我们后面谈论的moveToState方法抛出的,而moveToState执行的原因是execPendingActions被调用了,因此了解它被调用的时机是我们追踪问题的关键,关于调用的时机,我们都总结在下面的注释当中了:
    <!-- Activity.java -->
    final void performStart() {
        mFragments.execPendingActions(); //有可能在 Activity 的 onStart 方法执行前
        mInstrumentation.callActivityOnStart(this);
    }
    
    final void performResume() {
        performRestart();
        mFragments.execPendingActions(); //如果是从 Stopped 过来的,那么有可能在 onStart 到 onResume 之间。
        ....
        mInstrumentation.callActivityOnResume(this);
        ....
        mFragments.dispatchResume(); 
        mFragments.execPendingActions(); //有可能在 onResume 到 onPause 之间。
    }
    
    <!-- FragmentManager.java -->
    public void dispatchDestroy() { //这个调用在 onDestroy 之前。
        execPendingActions();
    }
    
    public boolean popBackStackImmediate() {
        executePendingTransactions();
    }
    
    public boolean popBackStackImmediate(String name, int flags) {
        executePendingTransactions();
    }
    

    关于FragmentManager的讨论我们先暂时放一放,看一下BackStackRecord是怎么执行链表内部的操作的:

    public void run() {
        Op op = mHead;
        while (op != null) {
            switch(op.cmd) {
                 case OP_ADD:
                     Fragment f = op.fragment;
                     f.mNextAnim = op.enterAnim;
                     mManager.addFragment(f, false);
                     break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        //遍历 mAdded列表,找到 containerId 相同的 old Fragment.
                        if (old == f) {
                            op.fragment = f = null;
                        } else {
                            if (op.removed == null) {
                                 op.removed = new ArrayList<Fragment>();
                            }
                            op.removed.add(old); //这里要把replace之前的记下来是为了后退栈准备的。
                            if (mAddToBackStack) {
                                 old.mBackStackNesting += 1;
                            }
                            mManager.removeFragment(old, transition, transitionStyle);
                        }
                    }
                    if (f != null) { 
                         f.addFragment(f, false);
                    }
                    break;
                    //后面的remove,hide,show,attach,detach就是调用了FragmentManager中相应的方法,没什么特别的,就不贴出来了
                    case xxx:
                       
                }
            }
            op = op.next;
        }
        //mCurState此时为FragmentManager当前的状态,其余的参数不用管。    
        mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); 
        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        } 
    }
    

    我们来看一下FragmentManagerImpl对应的addFragment等操作:

    public void addFragment(Fragment fragment, boolean moveToStateNow) {
       makeActive(fragment); //加入到mActive列表中。
       if (!fragment.mDetached) {
           if (mAdd.contains(fragment)) {
               //已经在mAdded列表,抛出异常。
           }
           mAdded.add(fragment);
           fragment.mAdded = true;
           fragment.mRemoving = false;
           if (moveToStateNow) {
               moveToState(fragment);
           }
       }
    }
    
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
        final boolean inactive = !fragment.isInBackStack();
        if (!fragment.mDetach || inactive) {
            if (mAdded != null) {
                mAdded.remove(fragment); //从mAdded列表中移除。
            }
            fragment.mAdded = false;
            fragment.mRemoving = true;
            //这里会根据是否加入后退栈来判断新的状态,最后会影响到Fragment生命周期的调用,如果是没有加入后退栈的,那么会多调用onDestroy、onDetach方法。
            moveToState(fragment, inactive ? Fragment.INITIALZING : Fragment.CREATED, transition, transitionStyle, false); 
        }
    }
    
    public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
        if (!fragment.mHidden) {
           fragment.mHidden = true;
           if (fragment.mView != null) {
              fragment.mView.setVisibility(View.GONE);
           }
        }
        fragment.onHiddenChanged(true);
    }
    
    public void showFragment(Fragment fragment, int transition, int transitionStyle) {
        if (fragment.mHidden) {
            fragment.mHidden = false;
            if (fragment.mView != null) {
                 fragment.mView.setVisibility(View.VISIBLE);
            }
            fragment.onHiddenChanged(false);
        }
    }
    
    public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
        if (!fragment.mDetached) {
            fragment.mDetached = true;
            if (fragment.mAdded) {
                 if (mAdded != null) {
                     mAdded.remove(fragment);
                 }
                 fragment.mAdded = false;
                 moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
            }
        }
    }
    
    public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
        if (fragment.mDetached) {
             if (!fragment.mAdded) {
                  if (mAdded.contains(fragment)) {
                      //mAdded列表中已经有,抛出异常,
                  }
                  mAdded.add(fragment);
                  fragment.mAdded = true;
                  moveToState(fragment, mCurState, transition, transitionStyle, false);
             }
        }
    
    }
    

    这里的操作很多,我们需要明白以下几点:

    mActive和mAdded的区别:mActive表示执行过add操作,并且其没有被移除(移除表示的是在不加入后退栈的情况下被removeFragment),所有被动改变Fragment状态的调用都是遍历这个列表;而 mAdded则表示执行过add操作,并且没有执行detachFragment/removeFragment,也就是说Fragment 是存在容器当中的,但是有可能是被隐藏的(hideFragment)。
    attachFragment 必须保证其状态是 mDetach 的,而该属性的默认值是 false,只有在执行过 detach 方法后,才能执行,执行它会把 f.mView 重新加入到 container 中。
    detachFragment 会把 f.mView 从 container 中移除。
    removeFragment 和 detachFragment 会强制改变 Fragment 的状态,这是因为它们需要改变 Fragment 在布局中的位置,而这通过被动地接收 FragmentManager 状态(即所在Activity的状态)是无法实现的。在 removeFragment 时,会根据是否加入后退栈来区分,如果假如了后退栈,因为有可能之后会回退,而回退时遍历的是 mActive 列表,如果把它的状态置为Fragment.INITIALZING,那么在 moveToState方法中就会走到最后一步,把它从mActive列表中移除,就找不到了也就无法恢复,因此这种情况下Fragment最终的状态的和detachFragment是相同的。
    在加入后退栈时,detachFragment 时,会把 mDetach置为true,这种情况下之后可以执行 attachFragment操作但不能执行 addFragment操作;removeFragment 之后可以执行 addFragment操作但不能执行 attachFragment操作。
    showFragment 和 hideFragment 并不会主动改变 Fragment 的状态,它仅仅是回调 onHiddenChanged方法,其状态还是跟着 FragmentManager 来走。
    mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true);
    这个方法才是 Fragment的核心,它的思想就是根据 Fragment 期望进入的状态和之前的状态进行对比,从而调用 Fragment相应的生命周期,那么问题就来,什么是期望进入的状态呢,我认为可以这么理解:

    用户没有进行主动操作,但是 Fragment 和 FragmentManager的状态不一致,这时需要发生变化。
    用户进行了主动操作,无论Fragment和 FragmentManager的状态是否一致,因为 Fragment 的状态发生了变化,因此这时也需要执行。
    这里我们为了简便起见先看一下和生命周期有关的代码:

    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STOPPED = 3;          // Fully created, not started.
    static final int STARTED = 4;          // Created and started, not resumed.
    static final int RESUMED = 5;          // Created started and resumed.
    
    void moveToState(int newState, int transit, int transitStyle, boolean always) {
       if (!always && mCurState == newState) {
          return;
       }
       mCurState = newState;
       if (mActive != null) {
           for (int i = 0; i < mActive.size; i++) {
               //在addFragment中通过makeActive加入进去
               Fragment f = mActive.get(i);
               moveToState(f, newState, transit, transitStyle, false);
           }
       }
    }
    
    void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
        if (f.mState < newState) { //新的状态高于当前状态
            switch(f.mState) {
                 case Fragment.INITIALZING:
                     f.onAttach(mHost.getContext());
                     if (f.mParentFragment == null) {
                         mHost.onAttachFragment(f);
                     }
                     if (!f.mRetaining) {
                         f.performCreate(f.mSavedFragmentState);
                     }
                     if (f.mFromLayout) {
                         f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
                         if (f.mHidden) f.mView.setVisibility(View.GONE);
                         f.onViewCreated(f.mView, f.mSavedFragmentState);
                     }
                 case Fragment.CREATED:
                      if (newState > Fragment.CREATED) {
                          if (!f.mFromLayout) {
                              ViewGroup container = null;
                              if (f.mCotainerId != null) {
                                   cotainer = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                   if (container == null && !f.mRestored) {
                                      //no view found
                                   }
                              }
                              f.mContainer = container;
                              f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState); 
                              if (f.mView != null) {
                                   f.mInnerView = f.mView;
                                   if (Build.VERSION.SDK >= 11) {
                                       ViewCompact.setSaveFromParentEnable(f.mView, false);
                                   } else {
                                       f.mView = NoSaveStateFrameLayout.wap(f.mView);
                                   }
                                   if (f.mHidden) f.mView.setVisibility(View.GONE);
                                   f.onViewCreated(f.mView, f.mSavedFragmentState);
                              } else {
                                   f.mInnerView = null;
                              }
                          }
                          f.performActivityCreated(f.mSavedFragmentState);
                      }
                 case Fragment.ACTIVITY_CRREATED:
                 case Fragment.STOPPED:
                     if (newState > Fragment.STOPPED) {
                          f.performStart();
                     }
                 case Fragment.STARTED:
                     if (newState > Fragment.STARTED) {
                          f.performResume();
                     }
            }
        } else if (f.mState > newState) { //新的状态低于当前状态
            switch(f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        f.performPause();
                    }
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        f.performStop();
                    }
                case Fragment.STOPPED::
                    if (newState < Fragment.STOPPED) {
                        f.performReallyStop();
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        f.performDestroyView(); //调用onDestory()
                        if (f.mView != null && f.mContainer != null) {
                            f.mContainer.removeView(f.mView); //把Fragment的View从视图中移除。
                       }
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                          if (f.mAnimationAway != null) {
                              ...
                          } else {
                               if (!f.mRetaining) {
                                   f.performDestory();
                               } else {
                                  f.mState = Fragment.INITIALIZING;
                               }
                               f.onDetach();
                               if (!f.mRetaining) {
                                   makeInActive(f);//把Fragment从mActive中移除,并把Fragment的所有状态恢复成初始状态,相当于它是一个全新的Fragment。
                               } else {
                                   f.mHost = null;
                                   f.mParentFragment = null;
                                   f.mFragmentManager = null;
                                   f.mChildFragmentManager = null;
                               }
                          }
                    }
            }
    }
    

    到 moveToState方法中,我们看到了许多熟悉的面孔,就是我们平时最常谈到的 Fragment 的生命周期,通过这段代码我们就可以对它的生命周期有更加直观的理解。

    展开全文
  • 博客《Fragment详解之六——如何监听fragment中的回退事件与怎样保存fragment状态》对应源码,博客地址:http://blog.csdn.net/harvic880925/article/details/45013501
  • 【Android】Fragment 使用及浅析

    千次阅读 2022-04-14 18:05:24
    Android Fragment 浅析 Fragment 是在 Android 3.0 (API level 11) 开始引入的。每个 Fragment 拥有自己的布局以及生命周期。 Fragment不能独立存在,必须依赖于Activity。一个Activity里可以有多个Fragment,并且一...
  • Android Fragment嵌套ViewPager,ViewPager嵌套多个FragmentFragment的多层嵌套。csdn博客讲解地址:http://blog.csdn.net/qq_24956515/article/details/50990506
  • FragmentFragment一、什么是Fragment?二、为什么要有Fragment?三、Fragment的特点四、Fragment的生命周期五、将fragment添加到Activity的两种方式参考 Fragment 一、什么是FragmentFragment:是Android3.0开始...
  • Fragment中嵌套(Fragment+ViewPager)完整Demo

    千次下载 2016-03-12 17:25:00
    该Demo为Fragment中嵌套(Fragment+ViewPager),在实际的项目中要注意Activity和Fragment的生命周期,以及它们随时可能被销毁的情况。
  • Fragment与Activity使用Handler进行交互

    千次下载 热门讨论 2014-06-27 12:26:19
    这里简单介绍了Fragment和Activity使用Handler方式进行交互。
  • 这是一个关于从一个activity跳到fragment,再从fragment跳到activity的页面之间的跳转!!!
  • Android Fragment实例

    热门讨论 2013-02-03 15:42:04
    Android Fragment实例,对应的教程也在我的资源里
  • fragment简介

    千次阅读 2021-08-10 19:34:52
    文章目录Fragment1、什么是Fragment2、为什么要有Fragment3、Fragment有什么优点4、Fragment的生命周期5、Fragment使用的一些方法**1.将 fragment添加到Activity的两种方式**a.静态注册:以标签的形式添加到Activity...
  • 第二章 Fragment

    千次阅读 多人点赞 2020-04-11 21:17:16
    文章目录第二章 Fragment(一)定义(二)作用(三)生命周期(1)生命周期方法详解(2)生命周期调用场景(3)Fragment与Activity生命周期对比(四)将Fragment添加到Activity(1)在Activity的layout.xml布局文件...
  • Fragment嵌套Fragment

    千次阅读 2019-04-01 12:57:45
    问题1、fragment嵌套fragment不显示问题 通常时候,我们制作底部Tab切换,会用到fragment。即一个Activity下,使用4种fragment。这次遇到的问题是关于fragment再次嵌套fragmen的问题,功能需要在其中一个fragment中...
  • Android在Fragment中调用另一个Fragment

    千次阅读 2019-11-29 19:36:26
    Fragment中调用另一个Fragment 需求源于,想要在一个Fragment的内ListView中点击item,然后在相同的界面上覆盖显示对应item的内容(一个LinecChart) 最初想的是在一个PopUpwindow中加载LineChart,但是失败了,遂...
  • 新一代的Fragment管理库:Navigation

    千次阅读 2019-12-30 18:42:25
    在以往的Fragment使用中,我们都是使用Fragment的事务进行添加,删除,替换等操作,为了快速开发,我们也会自行封装一个FragmentController。在去年,Google推出了Navigation库,目标是更优雅的管理Fragment。 正文 ...
  • Android开发-Fragment嵌套Fragment

    千次阅读 2020-04-11 14:38:34
    Android开发-Fragment嵌套Fragment前言使用依赖远程仓库地址布局实现使用控件xml代码Java实现效果图项目地址 前言 在大多数公司中,他们会尽量少写Activity,多使用Fragment,使项目变成一个千层饼,在本文章中我会...
  • 本篇文章主要提供一种监听 Fragment 可见性监听的方案,完美多种 case,有兴趣的可以看看。废话不多说,开始进入正文。 在开发当中, fragment 经常使用到。在很多应用场景中,我们需要监听到 fragment 的显示与隐藏...
  • Android动态加载fragment(fragment复用)
  • Android之Fragment的概述和使用

    千次阅读 多人点赞 2021-05-25 20:22:59
    Fragment的概述和使用 Android 自 3.0 版本开始引入了碎片的概念,它可以让界面在平板上更好地展示,支持更加动态和灵活的UI设计。 一、什么是碎片 碎片(Fragment)是一种可以嵌入在活动当中的 UI 片段,它能让程序...
  • Fragment里边嵌套Fragment

    万次阅读 2018-09-24 12:08:55
    一、如何切换Fragment ①、了解FragmentManager FragmentManager fm = getSupportFragmentManager(); 作用:管理Fragment的显示,存储。 FragmentManger中有三个容器。 第一个用来存储,Fragment的View,并控制...
  • Fragment实现横竖屏布局

    千次下载 热门讨论 2013-07-05 19:05:26
    Fragment实现的横竖屏不一样的布局,详情http://blog.csdn.net/xiaanming/article/details/9254749

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 318,934
精华内容 127,573
关键字:

fragment