Fragment是依賴於Activity存在的,Fragment也有自己的生命周期,首先來看下Fragment的生命周期:
這是官網的圖,可以看到Fragment比activity多了幾個生命周期函數:
public void onAttach(Context context),當Fragment與Activity發生關聯時調用
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
創建fragment的視圖
public void onActivityCreated(Bundle savedInstanceState) 當Activity的onCreate方法返回時調用
public void onDestroyView() 當fragment的視圖被銷毀時調用
public void onDetach() 當fragment於Activity失去關聯時調用
生命周期就說到這裡,下面看下靜態的fragment怎麼用:
package com.fq.myapplication;
import Android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Administrator on 2016/9/30.
*/
public class MyFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.myfragment_layout,container,false);
}
}
先定義一個MyFragment ,看下布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="MyFragment1"
android:textSize="20dp"
android:gravity="center"/>
<EditText
android:layout_width="match_parent"
android:layout_height="50dp" />
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20dp"
android:text="next"/>
</LinearLayout>
然後是Activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<fragment
android:id="@+id/fragment"
android:name="com.fq.myapplication.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></fragment>
</RelativeLayout>
直接靜態寫在Activity的布局文件中即可,注意要寫id和name,否則會有問題,效果圖如下:
接下來看下動態Fragment怎麼玩,直接看代碼:
MyFragment fragment1 = new MyFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.content, fragment1);
fragmentTransaction.commit();
getFragmentManager獲取到一個FragmentManager ,然後FragmentManager 調用beginTransaction開啟一個事務,保證原子操作,然後add,最後commit提交事物,除了add,還有其他幾個方法,這裡說明下:
fragmentTransaction.add 往activity中添加一個fragment
fragmentTransaction.remove 銷毀一個fragment
fragmentTransaction.replace 替換一個fragment,也就是先後執行remove和add操作
fragmentTransaction.hide 隱藏一個fragment,如果跳轉到另外一個fragment後,不希望當前的fragment被remove,那麼hide是絕佳選擇
fragmentTransaction.show,顯示一個fragment,接下來我們在fragment1 裡的按鈕點擊next的時候再新建一個fragment:
MyFragment2 fragment2 = new MyFragment2();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.hide(MyFragment.this);
fragmentTransaction.add(R.id.content,fragment2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
注意這句fragmentTransaction.addToBackStack(null);,加入回退棧的意思,如果希望在點返回按鈕的時候,能夠類似activity一樣,返回到剛才的fragment,那麼就需要加入回退棧,否則點擊返回鍵,無法回到上一個fragment,而是全部銷毀了。
好,接下來說一個當年面試被問到的問題,當我們旋轉屏幕的時候,activity的生命周期重新執行,那麼fragment的生命周期也重新執行,比如現在在fragment2的界面,旋轉屏幕後,發現fragment1也出現了,怎麼解決這個問題呢,其實很簡單,在屏幕旋轉的時候或者資源不夠被殺的時候,Activity中的protected void onCreate(Bundle savedInstanceState)函數裡savedInstanceState會保存一些值,也就是不為null,所以解決這個問題的辦法,加入savedInstanceState為null判斷即可,如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
MyFragment fragment1 = new MyFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.content, fragment1);
fragmentTransaction.commit();
}
}
}
接下來講下Activity向fragment數據傳遞,在activity裡獲取到fragment,然後調用fragment的setArguments方法進行傳遞,參數是Bundle,然後在Fragment通過getArguments獲取到剛才的Bundle,就可以得到傳遞的值了。
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment2 myFragment2 = new MyFragment2();
String argument = getIntent().getStringExtra(MyFragment.ARGUMENT);
Bundle bundle = new Bundle();
bundle.putString(MyFragment.ARGUMENT,argument);
myFragment2.setArguments(bundle);
fragmentTransaction.add(R.id.content2,myFragment2);
fragmentTransaction.commit();
Bundle bundle = getArguments();
if(bundle != null){
mArgument = bundle.getString(MyFragment.ARGUMENT);
Intent intent = new Intent();
intent.putExtra(MyFragment.RESPONSE,"From OhterActivity");
getActivity().setResult(MyFragment.REQUEST,intent);
}
這兩段代碼只關注我剛才說的點即可,其余代碼是用在另外一個場景,現在就說:
Fragment中可以類似activity一樣調用startActivityForResult來啟動另外一個Activity,並且有自己的onActivityResult函數,但是沒有setResult函數,其實也很好解決,用Activity的setResult即可,在Fragment中可以調用getActivity()得到當前的Activity,下面是這樣一個場景,在Fragment調用startActivityForResult啟動一個OtherActivity,然後在OtherActivity裡還有一個Fragment2,在Fragment2裡調用OtherActivity.setResult返回,最後fragment1中的回調onActivityResult執行,下面貼出關鍵代碼:
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(),OtherActivity.class);
intent.putExtra(ARGUMENT,"from MainActivity");
startActivityForResult(intent,REQUEST);
}
});
在第一個Fragment中startActivityForResult啟動OtherActivity:
public class OtherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
if(savedInstanceState == null){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment2 myFragment2 = new MyFragment2();
String argument = getIntent().getStringExtra(MyFragment.ARGUMENT);
Bundle bundle = new Bundle();
bundle.putString(MyFragment.ARGUMENT,argument);
myFragment2.setArguments(bundle);
fragmentTransaction.add(R.id.content2,myFragment2);
fragmentTransaction.commit();
}
}
}
在OtherActivity 中把得到的數據傳遞給MyFragment2 ,下面看MyFragment2的onCreate函數
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG,"MyFragment2 onCreate");
Bundle bundle = getArguments();
if(bundle != null){
mArgument = bundle.getString(MyFragment.ARGUMENT);
Intent intent = new Intent();
intent.putExtra(MyFragment.RESPONSE,"From OhterActivity");
getActivity().setResult(MyFragment.REQUEST,intent);
}
}
調用getArguments得到傳遞的數據,然後getActivity().setResult返回,最後看下第一個fragment的onActivityResult:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e(TAG,"MyFragment1 onActivityResult");
Log.e(TAG,"requestCode = " + requestCode);
if(requestCode == REQUEST){
mTextView.setText(data.getStringExtra(RESPONSE));
}
}
完整過程結束。
下面說另外一個問題,剛才是啟動另外一個Activity,然後再跟另外一個Activity中的fragment進行數據傳遞,如果是一個Activity呢,fragment中用setTargetFragment和getTargetFragment進行數據傳遞,下面看例子代碼:
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyFragment2 fragment2 = new MyFragment2();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragment2.setTargetFragment(MyFragment.this,REQUEST);
fragmentTransaction.hide(MyFragment.this);
fragmentTransaction.add(R.id.content,fragment2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return view;
我們看到這裡多了一句fragment2.setTargetFragment(MyFragment.this,REQUEST);,然後看fragment2中的代碼:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.e(TAG,"MyFragment2 onCreateView");
View view = inflater.inflate(R.layout.myfragment_layout2,container,false);
Intent intent = new Intent();
intent.putExtra(MyFragment.RESPONSE,"fragment回傳參數");
getTargetFragment().onActivityResult(MyFragment.REQUEST, Activity.RESULT_OK,intent);
return view;
}
getTargetFragment得到剛才setTargetFragment的fragment,然後調用了fragment的onActivityResult方法進行數據回傳。
好了, Fragment就分析到這裡,寫的比較倉促,如有問題,歡迎指正,謝謝。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11