很久以前就學過如何使用Fragment,但總感覺對它特別陌生,所以這次再一次認識Fragment,加深對Fragment的印象。
今天要弄懂的幾個問題:
- Fragment是什麼;
- 什麼時候會用到Fragment;
- Fragment的生命週期;
- 如何靜態和動態使用Fragment;
- Fragment回退棧;
- Fragment事務;
- 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時被回調;
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無效的解決方法