2019-03-19 Fragment详解

Fragment两种创建方式

fragment的创建方式有两种,所谓的静态创建就是通过XML的方式来创建,动态创建就是通过Java代码来创建

静态创建
<!--name属性是静态引用Fragment类,
Layout属性是让布局立马显示在此布局上(layout属性可有可无)
id属性是必须要引用的,不加的话会报错-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.zhiyuan3g.fragmenttest.MainActivity">

    <fragment
        android:name="com.zhiyuan3g.fragmenttest.Fragment1"
        android:id="@+id/fragment1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <fragment
        android:name="com.zhiyuan3g.fragmenttest.Fragment2"
        android:layout_width="0dp"
        android:id="@+id/fragment2"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
</LinearLayout>
public class Fragment1 extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View fragment1 = inflater.inflate(R.layout.fragment1, null);
        return fragment1;
    }
}
public class Fragment2 extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View fragment1 = inflater.inflate(R.layout.fragment1, null);
        return fragment1;
    }
}

代码如下:MainActivity.class

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
静态创建

1.创建Fragment的管理对象fragmentManager。
FragmentManager fragmentManager = getFragmentManager();
2.创建事务对象(Fragment事务对象不能抽取,因为每提交一次,就需要一个新的Fragment事务对象.(所有的事务都有这个特性))
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
3.动态创建Fragment
fragmentTransaction.replace(android.R.id.content, new Fragment());
4.提交事务对象
fragmentTransaction.commit();

主要逻辑代码如下:
//获取碎片管理者
mFragmentManager = getSupportFragmentManager();
//事务是不能共享的,每次用到都要重新开启一个事务,之后提交
FragmentTransaction fragmentTransactiontwo = mFragmentManager.beginTransaction();
//参数:1.父容器   2.要替换的fragment。
fragmentTransactiontwo.replace(R.id.framelayout, mFragmentTwo);
//提交事务
fragmentTransactiontwo.commit();

注:但是,我们开发中使用动态创建一般不用上面的这种方法,因为这种方法每次切换fragment时都会重新初始化(使用replace方法的弊端),所以我们用隐藏和添加来实现代替replace。通过事物对象的add方法添加或show方法显示(如果已经被添加了),然后在跳转前将当前的fragment隐藏。这样我们就不用每次切换fragment都初始化了,节省流量和手机资源。补充:碎片的回退实现方法,先通过事务对象的addToBackStack一个个放入栈中,再将通过popBackStack()从栈中拿出来,从而实现碎片回退功能。

//获取碎片管理者
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction1 = mFragmentManager.beginTransaction();
switch (v.getId()) {
    case R.id.frist:
        //判断fragmentOne是否已经存在
        if (mFragmentOne.isAdded()) {
            //如果fragmentOne已经存在,则隐藏当前的fragment,
            //然后显示fragmentOne(不会重新初始化,只是加载之前隐藏的fragment)
            fragmentTransaction1.hide(fragmentNow).show(mFragmentOne);
        } else {
            //如果fragmentOne不存在,则隐藏当前的fragment,
            //然后添加fragmentOne(此时是初始化)
            fragmentTransaction1.hide(fragmentNow).add(R.id.framelayout, mFragmentOne);
            fragmentTransaction1.addToBackStack(null);

        }
        //将加载的fragment赋给我们的中转量(用于记录屏幕当前显示的fragment)
        fragmentNow = mFragmentOne;
        fragmentTransaction1.commit();
        break;

下面是代码:
MainActivity.java

public class Main2Activity extends AppCompatActivity implements View.OnClickListener {

    private Button frist;
    private Button two;
    private FragmentManager mFragmentManager;
    private FrameLayout framelayout;
    private Fragment mFragmentOne;
    private Fragment mFragmentTwo, fragmentNow;
    private Button back_btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        initView();
        initDefaultFragment();

    }

    //初始化默认fragment的加载
    private void initDefaultFragment() {

        //开启一个事务
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        //add:往碎片集合中添加一个碎片;
        //replace:移除之前所有的碎片,替换新的碎片(remove和add的集合体)(很少用,不推荐,因为是重新加载,所以消耗流量)
        //参数:1.公共父容器的的id  2.fragment的碎片
        fragmentTransaction.add(R.id.framelayout, mFragmentOne);
        fragmentTransaction.addToBackStack(null);

        //提交事务
        fragmentTransaction.commit();
        fragmentNow = mFragmentOne;

    }

    private void initView() {
        frist = (Button) findViewById(R.id.frist);
        two = (Button) findViewById(R.id.two);

        frist.setOnClickListener(this);
        two.setOnClickListener(this);
        framelayout = (FrameLayout) findViewById(R.id.framelayout);
        //实例化FragmentOne
        mFragmentTwo = new FragmentTwo();
        mFragmentOne = new FragmentOne();
        //获取碎片管理者
        mFragmentManager = getSupportFragmentManager();

        framelayout.setOnClickListener(this);
        back_btn = (Button) findViewById(R.id.back_btn);
        back_btn.setOnClickListener(this);
    }

    //通过点击事件跳转到对应的fragment上
    @Override
    public void onClick(View v) {
        FragmentTransaction fragmentTransaction1 = mFragmentManager.beginTransaction();
        switch (v.getId()) {
            case R.id.frist:
                //判断fragmentOne是否已经存在
                if (mFragmentOne.isAdded()) {
                    //如果fragmentOne已经存在,则隐藏当前的fragment,
                    //然后显示fragmentOne(不会重新初始化,只是加载之前隐藏的fragment)
                    fragmentTransaction1.hide(fragmentNow).show(mFragmentOne);
                } else {
                    //如果fragmentOne不存在,则隐藏当前的fragment,
                    //然后添加fragmentOne(此时是初始化)
                    fragmentTransaction1.hide(fragmentNow).add(R.id.framelayout, mFragmentOne);
                    fragmentTransaction1.addToBackStack(null);

                }
                fragmentNow = mFragmentOne;
                fragmentTransaction1.commit();
                break;
            case R.id.two:
                if (mFragmentTwo.isAdded()) {
                    fragmentTransaction1.hide(fragmentNow).show(mFragmentTwo);
                } else {
                    fragmentTransaction1.hide(fragmentNow).add(R.id.framelayout, mFragmentTwo);
                    fragmentTransaction1.addToBackStack(null);
                }
                fragmentNow = mFragmentTwo;
                fragmentTransaction1.commit();
                break;
            case R.id.back_btn:
                //在上面给事务对象添加addToBackStack(null),
                //下面就可以通过碎片管理对象(mFragmentManager)调用popBackStack()方法来返回上一个碎片(此时碎片管理器只有两个碎片)
                //因为我们是通过add的方法添加fragment的,而且只是添加的两次,其余都是显示和隐藏来实现
                //又因为我们当前占了一个fragment,所以我们只能回退一次,第二次回退就会是空的fragment(什么都没有)
                mFragmentManager.popBackStack();
                break;
        }
    }
}
关于 getSupportFragmentManager()和getFragmentManager()区别答疑

FragmentManager使用getFragmentManager();使用3.0以下系统获取FragmentManager使用getSupportFragmentManager()。
首先,Fragmet在使用时是有两个包的,分别是app包和v4包。v4包主要用来兼容低版本系统也能正常显示Fragment,而app包在安卓4.2系统之前的设备运行Fragment时,程序会崩溃。因此我们一般使用Fragment都选择使用v4包中的Fragment以确保低版本的系统运行正常。
在Activity中:使用v4库的Fragment,要求Activity必须继承于FragmentActivty,并且对应的也该使用v4库中的方法获取FragmentManager。
由于v4库不能直接获取FragmentManager,因此这里使用getSupportFragmentManager()间接获取FragmentManager。
工程中Activity默认继承的AppCompatActivity也可以使用,查阅源码后发现AppCompatActivity是继承于FragmentActivity的,所以也可以放心使用。对于3.0以上版本的(也就是不需要使用v4包的Fragment的),则可以直接继承Activity,可以不继承FragmentActivity。
在Fragment中:可以使用getFragmentManager()直接获取FragmentManager。

V4,V7,V13包差异

Android v4、v7、v13 的区别

Android Support v4
这个包是为了照顾1.6及更高版本而设计的,这个包是使用最广泛的,eclipse新建工程时,都默认带有了。
Android Support v7
这个包是为了考虑照顾2.1及以上版本而设计的,但不包含更低,故如果不考虑1.6,我们可以采用再加上这个包,另外注意,v7是要依赖v4这个包的,即,两个得同时被包含。
Android Support v13
这个包的设计是为了android 3.2及更高版本的,一般我们都不常用,平板开发中能用到。
1、为什么还要用V7呢?V4向下兼容的版本不是更多吗?
V7版本不是为了提供一些V4提供不了的内容,它不是补丁。V7以后你如果创建一个工程,它给你创建的都是FragmentActivity了。
也就是说,以后Android开发所有的界面都可以是碎片模式了。V7是一种新的框架和更优解决方案.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容