现在主流的App中,基本的架构也都是一个主页,然后每个Tab项用Fragment做布局,不同选项做切换,使用起来也方便。Google推荐用Fragment来代替Activity。
Fragment为何要用
Fragment是Android 3.0被引用的,主要目的是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。通过将Activity布局分成片段,可以在运行时修改Activity的外观,并在由Activity管理的返回栈中留这些更改,如果仅仅只有Activity布局,那是不够的,不仅在手机上有一套布局,同时在平板上还需要设计一套布局,那样维护起来也麻烦,Fragment的优势是布局在不同设备上的适配。
除此之外,使用Fragment还有这么几方面优势:
(1)代码复用。
因为一个Fragment可以被多个Activity嵌套,是模块化UI的良好组件。
(2)Activity用来管理Fragment,Fragment可以被Attach添加和Detach释放。
(3)可控性
Fragment可以像普通对象那样自由的创建和控制,传递参数更加容易和方便。
(4)Fragment是view controller,它们包含可测试,解耦业务模块。
Fragment是什么?
可以理解为一个具有自己生命周期的控件,但又有自己处理输入事件的能力,又必须依赖于Activity,能互相通信和托管。
这张图是Fragment生命周期和Activity生命周期对比图,可以看到两者还是有很多相似的地方,比如都有onCreate(), onStart(), onPause(), onDestroy()等待,因为Fragment是托管到Activity中的,所以多了两个onAttach()和onDetach()。这里讲讲与Activity生命周期不一样的地方。
onAttach()
Fragment和Activity建立关联的时候被调用。
onCreate()
系统会在创建Fragment时调用此方法,可以初始化一段资源文件等待。
onCreateView()
系统会在Fragment首次绘制其用户界面时调用此方法,要想为Fragment绘制UI,从该方法返回View必须是Fragment布局的根视图,如果Fragment未提供UI,可以返回null
onViewCreated()
在Fragment被绘制后,调用此方法,可以初始化控件资源。
onActivityCreated()
当Activity被渲染绘制出来后。
onPause()
系统将此方法作为用户离开Fragment的第一个信号(但并不总是意味此Fragment会被销毁)进行调用。通常可以在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
onDestroyView()
Fragment中的布局被移除时调用。
onDetach()
与Activity解除关联的时候调用。
Fragment怎么用?
1.静态用法
(1)继承Fragment,重写onCreateView决定Fragment的布局。
(2)在Activity中声明此Fragment,就当和普通View一样。
例子:
fragment1.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is fragment 1"
android:textColor="#000000"
android:textSize="25sp" />
</LinearLayout>
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false" >
<fragment
android:id="@+id/fragment1"
android:name="com.example.fragmentdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
2.动态用法
上面仅仅是Fragment简单用法,它真正强大部分是动态的添加到Activity中。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display display = getWindowManager().getDefaultDisplay();
if (display.getWidth() > display.getHeight()) {
Fragment1 fragment1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
}
}
}
(1)获取到FragmentManager, 在Activity中可以直接通过getFragmentManager得到。
(2)开启一个事务,通过调用beginTransaction方法开启。
(3)向容器内加入Fragment,一般使用replace方法实现,需要传入容积的id和Fragment的实例。
(4)提交事务。
Fragment通信
Fragment可以通过getActivity()访问Activity实例,并轻松执行在Activity布局中查找视图等任务。
View listView = getActivity().findViewById(R.id.list);
同样的,Activity也可以使用findFragmentById或findFragmentByTag获取对Fragment的引用。
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
在某些情况下,可能需要通过与Activity共享事件。例如,如果一个新闻应用的Activity有两个Fragment,一个用于显示文章列表(Fragment A),另一个用于显示文章(B),那么A必须在列表项被选定后告知Activity,以便它告知B显示该文章。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
//
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
mListener.onArticleSelected(noteUri);//用户每次点击列表项时,会调用Activity,共享事件
//activity需要实现此接口
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
}