Fragment 简介
俗称“碎片”,Android是在Android 3.0 (API level 11)开始引入Fragment的。
Fragment名为碎片不过却和Activity十分相似,Fragment用来描述一些行为或一部分用户界面在一个Activity中,你可以合并多个fragment在一个单独的activity中建立多个UI面板,同时重用fragment在多个activity中.你可以认为fragment作为一个activity中的一节模块 ,fragment有自己的生命周期,接收自己的输入事件,你可以添加或移除从运行中的activity.
一个fragment必须总是嵌入在一个activity中,同时fragment的生命周期受activity而影响,举个例子吧,当activity 暂停,那么所有在这个activity的fragments将被destroy释放。然而当一个activity在运行比如resume时,你可以单独的操控每个fragment,比如添加或删除。
Fragment的两个包app包中的fragment和v4包中的fragment的使用的区别
1,app包中的fragment,因为这个是在3.0之后才有的,支持的版本太高,在低版本中是是用不了的
android.support.v4.app.Fragment:可以兼容到1.6的版本。
2,关于这两个fragment使用标签的问题:
app.fragment和v4.fragment都是可以使用<fragment>标签的,在布局中没什么区别
当v4.fragment使用标签的时候就要特别注意了:
当这个Activity要使用android.support.v4.app.Fragment的时候,这个Activity必须继承FragmentActivity,否则就会报错
Caused by: java.lang.ClassCastException: com.example.android_fragment_bottom.fragments.TopBarFragment cannot be cast to android.app.Fragment
此时如果不继承FragmentActivity的话,编译系统会把android.support.v4.app.Fragment当成app包中的Fragment来处理。但是此时我们导入的是v4包中的Fragment。
3,得到FragmentManager的方法不一样
android.app.Fragment:使用getFragmentManager()方法
android.support.v4.app.Fragment:使用getSupportFragmentManager()方法
Fragment优点:
1,Fragment可以使你能够将activity分离成多个可重用的组件,每个都有它自己的生命周期和UI。
2,Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。
3,Fragment是一个独立的模块,紧紧地与activity绑定在一起。可以运行中动态地移除、加入、交换等。
4,Fragment提供一个新的方式让你在不同的安卓设备上统一你的UI。
5,Fragment 解决Activity间的切换不流畅,轻量切换。
6,Fragment 替代TabActivity做导航,性能更好。
7,Fragment 在4.2.版本中新增嵌套fragmeng使用方法,能够生成更好的界面效果。
8,Fragment做局部内容更新更方便,原来为了到达这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替,只有在需要的时候才加载Fragment,提高性能
Fragment 的生命周期:
先上一张Andorid API上关于Fragment的生命周期图:
对比图:
Fragment 图
生命周期的经历
- 当一个fragment被创建的时候,它会经历以下状态.
onAttach()
onCreate()
onCreateView()
onActivityCreated() - 当这个fragment对用户可见的时候,它会经历以下状态。
onStart()
onResume() - 当这个fragment进入“后台模式”的时候,它会经历以下状态。
onPause()
onStop() - 当这个fragment被销毁了(或者持有它的activity被销毁了),它会经历以下状态。
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
下面对Fragment的每个生命周期方法以及与Activity的关联进行详细介绍:
1、onAttach()
这个时候 activity已经传进来了, 获得activity的传递的值 就可以进行 与activity的通信里, 当然也可以使用getActivity(),前提是这个fragment已经和宿主的activity关联,并且没有脱离,他只调用一次。注他还可以通过Activity参数强转成上下文
2、onCreate()
系统创建fragment的时候回调。
3、onCreateView()
第一次使用的时候 fragment会在这上面画一个layout出来, 要返回一个 布局的view,也可以返回null。尽量在这里不要做耗时操作,比如从数据库加载大量数据显示listview等。
4、onActivityCreated()
当Activity中的onCreate方法执行完后调用。
当执行onActivityCreated()的时候 activity的onCreate才刚完成,所以在onActivityCreated()调用之前 activity的onCreate可能还没有完成,所以不能在onCreateView()中进行与activity有交互的UI操作,UI交互操作可以在onActivityCreated()里面进行。
5、onStart()
Fragment 启动时回调,此时Fragment可见。
6、onResume()
获取焦点时回调。
7、onPause()
失去焦点时回调。
8、onStop()
Fragment不可见时回调。
9、onDestroyView()
Fragment中的布局被移除时调用。表示fragemnt销毁相关联的UI布局, 清除所有跟视图相关的资源。
10、onDestroy()
Fragment销毁时回调。
11、onDetach()
Fragment与Activity解除关联时回调。
activity和fragment同时运行时候的生命周期
oncreate
onAttach_Fragment
onCreate_Fragment
onCreateView_Fragment
onActivityCreated_Fragment
onStart
onStart_Fragment
onResume
onResume_Fragment
按下home按键
onPause_Fragment
onPause
onStop_Fragment
onStop
切换回前台
onRestart
onStart
onStart_Fragment
onResume
onResume_Fragment
销毁activity
onPause_Fragment
onPause
onStop_Fragment
onStop
onDestroyView_Fragment
onDestroy_Fragment
onDetach_Fragment
onDestroy
android.app.Fragment包下的
Fragment 的使用
1种是在布局中调用碎片id,width,height,name.通过name指定一个继承了Fragment的类
2种在代码中碎片替换布局,写一个碎片类(要继承Fragment),碎片类加载布局通过inflater.inflate方式加载布局然后return出他的返回值.
布局代码中:
package com.example.fragment_text1;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
private FragmentManager manager;
private Fragment_mymain mymain;
private Fragment_go fragment_go;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getFragmentManager();// 获取碎片管理者
mymain = new Fragment_mymain();// 首页
fragment_go = new Fragment_go();// 购物
// 一开始就是首页
open();
}
private void open() {
//链式调用
manager.beginTransaction().replace(R.id.layout_fragment, mymain).commit();
}
public void dian(View v) {
open();
}
public void wo(View v) {
// 开启事务2
FragmentTransaction beginTransaction = manager.beginTransaction();
// 替换布局
// 1,参数是要替换的布局
// 2,参数是碎片类
beginTransaction.replace(R.id.layout_fragment, fragment_go);
// 提交事务
beginTransaction.commit();
}
public void ya(View v) {
}
}
主布局中.xml写了一个要被替换的布局
<FrameLayout
android:id="@+id/layout_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#999">
</FrameLayout>
首页碎片布局类,里面加载了布局,要继承碎片哦
package com.example.fragment_text1;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment_mymain extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.layout_fragment, null);
return inflate;
}
}
购物碎片布局类,里面加载了布局,,要继承碎片哦
package com.example.fragment_text1;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment_go extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.fragment_go, null);
return inflate;
}
}
效果图可以完成一个切换效果
android.support.v4.app.包下的Fragment 的使用
主活动页面要继承FragmentActivity才能用getSupportFragmentManager支持碎片管理器,向里面添加或替换的碎片类都继承import android.support.v4.app.Fragment;包下的Fragment
其他的添加和切换的方式和上面的一样,有点就是支持版本1.6
Fragment 的使用2
使用add,和show,hide可以保留痕迹:因他是添加而不是上面的替换
在oncreter里面我写了
manager = getFragmentManager();//获取碎片管理器
mymain = new Fragment_mymain();// 首页
fragment_go = new Fragment_go();// 购物
transaction = manager.beginTransaction();//开启服务
transaction.add(R.id.hehe, mymain);//添加碎片,同样的注碎片只能添加一次
transaction.add(R.id.hehe, fragment_go);
transaction.commit();//开启一次服务就要提交一次
然后在点击事件中写
transaction = manager.beginTransaction();//开启
transaction.show(mymain);//显示碎片
transaction.hide(fragment_go);//隐藏碎片
transaction.commit();//提交
关于xml布局中Fragment与 FrameLayout的理解(动态替换的Fragment,为什么替换的布局是FrameLayout?)?
FrameLayout与Fragment标签都是用来放Fragment的,区别是,Fragment标签只能设置固定的Fragment,而FrameLayout中可以通过FragmentManager更换Fragment
注他A布局被替换之后他的属性和方法会在B替换碎片布局的身上
用fragment 替换 布局中的LinearLayout,然后如何换回来???
可以用.remove() 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。
两个Fragment之间如何传递数据?
访问:http://www.cnblogs.com/graphics/p/5151547.html
默认开始碎片布局是最后添加的布局
Fragment add replace 区别?
用法上add配合hide或是remove使用,replace一般单独出现。
注:mymain进行了操作切换他自己时mymain里面的数据不会被干掉(因为我在oncreate中new了一次)
当切换成其他碎片的时候就会把mymain给干掉换成fragment_go
如何隔类add show hide remove
就要给add方法添加第三个参数是tag
show 和 hide ,remove 通过管理者.findFragmentTag("来制定碎片")
1、activity--->碎片
(1)如果碎片是通过xml文件生成的
直接通过findViewById获取到碎片中的控件,然后给控件设置内容。
(2)如果碎片是通过代码生成的
activity中添加碎片的时候,通过碎片对象的.setArgments(bundle)
在fragment里面,通过getArgments()得到一个bundle对象,再从bundle对象里面获取内容
2、碎片--->activity
在activity中声明一个公共的方法,在这个方法中必须要有一个参数(参数类型就是要传递的数据类型)
在fragment里面,通过getActivity(),可以获取到宿主activity对象,再调用宿主对象中提供的公共方法,
把数据传递在这个方法中。
获取assets目录中的文件流的方法:getActivity().getAssets().open("day10.txt");
3、碎片--->碎片
先把一个碎片里的值传到它的宿主activity,再从宿主activity传到另一个碎片。
注意:
如果碎片中有按钮,那么按钮的点击事件只能用监听器的方式绑定,不能用属性onClick
碎片传递数据
发送
// 在Fragment1中创建Fragment2的实例
Fragment2 fragment2 = new Fragment2();
Bundle bundle = new Bundle();
// 传递实体类,需要实体类实现Serializable接口
bundle.putSerializable("key_entity", value_Entity);
// 传递字符串
bundle.putString("key_str",value_str);
// 传递int类型数
bundle.putInt("key_int",value_int);
//设置数据
fragment2.setArgument(bundle);
//调用上面的方法由 fragment1 跳转到 fragment2
showFragment(Fragment1.this, fragment2);
获取
// 获取由碎片1传递过来的实体类数据
Value_Entity value_Entity = (Value_Entity)getArgument.getSerializable("key_entity");
// 获取由碎片1传递过来的String类型数据
String value_str = (String)getArgument.getString("key_str");
// 获取由碎片1传递过来的int类型数据
int value_int = (String)getArgument.getInt("key_int");
}
View inflate = inflater.inflate(R.layout.fragment_xiaoxi, container, false);