Android支持库中Fragment的使用及参数传递
来源:互联网 发布:梦幻花园无法加载 网络 编辑:程序博客网 时间:2024/04/30 03:35
自己好久不写APK的界面部分了,平时的工作主要集中在APK的控制层和模型层,
或者干脆就深入到Android框架及更底层的部分了,因此许多界面的知识都有些遗忘了。
这次主要结合Android权威指南中的例子,回忆一下以前的知识,以博客的方式记录一下,
Android中使用android.support.v4.app.Fragment的基本方式。
一、Fragment的使用
我们知道Fragment的生命周期由嵌入的Activity管理。
Activity托管Fragment主要有如下两种方式:
1、在Activity的布局中添加fragment;
2、在Activity的代码中加入fragment。
第一种方式就是使用布局fragment。这种方式简单但不够灵活。
在Activity的布局中添加fragment,就等同于将fragment及其视图与activity的视图绑定在一起,
并且在activity的生命周期过程中,无法切换fragment视图。
第二种方式比较复杂,但也是唯一可以在运行时控制fragment的方式。
我们可以自行决定何时添加fragment、移除fragment等。
因此,为了追求真正灵活的UI设计,就必须以第二种方式,即以代码的方式添加fragment。
接下来,我们就看看以代码添加fragment的步骤。
考虑到兼容性,我们主要使用的是android支持库中的fragment,即android.support.v4.app.Fragment等相关类。
Fragment终究是需要嵌入到activity中,因此首先需要定义Activity的布局,示例如下:
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"></FrameLayout>
示例Activity的布局及其简单,就是定义一个FrameLayout,作为Fragment布局的容器。
对应的Activity代码如下:
//定义一个抽象的父类public abstract class SingleFragmentActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment); //FragmentManager管理fragment队列等 FragmentManager fm = getSupportFragmentManager(); //R.id.fragment_container是fragment容器的id //先从Fragment队列中查找是否有容器id对应的fragment Fragment fragment = fm.findFragmentById(R.id.fragment_container); if (fragment == null) { //由子类实现,创建Fragment fragment = createFragment(); //创建一个FragmentTransaction(fragment事务) fm.beginTransaction() //告诉fm, fragment应该放置的位置,同时用容器id作为fragment的标识符 //当需要向Activity添加多个fragment时,通常要分别为每个fragment创建具有不同资源ID的容器 .add(R.id.fragment_container, fragment) .commit(); } } protected abstract Fragment createFragment();}
从上面的代码可以看出,FragmentManager首先利用findFragmentById接口,
利用容器视图的资源ID,在fragment队列中查找对应的fragment。
当利用容器视图的资源ID找不到对应的fragment时,才创建新的fragment。
这是因为,当设备旋转或回收内存时,Android可能销毁当前的Activity。
当Activity被销毁时,它的FragmentManager会将fragment队列保存下来。
当Activity重建时,会再次调用其onCreate方法。
此时新的FragmentManager会首先获取保存的队列,然后重建fragment队列,从而恢复到原来的状态。
在SingleFragmentActivity的基础上,使用Fragment就变得很容易了。示例如下:
public class CrimeActivity extends SingleFragmentActivity { private static final String EXTRA_CRIME_ID = "stark.a.is.zhang.criminalintentapp.crime_id"; @Override //子类只需要实现createFragment方法即可 protected Fragment createFragment() { ............... return CrimeFragment.newInstance(crimeId); } ...........}
看看CrimeFragment的实现:
public class CrimeFragment extends Fragment{ ........... public static CrimeFragment newInstance(UUID crimeId) { .............. CrimeFragment crimeFragment = new CrimeFragment(); .............. return crimeFragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ............. } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //加载Fragment自己的视图 View v = inflater.inflate(R.layout.fragment_crime, container, false); ............. return v; }}
Activity的FragmentManager负责调用队列中fragment的生命周期方法。
Activity添加fragment供FragmentManager管理时,Fragment的onAttach、onCreate以及onCreateView方法会被调用。
托管Activity的onCreate方法执行后,Fragment的onActivityCreated方法也会被调用。
FragementManager将保证fragment与Activity的运行状态保持一致。
例如,在运行态的Activity中添加Fragment时,FragmentManager将立即调用Fragment的
onAttach、onCreate、onCreateView、onActivityCreated、onStart和onResume方法,使Fragment的运行状态“追赶”上Activity。
一旦fragment的状态与Activity保持了一致,FragmentManager就会接受操作系统的指示,
按照Activity的状态,调用Fragment的其他生命周期方法。
以上是Fragment的基本用法,接下来看看Fragment之间的参数传递。
二、Fragment通过Activity进行参数传递
Fragment可以利用startActivity的方式启动另一个Activity,并在Intent中携带额外的信息。
假设另一个Activity,也是由Fragment来完成界面的布局,那么目的Fragment可以从对应的托管Activity获取传递的参数。
例如:
public class CrimeFragment extends Fragment { ....... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //从托管Activity中获取Intent,然后再获取额外信息 UUID crimeId = (UUID) getActivity().getIntent().getSerializable(ARG_CRIME_ID); ................ }}
这种做法比较简单,但破坏了Fragment的封装性。
Fragment与特定的Activity绑定了,不再是可复用的构建单元。
针对上述问题,一种比较好的解决方案是使用Fragment的argument。
每个fragment实例都可以附带一个Bundle对象。
该Bundle对象包含键值对,一个键值对就是一个argument。
要附加argument给fragment,需要调用Fragment.setArguments方法,
且必须在fragment创建后、添加到activity前完成。
对于上面代码中例子,可以在Fragment的构造函数中,完成argument的设置:
public class CrimeActivity extends SingleFragmentActivity { ................. @Override //父类在将fragment加入到FragmentManager前,先调用该方法构造Fragment protected Fragment createFragment() { //获取启动的Intent,从中得到消息 UUID crimeId = (UUID) getIntent().getSerializableExtra(CrimeActivity.EXTRA_CRIME_ID); //调用Fragment提供的接口,设置arguments return CrimeFragment.newInstance(crimeId); } .....}
再看看Fragment的完整实现:
public class CrimeFragment extends Fragment{ ........... //个人觉得,CrimeFragment可以提供多种newInstance函数,以满足不同Activity的使用需求 //达到Fragment与Activity解耦的目的 public static CrimeFragment newInstance(UUID crimeId) { //在Fragment创建时,创建bundle Bundle args = new Bundle(); args.putSerializable(ARG_CRIME_ID, crimeId); CrimeFragment crimeFragment = new CrimeFragment(); //利用fragment的setArguments方法,将bundle设置到arguments中 crimeFragment.setArguments(args); return crimeFragment; } @Override //fragment被Activity加入到FragmentManager后,onCreate函数被调用 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //利用getArguments函数,得到Bundle对象,于是可以获取之前存入的数据 //如果被多个Activity使用,那么获取参数时就需要对应的判断了 UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID); ................ }}
通过上述的方式,可以一定程度上实现Fragment与托管Activity的解耦的目的。
在本文的最后,稍微提一点:
Fragment可以覆盖Activity的startActivityForResult方法和onActivityResult方法,于是可以处理启动Activity后的返回值。
不过Fragment没有定义setResult方法,因此目的Fragment如果需要设置返回结果,
需要调用托管Activity的setResult方法,即在Fragment中,需要调用类似如下代码:
...........getActivity.seResult(Activity.RESULT_OK, data);...........
三、同一个Activity托管Fragment之间的参数传递
源Fragment向目的Fragment传递参数时,与上文一样,仍然需要利用Fragment的arguments。
不过,由于是同一个Activity托管的两个Fragment,因此可以将它们之间的通信关系确定下来。
如下面的示例代码所示:
.............mDateButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { FragmentManager fm = getFragmentManager(); //目的Fragment为DatePickerFragment,在newInstance时,源Fragment将参数写入到其arguments中 DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate()); //调用目的Fragment的setTargetFragment方法,此时就将源、目的Fragment之间的关系确定下来了 //REQUEST_DATE与startActivityForResult中的request_code一致 dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE); //显示目的Fragment dialog.show(fm, DIALOG_DATE); }});...............
源Fragment和目的Fragment之间的关系确定后,目的Fragment就可以通过如下方式,将消息发送给源Fragment:
...............private void sendResult(int resultCode, Date date) { //判断是否有绑定的源Fragment if (getTargetFragment() == null) { return; } Intent intent = new Intent(); intent.putExtra(EXTRA_DATE, date); //直接调用源Fragment的onActivityResult返回结果 getTargetFragment().onActivityResult( getTargetRequestCode(), resultCode, intent);}..........
- Android支持库中Fragment的使用及参数传递
- Android中Fragment之间的通信和参数传递
- android两个fragment的使用localBroadcastManager来传递参数
- Android中Fragment数据参数传递
- android中传递复杂参数,activity之间和fragment之间的bundle传递集合/对象
- android中传递复杂参数,activity之间和fragment之间的bundle传递集合/对象
- android中传递复杂参数,activity之间和fragment之间的bundle传递集合/对象
- Android中Activity传递参数至Fragment中
- Android Bundle的使用及与Intent传递参数区别
- Android Bundle的使用及与Intent传递参数区别
- Android使用newInstance()实例化fragment&setArguments()传递参数
- Android Fragment之间参数传递通过使用bundle进行参数传递
- fragment之间的参数传递
- Fragment之间参数的传递
- Fragment间参数的传递
- Android中application的使用-------传递全局参数
- Android开发之Fragment传递参数的几种方法
- Android开发之Fragment传递参数的几种方法
- C语言指针的使用
- Zabbix Agent Centos6.5编译安装
- Android布局优化之ViewStub
- stm8L051使用库建工程(暂记录)
- 【pycharm 教程】(一)安装和首次使用
- Android支持库中Fragment的使用及参数传递
- ArchLinux-- OpenStreetMap瓦片服务器的新宿主
- BZOJ 1191: [HNOI2006]超级英雄Hero
- HDU2274-Magic WisKey
- 数字构图
- 数据库的乐观锁和悲观锁
- 代码去除标题和状态栏
- 【c++】处理语句
- 【Pycharm教程】(二)设置字体大小