Fragment碎片用法

QuibblerQuibbler 2020-02-26 约 19 分钟 2199 次阅读

开发者>文档>指南>Fragment">Fragment碎片用法

Fragment是一种可以嵌入在活动中的UI片段,能够让程序更加合理和充分地利用大屏幕的空间,出现的初衷是为了适应大屏幕的平板电脑,可以将其看成一个小型Activity,又称作Activity片段。

  • Fragment依赖于Activity,不能独立存在
  • 一个Activity可以有多个Fragment
  • 一个Fragment可以被多个Activity重用
  • Fragment有自己的生命周期,并能接收输入事件
  • 可以在Activity运行时动态地添加或删除Fragment

1、Fragment生命周期

        

  • onAttach():Fragment和Activity相关联时调用。通过该方法获取Activity引用,getArguments()获取参数。
  • onCreate():Fragment被创建时调用
  • onActivityCreated():当Activity完成onCreate()时调用
  • onStart():   当Fragment可见时调用。
  • onResume(): 当Fragment可见且可交互时调用
  • onPause():  当Fragment不可交互但可见时调用。
  • onStop():    当Fragment不可见时调用。
  • onDestroyView():当Fragment的UI从视图结构中移除时调用。
  • onDestroy(): 销毁Fragment时调用。
  • onDetach():  当Fragment和Activity解除关联时调用。

2、定义Fragment

2.1、Fragment派生类

Android已经预定义了一些Fragment派生类。可以继承它们二次封装,增加、完善功能使用。

①DialogFragment

显示浮动对话框。使用此类创建对话框可有效代替使用 Activity 类中的对话框辅助方法,因为您可以将片段对话框纳入由 Activity 管理的片段返回栈,从而使用户能够返回清除的片段。

②ListFragment

显示由适配器(如 SimpleCursorAdapter)管理的一系列项目,类似于 ListActivity。该类提供几种管理列表视图的方法,如用于处理点击事件的 onListItemClick() 回调。(请注意,显示列表的首选方法是使用 RecyclerView,而非 ListView。在此情况下,您需在列表布局中创建包含 RecyclerView 的片段。如需了解具体操作方法,请参阅使用 RecyclerView 创建列表)

③PreferenceFragmentCompat

        以列表形式显示 Preference 对象的层次结构。此类用于为您的应用创建设置屏幕。参考另一篇《Android设置界面:PreferenceScreen 》

        ④WebViewFragment deprecated in API level 28

显示WebView的片段。当片段暂停或恢复时,WebView将自动暂停和恢复。

2.2、自定义Fragment

继承Fragment或其派生类,重写onCreateView(),在方法中调用inflater.inflate()方法加载Fragment布局文件,接着返回加载的view对象

public class MyFragment extends Fragment {

        @Override
        public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.fragment, container, false);
        }
    
    }

注意:

①inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

②创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。

在Fragment的onAttach()中通过getArguments()获得传进来的参数。

③获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象

3、加载Fragment

3.1、静态加载:<fragment/>布局中指明

最直接的一种方式,添加<fragment />标签布局,使android:name 属性指定要在布局中进行实例化的 Fragment 类。静态加载添加后就不能在运行时删除。

<LinearLayout>
    
        <fragment
            android:id="@+id/fragment"
            //指明替换此fragment的Fragment类
            android:name=".fragment.MyFragment"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
            
    </LinearLayout>

创建此 Activity 布局时,系统会将布局中指定的每个片段实例化,并为每个片段调用 onCreateView() 方法,以检索每个片段的布局。系统会直接插入片段返回的 View,从而代替 <fragment> 元素。

        注意:每个片段都需要唯一标识符,重启 Activity 时,系统可使用该标识符来恢复片段(您也可以使用该标识符来捕获片段,从而执行某些事务,如将其移除)。可以通过两种方式为片段提供 ID:

  • 为 android:id 属性提供唯一 ID。
  • 为 android:tag 属性提供唯一字符串。

3.2、动态加载:FragmentManager+FrameLayout

布局中使用<FrameLayout/>标签先占位,需要指定id,不需要指定name。

<LinearLayout>
    
        <FrameLayout
            android:id="@+id/fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
            
    </LinearLayout>

在Activity代码中,先getSupportFragmentManager()获取到FragmentManager

FragmentManager fragmentManager = getSupportFragmentManager();

替换:replace(),先开启一个事务,替换,提交。

fragmentManager.beginTransaction()
                   .replace(R.id.fragment, new FirstFragment(), "My Fragment Tag")
                   .commit();

添加:使用add()方法添加Fragment。会导致多个Fragment会重叠在一起。

fragmentManager.beginTransaction()
                   .add(R.id.fragment, new SecondFragment()
                   .commit();

4、Fragment方法

操作Fragment,都是通过FragmentManager开启一个事务FragmentTransaction。

①FragmentTransaction.add()

         Activity里面添加一个片段

public FragmentTransaction add(int containerViewId,Fragment fragment,String tag)

第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。

注意:同一个Fragment对象,只能add一次,否则奔溃:
java.lang.IllegalStateException: Fragment already added: MyFragment{8fb7f5c (ed6589cc-db78-4e6c-ac7a-c78d088ad6c1) id=0x7f080069 My Fragment Tag}

②FragmentTransaction.replace()

另一个Fragment替换当前的,实际上是remove()然后add()的合体

③FragmentTransaction.remove()

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

④FragmentTransaction.hide()

隐藏当前Fragment,仅不可见,不会销毁

⑤FragmentTransaction.show()

显示之前隐藏的Fragment

⑥FragmentTransaction.detach()

会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。似乎detach之后不能再次添加到Fragment中

⑦FragmentTransaction.attach()

重建view视图

⑧FragmentTransaction.commit()

提交修改

⑨FragmentTransaction.addToBackStack()

将Fragment事务加入回退栈

⑩FragmentManager.findFragmentByTag()

从FragmentManager中查找Fragment对象

5、Fragment通信

Fragmen之间、Fragment和Activity之间如何通信?传递数据、信息。

5.1、Fragment->Acvtivity

Fragment向Activity传递信息,在Fragment中定义interface接口

public interface FragmentListener {
        void notifyActivity();
    }

Activity实现该接口:

public class MyFragmentActivity extends AppCompatActivity implements MyFragment.FragmentListener{
    ...
    @Override
    public void notifyActivity() {
        Log.d("QUIBBLER", "Fragment->Activity");
    }
}

在Fragment onAttach()的时候,通过Context也就是Activity,强转成定义的FragmentListener接口类型

@Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (context instanceof FragmentListener) {
            listener = (FragmentListener) context;
        
    }

这样就可以在Fragment中通过调用接口,Activity实现方法,与Activity通信。

listener.notifyActivity();

这种方式定义接口再去实现,似乎有点繁琐。推荐一个注解工具,GitHub:FABridge

5.2、Activity->Fragment

比起前面的Fragment向Activity通信,Activity向Fragment通信就方便的多,毕竟站在Activity上帝视角可以看到所有Fragment。

直接在Activity中获取到对应Fragment对象,调用其中定义的方法即可。

5.3、Fragment<->Fragment

Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信。

6、Fragment退回栈

        Android系统为Activity维护一个任务栈,Fragment的每次替换,添加,也是一条可寻“轨迹”。将每次Fragment的操作添加到Fragment退回栈中。

fragmentManager.beginTransaction()
            .add(R.id.fragment_two, new MyFragment(), "My Fragment Tag")
            .addToBackStack("MyFragment")
            .commit();

        当用户按返回按钮的时候,不是直接退出当前Activity,而是一次按照Fragment的添加修改顺序,退回。Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。

手动从Fragment退回栈中弹出Fragment:popBackStackImmediate()或popBackStack()。这里根据前面添加入栈的String name进行pop,如果多个入栈,但是使用了同一个name,会一次性全部退出栈。所以这个字符串name,可以看做是入栈“车次”"一批"。与前面返回键不同(每返回一次,退回一个Fragment)

fragmentManager.popBackStackImmediate(BlankFragment.class.getSimpleName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    //或者
    fragmentManager.popBackStack(BlankFragment.class.getSimpleName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);

        Fragment还会和ViewPager经常一起使用,这时候就要用到FragmentPagerAdapter、FragmentStatePagerAdapter。参考《ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager 》



参考:

          Android 开发者>文档>指南>Fragment 

         GitHub:FABridge

        《Fragment生命周期以及基本用法》

        《Android Fragment 非常详细的一篇》

        《Fragment懒加载实现,BaseFragment封装》

        《Fragment详解》

        《Fragment 与 FragmentPagerAdapter》

        《当Fragment遇上ViewPager》

        

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w