目录
fragment 能够减少 Actiivty 的数量,提高应用的性能
级别低于Activity
1、Fragments简介
Fragment是 Activity 中用户界面的一个行为或者是一部分。你可以在一个单独的 Activity 上把多个 Fragment 组合成为一个多区域的 Ul,并且可以在多个 Activity 中再使用。你可以认为 Fragment 是 Activity 的一个模块零件,它有自己的生命周期,接收它自己的输入事件,并且可以在 Activity 运行时添加或者删除。
Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接受其宿主activity的生命周期的影响。例如,一旦activity被暂停,它里面所有的fragment也被暂停,一旦activity被销毁,它里面所有的fragment也被销毁。
类似于activity的生命周期,它具有停止、暂停以及运行 状态,也拥有可以覆盖的方法,用来在关键节点完成一些任务。可以看到,许多方法对应着activity 的生命周期方法。
这种对应非常重要。因为fragment代表activity工作,所以它的状态应该反映activity的状态。 显然,fragment需要相对应的生命周期方法来处理activity的工作。
fragment生命周期与activity生命周期的一个关键区别就在于,fragment的生命周期方法由托 管activity而不是操作系统调用。操作系统不关心activity用来管理视图的fragment。fragment的使 用是activity内部的事情。
2、创建Fragment
要创建一个 fragment,必须创建一个 fragment 的子类(或是继承自它的子类)。fragment 类的代码看起来很像 activity。它与 activity 一样都有回调函数,例如 onCreate(),onStart(),onPause(),和onStop()。事实上,如果你正在将一个现成的Android应用转而使用 Fragment 来实现,可以简单的将代码从 activity 的回调函数移植到各自的 fragment 回调函数中。
除了基类 fragment,这里还有几个你可能会继承的子类:
DialogFragment、 ListFragment 、PreferenceFragment
直接显示fragment的demo:(核心代码)
1. MainActivity.java
利用 fragment 管理器进行查找 fragment 组件(前提它是一个fragment!!,且绑定了fragment类)。
public class MainActivity extends AppCompatActivity {
TitleFragment titleFragment;
ContentFragment contentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
titleFragment = (TitleFragment)getFragmentManager().findFragmentById(R.id.fragment_title);
contentFragment = (ContentFragment) getFragmentManager().findFragmentById(R.id.fragment_content);
}
}
2. activity_main.xml
fragment 组件需要利用 name 属性来进行绑定对应的 Java文件。
<fragment
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/fragment_title"
android:name="com.jiinng.hello_fragment.TitleFragment"/>
<fragment
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="3"
android:id="@+id/fragment_content"
android:name="com.jiinng.hello_fragment.ContentFragment"/>
3. title_layout(与间接显示通用)
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:text="热门"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"
android:text="最新"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button3"
android:text="关注"/>
该文件是用于实例化、动态加载布局文件
public class TitleFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.title_layout,null);
return view;
}
}
4. content_layout(与间接显示通用)
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="no data"
android:gravity="center"/>
public class ContentFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_layout,null);
return view;
}
}
最终效果
间接显示fragment的demo:(核心代码)
1. MainActivity.java
封装了一个addContentLayout(),其作用是利用事务的方式进行添加fragment。其中用到了fragmnetManager(fragment管理器) 和 fragmnetTransaction(事务) ,将 自定义的 fragment 加载到 activoty 中。
public class MainActivity2 extends AppCompatActivity {
ContentFragment contentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
addContentLayout();
}
// 通过将contentLayout代码添加 Fragment
public void addContentLayout(){
FragmentManager fm = getFragmentManager();
// 开启事务
// 将所有的步骤集合起来,要么同时完成,要么一步错误则全部失败。
FragmentTransaction ft = fm.beginTransaction();
contentFragment = new ContentFragment();
ft.add(R.id.frameLayout_content,contentFragment);
// ft.remove(); // 删除
// ft.replace(); // 替换
// 提交事务
ft.commit();
}
}
2. activity_main_2.xml
title利用的是直接显示法,content是间接显示法。
<fragment
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/fragment_title"
android:name="com.jiinng.hello_fragment.TitleFragment"/>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:id="@+id/frameLayout_content"></FrameLayout>
实现效果
效果与第一种一致
3、管理Fragments 与 处理Fragment事务
想要管理activity 中的 fragment,可以使用 FragmentManager。可以通过在 activity 中调用getFragmentManager() 获得。
使用 FragmentManager 可以做如下事情,包括:
(1)使用 findFragmentByld()(用于在 activity 布局中提供有界面的 fragment) 或者 findFragmentByTag() 获取activity中存在的 fragment( 用于有界面或者没有界面的fragment )。
(2)使用popBackStack()(模仿用户的 BACK命令)从后台栈弹出fragment。
(3)使用addOnBackStackChangedListener() 注册一个监听后台栈变化的监听器。
小demo
1. pop_back_task_activity.xml
两个按钮组件,点击时分别在下方显示不同的内容(frameLayout组件内)
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button_one"
android:onClick="oneClick"
android:text="one"/>
<Button
android:id="@+id/button_two"
android:onClick="twoClick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:text="two" />
<FrameLayout
android:id="@+id/frameLayout_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_marginTop="46dp" />
2. PopBackFragment
自定义 fragment文件,重写构造函数。将构造函数中所传入的参数显示在fragment布局文件上,之所以这样做是用来观察变化的。
public class PopBackFragment extends Fragment {
private String title;
public PopBackFragment(String title) {
this.title = title;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_pop_back, container, false);
TextView textView = view.findViewById(R.id.textView_text);
textView.setText(title);
return view;
}
}
布局文件,设置为空白,后通过上一步的方法进行修改设置。
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment"
android:id="@+id/textView_text"
android:gravity="center"/>
3. PopBackTaskActivity.java
1. 实现两个点击事件的方法内容:通过事务的方式显示自定义的 fragment。2. 监测键盘按下的状态: 使用popBackStack()(模仿用户的 BACK命令)从后台栈弹出fragment。
public class PopBackTaskActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pop_back_task);
}
public void oneClick(View view){
PopBackFragment fragment1 = new PopBackFragment("one");
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frameLayout_content,fragment1);
ft.addToBackStack(null);
ft.commit();
}
public void twoClick(View view){
PopBackFragment fragment2 = new PopBackFragment("two");
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.frameLayout_content,fragment2);
ft.addToBackStack(null);
ft.commit();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
/**
* @Description: 键盘按下时触发该方法
* @Params: * @param keyCode
* @param event
*/
if (keyCode == KeyEvent.KEYCODE_BACK){
// 点的是返回键时
if (getFragmentManager().getBackStackEntryCount() == 0){
// 返回的栈内没有东西,则销毁。
finish();
}else {
// 有东西,则出栈
getFragmentManager().popBackStack();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}
默认情况下,屏幕旋转时会重新创建Activity。因此当 fragment 应用上面所示传参方式(带参数的构造函数)且旋转时,参数会消失。
Fragment的传参方式
Activity传参时:PopBackFragment.getInstance("one");
自定义的fragment 内容:
public static PopBackFragment getlnstance(String title){
PopBackFragment fragment = new PopBackFragment();
Bundle bundle = new Bundle();
bundle.putString("title",title);
fragment.setArguments(bundle );
return fragment;
)
取参的方法
getArguments().getString("title")
4、与Activity交互
fragment可以通过getActivity() 函数访问 Activity,并且很容易的执行类似于查找 activity 布局中的视图的任务:
View listView = getActivity().findViewByld(R.id.list);
activity能够调用 fragment 的函数 findFragmentByld() 或者 findFragmentByTag(),从 FragmentManager 中获取 Fragment
ExampleFragment fragment =(ExampleFragment)getFragmentManager().findFragmentByld(R.id.example_fragment);
fragment与activity共享事件
一个好方法是在 fragment 内部定义一个回调接口,并需要宿主 activity 实现它。
当 activity 通过接口接收到回调时,可以在必要时与布局中的其它 fragment 共享信息。
找准触发源,在fragment定义一个回调接口,再让宿主activity实现它,
5、PreferenceFragment
有时候,我们的程序需要提供一些选项功能,能让用户去定制化自己的使用风格。例如,允许用户是否自动保存登录信息,允许用户设定某个页面的刷新时间等等。我们可以使用 PreferenceActivity 基类去显示给用户一个选项设置的界面。在 Android3.0 或更高的版本上,可以使用 PreferenceFragment 类去实现这个功能。
下面将展示如何去创建和使用PreferenceFragment。
1.在res文件夹下面新建一个xml文件夹,在xml文件夹下面新建一个文件:preferences.xml。
2.在包路径下面新建一个类:Fragment 继承 PreferenceFragment
3.从 xml 文件加载选项 addPreferencesFromResource(R.xml.preferences);
// 在本类中获取 shared_pref 文件
String name = getPreferenceManager ().getSharedPreferencesName();
// 获取默认的属性配置
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
boolean checkbox_preference = sp.getBoolean("checkbox_preference",false);