是一种嵌入到活动(Activity)中的UI片段,能包含布局,有生命周期。
4.2.1碎片的简单用法
下面做一个简单的碎片,在一个活动(activity)中添加两个碎片:
左侧碎片布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="#201CB3"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="20dp"
android:text="这是左边的Fragment"/>
</LinearLayout>
右侧碎片布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#CEBF3C"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="20dp"
android:text="这是右边的Fragment"/>
</LinearLayout>
新建一个leftFragment类,继承自Fragment,选择 android.support.v4.app.Fragment;包
package co.example.hanwei.fragmenttest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by hanwei on 2018/9/3 0003.
*/
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;
}
}
新建一个RightFragment类,继承自Fragment,选择 android.support.v4.app.Fragment;包
package co.example.hanwei.fragmenttest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by hanwei on 2018/9/3 0003.
*/
public class RightFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right_fragment,container,false);
return view;
}
}
接下来修改activity_main.xml,通过android:name属性来显示致命要添加的碎片类名,将类名的包名也带上
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context="co.example.hanwei.fragmenttest.MainActivity">
<fragment
android:id="@+id/left_frabment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:name="co.example.hanwei.fragmenttest.LeftFragment"/>
<fragment
android:id="@+id/right_fragment"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:name="co.example.hanwei.fragmenttest.RightFragment"/>
</LinearLayout>
4.2.2动态添加碎片
修改left_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="#201CB3"
android:layout_height="match_parent">
<Button
android:id="@+id/button_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="20dp"
android:text="这是左边的Fragment"/>
</LinearLayout>
添加代码:
package co.example.hanwei.fragmenttest;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button_left = (Button)findViewById(R.id.button_left);
button_left.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_left :
/*1.创建待添加的碎片实例,*/
replaceFragment(new AnotherRightFragment());
break;
default:
break;
}
}
public void replaceFragment(Fragment fragment){
/*2.创建待添加的碎片实例,获取FragmentManager,直接调用getSupportFragmentManager获得*/
FragmentManager fragmentManager = getSupportFragmentManager();
/*3.开启一个事物,调用beginTransaction获得*/
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
/*向容器内添加或替换碎片,用replace实现,参数为需要传入容器的id和待添加的碎片实例*/
fragmentTransaction.replace(R.id.right_layout,fragment);
/*提交事物,用commit方法完成*/
fragmentTransaction.commit();
}
}
4.2.3在碎片中模拟返回栈
修改代码,添加fragmentTransaction.addToBackStack(null);
public void replaceFragment(Fragment fragment){
/*2.创建待添加的碎片实例,获取FragmentManager,直接调用getSupportFragmentManager获得*/
FragmentManager fragmentManager = getSupportFragmentManager();
/*3.开启一个事物,调用beginTransaction获得*/
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
/*向容器内添加或替换碎片,用replace实现,参数为需要传入容器的id和待添加的碎片实例*/
fragmentTransaction.replace(R.id.right_layout,fragment);
/*在碎片中模拟返回栈,接受一个名字用于返回栈的状态,一般传入null,按back键先会退到RightFragment,再按RightFragment也会消失,再按就会退出*/
fragmentTransaction.addToBackStack(null);
/*提交事物,用commit方法完成*/
fragmentTransaction.commit();
}
4.2.4碎片和活动之间的通信
活动获得碎片的实例,调用碎片中的方法:
AnotherRightFragment anotherRightFragment = (AnotherRightFragment)getFragmentManager().findFragmentById(R.id.another_text);
碎片中调用活动中的方法:
MainActivity mainActivity = (MainActivity)getActivity();
动态切换fragemnt
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。
Fragment的生命周期
打印日志:
这时点击一下home键,打印日志如下:
如果你再重新进入进入程序,打印日志如下:
然后点击back键退出程序,打印日志如下:
看到这里,我相信大多数朋友已经非常明白了,因为这和Activity的生命周期太相似了。只是有几个Activity中没有的新方法,这里需要重点介绍一下:
onAttach方法:Fragment和Activity建立关联的时候调用。
onCreateView方法:为Fragment加载布局时调用。
onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
onDestroyView方法:Fragment中的布局被移除时调用。
onDetach方法:Fragment和Activity解除关联的时候调用
Fragment之间进行通信
主要都是通过getActivity这个方法实现的。getActivity方法可以让Fragment获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图了。
Activity和Fragment的生命周期:
activity生命周期:
(1)onCreat是activity正在被创建,也就是说此时的UI操作不会更新UI,比如setText操作,所以此时在子线程调用setText不会报线程错误。详解可见Android子线程更新View的探索,在这个方法内我们可以做一些初始化工作。
(2)onRestart需要注意的是:activity正在重新启动,一般情况下,activity从不可见状态到可见状态,onRestart才会被调用,但是一定要注意的是一般来说这是用户行为导致activity不可见的时候,此时变为可见的时候才会调用onRestart,这里所说的用户行为就是用户按home键,或者进入“新”的activity。这样的操作会使activity先执行onPause,后执行onStop,这样回到这个activity会调用onRestart。为什么我这里强调说用户行为导致的不可见状态,等下我会说。。。。
(3)onStart的时候,activity才可见,但是没有出现在前台,无法与用户交互
(4)onResume的时候,activity已经可见,并且出现在前台开始活动,与onStart相比,activity都已经可见,但是onStart的时候activity还在后台,onResume才显示在前台
(5)onPause主要注意的是:此时的activity正在被停止,接下来马上调用onStop。特殊情况下快速回到该activity,onStop不会执行,会去执行onResume。
一般在这个生命周期内做存储数据、停止动画工作,但不能太耗时。
为什么特殊强调呢,因为该activity的onPause执行完了,才回去执行新的activity的onResume,一旦耗时,必然会拖慢新的activity的显示。
(6)onStop:此时的activity即将停止。在这里可以做稍微重量级的操作,同样也不能耗时。
(7)onDestroy:此时的activity即将被回收,在这里会做一些回收工作和最终资源释放。
Frangment生命周期
这张图很好的说明了Fragment与Actvivity生命周期的整合情况。通过对Fragment和Activity对比,将会发现许多不同之处,主要原因是因为Activity和Fragment之间需要交互。
(1)onAttach:onAttach()回调将在Fragment与其Activity关联之后调用。需要使用Activity的引用或者使用Activity作为其他操作的上下文,将在此回调方法中实现。
需要注意的是:将Fragment附加到Activity以后,就无法再次调用setArguments()——除了在最开始,无法向初始化参数添加内容。
(2)onCreate(Bundle savedInstanceState):此时的Fragment的onCreat回调时,该fragmet还没有获得Activity的onCreate()已完成的通知,所以不能将依赖于Activity视图层次结构存在性的代码放入此回调方法中。在onCreate()回调方法中,我们应该尽量避免耗时操作。此时的bundle就可以获取到activity传来的参数。
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mLabel = args.getCharSequence("label", mLabel);
}
}
(3)onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState): 其中的Bundle为状态包与上面的bundle不一样。
注意的是:不要将视图层次结构附加到传入的ViewGroup父元素中,该关联会自动完成。如果在此回调中将碎片的视图层次结构附加到父元素,很可能会出现异常。
这句话什么意思呢?就是不要把初始化的view视图主动添加到container里面,以为这会系统自带,所以inflate函数的第三个参数必须填false,而且不能出现container.addView(v)的操作。
View v = inflater.inflate(R.layout.hello_world, container, false);
(4)onActivityCreated:onActivityCreated()回调会在Activity完成其onCreate()回调之后调用。在调用onActivityCreated()之前,Activity的视图层次结构已经准备好了,这是在用户看到用户界面之前你可对用户界面执行的最后调整的地方。
强调的point:如果Activity和她的Fragment是从保存的状态重新创建的,此回调尤其重要,也可以在这里确保此Activity的其他所有Fragment已经附加到该Activity中了
(5)Fragment与Activity相同生命周期调用:接下来的onStart()\onResume()\onPause()\onStop()回调方法将和Activity的回调方法进行绑定,也就是说与Activity中对应的生命周期相同,因此不做过多介绍。
(6)onDestroyView:该回调方法在视图层次结构与Fragment分离之后调用。
(7)onDestroy:不再使用Fragment时调用。(备注:Fragment仍然附加到Activity并任然可以找到,但是不能执行其他操作)
(8)onDetach:Fragme生命周期最后回调函数,调用后,Fragment不再与Activity绑定,释放资源。
那就是setRetainInstance()方法,此方法可以有效地提高系统的运行效率,对流畅性要求较高的应用可以适当采用此方法进行设置。
Fragment有一个非常强大的功能——就是可以在Activity重新创建时可以不完全销毁Fragment,以便Fragment可以恢复。在onCreate()方法中调用setRetainInstance(true/false)方法是最佳位置。当Fragment恢复时的生命周期如上图所示,注意图中的红色箭头。当在onCreate()方法中调用了setRetainInstance(true)后,Fragment恢复时会跳过onCreate()和onDestroy()方法,因此不能在onCreate()中放置一些初始化逻辑,切忌!