Android基礎總結2 ---- Fragment與Activity
在Android的基礎中,除了各種控件的使用之外,Fragment和Activity也是很重要的知識點。本博文參考了慕課網的Android的教學資源,學習了一段時間,很有一種想和大家分享的衝動。
- 1.Fragment作爲Activity界面的一部分組成出現
- 2.可以在一個Activity中同時出現多個Fragment,並且,一個Fragment亦可在多個Activity中使用。
- 3.在Activity運行過程中,可以添加、移除或者替換Fragment(add()、remove()、replace())
- 4.Fragment可以響應自己的輸入事件,並且有自己的生命週期,當然,它們的生命週期直接被其所屬的宿主activity的生命週期影響。
下面是Fragment的生命週期的驗證程序:注意看註釋就明白了
package com.example.fragmentdome;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class MyFragment3 extends Fragment {
private TextView tv;
// 啓動Fragment——>屏幕鎖屏——>屏幕解鎖——>
//切換到其他的Fragment——>回到桌面——>回到應用——>退出Fragment
/**
* 每次創建都會繪製Fragment的View組件時回調該方法
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.fragment2, container, false);
TextView tv = (TextView) view.findViewById(R.id.text);
tv.setText("第一個Fragment");
Log.i("Main", "Fragment1---onCreateView()");
return view;
}
/**
* 當Fragment被添加到Activity時候會回調這個方法,並且只調用一次
*/
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
Log.i("Main", "Fragment1---onAttach()");
}
/**
* 創建Fragment時會回調,只會調用一次
*/
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Log.i("Main", "Fragment1---onCreate()");
}
/**
* 當Fragment所在的Activty啓動完成後調用
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Log.i("Main", "Fragment1---onActivityCreated()");
}
/**
* 啓動Fragment
*
*/
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.i("Main", "Fragment1---onStart()");
}
/**
* 恢復Fragment時會被回調,調用onStart()方法後面一定會調用onResume()方法
*/
@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.i("Main", "Fragment1---onResume()");
}
/**
* 暫停Fragment
*/
@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
Log.i("Main", "Fragment1---onPause()");
}
/**
* 停止Fragment
*/
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
Log.i("Main", "Fragment1---onStop()");
}
/**
* 銷燬Fragment所包含的View組件時
*/
@Override
public void onDestroyView() {
// TODO Auto-generated method stub
super.onDestroyView();
Log.i("Main", "Fragment1---onDestroyView()");
}
/**
* 銷燬Fragment時會被回調
*/
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i("Main", "Fragment1---onDestroy()");
}
/**
* Fragment從Activity中刪除時會回調該方法,並且這個方法只會調用一次
*/
@Override
public void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
Log.i("Main", "Fragment1---onDetach()");
}
}
接下來看看Fragment的實現吧:
1 爲Frangment添加用戶界面:
fragment一般作爲activity的用戶界面的一部分,把它自己的layout嵌入到activity的layout中。一個要fragment提供layout,你必須實現onCreateView()回調方法,然後在這個方法中返回一個View對象,這個對象是fragment的layout的根。看下面的代碼:
public class MyFragment extends Fragment{
private String aaa;
public String getAaa() {
return aaa;
}
public void setAaa(String aaa) {
this.aaa = aaa;
}
/*
* setContentView和inflate的區別
* setContentView()一旦調用, layout就會立刻顯示UI
* 而inflate只會把Layout形成一個以view類實現成的對象,有需要時再用setContentView(view)顯示出來。
* 一般在activity中通過setContentView()將界面顯示出來,但是如果在非activity中如何對控件佈局設置操作了,
* 這就需要LayoutInflater動態加載。
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//layout佈局文件轉換成View對象
/**
* inflate就相當於將一個xml中定義的佈局找出來.
* inflater.inflate(resource, root, attachToRoot);
* resource:Fragment需要加載的佈局文件
* root:加載layout的父ViewGroup
* attactToRoot:false,不返回父ViewGroup
*/
View view = inflater.inflate(R.layout.fragment, container, false);
TextView text=(TextView) view.findViewById(R.id.text);
Button button=(Button) view.findViewById(R.id.button);
text.setText("靜態加載Fragment");
button.setText("獲取內容");
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String value = getAaa();
Toast.makeText(getActivity(), "value="+value, Toast.LENGTH_SHORT).show();
<span style="white-space:pre"> </span>}
});
return view;
}
}
上面的代碼中還要注意註釋部分:
/*
* setContentView和inflate的區別
* setContentView()一旦調用, layout就會立刻顯示UI
* 而inflate只會把Layout形成一個以view類實現成的對象,有需要時再用setContentView(view)顯示出來
* 一般在activity中通過setContentView()將界面顯示出來,但是如果在非activity中如何對控件佈局設置操作了,
* 這就需要LayoutInflater動態加載。
*/
<pre name="code" class="java" style="font-size: 18px;">//layout佈局文件轉換成View對象
/**
* inflate就相當於將一個xml中定義的佈局找出來.
* inflater.inflate(resource, root, attachToRoot);
* resource:Fragment需要加載的佈局文件
* root:加載layout的父ViewGroup
* attactToRoot:false,不返回父ViewGroup
*/
注:如果你的fragment是從ListFragment中派生的,就不需要實現onCreateView()方法了,因爲默認的實現已經爲你返回了ListView控件對象。 要從onCreateView()方法中返回layout對象,你可以從layoutxml中生成layout對象。爲了幫助你這樣做,onCreateView()提供了一個LayoutInflater對象。
另外,onCreateView()參數中的container是存放fragment的layout的ViewGroup對象。savedInstanceState參數是一個Bundle,跟activity的onCreate()中Bundle差不多,用於狀態恢復。此處的Bundle中存放的數據與onCreate()中存放的數據還是不同的。
Inflate()方法有三個參數:
- 1 layout的資源ID。
- 2 存放fragment的layout的ViewGroup。
- 3 布爾型數據表示是否在創建fragment的layout期間,把layout附加到container上了
2 把Frangment添加到Activity:
在Activity中加載Frangment的方式有2種,一種是靜態加載(通過XML靜態配置),一種是動態加載(通過程序動態創建)。
如方法一:在activity的layoutxml文件中聲明fragment (靜態配置)
看程序:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發送" />
<!-- 靜態加載傳值 -->
<fragment
android:id="@+id/frag"
android:name="com.example.fragmentdome.MyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
當系統創建layout時,它實例化fragment,然後調用onCreateView()方法,以獲取fragment的layout。系統把fragment返回的view對象插入到<fragment>元素的位置,直接代替<fragment>元素。每個fragment都需要提供一個ID,系統在activity重新創建時用它來恢復fragment們,你也可以用它來操作fragment進行其它的事物,比如刪除它。
有三種方法給fragment提供ID:
- 1 爲android:id屬性賦一個數字。
- 2 爲android:tag屬性賦一個字符串。
- 3如果你沒有使用上述任何一種方法,系統將使用fragment的容器的ID
方法二:在代碼中添加fragment到一個ViewGroup(動態加載)
<span style="white-space:pre"> </span>MyFragment2 fragment2=new MyFragment2();
//從 FragmentManager 獲得一個FragmentTransaction的實例 :
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
//通過Fragment的ID來加載
beginTransaction.add(R.id.frame, fragment2);
/*
* 在調用commint()之前,你可以用addToBackStack()把事務添加到一個後退棧中,
* 這個後退棧屬於所在的activity。有了它,就可以在用戶按下返回鍵時,返回到fragment們執行事務之前的狀態。
*/
beginTransaction.addToBackStack(null);
beginTransaction.commit();
/*
* 解釋:調用addToBackStack(),fragment就被放入後退棧中,於是當用戶按下返回鍵時,事務發生回溯,原先的fragment又回來了。
* 如果你向事務添加了多個動作,比如多次調用了add(),remove()等之後又調用了addToBackStack()方法,
* 那麼所有的在commit()之前調用的方法都被作爲一個事務。當用戶按返回鍵時,所有的動作都被反向執行(事務回溯)。
* 事務中動作的執行順序可隨意,但要注意以下兩點:
* 1. 你必須最後調用commit()。
* 2. 如果你添加了多個fragment,那麼它們的顯示順序跟添加順序一至(後顯示的覆蓋前面的)。
*/
爲了完成fragment的事務(比如添加,刪除,替換等),你必須使用FragmentTransaction的方法。你可以從activity獲取到FragmentTransaction,如上面的
FragmentManager fragmentManager
= getFragmentManager()
FragmentTransaction fragmentTransaction
= fragmentManager.beginTransaction();
然後你可以用add()方法添加一個fragment;
最後必須調用方法commit()提交這些改變。
3 與其他Fragment的通訊
這個其實很簡單,依靠Frangment的事務處理機制發送數據。首先定義一個Bundle,將要出入的數據設置好。然後利用fragment.setArguments(bundle);發送數據包,利用管理者模式,管理事務的模式,通過Fragment的Tag方式來加載到指定的Frangment.最後不要忘了提交事務。看程序:
package com.example.fragmentdome;
import com.example.fragmentdome.MyFragment5.MyListener;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity4 extends Activity implements MyListener {
private EditText editext;
private Button send;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main4);
editext = (EditText) findViewById(R.id.editText);
send = (Button) findViewById(R.id.send);
send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String text = editext.getText().toString();
MyFragment5 fragment5 = new MyFragment5();
Bundle bundle = new Bundle();
bundle.putString("name", text);
//發送數據包
fragment5.setArguments(bundle);
//管理者模式,管理事務的模式
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction beginTransaction = fragmentManager
.beginTransaction();
//通過Fragment的Tag方式來加載
beginTransaction.add(R.id.layout, fragment5, "fragment5");
beginTransaction.commit();
Toast.makeText(MainActivity4.this, "向Fragment發送數據" + text,
Toast.LENGTH_SHORT).show();
}
});
FragmentManager fragmentManager = getFragmentManager();
Fragment findFragmentById = fragmentManager.findFragmentById(R.id.frag);
MyFragment frag=(MyFragment) findFragmentById;
frag.setAaa("fragment靜態傳值");
}
@Override
public void thank(String code) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity4.this, "已成功接收到" + code + ",客氣了!",
Toast.LENGTH_SHORT).show();
}
}