动态加载Fragment的坑

来源:互联网 发布:诅咒淘宝店网址 编辑:程序博客网 时间:2024/06/07 09:46

以前Fragment虽然也在使用,但基本上都是配合ViewPager使用,对于Fragment的事务等知识点很少接触,最近在使用途中踩到了许多坑,所以记下来,下次遇到的话自己可以看看!

首先,我想要做的是在Activity的ui界面点击一个按钮,然后在点击事件中将Fragment展现出来,然后Fragment处理完业务之后,通过接口调用回到Activity将Fragment关闭,然后将Fragment业务结果显示出来。
如果上面的意思没有表达清楚,就直接看代码吧!
MainActivity:

package com.example.fragment;import android.app.Activity;import android.app.ActionBar;import android.app.Fragment;import android.app.FragmentTransaction;import android.graphics.Color;import android.os.Bundle;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;import android.os.Build;public class MainActivity extends Activity implements OnClickListener {    public interface ClickListener{        void OnClick();    }    private Button Btn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Btn = (Button)findViewById(R.id.btn_Click);        Btn.setOnClickListener(this);    }    /**     * A placeholder fragment containing a simple view.     */    public static class PlaceholderFragment extends Fragment {        private ClickListener listener;        public PlaceholderFragment() {        }        public void setListener(ClickListener mListener){            listener = mListener;        }        @Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            View rootView = inflater.inflate(R.layout.fragment_main, container, false);            rootView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View arg0) {                    listener.OnClick();                }            });            return rootView;        }    }    @Override    public void onClick(View arg0) {        final PlaceholderFragment fragment = new PlaceholderFragment();        final FragmentTransaction transaction = getFragmentManager().beginTransaction();        fragment.setListener(new ClickListener() {            @Override            public void OnClick() {//              MainActivity.this.getFragmentManager().beginTransaction().hide(fragment).commit();                transaction.hide(fragment).commit();                Btn.setBackgroundColor(Color.RED);            }        });        transaction.replace(R.id.container, fragment)      .commit();    }}

R.layout.activity_main:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.fragment.MainActivity"    tools:ignore="MergeRootFrame" >    <Button         android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="切换视图"        android:id="@+id/btn_Click"        android:gravity="center"/>   <!--  <ImageView         android:id="@+id/iv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:src="@drawable/ic_launcher"/> --></LinearLayout>

R.layout.fragment_main:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:gravity="center">    <TextView        android:id="@+id/fmt_Click"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="@string/hello_world" />    <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="退回"        /></LinearLayout>

逻辑很简单,但是事实上当我们点击文字的时候,Fragment并没有加载出来,why?

这里写图片描述

那我们将R.layout.activity_main的布局改一下,由线性布局改为相对布局试一下,看看行不行?为了显示效果明显,我们加一下背景以及HelloWorld的文字居中,接下来我们看见内容出来了!

这里写图片描述

这里写图片描述

其实使用FrameLayout也可以实现动态加载Fragment,但是LinerLayout为什么不支持动态加载Fragment呢?是它不支持吗?事实上在一定条件下,它也是支持的,我们对R.layout.activity_main做一个简单的修改,接着看看demo效果。为了演示加载效果,我们对需要加载的Linerlayout加一个蓝色的背景色。
修改后的R.layout.activity_main:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.fragment.MainActivity"    tools:ignore="MergeRootFrame" >    <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="切换视图"        android:id="@+id/btn_Click"        android:gravity="center"/>   <LinearLayout        android:id="@+id/ll_main"       android:layout_width="match_parent"       android:layout_height="match_parent"       android:orientation="vertical"       android:layout_marginTop="40dp"       android:background="@android:color/holo_blue_light"       android:layout_below="@+id/btn_Click">       <ImageView         android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher"/>         <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="不要点"        android:gravity="center"/>         <ImageView         android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher"/>         <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="不要点"        android:gravity="center"/>   </LinearLayout></RelativeLayout>

接着对MainActivity里接口实现的部分将id修改一下:

@Override    public void onClick(View arg0) {        final PlaceholderFragment fragment = new PlaceholderFragment();        final FragmentTransaction transaction = getFragmentManager().beginTransaction();        fragment.setListener(new ClickListener() {            @Override            public void OnClick() {//              MainActivity.this.getFragmentManager().beginTransaction().hide(fragment).commit();                transaction.hide(fragment).commit();                Btn.setBackgroundColor(Color.RED);            }        });        transaction.replace(R.id.ll_main, fragment)      .commit();    }

接下来看看加载效果:

这里写图片描述

这里写图片描述

这里说明LinerLayout还是可以动态加载Fragment的,接着我们可以来思考一下为什么刚刚直接替换整个LinerLayout会没有展示效果呢?

这里写图片描述

经过上面使用LinerLayout加载Fragment,我们肯定了一点,LinerLayout是可以动态加载Fragment的,但是也发现了一个问题,就是Fragment并没有覆盖LinerLayout,而是在其下方展示出来的。所以我们推断出Fragment其实是已经加载,只是其碍于界面太小,展示不出来而已(之前的View都已经占用了整个父布局了)。那么这种想法是不是正确的呢?

这里写图片描述

好吧,我们根据Fragment的生命周期图,在onResume方法中输出一个toast。为什么Fragment展示在前台的方法也是onResume呢?

这里写图片描述

不要想了,直接看图:
这里写图片描述

接着我们继续修改代码,Fragment增加一个onResume方法,然后对接口部分修改替换的id:

/**     * A placeholder fragment containing a simple view.     */    public static class PlaceholderFragment extends Fragment {        private ClickListener listener;        public PlaceholderFragment() {        }        public void setListener(ClickListener mListener){            listener = mListener;        }        @Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            View rootView = inflater.inflate(R.layout.fragment_main, container, false);            rootView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View arg0) {                    listener.OnClick();                }            });            return rootView;        }        @Override        public void onResume() {            super.onResume();            Toast.makeText(getActivity(), "加载完成了", Toast.LENGTH_LONG).show();        }    }    @Override    public void onClick(View arg0) {        final PlaceholderFragment fragment = new PlaceholderFragment();        final FragmentTransaction transaction = getFragmentManager().beginTransaction();        fragment.setListener(new ClickListener() {            @Override            public void OnClick() {//              MainActivity.this.getFragmentManager().beginTransaction().hide(fragment).commit();                transaction.hide(fragment).commit();                Btn.setBackgroundColor(Color.RED);            }        });        transaction.replace(R.id.container, fragment)      .commit();    }

然后我们继续点击,通过toast来判断Fragment是否有加载?

这里写图片描述

这下知道了LinerLayout加载Fragment的坑了,下次可以注意了!这里我们也完成了Fragment的加载,我已经使尽了我的洪荒之力了。接着我们点击Fragment,完成MainActivity的UI修改,这次记得要将MainActivity的布局修改为Farmelayout或者RelativeLayout,然后将需要替换的id修改为整个布局的id,然后我们点击Fragment将切换画面的Button背景色改为红色就可以洗碗了!!

11-06 04:23:43.800: E/AndroidRuntime(8144): FATAL EXCEPTION: main11-06 04:23:43.800: E/AndroidRuntime(8144): Process: com.example.fragment, PID: 814411-06 04:23:43.800: E/AndroidRuntime(8144): java.lang.IllegalStateException: commit already called11-06 04:23:43.800: E/AndroidRuntime(8144):     at android.app.BackStackRecord.commitInternal(BackStackRecord.java:583)11-06 04:23:43.800: E/AndroidRuntime(8144):     at android.app.BackStackRecord.commit(BackStackRecord.java:575)11-06 04:23:43.800: E/AndroidRuntime(8144):     at com.example.fragment.MainActivity$1.OnClick(MainActivity.java:80)11-06 04:23:43.800: E/AndroidRuntime(8144):     at com.example.fragment.MainActivity$PlaceholderFragment$1.onClick(MainActivity.java:57)

好不容易到这一步了,居然挂了!有没有一种天亮了还尿床了的感觉??
不着急,我们看看问题是什么?不知道的话我们直接将问题丢给度娘,看看这个“java.lang.IllegalStateException: commit already called”是什么东西?反正我以前也没有遇到过?

网上有文章说是事务的问题:

这里写图片描述

于是修改代码,再次尝试:

@Override            public void OnClick() {                MainActivity.this.getFragmentManager().beginTransaction().hide(fragment).commit();                Btn.setBackgroundColor(Color.RED);            }

这里写图片描述

OK,动态加载算是完成了,至于FragmentTransaction等知识点这里不做深究,大家可以自行找度娘,网上已经说得很详细了,这里就不再赘述了!

既然动态的我们实现了,那我们为什么不把静态的加载也实现呢?好,说干就干!!
R.layout.activity_main:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.fragment.view.MainActivity"    android:orientation="vertical"    tools:ignore="MergeRootFrame" >    <Button         android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="切换视图"        android:id="@+id/btn_Click"        android:gravity="center"/>   <LinearLayout        android:id="@+id/ll_main"       android:layout_width="match_parent"       android:layout_height="match_parent"       android:orientation="vertical"       android:layout_marginTop="40dp"       android:background="@android:color/holo_blue_light"       android:layout_below="@+id/btn_Click">       <ImageView         android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher"/>         <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="不要点"        android:gravity="center"/>         <ImageView         android:id="@+id/iv"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher"/>         <Button         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="不要点"        android:gravity="center"/>   </LinearLayout>   <fragment class="com.example.fragment.MainActivity$PlaceholderFragment"       android:layout_width="match_parent"       android:layout_height="match_parent"       android:id="@+id/fragment"/></RelativeLayout>

R.layout.fragment_main没有电变化就补贴代码了,看看MainActivity吧:

package com.example.fragment;import android.app.Activity;import android.app.Fragment;import android.app.FragmentTransaction;import android.graphics.Color;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener {    public interface ClickListener{        void OnClick();    }    private Button Btn;    private PlaceholderFragment fragment;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Btn = (Button)findViewById(R.id.btn_Click);        Btn.setOnClickListener(this);        fragment = (PlaceholderFragment) getFragmentManager().findFragmentById(R.id.fragment);        getFragmentManager().beginTransaction().hide(fragment).commit();    }    /**     * A placeholder fragment containing a simple view.     */    public static class PlaceholderFragment extends Fragment {        private ClickListener listener;        public PlaceholderFragment() {        }        public void setListener(ClickListener mListener){            listener = mListener;        }        @Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            View rootView = inflater.inflate(R.layout.fragment_main, container, false);            rootView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View arg0) {                    listener.OnClick();                }            });            return rootView;        }        @Override        public void onResume() {            super.onResume();            Toast.makeText(getActivity(), "加载完成了", Toast.LENGTH_LONG).show();        }    }    @Override    public void onClick(View arg0) {        final FragmentTransaction transaction = getFragmentManager().beginTransaction();        fragment.setListener(new ClickListener() {            @Override            public void OnClick() {                MainActivity.this.getFragmentManager().beginTransaction().hide(fragment).commit();//              transaction.hide(fragment).commit();                Btn.setBackgroundColor(Color.RED);            }        });//      transaction.replace(R.id.container, fragment).commit();//      findViewById(R.id.container).setVisibility(View.GONE);        transaction.show(fragment).commit();    }}

经过实践操作,发现即使LinerLayout静态加载Fragment也会踩到上面的坑。避坑措施为不使用LinerLayout作为最外层布局。

此坑填完!!

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 刚养的兔子不吃怎么办 熊猫兔不吃下喝怎么办 熊猫兔感冒了一直打喷嚏怎么办 兔子后腿骨断了怎么办 兔子的腿肿了怎么办 仓鼠喝了牛奶该怎么办 宠物兔不吃不喝怎么办 兔子把木屑吃了怎么办? 小车司机碰瓷大车司机怎么办 在淘宝买到假的护肤品怎么办 淘宝购物发现是假的怎么办 电脑键盘灯不亮不能打字怎么办 海棠兔屁股有屎怎么办 大冒险告白被接受了怎么办剧透微博 大冒险被告白了怎么办 腐书网 大冒险告白被接受了怎么办 006 大冒险告白被接受了怎么办广播剧 coolpad手机解锁图案忘了怎么办 装死兔严重掉毛怎么办 兔子嘴巴磕破了怎么办 嘴巴里面摔烂了怎么办 兔子的鼻子损了怎么办 两个人嘴巴被粘牙糖粘住怎么办 小鸟被老鼠粘粘住了怎么办 小猫被老鼠粘粘住怎么办 羊子嘴巴烂了怎么办 小孩突然嘴肿了怎么办 电视机图像颜色变了 怎么办 冰沙床垫结块了怎么办 冰沙床垫融化了怎么办 脚真菌感染肿了怎么办 水雾魔珠被吃了怎么办 怀孕40天出血了怎么办 联璧金融里的钱怎么办 提现的钱不对怎么办 究极日月蛋太多怎么办 人脸识别不匹配怎么办 地下城没有属强怎么办 传奇属性点错了怎么办 龙之谷技能太多怎么办 龙之谷pk卡怎么办