Fragment
Fragment最初是为了适应不同屏幕尺寸诞生的,它可以加载一个视图,然后对视图进行管理操作,类似于Activity,而Fragment本身又可作为一个视图模块,托管给Activity来管理。 这样就减轻了Activity的负担,大部分的功能可以在Fragment里实现,Activity只负责加载管理就可以了。
Fragment生命周期
Fragment与Activity类似,生命周期也有相似之处,但是多了与View和托管对象Activity有关的方法:
创建:
1.onAttach() Fragment与Activity关联时调用
2.onCreate() Fragment初始化创建
3.onCreateView() 建立并返回Fragment的View
4.onViewCreated()该方法官方没有介绍,实际上会调用,View创建完成时调用
5.onActivityCreated() 当托管该Fragment的Activity完成创建(onCreate)时调用创建完成开始运行
1.onStart()
2.onResume()
- 转入后台
1.onPause()
2.onStop()
以上方法与Activity是一样的,Activity调用时,Fragment也会跟着调用。
结束
1.onDestroyView()与onActivityCreated()对应,Fragment视图被移除时调用
2.onDestroy()
3.onDetach()与onAttach对应,与Activity解除关联时调用。状态保存与恢复
与Activity一样,非正常退出Fragment时,也会触发 onSaveInstanceState(Bundle outState)方法,将数据保存在Bundle中,恢复的时候会调用onViewRestrored(Bundle savedInstanceState)方法。在Activity中调用的方法是onRestoreInstanceState()。
Fragment使用
Fragment是API 11 才引入的,使用的时候有android.app.fragment和v4支持包两个选项。获取FragmentManager的API也不同,v4包中使用getSupportedFragmentManager,直接继承的使用getFragmentManager
静态使用Fragment
静态使用是指将Fragment当做一个空间,定义在Layout文件中。
先定义一个Fragment引用的layout文件:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Item Frament">
</TextView>
然后新建Fragment,加载视图:
public class ItemFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.item,container,false);
return v;
}
}
到这里Fragment的部分完成了,可以把这个Fragment当做控件在XMl中直接引用,下面是Activity的layout文件
<?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:layout_height="match_parent">
<fragment
android:id="@+id/frag_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.cris.miniweather.model.fragment.ItemFragment"/>
</LinearLayout>
在Activity里setContentView设置这个layout就可以了。注意fragment控件必须指定id,否则会崩溃
动态使用Fragment
和静态使用步骤类似,都需要先建立好Fragment和它对应的layout文件,不同的是在Activity中引用时,使用FragmentManager来管理Fragment。
先完成Fragment使用的layout(frag_list),这里用了Recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_title"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
Recyclerview的对应的layout文件(item.xml),一个TextView:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="Item Frament">
</TextView>
然后建立Fragment(TitleListFragment.java),这里实现的是一个最简单的recyclerview
public class TitleListFragment extends android.support.v4.app.Fragment{
private List<String> mItems;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mItems = new ArrayList<>();
for(int i = 0; i<50; i++ ){
String item = "Title No." + i;
mItems.add(item);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.list_title,container,false);
RecyclerView mRecyclerView = (RecyclerView) v.findViewById(R.id.frag_list);
RecyclerView.LayoutManager manager=new LinearLayoutManager(getActivity());
manager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(new RecycleAdapter());
return v;
}
private class RecycleHolder extends RecyclerView.ViewHolder{
private TextView mTextView;
public RecycleHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView;
}
}
private class RecycleAdapter extends RecyclerView.Adapter<RecycleHolder>
{
@Override
public RecycleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View TitleItemView = LayoutInflater.from(getActivity()).inflate(R.layout.item,parent,false);
return new RecycleHolder(TitleItemView);
}
@Override
public void onBindViewHolder(RecycleHolder holder, int position) {
holder.mTextView.setText(mItems.get(position));
}
@Override
public int getItemCount() {
return mItems.size();
}
}
}
到这里,Fragment的部分已经完成,可以在Activity里加载它了,先设置Activity的layout文件,一个空的FrameLayout,作为Fragment的容器:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frag_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
在Activity里加载Fragment:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_container);
FragmentManager fm= getSupportFragmentManager();
if(fm.findFragmentById(R.id.frag_container) ==null) {
fm.beginTransaction()
.add(R.id.frag_container, new TitleListFragment())
.commit();
}
}
注意:
1.在Activity里是用FragmentManager来管理Fragment的,findFragmentById里的参数是Fragment容器的id,返回的是它所管理的Fragment。
2.在add方法之前,需要加一个判断,如果为null才会去添加Fragment。因为Activity非正常退出,并且被回收的时候,FragmentManager 会将它所管理的Fragment队列保存下次,Activity重新建立的时候,FragmentManager 会先回复它所保存的队列,并重建Fragment。
Fragment常用API
与Fragment相关的API主要有以下两大类
- FragmentManager
- beginTransaction() 获取FragmentTransaction对象,用来操作Fragment
- findFragmentById(id) 获取id对应的父容器中的当前Fragment
- findFragmentByTag(String tag) 获取tag对应的Fragment,tag在add时添加
- getFragment(Bundle bundle, String key) 与putFragment对应,将一个Fragment对象放在Bundle数据中
- isDestroyed() 托管该Fragment的Activity执行onDestroy后,会返回true。
- void popBackStack() 将栈顶对象弹出。相当于back键
- saveFragmentInstanceState(Fragment f) 存储f的状态。
- FragmentTransaction
- add(Fragment fragment, String tag); 调用第三个方法,containerViewId为0
- add(int containerViewId, Fragment fragment) 调用第三个方法,tag为null
- add(int containerViewId, Fragment fragment, String tag);添加fragment到container中
- addToBackStack(String name)添加Fragment到name返回栈中,默认为null
- attach(Fragment fragment) 在使用detach方法与UI解除关联之后重新关联
- commit() 提交事物
- detach(Fragment fragment) 从UI中解除Fragment的绑定。
- remove(Fragment fragment) 移除一个已经存在了的Fragment。
- hide(Fragment fragment) 隐藏一个存在的Fragment
- show(Fragment fragment) 显示一个之前隐藏的Fragment。
- replace(int containerViewId, Fragment fragment, String tag);替换一个已经存在了的Fragment(先remove,在add)