fragent的使用总结

前言

fragment自动3.0推出以后,在碎片化处理方面一直很受欢迎,平时在项目中也在频繁使用,自从看了CSDN上郭大神和鸿洋大神对fragment的详细总结后,自己学习做个笔记。
  郭大神:http://blog.csdn.net/guolin_blog/article/details/8881711
 鸿洋大神:http://blog.csdn.net/lmj623565791/article/details/42628537

fragment的常用方法

(1) 静态使用

在布局文件xml中使用

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  android:baselineAligned="false" >  

  <fragment  
      android:id="@+id/fragmentOne"  
      android:name="com.ydscience.FragmentOne"  
      android:layout_width="0dp"  
      android:layout_height="match_parent"  
      android:layout_weight="1" />  
  <fragment  
      android:id="@+id/fragmentTwo"  
      android:name="com.ydscience.FragmentTwo"  
      android:layout_width="0dp"  
      android:layout_height="match_parent"  
      android:layout_weight="1" />  

</LinearLayout>  

具体的fragmentOne和fragmentTwo的代码就不粘贴啦,都是继承Fragment去实现的。

(2)动态使用

动态使用分为四个步骤
  (a)获取FragmentManager,通过方法getSupportFragmentManager()获取。
  (b)开启一个事物,通过beginTransaction方法开启。
  (c)向容器内加入Fragment,默认第一个是通过add()方法添加,后面再替换时通过replace方法实现,需要传入容器的id和Fragment的实例。
  (d)提交事务,调用commit方法提交。
xml中的代码为

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ydsciernce.studytest.MainActivity">
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/content_fragment"/>
</RelativeLayout>

Activity中的代码为

public class MainActivity extends AppCompatActivity implements FragementOne.FOneListener{
    FragmentTwo mFragmentTwo;
    FragementOne mFragmentOne;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null){
            Log.i("TAG","saveInstanece数据为空");
            FragmentManager manager = getSupportFragmentManager();
            FragmentTransaction transaction = manager.beginTransaction();
            mFragmentOne = new FragementOne();
            transaction.add(R.id.content_fragment,mFragmentOne,"ONE");
            transaction.commit();
        }else {
            Log.i("TAG","saveInstanece数据为"+savedInstanceState.toString());
        }
    }
    @Override
    public void onOneClick() {
        if (mFragmentTwo == null){
            mFragmentTwo =  new FragmentTwo();
        }
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        //transaction.hide(mFragmentOne);
        //transaction.add(R.id.content_fragment,mFragmentTwo,"TWO");
        transaction.replace(R.id.content_fragment,mFragmentTwo,"TWO");
        transaction.addToBackStack(null);
        transaction.commit();
    }
}

FragmentOne的代码为

public class FragementOne extends Fragment implements View.OnClickListener{

    private Button mButton;
    EditText test;
    public interface FOneListener{
        void onOneClick();
    }
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        Log.i("TAG"," on createview");
        View view = inflater.inflate(R.layout.content_one_fragment,null);
        mButton = (Button) view.findViewById(R.id.buttonOne);
        mButton.setOnClickListener(this);
        test = (EditText) view.findViewById(R.id.editText);
        Log.i("TAG","edit datda"+test.getText().toString());
        return view;
    }
     @Override
    public void onClick(View v) {
        if(getActivity() instanceof FOneListener){
            ((FOneListener)getActivity()).onOneClick();
        }
    }
}

注意事项:

a.在设置默认的fragment时,不能调用addToBackStack(null)方法,如果添加了在退出应用时会在Activity页面出现一个空白页面。
  b.在代码中有两个Fragment,分别为FrangmentOne和FragmentTwo,FragmentOne为默认的,从FragmentOne中的Button 去启动FragmentTwo,在鸿洋大神的分析中当我们从FragmentOne启动到FragmentTwo时使用的是replace方法,replace方法的实现过程是remove方法和add方法的合体,当我们在调用该方法时,如果不添加事务到回退栈,前一个Fragment实例会被销毁,调用了addToBackStack(null);将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryView和onCreateView,在这种情况下,再次返回到FragmentOne时等于新建了一个FragmentOne实例对象,在之前Fragment中保存的数据将不会存在,而在真实的案例中当我们从FragmentTwo返回到FragmentOne时希望数据还在,因此此时就不能使用replace方法,使用hide方法将FragmentOne隐藏起来,当FragmengTwo返回时会调用show方法显示,相应的数据也会被保存。
  c.当fragment遇到屏幕自动旋转时,会导致Activity和Fragment的重建在这种情况下可能会导致两个FragmentOne的实例对象存在,界面上也会存在重叠效果,导致这种现象的原因是当Activity重建时我们的fragment会被保存下来,但是会创建新的FragmentManager,新的FragmentManager会首先会去获取保存下来的fragment队列,重建fragment队列,从而恢复之前的状态。解决方法是在创建实例和获取FragmentManager时判断saveInstanceState状态,当我们第一次启动Activity时,saveInstanceState为空的,当因异常情况导致Activity重建时,自动会调用saveInstanceState会保存一些信息,因此通过判断saveInstanceState状态可以避免这种情况。
  d.在参考了大神的博客后自己尝试技能满足保存数据又可以避免在屏幕旋转后避免创建多个Fragment实例对象,实现方法为创建实例前对saveInstanceState状态进行判断,同时在启动其他的Fragment时不调用replace方法使用hide方法,但是出现nullPointerException,目前还没解决。

(3)Activity与Fragment以及Fragment与Fragment之间的通信。

a.Activity与Fragment

实现方式有以下几种
    ①.handler通信
    ②.接口回调 例如上面代码中在FragmentTwo 实现方式,在
     FragmentTwo中的点击事件通过接口回调交给Activity去处理。

声明接口
public interface FOneListener{
        void onOneClick();
    }
点击事件传递
 public void onClick(View v) {
        if(getActivity() instanceof FOneListener){
            ((FOneListener)getActivity()).onOneClick();
        }
    }
父类继承去实现
public class MainActivity extends AppCompatActivity implements FragementOne.FOneListener
@Override
public void onOneClick() {
    //处理点击事件
}

③.使用EventBus去实现。
   ④.使用广播BroadcastReceiver去实现。

b.同时存在同一个Activity中的页面中的两个Fragment之间的通信

在查看郭大神的博客后发现这种情况适用于存在于同一个页面之间FragmentA 去获取FragmentB(或者FragmentB 去获取FragmentA)中某个组件的信息。主要都是通过getActivity这个方法实现的,getActivity方法可以让Fragment获取到关联的Activity,然后再调用Activity的findViewById方法,就可以获取到和这个Activity关联的其它Fragment的视图,从而可以获取这个视图的数据。

 @Override  
    public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
        Button button = (Button) getActivity().findViewById(R.id.button);  
        button.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);  
                Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();  
            }  
        });  
    }  

(4)Fragment的复用以及与Activity之间的解耦

在我们项目想法中肯定会经常遇到ViewPager与Fragment之间的结合使用,使用Viewpager来切换不同的fragment,当第一次使用时可能会针对每一个主题都会创建一个Fragment去实现,这种实现方式在网上有很多案例,但是这种实现方式创建了很多的fragment,代码有太多的耦合性,自从Google官网给出了Tablayout这个组件时,它也是结合fragmen和viewpager去实现的。在这个具体实现时很好的复用了fragment。具体实现见代码吧,口头叙述态度都是扯淡,只有代码才是王道。

布局代码(content_history_record.xml)
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_centerInParent="true">
    <android.support.design.widget.TabLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tabLayout"
            app:tabBackground="@color/historyColorAccent"
            app:tabSelectedTextColor="@color/tabSelected"
            app:tabTextColor="@color/tabUnSelected"
            app:tabMode="scrollable"/>
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/label"
            android:id="@+id/viewpager_history"
            />
 </LinearLayout>
MainActivity的代码
public class HistoryRecordActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_history_record);
       init();
    }
    private void init(){
        HistoryFragmentPreferenceAdapter adapter = new HistoryFragmentPreferenceAdapter(getSupportFragmentManager(),this);
        ViewPager historyPager = (ViewPager) findViewById(R.id.viewpager_history);
        historyPager.setAdapter(adapter);
        TabLayout historyTabLayout = (TabLayout) findViewById(R.id.tabLayout);
        historyTabLayout.setupWithViewPager(historyPager);
        historyTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        historyTabLayout.setTabMode(TabLayout.MODE_FIXED);
    }
}
适配器的代码(HistoryFragmentPreferenceAdapter.java)
public class HistoryFragmentPreferenceAdapter extends FragmentPagerAdapter {
    private Context mContext;
    private final int coutnt = 5;
    private String [] titles ;
    public HistoryFragmentPreferenceAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.mContext = context;
        titles = context.getResources().getStringArray(R.array.history_title);
    }
    @Override
    public Fragment getItem(int position) {
        return PageFragment.getIntance(position+1);
    }
    @Override
    public int getCount() {
        return coutnt;
    }
    @Override
    public CharSequence getPageTitle(int position) {

        return titles[position];
    }
}
Fragment的代码(PageFragment.java)
public class PageFragment extends Fragment {
    public static final String TRANSFER_PAGE = "page";
    private int mPage;
    public static Fragment getIntance(int page){
        Bundle bundle = new Bundle();
        bundle.putInt(TRANSFER_PAGE,page);
        PageFragment pageFragment = new PageFragment();
        pageFragment.setArguments(bundle);
        return  pageFragment;
    }
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState); 
        Bundle bundle = getArguments();  
        if (bundle != null)  
            mArgument = bundle.getString(TRANSFER_PAGE);  
    }  

给Fragment添加newInstance方法,将需要的参数传入,设置到bundle中,然后setArguments(bundle),最后在onCreate中进行获取通过getArguments()去获取一个fragment的实例,通过这种方式可以实现Fragment的复用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,504评论 25 707
  • Fragment概述 Fragment是Activity中用户界面的一个行为或者说是一部分。主要是支持大屏幕上动态...
    wangling90阅读 11,521评论 5 76
  • 前言 Fragment想必大家不陌生吧,在日常开发中,对于Fragment的使用也很频繁,现在主流的APP中,基本...
    斜杠时光阅读 2,573评论 4 22
  • 作品简介: 魏晓天高中开学没多久喜欢上了校广播站的学姐江欣怡,江欣怡温柔大方,时常和他发信息并且一起见面。那时的他...
    温玉言阅读 566评论 2 2
  • 如果用一首歌记录2015,我想会是SkeeterDavis的《the end of the world》,因为这是...
    孟繁锦阅读 403评论 0 1