當還沒有Fragment功能出來以前,必須使用很多個Activity來轉換到另一個Activity的方式來設計功能,這在手機上使用來看,感覺起來沒什麼問題,但是平板出來之後,畫面變大,一個畫面可以容納更多的元件,所以為了讓Android UI在平板上可以有更好的展示效果,Android在3.0時加入了Fragment功能。
Fragment片段是Android提供的一個畫面區塊,可以將Fragment放在一個Activity中,Fragment可以說是Activity的子畫面。
開發上使用Fragment的好處是:
- 有自己的生命週期
- 可以重複利用降低開發成本
- 一個Fragment在手機和平板上可以有不同的使用者體驗
Fragment與Activity的生命週期:
Fragment的生命週期必須依附Activity的生命週期,意思是說,當 Activity 暫停時,其中的所有片段也會一併暫停;而當 Activity 遭到刪除時,所有片段也會一併刪除。 不過,當 Activity 執行時 (該 Activity 會處於繼續進行生命週期狀態),您可以個別操縱所有片段,例如新增或移除片段。
Fragment動態佈署主要分為動態新增(add)與動態置換(replace)兩種:
- replace是每次呼叫,不管有沒有建立過fragment,都會創建一個新的Fragment,所以生命週期也會重跑一遍,如果使用在需要經常更換fragment的時候,非常消耗資源。
- add則是可以搭配hide()與show()來建立Fragment,當要切換Fragment時,可以hide()當前的fragment,並且add()和show()新的fragment
動態置換(replace)程式碼:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp" />
<RadioGroup
android:id="@+id/id_radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<RadioButton
android:id="@+id/id_one"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page1"
android:onClick="onClick"/>
<RadioButton
android:id="@+id/id_two"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page2"
android:onClick="onClick"/>
<RadioButton
android:id="@+id/id_three"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page3"
android:onClick="onClick"/>
<RadioButton
android:id="@+id/id_four"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page4"
android:onClick="onClick"/>
</RadioGroup>
</RelativeLayout>
MainActivity.java:
public class MainActivity extends FragmentActivity {
private RadioButton id_one,id_two,id_three,id_four;
private int page = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findviewbyid();
changeFragment(DetailsFragment.newInstance(page));
}
public void onClick(View view){
switch (view.getId()){
case R.id.id_one:
changeFragment(DetailsFragment.newInstance(1));
break;
case R.id.id_two:
changeFragment(DetailsFragment.newInstance(2));
break;
case R.id.id_three:
changeFragment(DetailsFragment.newInstance(3));
break;
case R.id.id_four:
changeFragment(DetailsFragment.newInstance(4));
break;
}
}
private void findviewbyid(){
id_one = (RadioButton)findViewById(R.id.id_one);
id_two = (RadioButton)findViewById(R.id.id_two);
id_three = (RadioButton)findViewById(R.id.id_three);
id_four = (RadioButton)findViewById(R.id.id_four);
}
private void changeFragment(Fragment f) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, f);
transaction.commitAllowingStateLoss();
}
protected void onStart(){
super.onStart();
Log.i("tag","Activity onStart()");
}
protected void onResume(){
super.onResume();
Log.i("tag","Activity onResume()");
}
}
fragment_tmp.xml(fragment內容的佈局文件):
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/text_view"
android:text="fragment"
android:gravity="center"
android:textSize="20sp"/>
</LinearLayout>
DetailFragment.java:
public class DetailsFragment extends Fragment {
private View v;
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("tag","Fragment onCreateView()");
v = inflater.inflate(R.layout.fragment_tmp, container, false);
TextView text = (TextView)v.findViewById(R.id.text_view);
text.setText("Page" + getShownIndex());
return v;
}
}
執行結果:
動態新增(add)程式碼:
activity_main.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp" />
<RadioGroup
android:id="@+id/id_radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<RadioButton
android:id="@+id/id_one"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page1"
android:onClick="onClick"/>
<RadioButton
android:id="@+id/id_two"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:drawableTop="@mipmap/ic_launcher"
android:gravity="center_horizontal"
android:text="page2"
android:onClick="onClick"/>
</RadioGroup>
</RelativeLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private RadioButton id_one,id_two;
private Fragment1 mFragment01;
private Fragment2 mFragment02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findviewbyid();
mFragment01 = new Fragment1();
mFragment02 = new Fragment2();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, mFragment01,"TAG-mFragment01");
transaction.commitAllowingStateLoss();
}
private void findviewbyid(){
id_one = (RadioButton)findViewById(R.id.id_one);
id_two = (RadioButton)findViewById(R.id.id_two);
}
public void onClick(View view){
switch (view.getId()){
case R.id.id_one:
chaangefragment(mFragment01,"TAG-mFragment01");
break;
case R.id.id_two:
chaangefragment(mFragment02,"TAG-mFragment02");
break;
}
}
public void chaangefragment(Fragment fragment,String tag){
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
List fragments = fragmentManager.getFragments();
Fragment tmp=null;
for (Fragment f: fragments){
if (f!=null && f.isVisible()) {
System.out.println("hide"+f.getTag());
tmp=f;
}
}
// Fragment fragment = getSupportFragmentManager().findFragmentByTag("TAG-mFragment01");
// System.out.println(fragment);
if (fragment.isAdded()){
transaction.hide(tmp).show(fragment).commit();
}else {
transaction.hide(tmp).add(R.id.fragment_container,fragment,tag).commit();
}
}
}
fragment_layout.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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txt"
android:text="fragment"/>
</LinearLayout>
fragment1.java:
public class Fragment1 extends Fragment {
private TextView txt;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("tag","Fragment1 onCreateView");
return inflater.inflate(R.layout.fragment_layout, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i("tag","Fragment1 onActivityCreated");
txt = (TextView)getView().findViewById(R.id.txt);
txt.setText("fragment1");
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("tag","Fragment1 onAttach");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("tag","Fragment1 onCreate");
}
@Override
public void onStart() {
super.onStart();
Log.i("tag","Fragment1 onStart");
}
@Override
public void onResume() {
super.onResume();
Log.i("tag","Fragment1 onResume");
}
}
fragment2.java:
public class Fragment2 extends Fragment{
private TextView txt;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("tag","Fragment2 onCreateView");
return inflater.inflate(R.layout.fragment_layout, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i("tag","Fragment2 onActivityCreated");
txt = (TextView)getView().findViewById(R.id.txt);
txt.setText("fragment2");
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("tag","Fragment2 onAttach");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("tag","Fragment2 onCreate");
}
@Override
public void onStart() {
super.onStart();
Log.i("tag","Fragment2 onStart");
}
@Override
public void onResume() {
super.onResume();
Log.i("tag","Fragment2 onResume");
}
}
執行順續page1(起始) -> page2 -> page1 -> page2
執行結果:
可以看到fragment1和fragment2個別被建立1次後,之後再呼叫時就不會再被建立新的Fragment了。