很久以前就学过如何使用Fragment,但总感觉对它特别陌生,所以这次再一次认识Fragment,加深对Fragment的印象。
今天要弄懂的几个问题:
- Fragment是什么;
- 什么时候会用到Fragment;
- Fragment的生命周期;
- 如何静态和动态使用Fragment;
- Fragment回退栈;
- Fragment事务;
- Fragment与Activity的通信;
以下是参考的博客:
- http://blog.youkuaiyun.com/lmj623565791/article/details/37970961
以下是参考的书籍:
- 《疯狂的Android讲义》电子工业出版社
1.Fragment是什么
Fragment是Android3.0引入的新API,Fragment代表了Activity的子模块,因此可以把Fragment理解为Activity “片段”。虽然Fragment拥有自己的生命周期,但会受到其所在的Activity的生命周期控制,例如当Activity暂停时,该Activity内的所有Fragment都会暂停。也可以这样理解:Fragment是Activity的轻量级。在Activity在运行过程中,可以通过FragmentManager的add();remove();replace();方法去动态地添加、删除、替换 Fragment。一个Activity可以同时组合多个Fragment,反过来一个Fragment可以同时被多个Activity复用。
2.什么时候会用到Fragment
- 需频繁切换界面显示的需求下;
- 在资源有限的情况下;
- 缓解Activity任务过重的情况下;
- 处理在不同屏幕上的UI组件的布局问题(平板、横竖屏);
- 将屏幕分为多个碎片;
(如果还有,请评论补充!)
3.Fragment的生命周期
与Activity类似的是,Fragment也有:运行状态、暂停状态、停止状态、销毁状态;
onAttach():当Fragment被添加到Activity时被回调;
onCreate():创建Fragment时被回调;
onCreateView():每次创建、绘制view时被回调;
onActivityCreated():当Fragment所在的Activity被启动完成后被回调;
onStart():启动Fragment时被回调;
onResume():恢复Fragment时被回调;
onPause():暂停Fragment时被回调(可见,但不能获得焦点);
onStop():停止Fragment时被回调(不可见,失去焦点);
onDestroyView():销毁Fragment所包含的view组件时被调用;
onDestroy():销毁Fragment时被回调;
1
4.1 静态使用Fragment
静态就相当于主xml添加两个<fragment>控件,通过name属性再绑定两个java文件,并且java文件继承于Fragment,重新onCreateView(),return回各自绑定的xml文件。
代码我就不贴了,这个应该是最基础最基础的了。
4.2 动态使用Fragment
做个小demo,就是2个按钮,单击切换fragment
activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/id_content"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bta"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="A" />
<Button
android:id="@+id/btb"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="B" />
</LinearLayout>
</LinearLayout>
接下来是MainActivity
public class MainActivity extends ActionBarActivity implements View.OnClickListener {
private Button bta, btb;
private FragmentA newfragmenta;
private FragmentB newfragmentb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bta = (Button) findViewById(R.id.bta);
btb = (Button) findViewById(R.id.btb);
// 设置默认的Fragment
setDefaultFragment();
//按钮事件
bta.setOnClickListener(this);
btb.setOnClickListener(this);
}
private void setDefaultFragment() {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
newfragmenta = new FragmentA();
ft.replace(R.id.id_content, newfragmenta).commit();
}
@Override
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.bta:
if (newfragmenta == null) {
newfragmenta = new FragmentA();
}
ft.replace(R.id.id_content, newfragmenta).commit();
break;
case R.id.btb:
if (newfragmentb == null) {
newfragmentb = new FragmentB();
}
ft.replace(R.id.id_content, newfragmentb).commit();
break;
}
}
两个xml文件 fragmenta.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello I'm A" />
</LinearLayout>
fragmentb.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hey,I'm B " />
</LinearLayout>
两个fragment的java文件几乎一致,就只贴一个出来就行
public class FragmentA extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragmenta, container, false);
}
}
现在我们开看看效果
其关键的就是
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
newfragmenta = new FragmentA();
ft.replace(R.id.id_content, newfragmenta).commit()//用FragmentA 替换id_content
Fragment常用的三个类:
android.app.Fragment 主要用于定义Fragment
android.app.FragmentManager 主要用于在Activity中操作Fragment
android.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白~
a、获取FragmentManage的方式:getFragmentManager() // v4中,getSupportFragmentManager
b、主要的操作都是FragmentTransaction的方法:FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
- transaction.add() :往Activity中添加一个Fragment;
- transaction.remove() :从Activity中移除一个Fragment(没有添加到回退栈的情况);
- transaction.replace():使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体;
- transaction.hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁;
- transaction.show():显示之前隐藏的Fragment;
- transatcion.commit():提交事物;
注意:常用Fragment的哥们,可能会经常遇到这样Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
5.Fragment回退栈
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.id_content, fragmentB, "B");
ft.addToBackStack(null);//加入回退栈
ft.commit();
在代码中添加addToBackStack(null)这一句就将回退栈里,当按回退键的时候逐层返回,直至栈空然后完全退出到桌面。
可以看demo效果图:
我来解析一下这个demo,通过点击Abutton启动fragmentB,Bbutton启动fragmentC,然后单击回退键,逐层退出栈。
MainActivity的布局文件:
<LinearLayout 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"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/id_content"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
MainActivity.java文件:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.id_content, new FragmentA(), "A");
ft.commit();
}
FragmentA.java文件:
public class FragmentA extends Fragment implements View.OnClickListener {
private Button bta;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View viewboot = inflater.inflate(R.layout.fragmenta, container, false);
bta = (Button) viewboot.findViewById(R.id.bta);
bta.setOnClickListener(this);
return viewboot;
}
@Override
public void onClick(View v) {
FragmentB fragmentB = new FragmentB();//声明fragmentB
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.id_content, fragmentB, "B");
ft.addToBackStack(null);
ft.commit();
}
}
FragmentB.java文件:
public class FragmentB extends Fragment implements View.OnClickListener {
private Button btb;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View viewboot = inflater.inflate(R.layout.fragmentb, container, false);
btb = (Button) viewboot.findViewById(R.id.btb);
btb.setOnClickListener(this);
return viewboot;
}
@Override
public void onClick(View v) {
FragmentC fragmentc = new FragmentC();//声明fragmentC
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.hide(this);//将FragmnetB隐藏起来,负责会B、C重叠起来
ft.add(R.id.id_content, fragmentc, "C");
ft.addToBackStack(null);
ft.commit();
}
}
FragmentC.java文件:
public class FragmentC extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View viewboot = inflater.inflate(R.layout.fragmentc, container, false);
return viewboot;
}
}
3个XML文件就不贴出来了,就根据效果图来看就可以完成。
——————————————————————————————————
相关文章:
Fragment回退键addToBackStack无效的解决方法