文档章节

Fragment

 小牛仔
发布于 2015/02/13 13:46
字数 2115
阅读 75
收藏 1

如果使用Android3.0以下的版本,需要引入android.support.v4的JAR包,然后Activity继承FragmentActivity,通过getSupportFragmentManager获得FragmentManager。
Android在3.0以上版本,可直接使用Activity,通过getFragmentManager获得FragmentManager。

一. 生命周期:
onAttach(Activity):Fragment和Activity建立关联时调用。
onCreate(Bundle)
onCreateView(LayoutInflater, ViewGroup, Bundle):为Fragment加载布局时调用。
onActivityCreated(Bundle)
onStart()
onResume()
onPause()
onStop()
onDestroyView():Fragment中的布局被移除时调用。
onDestory()
onDetach():Fragment和Activity解除关联的时候调用。

二. 两种加载方法:
静态加载Fragment:在布局文件中直接布局<fragment>
<fragment android:id="@+id/id_fragment_title"
        android:name="com.test.fragment.TitleBarFragment"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
每一个fragment都需要一个唯一的标识,如果activity重启,系统可以用来恢复fragment(并且你也可以用来捕获fragment来处理事务,例如移除它. 有3种方法来为一个fragment提供一个标识:
为 android:id 属性提供一个唯一ID.
为 android:tag 属性提供一个唯一字符串.
如果以上2个都没有提供, 系统使用容器view的ID.

动态添加Fragment主要分为4步:
1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。

FragmentTransaction方法:
add(int containerViewId, Fragment fragment, String tag)  往containerView中添加一个Fragment
remove() 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
replace(int containerViewId, Fragment fragment, String tag) 使用Fragment替换当前的containerView,实际上就是remove()然后add()的合体
hide() 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
show() 显示之前隐藏的Fragment
detach() 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
attach() 重建view视图,附加到UI上并显示。
addToBackStack(String) 添加一个Fragment事务到回退栈。用户点击Back,就是Fragment回退栈不断的弹栈。
注:
将fragment从后台堆栈中弹出, 使用FragmentManager.popBackStack() (模拟用户按下BACK 命令).
使用FragmentManager.addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.

三. Fragment之间进行通信:
1. 在Fragment,使用getActivity()可以获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图了。

2. 在Activity,使用getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例。
但是以上两种方法都不提倡,因为Fragment和Activity之间耦合太紧,应采用观察者模式,设置Listener接口,在Activity中实现接口,在Fragment中调用接口函数,从而Fragment得事件就可以通知到Activity了。

3. 通过Hander来实现消息传送,但这也是紧耦合。
public void onAttach(Activity activity) {
    super.onAttach(activity);
    mActivity = (MainActivity) activity;
    mActivity.setHandler(mHandler);
}

4. 使用Bundle,也是紧耦合。
在Activity中动态添加Fragment时,用Bundle封装我们需要传递的数据。setArguments方法必须在fragment创建以后,添加给Activity前完成。
public void button(View view) {
    ArgFragment arg = new ArgFragment();
    Bundle bundle = new Bundle();
    bundle.putString("arg", "XXX");
    arg.setArguments(bundle);
    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.layout_fragment, arg);
    ft.commit();
 }
然后在ArgFragment取出Bundle对象:
Bundle bundle = getArguments();
if (bundle != null){
    String str = bundle.getString("arg");
}

四. 如果系统内存不足或者切换横竖屏或者app长时间在后台运行,Activity都可能会被系统回收,然后Fragment并不会随着Activity的回收而被回收,从而导致,Fragment丢失对应的Activity。解决方案是:

1. Activity重写onSaveInstanceState方法,将super.onSaveInstanceState(outState);注释掉,让其不再保存Fragment的状态,达到其随着Activity一起被回收的效果!

2. 根据savedInstanceState来区别处理:
public class MainActivity extends FragmentActivity {
    private FragmentManager fragmentManager;
    private AFragment aFragment;
    private BFragment bFragment;
    private int currentIndex = TempData.fragmentNo; //默认为0

    private void getIntentData() {
        boolean hasData = false;
        Bundle b = getIntent().getExtras();
        if( b!=null && !b.isEmpty() && b.containsKey("index") ) {
            hasData = true;
            int index = b.getInt("index");
            currentIndex = index;
        }
    }

    @Override
    /* can be restored via {@link #onCreate} or {@link #onRestoreInstanceState}
    * */
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("currentIndex", currentIndex);
        UtilLog.d(TAG, "MainActivity onSaveInstanceState(): currentIndex = " + currentIndex);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if ( savedInstanceState == null ) {
            UtilLog.d(TAG, "MainActivity onRestoreInstanceState(null)");
            changeFragment(currentIndex);
        } else {
            // 说明FragmentActivity曾经被系统回收,而Fragment可能是没有被回收的,
            // 需要先找回当前处于显示状态的Fragment,并找回所有没有被回收的Fragment,
            // 从而避免Fragment显示重叠。
            if (savedInstanceState.containsKey("currentIndex")) {
                currentIndex = savedInstanceState.getInt(
                        "currentIndex", TempData.fragmentNo);
                UtilLog.d(TAG, "MainActivity onRestoreInstanceState(savedInstanceState): currentIndex = " + currentIndex);
            }
            UtilLog.d(TAG, "MainActivity onRestoreInstanceState(savedInstanceState)");
            showExistedFragment(currentIndex);
        }
    }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        UtilLog.d(TAG, "MainActivity onCreate() <--");
        super.onCreate(savedInstanceState);
        getIntentData();

            setContentView(R.layout.activity_main);
            fragmentManager = getSupportFragmentManager();
        
            getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
                        WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

        if ( savedInstanceState == null ) {
            UtilLog.d(TAG, "MainActivity onCreate(null)");
            changeFragment(currentIndex);
        } else {
            // “内存重启”时调用, 此时Fragment可能还存在,需要通过Tag找回
            if (savedInstanceState.containsKey("currentIndex")) {
                currentIndex = savedInstanceState.getInt(
                        "currentIndex", TempData.fragmentNo);
                UtilLog.d(TAG, "MainActivity onCreate(savedInstanceState): currentIndex = " + currentIndex);
            }
            UtilLog.d(TAG, "MainActivity onCreate(savedInstanceState)");
            showExistedFragment(currentIndex);
        }
        UtilLog.d(TAG, "MainActivity onCreate() -->");
        }

    @Override
        protected void onNewIntent(Intent intent) {
        UtilLog.d(TAG, "MainActivity onNewIntent() <--");
            super.onNewIntent(intent);
            // must store the new intent unless getIntent() will return the old one
        setIntent(intent);

            if ( (Intent.FLAG_ACTIVITY_CLEAR_TOP & intent.getFlags()) != 0 ) {
            getIntentData();
            if( TempData.fragmentNo != currentIndex ) {
                    changeFragment(currentIndex);
            }
        }
    }

    private void hideFragment(FragmentTransaction fragmentTransaction) {
        if (aFragment != null ) {
            fragmentTransaction.hide(aFragment);
        }
        if (bFragment != null) {
            fragmentTransaction.hide(bFragment);
        }
    }

    private void changeFragment(int index) {
        FragmentTransaction fragmentTransaction = fragmentManager
                .beginTransaction();
        
        currentIndex = index;
        TempData.fragmentNo = index;
        hideFragment(fragmentTransaction);
        
        switch (index) {
        case 0:
            if(aFragment!=null && aFragment.isAdded()){
                fragmentTransaction.show(aFragment);
            }else {
                aFragment = new AFragment();
                    fragmentTransaction.add(R.id.details, aFragment, "AFragment");
            }
            break;
        case 1:
            if(bFragment!=null && bFragment.isAdded()){
                fragmentTransaction.show(bFragment);
            }else {
                bFragment = new BFragment();
                    fragmentTransaction.add(R.id.details, bFragment, "BFragment");
            }
            break;
        default:
            break;
        }
        fragmentTransaction.commitAllowingStateLoss();
    }
    
    private void showExistedFragment(int index) {
        Fragment first = fragmentManager.findFragmentByTag("AFragment");
        if(first!=null && first instanceof AFragment) {
            aFragment = (AFragment) first;
        }
        
        Fragment second = fragmentManager.findFragmentByTag("BFragment");
        if(second!=null && second instanceof BFragment) {
            bFragment = (BFragment) second;
        }
        
        changeFragment(index);
    }
}

Fragment内存重启的模拟和处理:
adb shell pm list packages     读取到本机安装的应用列表
adb shell am kill 包名        将该应用置于后台,然后模拟该应用的内存重启

 

http://www.yrom.net/blog/2013/03/10/fragment-switch-not-restart/

http://www.cnblogs.com/kissazi2/p/4116456.html

五. 第三方fragmentation
// https://github.com/YoKeyword/Fragmentation
    compile 'me.yokeyword:fragmentation:0.10.4'

1. 加载多个同级根Fragment,没有添加Fragment事务到回退栈。切换采用showHideFragment(...)

public class MainActivity extends SupportActivity{
    @Override
    /* can be restored via {@link #onCreate} or {@link #onRestoreInstanceState}
    * */
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("mSelectedTabbar", mSelectedTabbar);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.zhihu_activity_main);

        if (savedInstanceState == null) {
            mFragments[FIRST] = ZhihuFirstFragment.newInstance();
            mFragments[SECOND] = ZhihuSecondFragment.newInstance();
            mFragments[THIRD] = ZhihuThirdFragment.newInstance();
            mFragments[FOURTH] = ZhihuFourthFragment.newInstance();
            // loadMultipleRootFragment的作用:
            // 一次性加载多个Fragments,但是containerId只默认显示其中一个,
            // 默认显示的那个Fragment会依次调用onCreateView(),onLazyInitView()
            // 其他被隐藏的Fragment会依次调用onHiddenChanged(true),onCreateView()
            loadMultipleRootFragment(R.id.fl_container, FIRST,
                    mFragments[FIRST],
                    mFragments[SECOND],
                    mFragments[THIRD],
                    mFragments[FOURTH]);
        } else {
            // 这里库已经做了Fragment恢复,所有不需要额外的处理了, 不会出现重叠问题
            // 这里我们需要拿到mFragments的引用,也可以通过getSupportFragmentManager.getFragments()自行进行判断查找(效率更高些),用下面的方法查找更方便些
            mFragments[FIRST] = findFragment(ZhihuFirstFragment.class);
            mFragments[SECOND] = findFragment(ZhihuSecondFragment.class);
            mFragments[THIRD] = findFragment(ZhihuThirdFragment.class);
            mFragments[FOURTH] = findFragment(ZhihuFourthFragment.class);
            if ( savedInstanceState.containsKey("mSelectedTabbar") ) {
                mSelectedTabbar = savedInstanceState.getInt("mSelectedTabbar", FIRST);
            }
        }
        initView();
    }


    public void onTabSelected(int position, int prePosition) {
                mSelectedTabbar = position;
                // 在做Fragment的切换时,showHideFragment的作用:
                // 待显示的Fragment如果没有加载过界面,会先调用onLazyInitView(),然后调用onHiddenChanged(false)
                // 待隐藏的Fragment调用onHiddenChanged(true)
                showHideFragment(mFragments[position], mFragments[prePosition]);
            }

}

public class NewFeatureFragment extends SupportFragment {

@Override
    public void onLazyInitView(@Nullable Bundle savedInstanceState) {
        super.onLazyInitView(savedInstanceState);
        // 懒加载
        // 同级Fragment场景、ViewPager场景均适用
    }

    @Override
    public void onSupportVisible() {
        super.onSupportVisible();
        // 当对用户可见时 回调
        // 不管是 父Fragment还是子Fragment 都有效!
    }

    @Override
    public void onSupportInvisible() {
        super.onSupportInvisible();
        // 当对用户不可见时 回调
        // 不管是 父Fragment还是子Fragment 都有效!
    }
}

2. loadRootFragment(int containerId, SupportFragment toFragment)
加载根Fragment,将Fragment事务添加到回退栈中,是栈底元素。

3. replaceLoadRootFragment(int containerId, SupportFragment toFragment, boolean addToBack)
以replace方式加载根Fragment, 由addToBack参数决定是否将Fragment事务添加到回退栈。

public class MainActivity extends SupportActivity {
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            // 加载根Fragment,这里是将HomeFragment事务添加到回退栈中,是栈底元素
            loadRootFragment(R.id.fl_container, HomeFragment.newInstance());
        }
    }

    // 不管切换多少项,内存中始终只保留根Fragment(HomeFragment)和可见的Fragment。
    public void changeContainer( int id ) {
        
                final SupportFragment topFragment = getTopFragment(); // 获取根Fragment

                if (id == R.id.nav_home) {
                    HomeFragment fragment = findFragment(HomeFragment.class);
                    Bundle newBundle = new Bundle();
                    newBundle.putString("from", "主页-->来自:" + topFragment.getClass().getSimpleName());
                    fragment.putNewBundle(newBundle);
                    start(fragment, SupportFragment.SINGLETASK);
                } else if (id == R.id.nav_discover) {
                    DiscoverFragment fragment = findFragment(DiscoverFragment.class);
                    if (fragment == null) {
                        // 将栈中的Fragment出栈直到HomeFragment为止,
                        // 出栈的Fragment会被析构掉,出栈完成后,启动DiscoverFragment并入栈.
                        popTo(HomeFragment.class, false, new Runnable() {
                            @Override
                            public void run() {
                                start(DiscoverFragment.newInstance());
                            }
                        });
                    } else {
                        // 如果已经在栈内,则以SingleTask模式start,也可以用popTo
                        start(fragment, SupportFragment.SINGLETASK);
                    }
                } else if (id == R.id.nav_msg) {
                    ShopFragment fragment = findFragment(ShopFragment.class);
                    if (fragment == null) {
                        popTo(HomeFragment.class, false, new Runnable() {
                            @Override
                            public void run() {
                                start(ShopFragment.newInstance());
                            }
                        });
                    } else {
                        // 如果已经在栈内,则以SingleTask模式start,也可以用popTo
                        popTo(ShopFragment.class, false);
                    }
                } 
    }
}

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 34
码字总数 35169
作品 0
成都
Fragment与Fragment相互切换之间的生命周期方法

Fragment 1 切换到 Fragment 2时生命周期变化 1、通过 add hide show 方式来切换 Fragment Fragment1 的生命周期变化为:onCreate()、onCreateView、onStart()、onResume() Fragment2 ...

李培能
08/01
0
0
Android的Fragment

1、Fragment的产生与介绍 Android 运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布 局以...

西红柿的眼泪
2016/07/22
17
0
构建灵活的界面

在设计支持各种屏幕尺寸的应用时,你可以在不同的布局配置中重复使用 Fragment ,以便根据相应的屏幕空间提供更出色的用户体验。 例如,一次只显示一个 Fragment 可能就很适合手机这种单窗格...

海阔天空玩世不恭
2015/12/29
6
0
Android之Fragment

目录: 一. Fragment的生命周期 二.静态加载Fragment 三.动态加载Fragment <用的V4包> 四.Activity向Fragment通信 五.Fragment向Activity通信 六.Fragment中更新activity中的ui组件 七.Frag...

我家的猫跳楼了
2015/09/09
20
0
Android Fragment基本用法

Fragment   Android是在Android 3.0 (API level 11)开始引入Fragment的。   可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的生命周期,单独处理自己的输入,在Act...

PurpleXuan
2015/04/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

自定义Ubuntu/Windows双系统引导菜单主题

学习Linux自然少不了要装双系统,其中Ubuntu便是我们用的最多的Linux系统。装完双系统后,Ubuntu会自动生成grub开机引导及菜单,及其丑陋,而且很多我们用不到的选项。今天我们就介绍burg:修...

Linux就该这么学
3分钟前
0
0
Go 并发(二)

Go Mutex 通过Mutex和信道处理竞态条件。 临界区 当程序并发运行时,多个协程不应该同时访问那些修改共享资源的代码,这些修改共享资源的代码称为临界区。 Go中通过Mutex可以避免同时访问临界...

春哥大魔王的博客
6分钟前
0
0
CentOS 7安装和部署Docker

Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker 。通过 uname -r 命令查看你当前的内核版本 uname -r3.10.0-514.el7.x86_64 1、...

狼王黄师傅
9分钟前
0
0
php扩展可以通过pecl 或者phpize 安装

pecl 算是 php 扩展的一个官方聚合平台,一些比较有名,有特点的扩展会被 pecl 收录,收录后可以通过 pecl 的方式安装。但是更多的扩展是没有收录在 pecl 上的,这些扩展还是需要通过 phpize...

bengozhong
10分钟前
0
0
CentOS中如何安装7ZIP

执行以下命令下载安装: wget http://nchc.dl.sourceforge.net/project/p7zip/p7zip/9.20.1/p7zip_9.20.1_src_all.tar.bz2tar -jxvf p7zip_9.20.1_src_all.tar.bz2cd p7zip_9.20.1make......

凯文加内特
16分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部