Fragment代表一个UI界面或一个任务;有自己的生命周期,但依赖于Activity;让代码模块化,结构更清晰;方便重用,创建动态UI。
1、例一:
1) MainActivity.java
/**
* <p>Fragment的意义:</p>
* <ul><li>让代码模块化,更清晰;<li>代表一个界面或后台操作;<li>有生命周期但依赖于Activity;<li>可重用,创建动态UI,方便调整界面</ul>
*/
public class MainActivity extends FragmentActivity implements OnStringChangedListener{
private static final String TAG = MainActivity.class.getSimpleName();
TextView tv;
/**
* container for fragments,执行Fragment的增、删、替换和查找
*/
FragmentManager mFragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.txt);
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container_title, new TitleFragment(), "title");
fragmentTransaction.add(R.id.container_detail, new DetailFragment(), "detail");
fragmentTransaction.add(new BackFragment(), "back");
fragmentTransaction.commit();
}
@Override
protected void onStart() {
Log.d(TAG, "onStart");
super.onStart();
}
@Override
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
}
@Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.d(TAG, "onSaveInstanceState");
super.onSaveInstanceState(outState);
}
public void onClick(View v){
switch(v.getId()){
case R.id.btn:
//通过setVisibility来改变UI
if(tv.getVisibility()!=View.VISIBLE){
tv.setVisibility(View.VISIBLE);
}else{
tv.setVisibility(View.GONE);
}
break;
case R.id.btn_interact:
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
// fragmentTransaction.remove(mFragmentManager.findFragmentByTag("detail"));
// fragmentTransaction.add(R.id.container_detail, new OtherFragment(), "other");
//相当于remove&add或add
fragmentTransaction.replace(R.id.container_detail, new OtherFragment(), "other");
//摁back键返回到前一个布局或回滚到前一个已执行的transaction
fragmentTransaction.addToBackStack(null);
//进入退出动画
// fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.setCustomAnimations(R.anim.move_next_in, R.anim.move_next_out,
R.anim.move_previous_in, R.anim.move_previous_out);
fragmentTransaction.commit();
}
}
@Override
public void onStringChanged(String newStr) {
Log.d(TAG, "onStringChanged-"+newStr);
}
}
2) activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android"
android:baselineAligned="false">
<!-- <fragment android:name="com.qinuli.fragment.TitleFragment"
android:tag="title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#FFFF0000"/>
<fragment android:name="com.qinuli.fragment.DetailFragment"
android:tag="detail"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent"/> -->
<FrameLayout
android:id="@+id/container_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></FrameLayout>
<FrameLayout
android:id="@+id/container_detail"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"></FrameLayout>
</LinearLayout>
3) TitleFragment.java
public class TitleFragment extends Fragment {
private static final String TAG = TitleFragment.class.getSimpleName();
Button button;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_title, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
//通过Activity可搜索到其他Fragment中的View
button = (Button) getActivity().findViewById(R.id.btn_interact);
super.onActivityCreated(savedInstanceState);
}
public void changeColor(){
Log.d(TAG, "changeColor");
button.setBackgroundColor(Color.parseColor("#FF00FFFF"));
}
}
4) fragment_title.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Weather Forecast"
android:textSize="25sp"/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="changeState"
android:onClick="onClick"/>
<Button
android:id="@+id/btn_interact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="interact"
android:onClick="onClick"/>
</LinearLayout>
5) DetailFragment.java,演示生命周期
public class DetailFragment extends Fragment {
private static final String TAG = DetailFragment.class.getSimpleName();
private FragmentActivity mFragmentActivity;
@Override
public void onAttach(Activity activity) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onAttach(activity);
mFragmentActivity = (FragmentActivity) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
return inflater.inflate(R.layout.fragment_detail, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onStart();
}
@Override
public void onResume() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onResume();
}
@Override
public void onPause() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onPause();
}
@Override
public void onStop() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDetach();
}
}
6) fragment_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#FFFFFF00">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="clear and sunshiny"
android:textSize="20sp"/>
</LinearLayout>
7) OtherFragment.java,演示两个Fragment替换
public class OtherFragment extends Fragment {
private static final String TAG = OtherFragment.class.getSimpleName();
public interface OnStringChangedListener{
void onStringChanged(String newStr);
}
private String currentStr;
private OnStringChangedListener mOnStringChangedListener;
private void setStr(String newStr){
currentStr = newStr;
mOnStringChangedListener.onStringChanged(currentStr);
}
@Override
public void onAttach(Activity activity) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onAttach(activity);
mOnStringChangedListener = (OnStringChangedListener) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
return inflater.inflate(R.layout.fragment_other, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onActivityCreated(savedInstanceState);
getActivity().findViewById(R.id.btn_communication).setOnClickListener(mOnClickListener);
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onViewStateRestored(savedInstanceState);
}
@Override
public void onStart() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onStart();
}
@Override
public void onResume() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onResume();
}
@Override
public void onPause() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onPause();
}
@Override
public void onSaveInstanceState(Bundle outState) {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onSaveInstanceState(outState);
}
@Override
public void onStop() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
super.onDetach();
}
private OnClickListener mOnClickListener = new OnClickListener() {
private int count = 0;
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btn_communication:
setStr("点击"+(++count)+"次");
}
}
};
}
8) fragment_other.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFF00FF"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="outdoor activity"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_communication"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Communication"/>
</LinearLayout>
9) BackFragment.java,演示用Fragment执行一个后台任务
/**
* Caused by: java.lang.SecurityException: Neither user 10277 nor current process has android.permission.WAKE_LOCK.
* <li>每次安装APK,会分配一个唯一的Linux用户ID
* <li>安装时会有权限检查,未给APP请求权限,会报SecurityException
*/
public class BackFragment extends Fragment {
private static final String TAG = BackFragment.class.getSimpleName();
private MainActivity mActivity;
private MyAsyncTask myAsyncTask;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = (MainActivity) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
myAsyncTask = new MyAsyncTask();
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
myAsyncTask.execute("horse","wolf","fox");
super.onActivityCreated(savedInstanceState);
}
//通过WakeLock让屏幕常亮或防止手机进入休眠,属于PowerManager范畴
WakeLock mWakeLock;
private class MyAsyncTask extends AsyncTask<String, Integer, Character> {
@Override
protected Character doInBackground(String... params) {
PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
//创建WakeLock时指定类型
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
mWakeLock.acquire();
return 'T';
}
@Override
protected void onPostExecute(Character result) {
if(result.charValue()=='T'){
Log.d(TAG, "onPostExecute-"+result);
}
//通过Activity跟UI交互
mActivity.findViewById(R.id.btn).setBackgroundColor(Color.parseColor("#FFFF0000"));
//解耦合;跟其他Fragment交互
TitleFragment titleFragment = (TitleFragment) getActivity().getSupportFragmentManager().findFragmentByTag("title");
titleFragment.changeColor();
super.onPostExecute(result);
mWakeLock.release();
}
}
}
10) AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qinuli.fragment"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- targetSdkVersion和allowBackup用于API Level4及以上 -->
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity android:name="com.qinuli.fragment.MainActivity"
android:screenOrientation="portrait">
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
2、例二。Android平板有一种界面效果,左边菜单,右边内容。点每一个菜单项,显示不同同内容。这个用Fragment实现很方便。
下图是我做出的一个效果。
左边列表用一个ListFragment展示,右边点Spring时弹出一个Fragment,点Summer弹出另一个Fragment。
总共用到8个文件,一个Activity极其布局文件,左边ListFragment极其布局文件,右边两个Fragment极其布局文件。
先看下源代码
MainActivity.java
public class MainActivity extends Activity implements OnArticleSelectedListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onArticleSelected(int position) {
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
switch (position) {
case 0:
Fragment1 fragment1 = new Fragment1();
transaction.replace(R.id.layout, fragment1);
break;
case 1:
Fragment2 fragment2 = new Fragment2();
transaction.replace(R.id.layout, fragment2);
}
transaction.commit();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:weightSum="3"
android:baselineAligned="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<fragment
android:name="com.me.fragmenttest2.FragmentA"
android:id="@+id/fragmenta"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="@+id/layout"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="fill_parent"/>
</LinearLayout>
FragmentA.java
public class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
String[] seasons = {"Spring","Summer","Autumn","Winter"};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragmenta, container, false);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, seasons));
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Toast.makeText(getActivity(), seasons[position]+"-"+id, Toast.LENGTH_SHORT).show();
mListener.onArticleSelected(position);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()+" must implements OnArticleSelectedListener");
}
}
public interface OnArticleSelectedListener{
public void onArticleSelected(int position);
}
}
fragmenta.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"/>
</LinearLayout>
Fragment1.java
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container,false);
}
}
fragment1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/txt_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Congratulations"/>
</LinearLayout>
Fragment2.java
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment2, container,false);
}
}
fragment2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
activity_main.xml文件中的FrameLayout用于动态放置不同的Fragment。
这里面的难点在于左边ListFragment和Activity及右边Fragment通信,通过在ListFragment中创建内部接口OnArticleSelectedListener,并让Activity实现接口来实现。