Fragment 和 FragmentActivity的使用
今天学习下 Android中的 Fragment 和 FragmentActivity,因为没有4.0手机,平台是2.3.3 所以我是使用 v4 support 包来进行学习。
要想用Fragment 功能必须先让activity继承FragmentActivity,其原因是里面包含了Fragment运作的FragmentManager接口的实现类 FragmentManagerImpl ,由这个类管理所有Fragment的显示、隐藏
1.使用最简单的Fragment,我们只要继承Fragment就可以
- publicclassTextFragmentextendsFragment{
- privateStringmMsg;
- publicvoidsetMessage(Stringmessage){
- this.mMsg=message;
- }
- @Override
- publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
- BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- finalContextcontext=getActivity();
- FrameLayoutroot=newFrameLayout(context);
- root.setBackgroundColor(Color.YELLOW);
- TextViewtv=newTextView(context);
- tv.setText(mMsg);
- tv.setGravity(Gravity.CENTER);
- root.addView(tv,newFrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.FILL_PARENT));
- returnroot;
- }
- }
首先Fragment 就可以把它当作一个view , 只不过这个view 与 activity一样有了生命周期函数
Fragment.onCreateView() 函数就是用于生成这个Fragment布局的view的,类似baseadapter.getView()
这样一个包含一个TextView的简单布局就完成了。
2.重写我们自己的FragmentActivity.
这里面主要要通过FragmentManager 来进行Fragment的添加和删除:
- publicclassDoorFragmentActivityextendsFragmentActivity{
- publicstaticfinalStringFRAG_SMS="sms_list_frag";
- publicstaticfinalStringFRAG_TEXT="text_frag";
- privateFragmentmSMSFragment;
- privateFragmentmTextFragment;
- privateFragmentManagermFragMgr;
- privateButtonmMenuBtn;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.door_fragment_activity_layout);
- mFragMgr=getSupportFragmentManager();
- mMenuBtn=(Button)findViewById(R.id.door_menu_btn);
- mMenuBtn.setOnClickListener(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- showFragments(FRAG_TEXT,true);
- }
- });
- mMenuBtn.setOnLongClickListener(newOnLongClickListener(){
- @Override
- publicbooleanonLongClick(Viewv){
- //TODOAuto-generatedmethodstub
- returnfalse;
- }
- });
- initFragments();
- showFragments(FRAG_SMS,false);
- }
- privatevoidinitFragments(){
- mSMSFragment=newSMSListFragment();
- TextFragmenttextfrag=newTextFragment();
- textfrag.setMessage("这是菜单界面");
- mTextFragment=textfrag;
- }
- privatevoidshowFragments(Stringtag,booleanneedback){
- FragmentTransactiontrans=mFragMgr.beginTransaction();
- if(needback){
- trans.setCustomAnimations(R.anim.frag_enter,
- R.anim.frag_exit);
- trans.add(R.id.door_root_content_fl,getFragmentByTag(tag),tag);
- trans.addToBackStack(tag);
- }else{
- trans.replace(R.id.door_contents_fl,getFragmentByTag(tag),tag);
- }
- trans.commit();
- }
- privateFragmentgetFragmentByTag(Stringtag){
- if(FRAG_SMS.equals(tag)){
- returnmSMSFragment;
- }
- if(FRAG_TEXT.equals(tag)){
- returnmTextFragment;
- }
- returnnull;
- }
- }
- 首先我们获取FragmentManager实现:直接调用 FragmentActivity.getSupportFragmentManager(),看源码可以知道这返回的是FragmentManager内部定义的实现类FragmentManagerImpl。
- 我们获取了FragmentManagerImpl后我们其实不咋操作这个类,只调用FragmentManager.beginTransation(),这个获取FragmentTransation接口的实现类(里面具体是BackStackRecord类的实例),我们关于Fragment的所有操作都是通过它来完成的,因为没仔细研究,我只了解直接自己在代码里面定义Fragment而没有在xml里面写(xml写觉得有点别扭)
1)trans.add(fragment, tag); 这个实际是 containerViewId = 0 调用的3)
2)trans.add(containerViewId, fragment); 这个实际是 tag = null 调用的 3)
3)trans.add(containerViewId, fragment, tag); 如果containerViewId != 0实际上调用的是获取到
fragment的 onCreateView方法返回的view 并加入到containerViewId这个viewgroup中去即 viewgroup.addView(fragment.onCreateView());
未解决问题:containerViewId = 0 的时候代表什么??
4) trans.replace(containerViewId, fragment) 一样是null tag调用 5)
5)trans.replace(containerViewId, fragment, tag) 这个一样是添加一个fragment到对应的container中去,只不过比add多了一步对相同containerViewId中已有的fragment检索,进行removeFragment操作,再去添加这个新来的fragment
6) trans.addToBackStack(tag); 如果你的fragment对于back键有类似activity的回退响应,就要记得把它加入到里面去,trans里面模拟了栈,但是我的回退没有响应我设置的exit anim 这个无语还没解决
3.再使用下ListFragment,我这里写的是SMSListFragment继承了ListFragment:
- publicclassSMSListFragmentextendsListFragment{
- privateConversationListAdaptermAdapter;
- privateConversationQuerymQuery;
- privatelongstartTime;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- mAdapter=newConversationListAdapter(getActivity());
- mQuery=newConversationQuery(getActivity().getContentResolver());
- }
- @Override
- publicvoidonActivityCreated(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onActivityCreated(savedInstanceState);
- setListAdapter(mAdapter);
- }
- @Override
- publicvoidonStart(){
- //TODOAuto-generatedmethodstub
- super.onStart();
- startAsyncQuery();
- }
- @Override
- publicvoidonStop(){
- //TODOAuto-generatedmethodstub
- super.onStop();
- mAdapter.getCursor().close();
- mAdapter.changeCursor(null);
- }
- publicvoidstartAsyncQuery(){
- startTime=System.currentTimeMillis();
- mQuery.startQuery(1,null,Conversation.sAllThreadsUri,
- Conversation.ALL_THREADS_PROJECTION,null,null,
- Conversation.CONVERSATION_ORDER);
- }
- privatefinalclassConversationQueryextendsAsyncQueryHandler{
- publicConversationQuery(ContentResolvercr){
- super(cr);
- //TODOAuto-generatedconstructorstub
- }
- @Override
- protectedvoidonQueryComplete(inttoken,Objectcookie,Cursorcursor){
- //TODOAuto-generatedmethodstub
- System.out.println("conversationcursorsize:"
- +cursor.getCount());
- mAdapter.changeCursor(cursor);
- Toast.makeText(
- getActivity(),
- "查询短信会话个数:"+cursor.getCount()+",花费"
- +(System.currentTimeMillis()-startTime)+"ms",
- Toast.LENGTH_LONG).show();
- }
- }
- }
onCreate()中完成自己要一次性初始的东西,我在里面主要是初始化一个adapter和一个对sms数据库的查询
在onActivityCreated()中将adapter设置给listview,这个不确定有没有更好的位置,
然后进入我们熟悉的生命周期方法:
onStart()中,开启查询
onStop()中,我们界面已经不在显示了,所以我们不关心数据库变化了,close cursor
4.主页面的布局文件:
- <?xmlversion="1.0"encoding="utf-8"?>
- <FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/door_root_content_fl"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <FrameLayout
- android:id="@+id/door_contents_fl"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="55dp"
- android:orientation="horizontal">
- <Button
- android:id="@+id/door_menu_btn"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="菜单"/>
- </LinearLayout>
- </LinearLayout>
- </FrameLayout>