本帖最后由 就业部_安卓组 于 2016-11-26 21:05 编辑
Fragment 介绍
学习 Android 一个新的知识点,最好是从官方文档学起,没有什么理由,只因为这里是最官方的。 除了四大组件外,我们听的或者说用的最多的就是 Fragment 了。甚至 Fragment 用的比四大组件都要多。 那 Fragment 究竟是什么呢? 文档上说: A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub activity” that you can reuse in different activities).
一个 Fragment 表示一个行为或在一个用户接口的一部分 Activity。您可以在一个单一的 activity 结合多个 fragment 来构建一个多窗格界面和重用在多个activity片段。你可以把一 fragment 作为一个 activity ,它有自己的生命周期的一个模块化部分,接收其自己的输入事件,你可以在activity运行的时候添加或移除 fragment(有点像一个“子activity”,你可以在不同的 activity 重用)。 也就是说,你可以在一个 Activity 中放多个 Fragment,也可以多个 Activity 共用一个 Fragment。
When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity’s view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity’s layout file, as a element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.
当你将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。你可以选择布局声明的方式将 Fragment 插入到 Activity 中,还可以通过代码的形式动态插入。
设计理念 Android introduced fragments in Android 3.0 (API level 11), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet’s screen is much larger than that of a handset, there’s more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity’s appearance at runtime and preserve those changes in a back stack that’s managed by the activity.
在 Android 3.0 的(API级别11)引入了 Fragment,加入这个新的 API 主要是为了支持在大屏幕上更具活力和灵活的用户界面设计,如平板电脑。由于平板电脑的屏幕比手机大很多,有更多的空间来结合和交换UI组件。
例如,一个新闻类的 app 在平板上运行,一个 Activity 就可以展示两个 Fragment,其中左边的 Fragment 显示新闻的标题,右边的 Fragment 可以显示新闻内容,如果这个 app 是在手机上运行,那么这个时候一个 Activity 是无法展示两个 Fragment 的,所以两个 Fragment 就需要放在两个Activity中,如下所示:
讲了这么多,那怎么创建一个 Fragment 呢?
Fragment 的创建
To create a fragment, you must create a subclass of Fragment (or an existing subclass of it). The Fragment class has code that looks a lot like an Activity. It contains callback methods similar to an activity, such as onCreate(), onStart(), onPause(), and onStop(). In fact, if you’re converting an existing Android application to use fragments, you might simply move code from your activity’s callback methods into the respective callback methods of your fragment.
要创建一个fragment,你必须创建Fragment的子类。Fragment看起来很像Activity。它包含类似于一个activity回调方法,例如onCreate(),onStart(), onPause(),和onStop()。事实上,如果你在现有的Android应用程序中使用fragment,你可能只需从activity的回调方法的把代码移动到你的fragment各自的回调方法中就可以了。
通常情况下,你应该实现至少下列生命周期方法:
onCreate()
创建fragment时,系统调用此方法。在你的实现,你应该初始化要当片段被暂停或停止保留片段的重要组成部分,然后重新开始。
onCreateView()
Fragment 首次被绘制时,调用这个方法。这个方法有个View对象的返回值,这个View对象是Fragment的根视图,如果Fragment不需要展示UI,那么就将它返回个null.
onPause()
系统调用此方法如用户正在离开片段(尽管它并不总是意味着该片段被破坏)的第一指示。这通常是你应该犯应当超越当前用户会话被持久化(因为用户可能不会回来)的任何变化。
绝大多数的应用会重写以上三种方法,有些时候还要其他生命周期方法,下面是 Fragment 的生命周期
Fragment 生命周期
以上是 Fragment 的生命周期,跟 Activity 差不太多,只是多了几个而已。 这些都是什么意思呢? 我们创建一个 Fragment 来看一下它的生命周期。 首先 MainActivity 的代码 [Java] 纯文本查看 复制代码 package com.mesmerize.helloworld;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
} 可以看到,代码很简单,什么也没做,那我们去看看 activity_main 这个 xml 文件。 [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:orientation="vertical">
<fragment
android:id="@+id/fragment_test"
android:name="com.mesmerize.helloworld.TestFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></fragment>
</LinearLayout>
也就是 fragment 这个节点,设置宽高和 id 之后,有个 name 的属性,这里要写上全类名,我们快速的在 com.mesmerize.helloworld 包下创建一个名为 TestFragment 的类,代码如下: [Java] 纯文本查看 复制代码 package com.mesmerize.helloworld;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by mesmerize on 2016/11/9.
*/
public class TestFragment extends Fragment {
public static final String TAG = "TestFragment";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
return new TextView(getActivity());
}
// 23 才有的api
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach");
}
// 22 之后过时
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d(TAG, "onAttach");
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.d(TAG, "onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.d(TAG, "onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.d(TAG, "onStart");
super.onStart();
}
@Override
public void onResume() {
Log.d(TAG, "onResume");
super.onResume();
}
@Override
public void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
@Override
public void onStop() {
Log.d(TAG, "onStop");
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(TAG, "onDestroyView");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(TAG, "onDetach");
super.onDetach();
}
}
上述代码可以看到我重写了 Fragment 的生命周期的所有方法,当我运行的时候,log 如下: [AppleScript] 纯文本查看 复制代码 com.mesmerize.helloworld D/TestFragment: onAttach
com.mesmerize.helloworld D/TestFragment: onAttach
com.mesmerize.helloworld D/TestFragment: onCreate
com.mesmerize.helloworld D/TestFragment: onCreateView
com.mesmerize.helloworld D/TestFragment: onViewCreated
com.mesmerize.helloworld D/TestFragment: onActivityCreated
com.mesmerize.helloworld D/TestFragment: onStart
com.mesmerize.helloworld D/TestFragment: onResume 点击一下 home 键 : [AppleScript] 纯文本查看 复制代码 com.mesmerize.helloworld D/TestFragment: onPause
com.mesmerize.helloworld D/TestFragment: onStop
重新进入应用 : [AppleScript] 纯文本查看 复制代码 com.mesmerize.helloworld D/TestFragment: onStart
com.mesmerize.helloworld D/TestFragment: onResume
如果这个时候按 back(后退键) 退出应用 : [AppleScript] 纯文本查看 复制代码 com.mesmerize.helloworld D/TestFragment: onPause
com.mesmerize.helloworld D/TestFragment: onStop
com.mesmerize.helloworld D/TestFragment: onDestroyView
com.mesmerize.helloworld D/TestFragment: onDestroy
com.mesmerize.helloworld D/TestFragment: onDetach 粗略看一眼,这不跟 Activity 一样么?
的确是非常相似的,但是多了几个方法,这里简单讲一下多了的这几个方法。
onAttach:从名字上也可以看出,这是 Fragment 和 Activity 建立关联的时候调用的。细心的朋友可能注意到,在我刚进入应用的时候,是走了两次 onAttach 方法的,其实这不是我上传代码弄错了,而是我重写了两个 onAttach 方法。他们的参数不同,一个是 onAttach(Activity activity) ,另一个是 onAttach(Context context) 。他们的区别是,onAttach(Context context) 是 API 23 之后才添加的,而 onAttach(Activity activity) 在 API 22 之后就过时了,所以如果你的编译版本是 22 之后的话,使用 onAttach(Activity activity) 是不建议的,推荐使用 onAttach(Context context) 。虽然他们一个是 Activity ,一个是 Context ,但他们是同一个对象,内存地址也是一样的,至于原因,由于篇幅的限制,我就不在此累述,感兴趣的小伙伴可以查看我在进阶篇里的帖子 : Context 的理解
onCreateView:为Fragment加载布局时调用,返回的 View 就是 fragment 显示的 View。
onViewCreated:onViewCreated在onCreateView执行完后立即执行,其中的参数 view 就是 onCreateView 里返回的 view。比如说我书写如下代码:
[Java] 纯文本查看 复制代码 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
return new TextView(getActivity());
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.d(TAG, "onViewCreated");
((TextView)view).setText("哈哈哈");
super.onViewCreated(view, savedInstanceState);
}
显示效果为:
而如果我强行将 onViewCreated 中的 view 强转为 ImageView 或者其他类型的 View,就会报错说 “Caused by: java.lang.ClassCastException: android.widget.ImageView cannot be cast to android.widget.TextView”,因此 onViewCreated 中的 view 就是 onCreateView 所 return 的 View。
onActivityCreated:当Activity中的onCreate方法执行完后调用。
onDestroyView:Fragment中的布局被移除时调用。
onDetach:Fragment和Activity解除关联的时候调用。
发现没有,从始至终我们都不需要去 AndroidManifest.xml 里注册任何东西,拿来直接用就可以了。 当然这只是 Fragment 的其中一种使用方式罢了。
那还有其他的使用方式吗?下篇将详细讲述静态和动态两种方式。
Android 人事+技术总贴
Android 基础篇总贴
Android 进阶篇总贴
Android 讨论区
以上言论,如有错误或者表达不准确或者有纰漏的地方还请指正,同时欢迎大家在评论区留言给予一定的建议,我会根据大家的意见进行相应的改正,谢谢各位!
|