【幻化万千戏红尘】qianfeng-Android-Day18_Fragment

来源:互联网 发布:阿里云iot市场 编辑:程序博客网 时间:2024/04/27 15:06

Fragment

一、Fragment的概念和用法:

(一)、概念:

        Fragment是在Android 3.0 (API level 11)开始引入新的API技术。

        为了提高代码重用性和改善用户体验,我们将Activity中的UI组件进行分组和模块化管理。这些分组后的UI组件就是Fragment

        一个Activity页面中可以包含多个Fragment模块,而同一个Fragment模块也可以被多个Activity使用。每个Fragment有自己的布局,有自己的生命周期。虽然Fragment拥有自己的生命周期,但因为Fragment必须被嵌入到Activity中使用,因此Fragment的生命周期是受其Activity宿主的生命周期所控制的。当Activity暂停时,该Activtiy内的所有Fragment都会暂停;当Activity被销毁时,该Activity内的所有Fragment都会被销毁。

 

 

(二)、Fragment为什么能改善用户体验,另外Fragment能用于平板电脑,那么普通的手机屏幕适用吗?

答案是肯定的。Fragment本身是可复用的组件。是否在一个Activity页面中放置多个Fragment取决了屏幕的大小,如果屏幕大小不够,那么就可以在Activity A中只包含Fragment A,在Activity B中只包含Fragment B,点击A中的item跳转到B就可以。

 

 

(三)、Fragment要点:【重点

    1Fragment作为Activity界面的一部分组成出现;

    2、可以在一个Activity中同时出现多个Fragment,并且,一个Fragment亦可在多个Activity中使用;

    3、在Activity运行过程中,可以添加移除替换、隐藏、显示Fragmentadd()remove()replace()hide()show());

    4Fragment可以响应自己的输入事件,并且有自己的生命周期,当然,它们的生命周期直接受其所属的宿主Activity的生命周期控制。

    5FragmenetTransaction的方法:

· 使用replace()替换后会将之前的fragmentviewviewtree中删除

· 使用hide()方法只是隐藏了fragmentview并没有将viewviewtree中删除,随后可用show()方法将view设置为显示

(四)、Fragment家族常用的API

1、Fragment常用的三个类:

· android.app.Fragment 主要用于定义Fragment 

· android.app.FragmentManager 主要用于在Activity中操作Fragment 

· android.app.FragmentTransaction  

 

 

2、获取FragmentManage的方式:

getFragmentManager() // v4中,getSupportFragmentManager

 

3、主要的操作都是FragmentTransaction的方法

    FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务

· transaction.add()      Activity中添加一个Fragment 

· transaction.remove()    Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。

· transaction.replace()    使用另一个Fragment替换当前的,实际上就是remove()+add()的合体 

· transaction.hide()    隐藏当前的Fragment,仅仅是设为不可见,并不会销毁 

· transaction.show()   显示之前隐藏的Fragment 

· transatcion.commit()    提交一个事务

· fragment.isAdded()  判断一个Fragment是否已经被添加到事务中 

二、Fragment生命周期:

(一)、Fragment基本状态:

    1、活动状态:Resumed   当前Fragment位于前台,用户可见,可以获得焦点;

    2、暂停状态:  Paused   另一个Activity处于前台并拥有焦点,但是该Fragment所在的Activity仍然可见(前台Activity局部透明或者没有覆盖整个屏幕),不过不能获得焦点;

    3、停止状态:Stopped

要么是宿主Activity已经被停止,要么是FragmentActivity被移除但被添加到回退栈中;停止状态的Fragment仍然活着(所有状态和成员信息被系统保持着)。 然而, 它对用户不再可见,并且如果Activity被销毁,它也会被销毁;

    4、销毁状态:Destroyed  只能等待被回收。

 

(二)、Fragment生命周期:【重点

 

 

方法

描述

onAttach(Activity)

当前Fragment与Activity关联,调用!

onCreate()

完成fragment的初始化创建

 

onCreateView()

创建并返回与当前fragment相关联的层次视图view

 

onActivityCreated()

主activity的onCreate()执行完后,该方法才执行

 

onStart()

fragment可见,当主activity处于started状态后执行

 

 

onResume()

fragment能与用户交互,当主activity处于resumed状态后执行

 

 

onPause()

fragment不在与用户交互,可能在主activity将要处于paused前执行,可能该fragment被修改

 

onStop()

fragment不在可见,可能在主activity将要处于stopped前执行,可能该fragment被修改

 

onDestroyView()

允许该fragment清理视图相关资源

onDestroy()

清理掉视图state信息

onDetach()

该fragment不在于activity关联

 

1onAttach():当该Fragment被添加到Activity时被回调。该方法只会被调用一次;

2onCreate():  当创建Fragment时被回调。该方法只会被调用一次;

3onCreateView():每次创建、绘制该FragmentView组件时回调该方法,Fragment将会显示该方法返回的View组件;

4onActivityCreated():Fragment的宿主Activity被启动完成后回调该方法;

5onStart():启动Fragment时被回调;

6onResume():  onStart()方法后一定会回调onResume()方法;

7onPause():暂停Fragment时被回调;

8onStop():停止Fragment时被回调;

9onDestroyView():  销毁该Fragment所包含的View组件时调用;

10onDestroy():  销毁Fragment时被回调。该方法只会被调用一次;

11onDetach():  FragmentActivity中删除、替换完成时调用该方法。onDestroy()方法后一定会回调onDetach()方法。该方法只会被调用一次。

 

【备注:】其中大多数程序必须实现Fragment的三个回调方法分别为: 

onCreate :系统创建Fragments时调用,可做执行初始化工作或者当程序被暂停或停止时用来恢复状态,跟Activity中的onCreate相当。 

onCreateView :用于首次绘制用户界面的回调方法,必须返回要创建的Fragment视图UI。假如你不希望提供Fragment用户界面则可以返回NULL 

onPause  当用户离开这个Fragment的时候调用,这时你要提交任何应该持久的变化,因为用户可能不会回来。

 

(三)、示例代码:

1Fragment的布局文件:

<fragment
    android:id="@+id/fg"
    android:name="org.mobiletrain.fragment1.MyFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:layout="@layout/myfragment_layout"
/>

 

3Fragment文件中的java代码:

public class MyFragmentextends Fragment implements View.OnClickListener {

    private static final StringTAG = "fragment";

    //当Fragment和Activity产生关联的时候调用
    //参数activity表示宿主Activity
    
@Override
    public voidonAttach(Activity activity) {
        super.onAttach(activity);
        Log.d(TAG,"onAttach() returned: ");
    }

    //创建fragment时调用该方法
    
@Override
    public voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG,"onCreate() returned: ");
    }

    //返回Fragment的布局
    
@Nullable
    @Override
    publicView onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG,"onCreateView() returned: ");
        View view = inflater.inflate(R.layout.myfragment_layout,null);
        Button button = (Button) view.findViewById(R.id.go);
        button.setOnClickListener(this);
        return view;
    }

    //当宿主Activity创建完成时调用
    
@Override
    public voidonActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG,"onActivityCreated() returned: ");
    }

    @Override
    public voidonStart() {
        super.onStart();
        Log.d(TAG,"onStart() returned: ");
    }

    @Override
    public voidonResume() {
        super.onResume();
        Log.d(TAG,"onResume() returned: ");
    }

    @Override
    public voidonPause() {
        super.onPause();
        Log.d(TAG,"onPause() returned: ");
    }

    @Override
    public voidonStop() {
        super.onStop();
        Log.d(TAG,"onStop() returned: ");
    }

    //销毁Fragment的视图
    
@Override
    public voidonDestroyView() {
        super.onDestroyView();
        Log.d(TAG,"onDestroyView() returned: ");
    }

    //销毁Fragment
    
@Override
    public voidonDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestroy() returned: ");
    }

    //Fragment和Activity解除关系时调用
    
@Override
    public voidonDetach() {
        super.onDetach();
        Log.d(TAG,"onDetach() returned: ");
    }

    @Override
    public voidonClick(View v) {
        switch (v.getId()) {
            case R.id.go:
                startActivity(new Intent(getActivity(), BActivity.class));
                break;
        }
    }
}

(四)、运行结果观察:

1、第一次加载Fragment

onAttach()àonCreate()àonCreateView()àonActivityCreated()àonStart()àonResume()

2、在MainActivity中,点击返回键退出程序:

onPause()àonStopàonDestoryView()àonDestoty()àonDetach()

3、在MainActivity中,点击“HOME退出程序:

onPause()àonStop()

【备注:】请注意第二种和第三种情况的区别。如果点HOME键退出,则少调用了onDestroyView()onDestroy()onDetach()三个回调方法。

4、点击下一页,进入NextActivity页面:

onPause()àonStop()

(五)、跟Fragment生命周期相关的其他方法:

1onInflate():在onCreate()方法之前调用,这时窗体上的控件都没有被创建,所以不能通过getActivity().findViewById(),因为此时getActivity()返回null

2onViewCreated():在onCreateView()方法后会立刻调用onViewCreated()方法。通常在该方法中完成创建Fragment的最后工作

(六)、如果Activity生命周期和Fragment生命周期的Log都开启,那么依次会如何输出信息呢?

 

1、第一次加载MainActivity页面:

A-onCreate()àF-onAttach()àF-onCreate()àF-onCreateViewàF-onActivityCreated()àA-onStart()àF-onStart()àA-onResume()àF-onResume()

2、在MainActivity页面中,点击返回键退出程序:

F-onPause()àA-onPause()àF-onStop()àA-onStop()àF-onDestoryViewàF-onDestory()àonDetach()àA-onDestory

   3、在MainActivity中,点击“HOME退出程序:

F-onPause()àA-onPause()àF-onStop()àA-onStop()

【备注:】请同学们注意观察Activity回调方法和Fragment回调方法执行的顺序。请设想各种操作步骤,写出生命周期回调方法执行的顺序。

 

特别强调:】

ActivityonCreate()方法中,如果将Log的位置放在setContentView(R.layout.activity_main)之前,那么ActivityonCreate()方法就会在最先执行,如果将日志写在setContentView(R.layout.activity_main)之后,那么ActivityonCreate()方法就会在FragmentonViewCreated()之后执行。

三、创建Fragment:

(一)、创建Fragment的步骤:【只需要两步

1、创建一个Fragment,必须继承Fragment这个基类或其子类;

2、实现回调方法:

        Fragment类的代码看起来很像 Activity 。它包含了和activity类似的回调方法, 例如onCreate()、 onStart()、onPause()以及 onStop()。事实上,,如果你准备将一个现成的Android应用转换到使用Fragment,可能只需要将代码从你的Activity的回调方法中分别移动到你的Fragment的回调方法即可。

        通常,应当至少实现如下的生命周期方法:

onCreate()

当创建fragment时, 系统调用该方法. 

在实现代码中,应当初始化想要在fragment中保持的必要组件, 当fragment被暂停或者停止后可以恢复.

onCreateView()

fragment第一次绘制它的用户界面的时候, 系统会调用此方法. 为了绘制fragment的UI,此方法必须返回一个View, 这个view是你的fragment布局的根view. 如果fragment不提供UI, 可以返回null.

onPause()

用户将要离开fragment时,系统调用这个方法作为第一个指示(然而它不总是意味着fragment将被销毁.) 。在当前用户会话结束之前,通常应当在这里提交任何应该持久化的变化(因为用户有可能不会返回).

    【备注:】对于大部分Fragment而言,通常实现三个回调方法即可。但是实际开发中可以根据需要重写Fragment生命周期中的任意回调方法。    

四、动态创建Fragment:

(一)、概念:

如果将Fragment写在布局文件中,那么就是静态创建fragment;如果没有在布局文件中写<fragment>标签,而是在java文件中通过实例化Fragment创建Fragment的方式就是动态创建Fragment。

(二)、动态创建Fragment的步骤:

1、步骤:

(1)获得一个Fragment管理器

FragmentManager manager = getFragmentManager();

(2)开启一个事务

FragmentTransaction transaction = manager.beginTransaction();

(3)添加或者替换Fragment

//用Fragment替换Linearlayout(remove和add结合体)
//        transaction.replace(R.id.ll, new MyFragment());
        //添加一个Fragment
//        transaction.add(R.id.ll, new MyFragment());

2、Activity布局文件代码:

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="org.mobiletrain.fragment1.MainActivity"
>

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
></LinearLayout>
</RelativeLayout>

 

五、Fragment之间的数据交互:

(一)、FragmentFragment传递数据:Arguments

1、做法:

        可以通过Fragment.setArguments()方法向Fragment传递数据,并且通过getArguments()方法获取传递的数据。

2、核心代码:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public voidonItemClick(AdapterView<?> parent, View view, intposition, long id) {
        //第一种通信方式
        
String s = list.get(position);
        Fragment fragment = new RightFragment();
        Bundle args = new Bundle();
        args.putString("value", s);
        //通过setArguments方式传递参数
        
fragment.setArguments(args);
        FragmentManager manager = getFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(R.id.ll, fragment);
        transaction.commit();
    }
});

(二)、Fragment回调机制

1、原则:

Fragment类要尽量保证其独立性Fragment类中不应该有访问其他Fragment和Activity中资源的代码,否则这个Fragment就不能在不改动代码的情况下用在其他地方。

如何让多个Fragment之间可以独立多次使用,而不是紧密地绑定到一起?通常的做法就是在Fragment类中编写一个接口,然后在该Fragment的宿主窗口类中实现该接口。这样Fragment与其宿主就实现了信息交互。

2、Fragment接口回调的步骤:(五步曲)

1.Fragment文件中定义接口:MyItemClickInterface,定义抽象方法public void updateText(String fileName);

2.Fragment文件中定义属性:private MyItemClickInterface myactivity;

3.Fragment文件中的onAttach()方法中执行:if (activity instanceof MyItemClickInterface) {

            myactivity = (MyItemClickInterface) activity;

        }

4.Fragment文件中,给某个控件增加监听器,在监听器中执行://5.调用接口
myactivity.updateText(list.get(position));

5.MainActivity实现MyItemClickInterface,重写updateText(String fileName)方法。参数就是Fragment传递的数据信息,在该方法中执行希望的逻辑操作。

六、FragmentManager与Fragment事务:  【重要】

(一)、FragmentManager与FragmentTransaction示例代码:

Fragment的布局文件:

// 构建Bundle对象,将文章title放在其中。

Bundle bundle = new Bundle();

bundle.putString("fileName",fileName);

// 构建文章内容的Fragment

RightFragment fragment = new RightFragment();

// 通过fragment对象的setArguments(bundle)方法将数据传输给其他Fragment。

fragment.setArguments(bundle);

 

// 通过getFragmentManager()方法构建FragmentManager对象

FragmentManager fragManager = getFragmentManager();

// 通过FragmentManager对象的beginTransaction()方法构建FragmentTransaction对象

FragmentTransaction trans = fragManager.beginTransaction();

// 将主页面布局文件中的ViewGroup容器替换成文章内容Fragment

trans.replace(R.id.fragment_content, fragment);

// 提交事务

trans.commit();

(二)、 FragmentTransaction中的replace方法与add、hide、show方法的区别:【重要】

1.  * 使用replace()方法实现。 每次replace都会将当前的碎片进行销毁,新创建一个碎片将原有的进行替换

2.  * 使用add()、hide()、show()方法实现。被加载出来的碎片在导航切换过程中不会被销毁,只是在隐藏和显示两个状态切换而已。

3.  * 因为切换过的碎片不被销毁,自然会有内存占用上的开销,但是因为不用重新加载碎片而在性能上是优于replace的。

0 0
原创粉丝点击