Android Fragment两种加载方式及ViewPage(二)

Fragment 生命周期(一)

Fragment两种加载方式及ViewPage(二)

Fragment 传递数据的三种方法(三)

本节前言

上一节我们介绍了Fragement的横竖切换屏的用法,今天我们就介绍一下Fragment的基本用法

示例说明用法

一、常见的两种加载方式

方式一:FragmentTranscation

并使用FragmentManager管理下的FragmentTranscation来进行Fragment或者Fragment列表的加载(add)、替换(replace)、删除(remove)等操作,此时的Fragment所在的容器一般选择用FrameLayout。

//将一个fragment实例添加到Activity的最上层  
add(int containerViewId, Fragment fragment, String tag);  
//将一个fragment实例从Activity的fragment队列中删除  
remove(Fragment fragment);  
//替换containerViewId中的fragment实例,注意,它首先把containerViewId中所有fragment删除,然后再add进去当前的fragment  
replace(int containerViewId, Fragment fragment);  

Demo

private void removeFragment2() {  
    FragmentManager manager = getSupportFragmentManager();  
    Fragment fragment = manager.findFragmentByTag("fragment2");  
    FragmentTransaction transaction = manager.beginTransaction();  
    transaction.remove(fragment);  
    transaction.commit();  
}  

【关于FragmentManager和FragmentTranscation】

FragmentManager:Activity中有个FragmentManager,其内部维护fragment队列,以及fragment事务的回退栈。在Fragment被创建、并由FragmentManager管理时,FragmentManager就把它放入自己维护的fragment队列中。

FragmentTransaction:知道了FragmentManger可以管理和维护Fragment,那么FragmentManager是直接去绑定Fragment然后把它set进自己的队列中吗?不是的,而是用FragmentTransaction(Fragment事务),FragmentManager调用beginTransaction()方法返回一个新建的事务,用于记录对于Fragment的add、replace等操作,最终将事务commit回FragmentManager,才开始启动执行事务的内容,实现真正的Fragment显示。

代码如下

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

MyFragmentA fragmentA = new MyFragmentA();
getSupportFragmentManager().beginTransaction().add(R.id.frame_root_fragment,fragmentA).commit();
}

其实是这样写的缩减

FragmentManager manager = getSupportFragmentManager();  
FragmentTransaction transaction = manager.beginTransaction();  
Fragment1 fragment1 = new Fragment1();  
transaction.add(R.id.fragment_container, fragment1);  
transaction.commit();  

有关回滚——FragmentTransaction

1、FragmentTransaction事务回滚使用方法:

上部分,我们讲了有关添加、删除Fragment的操作,想将上一次commit的操作返回时,要怎么做呢。这就需要FragmentTransaction的回滚功能了。

要使用回滚功能,只需要要使用下面两个代码:

在transaction.commit()之前,使用addToBackStack()将其添加到回退栈中。

transaction.addToBackStack(String tag);  

在需要回退时,使用popBackStack()将最上层的操作弹出回退栈。

manager.popBackStack();  

这里的popBackStack()是弹出默认的最上层的栈顶内容。
当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层。函数如下:

void popBackStack(int id, int flags);  
void popBackStack(String name, int flags);

参数int id是当提交变更时transaction.commit()的返回值。
参数string name是transaction.addToBackStack(String tag)中的tag值;
至于int flags有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE;
当取值0时,表示除了参数一指定这一层之上的所有层都退出栈,指定的这一层为栈顶层;
当取值POP_BACK_STACK_INCLUSIVE时,表示连着参数一指定的这一层一起退出栈;
除了这几个函数,还有下面几个函数:有关他们的使用,我们在这小部分结尾时会提到

popBackStackImmediate()  
popBackStackImmediate(String tag)  
popBackStackImmediate(String tag, int flag)  
popBackStackImmediate(int id, int flag)  

方式二:使用ViewPager

使用ViewPager等容器去装载Fragment列表并通过他们自己的页面切换能力去切换Fragment。

【关于ViewPager适配器相关类:FragmentPagerAdapter与FragmentStatePagerAdapter】

FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。

FragmentStatePagerAdapter:会销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragment从当前Activity的FragmentManager中移除,state标明,销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。总结:使用FragmentStatePagerAdapter当然更省内存,但是销毁新建也是需要时间的。一般情况下,如果你是制作主页面,就3、4个Tab,那么可以选择使用FragmentPagerAdapter,如果你是用于ViewPager展示数量特别多的条目时,那么建议使用FragmentStatePagerAdapter。

第一步布局activity_main.xml

<?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"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
    <android.support.design.widget.TabLayout
        ……
        />
    <android.support.v4.view.ViewPager
        android:id="@+id/vp_main"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />
</LinearLayout>

第二步布局Fragment.xml以及代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/bg_white"
    android:orientation="vertical">

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="呵呵"
        android:textColor="@color/text_yellow"
        android:textSize="20sp" />

</LinearLayout>

MyFragment1.java:

public class MyFragment1 extends Fragment {

    public MyFragment1() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fg_content, container, false);
        TextView txt_content = (TextView) view.findViewById(R.id.txt_content);
        txt_content.setText("第一个Fragment");
        return view;
    }
}

另一个照葫芦画瓢,换点东西就好!

第三步自定义FragmentPagerAdapter

public class FragAdapter extends FragmentPagerAdapter {  
  
    private List<Fragment> mFragments;  
      
    public FragAdapter(FragmentManager fm,List<Fragment> fragments) {  
        super(fm);  
        // TODO Auto-generated constructor stub  
        mFragments=fragments;  
    }  
  
    @Override  
    public Fragment getItem(int arg0) {  
        // TODO Auto-generated method stub  
        return mFragments.get(arg0);  
    }  
  
    @Override  
    public int getCount() {  
        // TODO Auto-generated method stub  
        return mFragments.size();  
    }  
  
}  

这里有三个函数,根据第一部分的官方文档,可知,对于FragmentPagerAdapter的派生类,只重写getItem(int)和getCount()就可以了。

对于构造函数,这里申请了一个Fragment的List对象,用于保存用于滑动的Fragment对象,并在创造函数中初始化:

public FragAdapter(FragmentManager fm,List<Fragment> fragments) {  
    super(fm);  
    // TODO Auto-generated constructor stub  
    mFragments=fragments;  
}  

然后在getItem(int arg0)中,根据传来的参数arg0,来返回当前要显示的fragment,下面是getItem的官方解释,难度不大,不再细讲。

第四部、主Activity的实现

public class MainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        //构造适配器  
        List<Fragment> fragments=new ArrayList<Fragment>();  
        fragments.add(new Fragment1());  
        fragments.add(new Fragment2());  

        FragAdapter adapter = new FragAdapter(getSupportFragmentManager(), fragments); 
        //设定适配器  
        ViewPager vp = (ViewPager)findViewById(R.id.viewpager);  
        vp.setAdapter(adapter);  
    }  
  
} 

这里有一个特别注意的两点

1.问题:在MainActivity中,当写到这句:fragments.add(new Fragment1()); 向Fragment列表中添加Fragement对象实例时,会提示“无法将Fragment1()转换为fragment”

解决办法 :这是因为导入包不一致,一般的问题在于:在Fragment1中导入的是android.app.Fragment, 而在这里导入类确是:android.support.v4.app.Fragment,包不同当然无法转换,统一导入为android.support.v4.app.Fragment

2.当我们第一步仍没有办法解决办法,或者说。v4包里并没有该类,比如继承PreferenceFragment,import android.preference.PreferenceFragment;

解决办法:这时候我们就需要修改FragmentPagerAdapter的包,把import android.support.v4.app.FragmentPagerAdapter;修改成import android.support.v13.app.FragmentPagerAdapter;
这里的原因我也不是很清楚,有兴趣的可以研究下

    原文作者:侯蛋蛋_
    原文地址: https://www.jianshu.com/p/0420a16eefb4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞