【Android】学习Fragment

2019-03-14  本文已影响0人  irenb

前言:除了安卓四大组件(activityservicecontent providerbroadcast receiver)之外,还有一个最重要的知识点是:fragment

1. Fragment 是什么?

Fragment 也叫碎片,片段(相当于 迷你的 Activity ,或者是 Activity 的模块化的组件)。是 Google 在 Android 3.0 引入的,主要为了给大屏幕的 UI 提供支持的。

实际开发中两个作用:

Fragment 可以理解为一个迷你的 Activity 或者是 Activity 的模块化的组件,它有自己的生命周期与显示界面,我们可以利用多个 Fragment 嵌套在 Activity 达到以下的功能,如适配平板,或适配横竖屏幕,或者在程序运行的过程中动态的更改我们的 UI 界面。如下图:


上图是显示应用运行在手机情况下,从一个列表页面跳转到详细页面的例子。如果我们不使用 Fragment 的情况,当应用运行在平板上面的情况,就只能显示放大版的手机显示的界面,为了利用平板的特性,Android 在 3.0 版本中提供了Fragment 技术,我们就可以将列表与内容以组件的方式插入,在手机上分屏显示两个内容,在平板上面就可以左右显示两个内容。

你可以将片段视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且你可以在 Activity 运行时添加或删除片段(有点像你可以在不同 Activity 中重复使用的“子 Activity ”)。

片段必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。

2. 如何使用 Fragment

2.1 创建 Fragment

如果需要使用 Fragment 的话,需继承 Fragment 类,目前有两个 Fragment 类:

继承 Fragment 至少需实现以下方法:

import android.support.v4.app.Fragment;

public class FirstFragment extends Fragment {
    @Nullable
    @Override
    /* 系统会在片段首次绘制其用户界面时调用此方法,并将创建的UI界面返回 */
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        /* 返回一个view,把布局返回去 */
        View view = inflater.inflate(R.layout.fragment_first, null);
        
        return view;
    }
}

2.2 使用 Fragment

方式1:在 Activity 的布局文件中添加一个 Fragment 控件

<!-- 使用 XML 添加 fragment 子模块 -->
<fragment android:name="com.example.testfragment.FirstFragment"
    android:id="@+id/abc"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

android:name 属性指定要在布局中实例化的 Fragment 类。注意如果是在 xml 中声明的 Fragment 的话,必须给这个 Fragment 设置 id 或者 tag。

方式2:动态添加一个 Fragment 到 Activity 指定的控件内部

FirstFragment firstFragment = new FirstFragment();

// 获取到低版本兼容的 FragmentManager( getFragmentManager(); 支持3.0以上版本 )
FragmentManager fm = getSupportFragmentManager();

// 1.开启一个 Fragment 事务(即可对 Fragment 进行操作)
FragmentTransaction transaction = fm.beginTransaction();

// 2.添加一个 Fragment 到 Activity 指定的控件内部(每调用一次 add 方法,就添加一次,会重复叠加)
// (参数:布局容器 FrameLayout 的 ID,fragment 对象,动态添加时需要设置一个 id/tag)
transaction.add(R.id.content, firstFragment, "abc");

// 3.提交(对 Fragment 进行任何操作都必须提交)
transaction.commit();

2.3 传值给 Fragment

// 页面之间的传值:Bundle是传递数据的集合
Bundle bundle = new Bundle();
bundle.putString("title", "Fragment的标题");
// bundle.putCharSequence("title", title);
// 通过 Bundle 把参数从 Activity 中传给 Fragment
firstFragment.setArguments(bundle);
/* 接收传递的参数 */
Bundle bundle = getArguments();
String title = bundle.getString("title");

3. Fragment 的生命周期


创建的生命周期:

4. Fragment 的操作 FragmentTransaction

我们可以使用 FragmentTransaction 来对 Fragment 进行操作,如 add、replace、attach、detach、remove、show、hide。

4.1 add() 方法

作用:将一个 Fragment 添加到一个页面,可以重复叠加
add(int containerViewId, Fragment fragment, String tag)

FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.content, firstFragment, "abc");
transaction.commit();

4.2 replace() 方法

作用:将容器内的 Fragemnt 移除后,再进行添加
replace(int containerViewId, Fragment fragment, String tag)

FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.content, firstFragment, "abc");
transaction.commit();

4.3 detach() 方法

作用:将一个 Fragment 从 UI 上面解绑

 Fragment fragment =  fm.findFragmentByTag("abc");
 FragmentTransaction transaction = fm.beginTransaction();
 transaction.detach(fragment);

4.4 attach() 方法

作用:将一个 Fragment 重新绑定到 UI

FragmentManager fm =  getSupportFragmentManager();
Fragment fragment =  fm.findFragmentByTag("abc");
FragmentTransaction transaction = fm.beginTransaction();
transaction.attach(fragment);
transaction.commit();

4.5 remove() 方法

作用:将一个 Fragment 从 Activity 删除

FragmentManager fm =  getSupportFragmentManager();
Fragment fragment =  fm.findFragmentByTag("abc");
FragmentTransaction transaction = fm.beginTransaction();
transaction.remove(fragment);
transaction.commit();

4.6 show() 方法

作用:显示一个 Fragment(不会调用任何生命周期方法,常用这个)

FragmentManager fm =  getSupportFragmentManager();
Fragment fragment =  fm.findFragmentByTag("abc");
FragmentTransaction transaction = fm.beginTransaction();
transaction.show(fragment);
transaction.commit(); 

4.7 hide() 方法

作用:隐藏一个 Fragment(不会调用任何生命周期方法,常用这个)

FragmentManager fm =  getSupportFragmentManager();
Fragment fragment =  fm.findFragmentByTag("abc");
FragmentTransaction transaction = fm.beginTransaction();
transaction.hide(fragment);
transaction.commit(); 

4.8 commit() 和 commitAllowingStateLoss() 方法的区别

Activity 在以下的操作下容易引起回收并触发 onSaveInstanceState()

以上几种情况下不能进行状态的提交,如果提交的话会出现以下错误
Can not perform this action after onSaveInstanceState

出现这个错误的时候,我们有两个解决方法:

为了防止在 onSaveInstanceState 方法中调用 commit 会报错,我们使用 commitAllowingStateLoss,可以防止状态丢失报错!

5. Fragment 与返回键

默认情况下,Fragment 是不会响应返回键的。如果需要做到类似Activity回退到上一个界面这样的效果,必须将 FragmentTransaction 加入返回栈。

FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.content, firstFragment, "abc" + index);
// 加入返回任务栈,可通过系统返回按钮控制返回
transaction.addToBackStack(null); // 任务名可为空,也可通过任务名控制多层返回

addToBackStack(String name);
name 参数代表这次 FragmentTransion 的名称,我们可以根据这 个名称找到相应的操作,并进行回退动作。也可以传null,代表不记录该次操作的名称。

如果我们将某次操作加入回退栈的话,我们有以下几种方式进行回退:

popBackStack() 回退到上一次操作前的状态 。
popBackStack(String name, int flags) 回退到某次 name 的操作状态。
flag 为 0 表示回退到任务 name 的操作状态的这一步。
flag 为 POP_BACK_STACK_INCLUSIVE 表示回退到任务 name 的操作状态的上一步。
popBackStack(int id, int flags) 回退某个 id 的操作状态,id 为 commit() 返回的。

@Override
public void onBackPressed() {
    Log.i("11", "点击了系统返回按钮");
    super.onBackPressed();

    FragmentManager fm = getSupportFragmentManager();
    /* 返回到上一页 */
    // fm.popBackStack();
    /* 返回到指定页(参数:加入返回任务栈的任务名, 标记) */
    fm.popBackStack("abc", 0);
}

6. Fragment 动画

默认情况下 Fragment 显示和隐藏是不显示动画的,不过 FragmentTransaction 提供了三种显示的动画的方式:

7. Fragment 间的交互(通信)

使用回调的方式,让 FragmentActivity 充当中间交互的桥梁。
先定义一个接口(一种规范,这里相当于 FragmentActivity 的基类,方便多个不同的 Activity 使用),再在 FragmentActivity 中实现接口中定义的方法。
1》定义一个接口(OneOnClickListener.java)

package net.cbi360.testfragment;

public interface OneOnClickListener {
    public void OneOnClick(int index);
}

2》实现接口的方法

public class CommonActivity extends FragmentActivity implements OneOnClickListener {
    TwoFragment two;

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

        FragmentManager fm = getSupportFragmentManager();
        OneFragment one = (OneFragment)fm.findFragmentByTag("one");
        one.setOneOnClickListener(this);
        two = (TwoFragment)fm.findFragmentByTag("two");
    }

    public void OneOnClick(int index) {
        String msg = "点击了" + index + "按钮";
        Log.i("CommonActivity", msg);
        two.setMessage(msg);
    }
}
public class OneFragment extends Fragment {
    OneOnClickListener activity;
    int index = 0;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (null != savedInstanceState) {
            // 恢复参数的值
            index = savedInstanceState.getInt("index");
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_one, null);
        Button button = (Button)view.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Log.i("OneFragment", "点击了按钮");
                index++;
                activity.OneOnClick(index);
            }
        });
        return view;
    }

//    public void setActivity(CommonActivity activity) {
//        this.activity = activity;
//
//    }

    // 解耦(减少关联性,方便不同activity重用)
    public void setOneOnClickListener(OneOnClickListener activity) {
        this.activity = activity;

    }

//    @Override
//    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
//        super.onActivityCreated(savedInstanceState);
//        // 也可以从生命周期方法中拿到 Activity
//        activity = (OneOnClickListener)getActivity();
//    }


    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        // 保存参数的值
        outState.putInt("index", index);
    }
}
/* 这个方法的作用是:当页面的状态/参数值丢失时我们来进行保存(缓存页面参数的值) */
@Override
// 当页面翻转时/按下Home键时/按下电源键时/Activity跳转时,会触发下面这个方法
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);

    // 保存值
    outState.putInt("index", index);
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 获取保存的值(注意:先判断一下是否有上次缓存的信息,有的话再获取)
    if (null != savedInstanceState) {
        index = savedInstanceState.getInt("index");
    }
}
上一篇 下一篇

猜你喜欢

热点阅读