Fragment学习笔记——Fragment生命周期和Fragment通信

引入Fragment的初衷是为了适应大屏幕的平板电脑 。由于平板电脑很大可以容纳更多的控件。所以使用手机的布局就有些不合适了。所以在Android3.0以前平板电脑往往需要一个单独的版本。但是有了Fragment就可以在一个版本中分别匹配手机和平板。如下图所示
这里写图片描述

Fragment的生命周期

Fragment必须嵌入到Activity中使用,因此虽然Fragment也拥有自己的生命周期,但Fragment的生命周期会受到它所在的Activity生命周期控制。
与Activity类似的是,Fragment也存在如下的状态。

  • 运行状态: 当前Fragment位于前台,用户可见,可以获得焦点。
  • 暂停状态: 其他Activity位于前台,该Fragment依然可见,只是不能获得焦点。
  • 停止状态: 该Fragment不可见,失去焦点。
  • 销毁状态: 该Fragment被完全删除,或该Fragment所在的Activity被结束。

Fragment的生命周期如下图所示
这里写图片描述

  • onAttach():当该Fragment被添加到Activity时被回调。该方法只会被调用一次。
  • onCreate(Bundle saveInstanceState):创建Fragment时被回调。该方法只会被调用一次。
  • onCreateView():每次创建、绘制该Fragment的View组件时回调该方法,Fragment将会显示该方法返回的View组件。
  • onActivityCreated():当Fragment所在的Activity被启动完成后回调该方法。
  • onStart():启动Fragment时被回调。
  • onResume():恢复Fragment时被回调,在onStart()方法后一定会回调onResume()方法。
  • onPause():暂停Fragment时被回调。
  • onStop():停止Fragment时被回调。
  • onDestroyView():销毁Fragment时被回调。该方法只会被调用一次。
  • onDestroy():销毁Fragment时被回调。该方法只会被调用一次。
  • onDetach():将该Fragment从Activity中删除、替换完成时回调该方法、在onDestroy()方法后一定会回调onDetach()方法。该方法只会被调用一次。

首先写一个小程序,简单使用Fragment并且验证它的生命周期

首先建立fragment1.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 1"
        android:textColor="#000000"
        android:textSize="25sp" />

</LinearLayout>

然后是fragment2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff00" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 2"
        android:textColor="#000000"
        android:textSize="25sp" />

</LinearLayout>

这两个布局基本一样只是换了颜色。

然后新建类Fragment1.java 继承Fragment 我们在这个类中验证生命周期
注1 :onCreateView方法,我们在这个方法中加载fragment1.xml。
注2 :还有好多老的资料onAttach(Activity activity)方法已经弃用了,所以使用onAttach(Context context)。

public class Fragment1 extends Fragment {
    public static final String TAG = "Fragment1";


    @Override
    public void onAttach(Context context) {
        super.onAttach(activity);
        Log.d(TAG, "onAttach");
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView");
        return inflater.inflate(R.layout.fragment1, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "onActivityCreated");
    }

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

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

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

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

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "onDetach");
    }
}

然后新建类Fragment2.java 继承Fragment。这个类就比较简单了

public class Fragment2 extends Fragment {

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

然后打开activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的Fragment:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false" >

    <fragment
        android:id="@+id/fragment1"
        android:name="com.example.fragmentdemo.Fragment1"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment2"
        android:name="com.example.fragmentdemo.Fragment2"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

最后打开MainActivity:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

}

最后运行如下所示:
这里写图片描述

然后打开logcat验证生命周期。
打开程序日志如下:
这里写图片描述

按home键:
红字是Android6.0的问题不用管它
这里写图片描述

在进入程序:
这里写图片描述

最后按back键:
这里写图片描述

在结合Activity生命周期以及开始的文字说明,就应该懂了。

动态添加Fragment

在上一节代码的基础上修改,打开activity_main.xml,将其中对Fragment的引用都删除,只保留最外层的LinearLayout,并给它添加一个id,因为我们要动态添加Fragment,不用在XML里添加了,删除后代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false" >

</LinearLayou

然后打开MainActivity,修改其中的代码如下所示:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Point size = new Point();
        Display display = getWindowManager().getDefaultDisplay();
        display.getSize(size);
        int width = size.x;
        int height = size.y;
        if(width > height){
            Fragment1 fragment1 = new Fragment1();
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
        }else{
            Fragment1 fragment2 = new Fragment1();
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();
        }
    }

}

首先,我们要获取屏幕的宽度和高度,然后进行判断,如果屏幕宽度大于高度就添加fragment1,如果高度大于宽度就添加fragment2。动态添加Fragment主要分为4步:
1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。

运行程序, 竖屏就显示fragment1。横屏就显示fragment2。

Fragment的通信

Fragment之间进行通信

通常情况下,Activity都会包含多个Fragment,这时多个Fragment之间如何进行通信就是个非常重要的问题了。我们通过一个例子来看一下,如何在一个Fragment中去访问另一个Fragment的视图。
还是在上一节代码的基础上修改,首先打开fragment2.xml,在这个布局里面添加一个按钮:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#ffff00" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 2"
        android:textColor="#000000"
        android:textSize="25sp" />

    <Button 
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get fragment1 text"
        />

</LinearLayout>

然后打开fragment1.xml,为TextView添加一个id:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00" >

    <TextView
        android:id="@+id/fragment1_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 1"
        android:textColor="#000000"
        android:textSize="25sp" />

</LinearLayout>

接着打开Fragment2.java,添加onActivityCreated方法,并处理按钮的点击事件:

public class Fragment2 extends Fragment {

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

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = (Button) getActivity().findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);
                Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();
            }
        });
    }

}

可以看到,在fragment2中成功获取到了fragment1中的视图,并弹出Toast。这是怎么实现的呢?主要都是通过getActivity这个方法实现的。getActivity方法可以让Fragment获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图了。

Fragment与Activity通信

Fragment与Activity通信的方式有两种:

第一种:通过setArgument()传递Bundle。
在动态添加Fragment时我们通过Fragment.setArgument(Bundle bundle)的方法为Fragment传递数据。
在onAttach()方法中通过getArgument()得到一个Bundle数据。

在上一节修改程序:

修改MainActivity.java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Fragment1 fragment1 = new Fragment1();
        Bundle arguments = new Bundle();
        arguments.putString("FragmentText", "这是新的Fragment1");
        fragment1.setArguments(arguments);
        getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();

    }

之后修改Fragment1.java

public class Fragment1 extends Fragment {

    private TextView textView;
    private String data;

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

    }

    @Override
    public void onResume(){
        super.onResume();
        textView = (TextView) getActivity().findViewById(R.id.fragment1_text);
        data = getArguments().getString("FragmentText");
        textView.setText(data);
    }
}

之后就可以运行就可得到
这里写图片描述

第二种: 在Fragment内部定义一个内部回调接口,在让包含该Fragment的Activity实现该回调接口,这样Fragment就可以调用该回调方法将数据传给Activity了。

示例程序:

新建left_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#00ff00"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/first_button"
        android:text="first button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/second_button"
        android:text="second button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/third_button"
        android:text="third button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

新建right_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#ff0000"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/right_text"
        android:text="haha"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

新建LeftFragment.java继承Fragment

public class LeftFragment extends Fragment implements View.OnClickListener {

    private MyListener myListener;
    private Button firstButton;
    private Button secondButton;
    private Button thirdButton;

    @Override
    public void onAttach(Context context){
        super.onAttach(context);

        myListener = (MyListener) context;
    }


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

    @Override
    public void onResume(){
        super.onResume();
        firstButton = (Button) getActivity().findViewById(R.id.first_button);
        secondButton = (Button) getActivity().findViewById(R.id.second_button);
        thirdButton= (Button) getActivity().findViewById(R.id.third_button);

        firstButton.setOnClickListener(this);
        secondButton.setOnClickListener(this);
        thirdButton.setOnClickListener(this);
    }

    public interface MyListener{
        void showMessage(int index);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.first_button:
                myListener.showMessage(1);
                break;
            case R.id.second_button:
                myListener.showMessage(2);
                break;
            case R.id.third_button:
                myListener.showMessage(3);
                break;
        }
    }
}

新建RightFragment.java

public class RightFragment extends Fragment{

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

修改activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/left_layout"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">

    </LinearLayout>
    <LinearLayout
        android:orientation="vertical"
        android:id="@+id/right_layout"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">

    </LinearLayout>
</LinearLayout>

最后MainActivity.java

public class MainActivity extends Activity implements LeftFragment.MyListener {

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        android.app.FragmentManager manager = getFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        LeftFragment leftFragment = new LeftFragment();
        RightFragment rightFragment = new RightFragment();
        transaction.add(R.id.left_layout, leftFragment, "leftLayout");
        transaction.add(R.id.right_layout, rightFragment, "RightLayout");
        transaction.commit();

    }

    @Override
    public void onResume(){
        super.onResume();
        textView = (TextView)findViewById(R.id.right_text);
    }



    public void showMessage(int index){
        switch (index){
            case 1:
                textView.setText("这是第一段文本");
                break;
            case 2:
                textView.setText("这是第二段文本");
                break;
            case 3:
                textView.setText("这是第三段文本");
                break;
        }
    }
}

最后运行可得到结果。

参考书籍博客

《疯狂Android讲义》
Android Fragment完全解析,关于碎片你所需知道的一切
Android手机平板两不误,使用Fragment实现兼容手机和平板的程序
Android Fragment应用实战,使用碎片向ActivityGroup说再见
android中fragment与activity之间通信原理以及例子
【Android开发】之Fragment与Acitvity通信
博客内容是我阅读以上资料加上自己的理解所得,有部分摘抄自以上资料,侵删。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值