學習Fragment

很久以前就學過如何使用Fragment,但總感覺對它特別陌生,所以這次再一次認識Fragment,加深對Fragment的印象。

今天要弄懂的幾個問題:

  1. Fragment是什麼;
  2. 什麼時候會用到Fragment;
  3. Fragment的生命週期;
  4. 如何靜態和動態使用Fragment
  5. Fragment回退棧;
  6. Fragment事務;
  7. Fragment與Activity的通信;


以下是參考的博客:
- http://blog.csdn.net/lmj623565791/article/details/37970961
以下是參考的書籍:
- 《瘋狂的Android講義》電子工業出版社

                                                                                    

1.Fragment是什麼

Fragment是Android3.0引入的新API,Fragment代表了Activity的子模塊,因此可以把Fragment理解爲Activity “片段”。雖然Fragment擁有自己的生命週期,但會受到其所在的Activity的生命週期控制,例如當Activity暫停時,該Activity內的所有Fragment都會暫停。也可以這樣理解:Fragment是Activity的輕量級。在Activity在運行過程中,可以通過FragmentManager的add()remove()replace();方法去動態地添加、刪除、替換 Fragment。一個Activity可以同時組合多個Fragment,反過來一個Fragment可以同時被多個Activity複用。


2.什麼時候會用到Fragment

  • 需頻繁切換界面顯示的需求下;
  • 在資源有限的情況下;
  • 緩解Activity任務過重的情況下;
  • 處理在不同屏幕上的UI組件的佈局問題(平板、橫豎屏);
  • 將屏幕分爲多個碎片;

         (如果還有,請評論補充!)


3.Fragment的生命週期

與Activity類似的是,Fragment也有:運行狀態暫停狀態停止狀態銷燬狀態

onAttach():當Fragment被添加到Activity時被回調;

onCreate():創建Fragment時被回調;

onCreateView()每次創建、繪製view時被回調;

onActivityCreated():當Fragment所在的Activity被啓動完成後被回調;

onStart():啓動Fragment時被回調;

onResume():恢復Fragment時被回調;

onPause():暫停Fragment時被回調(可見,但不能獲得焦點);

onStop():停止Fragment時被回調(不可見,失去焦點);

onDestroyView()銷燬Fragment所包含的view組件時被調用;

onDestroy():銷燬Fragment時被回調;

onDetach():將Fragment從Activity中刪除、替換完成時被回調;


1




4.1 靜態使用Fragment

靜態就相當於主xml添加兩個<fragment>控件,通過name屬性再綁定兩個java文件,並且java文件繼承於Fragment,重新onCreateView(),return回各自綁定的xml文件。


代碼我就不貼了,這個應該是最基礎最基礎的了。

4.2 動態使用Fragment

做個小demo,就是2個按鈕,單擊切換fragment

activity_main.xml

<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"
    tools:context=".MainActivity">
 

    <FrameLayout
        android:id="@+id/id_content"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/bta"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="A" />

        <Button
            android:id="@+id/btb"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="B" />
    </LinearLayout>

 </LinearLayout>

接下來是MainActivity

public class MainActivity extends ActionBarActivity implements View.OnClickListener {
    private Button bta, btb;
    private FragmentA newfragmenta;
    private FragmentB newfragmentb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bta = (Button) findViewById(R.id.bta);
        btb = (Button) findViewById(R.id.btb);

        // 設置默認的Fragment  
        setDefaultFragment();

        //按鈕事件
        bta.setOnClickListener(this);
        btb.setOnClickListener(this);
    }

    private void setDefaultFragment() {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        newfragmenta = new FragmentA();
        ft.replace(R.id.id_content, newfragmenta).commit();
    }

    @Override
    public void onClick(View v) {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();

        switch (v.getId()) {
            case R.id.bta:
                if (newfragmenta == null) {
                    newfragmenta = new FragmentA();
                }
                ft.replace(R.id.id_content, newfragmenta).commit();
                break;
            case R.id.btb:
                if (newfragmentb == null) {
                    newfragmentb = new FragmentB();
                }
                ft.replace(R.id.id_content, newfragmentb).commit();
                break;
        }

    }

兩個xml文件 fragmenta.xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello I'm A" />
</LinearLayout>

fragmentb.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hey,I'm B " />
</LinearLayout>
兩個fragment的java文件幾乎一致,就只貼一個出來就行

public class FragmentA extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragmenta, container, false);
    }
}
現在我們開看看效果

其關鍵的就是

        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        newfragmenta = new FragmentA();   
        ft.replace(R.id.id_content, newfragmenta).commit()//用FragmentA 替換id_content


Fragment常用的三個類:

android.app.Fragment 主要用於定義Fragment

android.app.FragmentManager 主要用於在Activity中操作Fragment

android.app.FragmentTransaction 保證一些列Fragment操作的原子性,熟悉事務這個詞,一定能明白~


a、獲取FragmentManage的方式:getFragmentManager() // v4中,getSupportFragmentManager


b、主要的操作都是FragmentTransaction的方法:FragmentTransaction transaction = fm.benginTransatcion();//開啓一個事務

  • transaction.add() :往Activity中添加一個Fragment;
  • transaction.remove() 從Activity中移除一個Fragment(沒有添加到回退棧的情況);
  • transaction.replace():使用另一個Fragment替換當前的,實際上就是remove()然後add()的合體;
  • transaction.hide():隱藏當前的Fragment,僅僅是設爲不可見,並不會銷燬;
  • transaction.show():顯示之前隱藏的Fragment;
  • transatcion.commit():提交事物;

注意:常用Fragment的哥們,可能會經常遇到這樣Activity狀態不一致:State loss這樣的錯誤。主要是因爲:commit方法一定要在Activity.onSaveInstance()之前調用。

————————————————————————

5.Fragment回退棧

  FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.id_content, fragmentB, "B");
        ft.addToBackStack(null);//加入回退棧
       ft.commit();
在代碼中添加addToBackStack(null)這一句就將回退棧裏,當按回退鍵的時候逐層返回,直至棧空然後完全退出到桌面。

可以看demo效果圖:


我來解析一下這個demo,通過點擊Abutton啓動fragmentB,Bbutton啓動fragmentC,然後單擊回退鍵,逐層退出棧。


MainActivity的佈局文件:

<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"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/id_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></FrameLayout>


</LinearLayout>
MainActivity.java文件:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(R.id.id_content, new FragmentA(), "A");
        ft.commit();

    }
FragmentA.java文件:

public class FragmentA extends Fragment implements View.OnClickListener {

    private Button bta;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View viewboot = inflater.inflate(R.layout.fragmenta, container, false);
        bta = (Button) viewboot.findViewById(R.id.bta);
        bta.setOnClickListener(this);
        return viewboot;
    }

    @Override
    public void onClick(View v) {
        FragmentB fragmentB = new FragmentB();//聲明fragmentB
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.id_content, fragmentB, "B");
        ft.addToBackStack(null);
        ft.commit();
    }
}

FragmentB.java文件:

public class FragmentB extends Fragment implements View.OnClickListener {

    private Button btb;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View viewboot = inflater.inflate(R.layout.fragmentb, container, false);

        btb = (Button) viewboot.findViewById(R.id.btb);
        btb.setOnClickListener(this);
        return viewboot;
    }

    @Override
    public void onClick(View v) {
        FragmentC fragmentc = new FragmentC();//聲明fragmentC
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.hide(this);//將FragmnetB隱藏起來,負責會B、C重疊起來
        ft.add(R.id.id_content, fragmentc, "C");
        ft.addToBackStack(null);
        ft.commit();
    }
}

FragmentC.java文件:

public class FragmentC extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View viewboot = inflater.inflate(R.layout.fragmentc, container, false);
        return viewboot;
    }
}
3個XML文件就不貼出來了,就根據效果圖來看就可以完成。

——————————————————————————————————

相關文章:

Fragment回退鍵addToBackStack無效的解決方法 

兩個簡單Fragment之間的通信







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章