安卓_了解Fragment

本文详细介绍了Android中的Fragment组件,包括其概念、生命周期、与Activity的交互方式以及如何管理和添加Fragment。

1.概述

  Fragment是Activity中用户界面的一个行为或者是一部分。主要是支持在大屏幕上动态和更为灵活的去组合或是交换UI组件,通过将activity的布局分割成若干个fragment,可以在运行时编辑activity的呈现,并且那些变化会被保存在由activity管理的后台栈里面。

  Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接受其宿主activity的生命周期的影响。你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在activity运行时添加或者删除。

  应该将每一个fragment设计为模块化的和可复用化的activity组件。也就是说,你可以在多个activity中引用同一个fragment,因为fragment定义了它自己的布局,并且使用它本身生命周期回调的行为。

2.Fragment的生命周期

先看fragment生命周期图:

这里写图片描述

  fragment所生存的activity生命周期直接影响着fragment的生命周期,由此针对activity的每一个生命周期回调都会引发一个fragment类似的回调。例如,当activity接收到onPause()时,这个activity之中的每个fragment都会接收到onPause()。 
  这有Activity的详细说明

  Fragment有一些额外的生命周期回调方法(创建和销毁fragment界面).

  • onAttach()

      当fragment被绑定到activity时调用(Activity会被传入)。

  • onCreateView()

      将本身的布局构建到activity中去(fragment作为activity界面的一部分) 
      

  • onActivityCreated()

      当activity的onCreate()函数返回时被调用。

  • onDestroyView()

      当与fragment关联的视图体系正被移除时被调用。

  • onDetach()

      当fragment正与activity解除关联时被调用。

当activity接收到它的onCreate()回调时,activity之中的fragment接收到onActivityCreated()回调。

  一旦activity处于resumed状态,则可以在activity中自由的添加或者移除fragment。因此,只有当activity处于resumed状态时,fragment的生命周期才可以独立变化。 
   
fragment会在 activity离开恢复状态时 再一次被activity推入它的生命周期中。

管理fragment生命周期与管理activity生命周期很相像。像activity一样,fragment也有三种状态:

  • Resumed

      fragment在运行中的activity可见。

  • Paused

      另一个activity处于前台且得到焦点,但是这个fragment所在的activity仍然可见(前台activity部分透明,或者没有覆盖全屏)。

  • Stopped

      fragment不可见。要么宿主activity已经停止,要么fragment已经从activity上移除,但已被添加到后台栈中。一个停止的fragment仍然活着(所有状态和成员信息仍然由系统保留着)。但是,它对用户来讲已经不再可见,并且如果activity被杀掉,它也将被杀掉。

      如果activity的进程被杀掉了,在activity被重新创建时,你需要恢复fragment状态。可以执行fragment的onSaveInstanceState()来保存状态(注意在fragment是在onCreate(),onCreateView(),或onActvityCreate()中进行恢复)。

      在生命周期方面,activity与fragment之间一个很重要的不同,就是在各自的后台栈中是如何存储的。 
      当activity停止时,默认情况下activity被安置在由系统管理的activity后台栈中;  
      fragment仅当在一个事务被移除时,通过显式调用addToBackStack()请求保存的实例,该fragment才被置于由宿主activity管理的后台栈。 

要创建一个fragment,必须创建一个fragment的子类。一般情况下,我们至少需要实现以下几个fragment生命周期方法:

onCreate()

  在创建fragment时系统会调用此方法。在实现代码中,你可以初始化想要在fragment中保持的那些必要组件,当fragment处于暂停或者停止状态之后可重新启用它们。

onCreateView()

  在第一次为fragment绘制用户界面时系统会调用此方法。为fragment绘制用户界面,这个函数必须要返回所绘出的fragment的根View。如果fragment没有用户界面可以返回空。

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> View <span class="hljs-title" style="box-sizing: border-box;">onCreateView</span>(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { 

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Inflate the layout for this fragment</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> inflater.inflate(R.layout.example_fragment, container, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);
        }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

inflate()函数需要以下三个参数:

①要inflate的布局的资源ID。 

②被inflate的布局的父ViewGroup。

③一个布尔值,表明在inflate期间被infalte的布局是否应该附上ViewGroup(第二个参数Container)。(在这个例子中传入的是false,因为系统已经将被inflate的布局插入到容器中(container)——传入true会在最终的布局里创建一个多余的ViewGroup。) 

onPause()

  系统回调用该函数作为用户离开fragment的第一个预兆(尽管这并不总意味着fragment被销毁)。在当前用户会话结束之前,通常要在这里提交任何应该持久化的变化(因为用户可能不再返回)。

3.将fragment添加到activity之中

  可以通过在activity布局文件中声明fragment,用fragment标签把fragment插入到activity的布局中,或者是用应用程序源码将它添加到一个存在的ViewGroup中。  
   
  但fragment并不是一个定要作为activity布局的一部分,fragment也可以为activity隐身工作。

3.1在activity的布局文件里声明fragment

  可以像为view一样为fragment指定布局属性。例如:

<code class="hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">xmlns:android</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"http://schemas.android.com/apk/res/android"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:orientation</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"horizontal"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span>></span> 

        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">fragment</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"com.example.test.FragmentOne"</span>
                <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/fo"</span>
                <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span>
                <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span> /></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout</span>></span>
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

  fragment标签中的Android:name 属性指定了布局中实例化的Fragment类。

  当系统创建activity布局时,它实例化了布局文件中指定的每一个fragment,并为它们调用onCreateView()函数,以获取每一个fragment的布局。系统直接在元素的位置插入fragment返回的View。

  注意:每个fragment都需要一个唯一的标识,如果重启activity,系统可用来恢复fragment(并且可用来捕捉fragment的事务处理,例如移除)。为fragment提供ID有三种方法:

  • 用android:id属性提供一个唯一的标识。 

  • 用android:tag属性提供一个唯一的字符串。 

  • 如果上述两个属性都没有,系统会使用其容器视图(view)的ID。 

3.2通过编码将fragment添加到已存在的ViewGroup中

  在activity运行的任何时候,你都可以将fragment添加到activity布局中。 
   
  要管理activity中的fragment,可以使用FragmentManager。可以通过在activity中调用getFragmentManager()获得。使用FragmentManager 可以做如下事情,包括:

  • 使用findFragmentById()(用于在activity布局中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment)。  

  • 使用popBackStack()(模仿用户的BACK命令)从后台栈弹出fragment。  

  • 使用addOnBackStackChangedListener()注册一个监听后台栈变化的监听器。

在Android中,对Fragment的事务操作都是通过FragmentTransaction来执行。操作大致可以分为两类:

  • 显示:add() replace() show() attach()  

  • 隐藏:remove() hide() detach() 

说明: 
  调用show() & hide()方法时,Fragment的生命周期方法并不会被执行,仅仅是Fragment的View被显示或者​隐藏。

  执行replace()时(至少两个Fragment),会执行第二个Fragment的onAttach()方法、执行第一个Fragment的onPause()-onDetach()方法,同时containerView会detach第一个Fragment的View。

  add()方法执行onAttach()-onResume()的生命周期,相对的remove()就是执行完成剩下的onPause()-onDetach()周期。

可以像下面这样从Activity中取得FragmentTransaction的实例:

<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">FragmentManager fragmentManager </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> getFragmentManager() 
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

可以用add()函数添加fragment,并指定要添加的fragment以及要将其插入到哪个视图(view)之中(注意commit事务):

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ExampleFragment fragment = new ExampleFragment()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
    fragmentTransaction<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.add</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.fragment</span>_container, fragment)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
    fragmentTransaction<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.commit</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

3.3添加没有界面的fragment

  也可以使用fragment为activity提供后台动作,却不呈现多余的用户界面。

  想要添加没有界面的fragment ,可以使用add(Fragment, String)(为fragment提供一个唯一的字符串“tag”,而不是视图(view)ID)。这样添加了fragment,但是,因为还没有关联到activity布局中的视图(view) ,收不到onCreateView()的调用。所以不需要实现这个方法。  
   
  对于无界面fragment,字符串标签是唯一识别它的方法。如果之后想从activity中取到fragment,需要使用findFragmentByTag()。 

4.fragment事务后台栈

  在调用commit()之前,可以将事务添加到fragment事务后台栈中(通过调用addToBackStatck())。这个后台栈由activity管理,并且允许用户通过按BACK键回退到前一个fragment状态。

  下面的代码中一个fragment代替另一个fragment,并且将之前的fragment状态保留在后台栈中:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> Fragment newFragment = new ExampleFragment()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
 FragmentTransaction transaction = getFragmentManager()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.beginTransaction</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>

 transaction<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.replace</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.fragment</span>_container, newFragment)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
 transaction<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addToBackStack</span>(null)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>

 transaction<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.commit</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

注意:

   如果添加多个变更事务(例如另一个add()或者remove())并调用addToBackStack(),那么在调用commit()之前的所有应用的变更被作为一个单独的事务添加到后台栈中,并且BACK键可以将它们一起回退。

  当移除一个fragment时,如果调用了addToBackStack(),那么之后fragment会被停止,如果用户回退,它将被恢复过来。

  调用commit()并不立刻执行事务,相反,而是采取预约方式,一旦activity的界面线程(主线程)准备好便可运行起来。然而,如果有必要的话,你可以从界面线程调用executePendingTransations()立即执行由commit()提交的事务。

  只能在activity保存状态(当用户离开activity时)之前用commit()提交事务。如果你尝试在那时之后提交,会抛出一个异常。这是因为如果activity需要被恢复,提交后的状态会被丢失。对于这类丢失提交的情况,可使用commitAllowingStateLoss()

5.与Activity交互

  • Activity中已经有了该Fragment的引用,直接通过该引用进行交互。

    -如果没引用可以通过调用fragment的函数findFragmentById()或者findFragmentByTag(),从FragmentManager中获取Fragment的索引,例如:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ExampleFragment fragment = (ExampleFragment) getFragmentManager()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.findFragmentById</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.id</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.example</span>_fragment)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
  • 在Fragment中可以通过getActivity得到当前绑定的Activity的实例。

  • 创建activity事件回调函数,在fragment内部定义一个回调接口,宿主activity来实现它。

参考:

fragments API Guides

FragmentTransaction Reference

<think>好的,我现在需要帮助用户查找关于VTS FirmwareDtboVerification测试和ufdt_verify_fragment实现细节或错误解决方案的信息。首先,我应该回忆一下之前用户提到的引用内容,里面提到了VTS验证的几个方面,比如内核命令行参数、系统属性的有效性、DTBO分区的有效性以及生成的设备树中的更改是否正确应用。用户现在具体想了解的是FirmwareDtboVerification测试和ufdt_verify_fragment的相关技术细节或问题解决。 首先,我需要确定FirmwareDtboVerification测试的具体内容。根据之前的知识,VTS(Vendor Test Suite)是用于验证Android设备兼容性的测试框架,其中Firmware部分可能涉及固件相关的测试,特别是设备树覆盖(DTBO)的验证。DTBO用于在设备启动时动态修改设备树,以支持不同的硬件配置或版本。而FirmwareDtboVerification测试可能检查DTBO的正确性,包括索引、叠加层的有效性以及内核是否正确应用了这些更改。 接下来,ufdt_verify_fragment这个函数可能属于UFDT(Flattened Device Tree Overlay)库的一部分,用于验证设备树叠加层的有效性。UFDT库用于处理设备树叠加层的应用和合并,可能是在启动过程中由bootloader或内核使用的。ufdt_verify_fragment的具体实现可能涉及检查叠加层的结构是否符合预期,节点和属性的正确性,以及是否有冲突或无效的修改。 用户可能遇到了VTS测试失败,特别是FirmwareDtboVerification相关的错误,需要了解如何调试或解决这些问题。常见的错误可能包括DTBO索引无效、叠加层无法正确应用,或生成的设备树中存在冲突。 我需要考虑以下几个方面来回答用户的问题: 1. VTS FirmwareDtboVerification测试的具体检查点。 2. ufdt_verify_fragment的实现细节,例如它如何验证叠加层。 3. 常见的错误场景和解决方法,比如如何处理索引错误、叠加层无效或合并后的设备树问题。 可能还需要参考Android开源项目中的相关代码,比如AOSP中的VTS测试用例和UFDT库的实现。例如,在AOSP的源代码中,FirmwareDtboVerification测试可能位于vendor/test/vts-testcase/kernel/firmware目录下,而ufdt_verify_fragment可能在system/libufdt或类似的路径中。 另外,用户提到的引用[^1]中提到的ro.boot.dtbo_idx属性有效性、DTBO分区的有效性以及叠加层的应用结果,这些都是需要检查的关键点。如果测试失败,用户可能需要检查这些属性是否正确设置,DTBO分区是否存在或损坏,以及叠加层是否基础设备树兼容。 可能的解决方案包括确认DTBO映像的索引是否正确,检查叠加层的语法和结构是否正确使用工具如dtc(设备树编译器)验证叠加层的有效性,以及确保bootloader正确传递了相关参数。 总结来说,我需要整理出FirmwareDtboVerification的测试流程、ufdt_verify_fragment的作用和实现要点,并提供常见错误的排查步骤和解决方法。同时,建议用户查阅相关AOSP文档和代码,使用调试工具进行分析,并检查设备树相关的配置是否正确。</think>关于VTS FirmwareDtboVerification测试及`ufdt_verify_fragment`的实现细节,以下是技术要点和问题排查方向: --- ### 一、FirmwareDtboVerification测试目标 该测试验证设备树叠加层(DTBO)的完整性和正确性,关键检查点包括: 1. **索引有效性**:检查`androidboot.dtbo_idx`参数是否通过`ro.boot.dtbo_idx`系统属性正确传递[^1] 2. **DTBO分区验证**:确保DTBO分区中的叠加层基础设备树(DTB)兼容 3. **叠加层应用效果**:验证合并后的设备树是否将节点/属性正确传递给Linux内核 --- ### 二、`ufdt_verify_fragment`实现原理 该函数属于UFDT(Unflattened Device Tree)工具链,主要职责为: ```c // 伪代码逻辑 int ufdt_verify_fragment(struct fdt_header *fdt, struct fdt_header *overlay) { 1. 检查叠加层基础节点是否存在 2. 验证叠加层属性是否符合语法规则(如节点路径、phandle引用) 3. 检测基础设备树的属性冲突(同路径节点的重复属性) 4. 返回错误码或验证通过状态 } ``` --- ### 三、常见错误及解决方案 #### 1. **VTS测试失败:`Missing dtbo_idx`** - **原因**:Bootloader未正确传递`androidboot.dtbo_idx`参数 - **修复**: - 检查内核命令行参数是否包含`androidboot.dtbo_idx=X,Y` - 验证`ro.boot.dtbo_idx`属性是否被Init进程正确解析[^1] #### 2. **`ufdt_verify_fragment返回-22`(EINVAL)** - **典型场景**:叠加层中存在无效节点路径 - **调试方法**: ```bash # 使用dtc工具手动验证叠加层 dtc -I dtb -O dts -o overlay.dts overlay.dtbo # 检查输出文件中是否存在未闭合节点或非法属性 ``` #### 3. **DTBO应用后内核无法启动** - **排查方向**: - 使用`dmesg | grep fdt`查看内核解析设备树的错误日志 - 通过`fdtdump`工具对比基础DTB合并后的DTB差异 - 检查叠加层是否修改了关键节点(如内存节点导致地址冲突) --- ### 四、深度调试建议 1. **启用UFDT调试日志**: ```c // 修改system/libufdt/ufdt_overlay.c #define DEBUG 1 ``` 2. **捕获VTS测试中间数据**: - 提取测试过程中生成的临时DTB/DTBO文件 - 使用`diff -u`对比预期实际叠加结果 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值