• Fragment的使用
      • fragment基本信息
      • fragment在activity中的调用步骤
      • fragment切换replaceadd
      • FragmentManager的功能
    • fragment和activity通信
    • fragment的生命周期
      • 四大状态
      • 生命周期主要回调函数介绍
      • 生命周期完整图
      • 活动和碎片生命周期对比
    • 使用fragment argument
      • 附加extra信息
      • 获取extra信息
      • 直接获取extra信息方式的缺点
    • fragment argument
      • 附加argument给fragment
      • 获取 argument
    • 通过fragment获取返回结果
    • fragment的保留
      • 保留fragment实例
      • 设备旋转与保留的fragment
      • 注意
      • 设备旋转处理与 onSaveInstanceStateBundle 方法
    • 动态加载布局技巧之后转移到专门的布局文
      • 使用限定符Qualifiers
      • 使用最小宽度限定符Smallest-width Qualifier

Fragment的使用

public class LeftFragment extends Fragment {    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view = inflater.inflate(R.layout.left_fragment, container, false);return view;}}

fragment基本信息

参考链接:http://blog.csdn.net/xyz_lmn/article/details/6927763

一、 FragmentManager可以做如下一些事情:

1、使用findFragmentById() (用于在activity layout中提供一个UI的fragment)或findFragmentByTag()
(适用于有或没有UI的fragment)获取activity中存在的fragment
2、将fragment从后台堆栈中弹出, 使用 popBackStack() (模拟用户按下BACK 命令).
3、使用addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.

添加变化到 FragmentTransaction的顺序不重要, 除以下例外:
(1)必须最后调用 commit().
(2)如果添加多个fragment到同一个容器, 那么添加的顺序决定了它们在view hierarchy中显示的顺序.当执行一个移除fragment的事务时, 如果没有调用 addToBackStack(), 那么当事务提交后, 那个fragment会被销毁,并且用户不能导航回到它. 有鉴于此, 当移除一个fragment时,如果调用了 addToBackStack(), 那么fragment会被停止, 如果用户导航回来,它将会被恢复.

提示: 对于每一个fragment事务, 你可以应用一个事务动画, 通过在提交事务之前调用setTransition()实现.
调用 commit() 并不立即执行事务.恰恰相反, 它将事务安排排期, 一旦准备好, 就在activity的UI线程上运行(主线程).如果有必要, 无论如何, 你可以从你的UI线程调用 executePendingTransactions() 来立即执行由commit()提交的事务. 但这么做通常不必要, 除非事务是其他线程中的job的一个从属.
警告: 你只能在activity保存它的状态(当用户离开activity)之前使用commit()提交事务.
如果你试图在那个点之后提交, 会抛出一个异常.这是因为如果activity需要被恢复, 提交之后的状态可能会丢失.对于你觉得可以丢失提交的状况, 使用 commitAllowingStateLoss().

fragment在activity中的调用步骤

  1. 获取FragmentManager。
  2. 获取事物FragmentTransaction,
  3. transaction对fragment进行操作,如replace(),add(),remove()等。
  4. 提交事物。transaction.commit()
FragmentManager fragmentManager = getFragmentManager();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.right_layout, fragment);transaction.commit();

fragment切换replace\add

一个container上面的多个fragment切换,如果使用replace,每次切换的时候,Fragment都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。

正确的切换方式是add(),切换时hide(),add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。这样就能做到多个Fragment切换不重新实例化

  public void switchFragment(Fragment from, Fragment to) {    if (from == null || to == null)      return;    FragmentTransaction transaction = getSupportFragmentManager()        .beginTransaction().setCustomAnimations(R.anim.tran_pre_in,            R.anim.tran_pre_out);    if (!to.isAdded()) {        // 隐藏当前的fragment,add下一个到Activity中        transaction.hide(from).add(R.id.fl_main, to).commit();      } else {        // 隐藏当前的fragment,显示下一个        transaction.hide(from).show(to).commit();      }  }

优缺点分析
在大部分情况下,这两个的表现基本相同。一般,会使用一个FrameLayout来当容器,而每个Fragment被add 或者 replace 到这个FrameLayout的时候,都是显示在最上层的。所以你看到的界面都是一样的。但是,使用add的情况下,这个FrameLayout其实有2层,多层肯定要比一层的来得浪费,所以还是推荐使用replace。当然有时候还是需要使用add的。比如要实现轮播图的效果(切换),每个轮播图都是一个独立的Fragment,而他的容器FrameLayout需要add多个Fragment,这样他就可以根据提供的逻辑进行轮播了。

FragmentManager的功能

  1. 使用findFragmentById()或findFragmentByTag()方法来获取指定的Fragment。
  2. 调用popBackStack()方法将Fragment从后台栈中弹出(模拟用户按下BACK键)
  3. 调用addOnBackStackChangeListener()注册一个监听器,用于监听后台栈的变化。
  4. 如果需要添加、删除、替换Fragment,则需要借助与FragmentTransaction对象。FragmentTransaction代表Activity对Fragment执行的多个改变。

fragment和activity通信

  • fragment在activity的布局之中
RightFragment rightFragment = (RightFragment) getFragmentManager().findFragmentById(R.id.right_fragment);调用 FragmentManager 的 findFragmentById()方法,可以在活动中得到相应碎片的实例,然后就能轻松地调用碎片里的方法了。
  • fragment通过getActivity()方法来得到和当前fragment相关联的活动实例
MainActivity activity = (MainActivity) getActivity();有了活动实例之后,在碎片中调用活动里的方法就变得轻而易举了。另外当碎片中需要使用 Context对象时,也可以使用 getActivity()方法,因为获取到的活动本身就是一个 Context对象了。
  • 两个fragment交互

一个碎片中获取相关联的活动,再通过这个活动去获取另一个碎片实例。

  • fragment通过回调和activity交互
    直接拿疯狂android讲义的例子,一看就明白
public class BookListFragment extends ListFragment{    private Callbacks mCallbacks;    // 定义一个回调接口,该Fragment所在Activity需要实现该接口    // 该Fragment将通过该接口与它所在的Activity交互    public interface Callbacks    {        public void onItemSelected(Integer id);    }    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        // 为该ListFragment设置Adapter        setListAdapter(new ArrayAdapter(getActivity(),                android.R.layout.simple_list_item_activated_1,                android.R.id.text1, BookContent.ITEMS));    }    // 当该Fragment被添加、显示到Activity时,回调该方法    @Override    public void onAttach(Activity activity)    {        super.onAttach(activity);        // 如果Activity没有实现Callbacks接口,抛出异常        if (!(activity instanceof Callbacks))        {            throw new IllegalStateException(                "BookListFragment所在的Activity必须实现Callbacks接口!");        }        // 把该Activity当成Callbacks对象        mCallbacks = (Callbacks)activity;    }    // 当该Fragment从它所属的Activity中被删除时回调该方法    @Override    public void onDetach()    {        super.onDetach();        // 将mCallbacks赋为null。        mCallbacks = null;    }    // 当用户点击某列表项时激发该回调方法    @Override    public void onListItemClick(ListView listView        , View view, int position, long id)    {        super.onListItemClick(listView, view, position, id);        // 激发mCallbacks的onItemSelected方法        mCallbacks.onItemSelected(BookContent            .ITEMS.get(position).id);    }    public void setActivateOnItemClick(boolean activateOnItemClick)    {        getListView().setChoiceMode(                activateOnItemClick ? ListView.CHOICE_MODE_SINGLE                        : ListView.CHOICE_MODE_NONE);    }}

在activity中,在onItemSelected会创建一个新额fragment并且赋值他的arguments,这在接下来会讲到。

public class SelectBookActivity extends Activity implements        BookListFragment.Callbacks{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        // 加载/res/layout目录下的activity_book_twopane.xml布局文件        setContentView(R.layout.activity_book_twopane);    }    // 实现Callbacks接口必须实现的方法    @Override    public void onItemSelected(Integer id)    {        // 创建Bundle,准备向Fragment传入参数        Bundle arguments = new Bundle();        arguments.putInt(BookDetailFragment.ITEM_ID, id);        // 创建BookDetailFragment对象        BookDetailFragment fragment = new BookDetailFragment();        // 向Fragment传入参数        fragment.setArguments(arguments);        // 使用fragment替换book_detail_container容器当前显示的Fragment        getFragmentManager().beginTransaction()            .replace(R.id.book_detail_container, fragment)            .commit();  //①    }}

获取到自己的arguments

public class BookDetailFragment extends Fragment{    public static final String ITEM_ID = "item_id";    // 保存该Fragment显示的Book对象    BookContent.Book book;    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        // 如果启动该Fragment时包含了ITEM_ID参数        if (getArguments().containsKey(ITEM_ID))        {            book = BookContent.ITEM_MAP.get(getArguments()                .getInt(ITEM_ID)); //①        }    }}

fragment的生命周期

四大状态

1、运行状态

fragment课件,并且关联的activity处于运动状态。

2、暂停状态

活动进入暂停,与其关联的可见fragment就进入到暂停状态。

3、停止状态

活动进入停止状态,与其关联的fragment也进入停止状态
或者:通过调用FragmentTransaction的 remove()、replace()方法将碎片从活动中移除,但有在事务提
交之前调用 addToBackStack()方法,这时的碎片也会进入到停止状态。总的来说,进入
停止状态的碎片对用户来说是完全不可见的,有可能会被系统回收

4、销毁状态

碎片总是依附于活动而存在的,因此当活动被销毁时,与它相关联的碎片就会进入
到销毁状态。或者通过调用 FragmentTransaction 的 remove()、replace()方法将碎片从活
动中移除,但在事务提交之前并没有调用 addToBackStack()方法,这时的碎片也会进入
到销毁状态。

生命周期主要回调函数介绍

生命周期完整图

活动和碎片生命周期对比

在碎片中你也是可以通过 onSaveInstanceState()方法来保存数据的,
因为进入停止状态的碎片有可能在系统内存不足的时候被回收。保存下来的数据在
onCreate()、onCreateView()和 onActivityCreated()这三个方法中你都可以重新得到,它们都含
有一个 Bundle 类型的 savedInstanceState 参数。

使用fragment argument

附加extra信息

fragment 中启动Activity并且携带extra信息。

  Intent i = new Intent(getActivity(), XXXActivity.class);  i.putExtra(key, value);  startActivity(i);

获取extra信息

fragment启动了一个activity,这个activity中的fragment获取其所携带的extra信息。

getActivity().getIntent().getSerializableExtra(key);//注意类型转换

直接获取extra信息方式的缺点

只需几行简单的代码,就可以实现让fragment直接获取托管activity的intent。但是这种方式是以牺牲fragment的封装性为代价的。这个fragment不再是可复用的构建单元,总需要由某个具体的activity托管着。

fragment argument

每个fragment实例都可以附带一个Bundle对象,该Bundle包含有key-value对。要创建fragment argument,首先需创建 Bundle 对象。然后,使用 Bundle 限定类型的“put”
方法(类似于 Intent 的方法),将argument添加到bundle中(如以下代码所示)。

Bundle args = new Bundle();args.putSerializable(key, Object);args.putInt(key, myInt);args.putCharSequence(MY_STRING, myString);

附加argument给fragment

Fragment.setArguments(Bundle)

调用上面的方法将argument bundle 传递给fragment。注意,该任务必须在fragment创建后、添加给activity前完成。

为满足以上苛刻的要求,Android开发者遵循的习惯做法是:
(1)添加名为 newInstance() 的静态方法给 Fragment 类。使用该方法,完成fragment实例及bundle对象的创建,然后将argument放入bundle中,最后再附加给fragment。
(2)托管activity需要fragment实例时,需调用 newInstance() 方法,而非直接调用其构造方法。而且,为满足fragment创建argument的要求,activity可传入任何需要的参数给 newInstance() 方法。

public static XXFragment newInstance((视情况定参数)){    Bundle args = new Bundle();    args.putSerializable(key, value);    XXFragment fragment = new XXFragment();    fragment.setArguments(args)    return fragment;

交互的activity和fragment不需要也无法同时保持通用独立性。 XXActivity 必须了解XXFragment 的内部细节,比如知晓它内部有一个 newInstance(UUID) 方法 。这很正常。托管activity就应该知道有关托管fragment方法的细节,但fragment则不必知道其托管activity的细节问题。至少在需要保持fragment通用独立性的时候是如此。

获取 argument

Fragment的getArguments()方法,接着调用Bundle的限定类型的“get”方法

通过fragment获取返回结果

调用 Fragment.startActivityForResult(…) 方法,而非Activity的startActivityForResult(…) 方法;选择覆盖 Fragment.onActivityResult(…) 方法,而非 Activity.onActivityResult(…) 方法。

除将返回结果从托管activity传递给fragment的额外实现代码之外, Fragment.startActivity-ForResult(Intent,int) 方法的实现代码与 Activity 的同名方法基本相同。从fragment中返回结果的处理稍有不同。fragment能够从activity中接收返回结果,但其自身无法产生返回结果。只有activity拥有返回结果。因此,尽管 Fragment 有自己的startActivityForResult(…)和 onActivityResult(…) 方法,但却不具有任何 setResult(…) 方法。

fragment的保留

保留fragment实例

在fragment的onCreat()方法中

fragment的 retainInstance 属性值默认为false。这表明其不会被保留。因此,设备旋转时
fragment会随托管activity一起销毁并重建。调用 setRetainInstance(true) 方法可保留fragment。已保留的fragment不会随activity一起被销毁。相反,它会被一直保留并在需要时原封不动的传递给新的activity。
对于已保留的fragment实例,其全部实例变量(如 mPlayButton 、 MPlayer 和 mStopButton )值也将保持不变,因此可放心继续使用

设备旋转与保留的fragment

保留的fragment的工作原理:可销毁和重建fragment的视图,但无需销毁fragment自身。设备配置发生改变时, FragmentManager 首先销毁队列中的fragment的视图。在设备配置改变时,总是销毁与重建fragment与activity的视图,都是基于同样的理由:新的配置可能需要新的资源来匹配;当有更合适的匹配资源可以利用时,则需重新创建视图。紧接着, FragmentManager 检查每个fragment的 retainInstance 属性值。
如属性值为false(初始默认值), FragmentManager 会立即销毁该fragment实例。随后,为适应新的设备配置,新activity的新 FragmentManager 会创建一个新的fragment及其视图。

属性值为true时。则该fragment的视图立即被销毁,但fragment本身不会被销毁。为适应新的设备配置,当新的activity创建后,新的 FragmentManager 会找到被保留的fragment,并重新创建它的视图,

(1) fragment必须同时满足两个条件才能进入保留状态:
 已调用了fragment的 setRetainInstance(true) 方法
 因设备配置改变(通常为设备旋转),托管activity正在被销毁
(2)Fragment处于保留状态的时间非常短暂,即fragment脱离旧activity到重新附加给立即创建的
新activity之间的一段时间

注意

只有当activity因设备配置发生改变被销毁时,fragment才会短时间处于被保留状态。如果activity是因操作系统需要回收内存而被销毁,则所有被保留的fragment也会被随之销毁。

设备旋转处理与 onSaveInstanceState(Bundle) 方法

onSaveInstanceState(…) 方法的设计用途——保存并恢复应用的UI状态
Fragment.onSaveInstanceState(…) 方法与保留fragment方法的主要区别在于,数据可以保存多久。如只需短暂保留数据,能应对设备配置改变就可以了,则保留fragment可以很轻松地解决问题。如果是保存对象,则更能体会使用保fragment的便利。因为我们再也无需操心要保存的对象是否已实现 Serializable 接口了。如需持久地保存数据,保留fragment的方式就行不通了。用户暂时离开应用后,如系统因回收内存需要销毁activity,则保留的fragment也会被随之销毁。

动态加载布局技巧(之后转移到专门的布局文)

使用限定符Qualifiers

使用最小宽度限定符(Smallest-width Qualifier)

最小宽度限定符允许我们对屏幕的宽度指定一个最小指(以 dp 为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载一个布局,屏幕宽度小于这个值的设备就加载另一个布局。比如: res 目录下新建 layout-sw600dp 文件夹

更多相关文章

  1. Android:静态注册BroadcastReceiver
  2. Android(安卓)教你一步步搭建MVP+Retrofit+RxJava网络请求框架
  3. Android(安卓)Studio增量更新方法
  4. Android中与外部进程通信和调用外部程序
  5. Android中persistent属性用法详解
  6. 秒懂Android(安卓)Studio的奇技淫巧
  7. Android开发艺术探索
  8. Android(安卓)View的onTouch、onClick和onLongClick事件分析
  9. Android网页WebView图片文件上传的问题

随机推荐

  1. Android(安卓)统一工具类
  2. 迅为电子推出四核ARM开发板,Android开发
  3. Android与H5前端数据交互实现
  4. Android权限之三共享UID和签名
  5. Android的MVVM模式优缺点
  6. AndroidStudio NDK的接入FFmpeg填坑记
  7. Android中ImageView 中xml属性值android:
  8. android studio 使用AIDL实现IPC
  9. Android日志通过logcat实时输出至文件
  10. Android中常用的五种布局方式:LinearLayo