Android Fragment两种加载方式及ViewPage

作者: 侯蛋蛋_ | 来源:发表于2017-09-10 16:20 被阅读121次

    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;
    这里的原因我也不是很清楚,有兴趣的可以研究下

    相关文章

      网友评论

        本文标题:Android Fragment两种加载方式及ViewPage

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